diff --git a/.gitignore b/.gitignore index d4ea73c8..651d8ec 100644 --- a/.gitignore +++ b/.gitignore
@@ -319,6 +319,7 @@ /tools/metrics/histograms/metadata/*/*.before.pretty-print.xml /tools/metrics/histograms/enums.before.pretty-print.xml /tools/page_cycler/acid3 +/tools/bluetooth /tools/reclient /tools/skia_goldctl/ /tools/tryserver
diff --git a/DEPS b/DEPS index f6e2f7f..5f96c95 100644 --- a/DEPS +++ b/DEPS
@@ -297,15 +297,15 @@ # 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': 'faf97e5d2c2b879cb64db6da8599262b7674b807', + 'skia_revision': '0cc4b51ab9d5c72c052db4cf3782583df0dfa44e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '1104a81a2a08c3b25b400d2ddf283573e14eb9e5', + 'v8_revision': 'f43f657e166b75db1f91f9f554ec8c474f87194b', # 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': '6f80f0f0373f9b4f014264e337443939021461b6', + 'angle_revision': '8050079c116c993a5385737da12ad871c4f53fed', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -376,7 +376,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '82d6d5debc352225088c5d78ff2168955fbc204f', + 'devtools_frontend_revision': '50a84ca8e5b556e27bb285477f21a99f0ccb7050', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -412,7 +412,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '6d5542d7036730f268bf1deb2d566ba815436caf', + 'dawn_revision': '1eed2c2e3638a0c2fbb9494549798cea096d15e5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -440,7 +440,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': 'c495cf830fe2fc59de34beacfe0356f4405f9c0d', + 'nearby_revision': '0a8f1f1c39af06dff550d8ca96c6e087994155b7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -460,7 +460,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'libunwind_revision': 'c38cbd4028118906853431635e8dbb74a90ad0a2', + 'libunwind_revision': 'a097a1ada6ca6a585f90299b934695dffb88914c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -773,7 +773,7 @@ Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248', 'src/docs/website': { - 'url': Var('chromium_git') + '/website.git' + '@' + '47ba73287a73719d6f61024b639a86c09e0ba395', + 'url': Var('chromium_git') + '/website.git' + '@' + 'e1675f6b5f878818b9ecc355be8186061867c170', }, 'src/ios/third_party/earl_grey2/src': { @@ -1693,7 +1693,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@3cb199eedd80578a2c0cf432035f929ee8a04d44', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@30403bafe4dc5b14e820ae922278455053e8f7e2', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907', @@ -1805,7 +1805,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@635d7982b4eb830d18a166ef5a48a1d43c71d57a', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@fe63cb6846edc3c548739c989e6a85a6fa568bde', 'condition': 'checkout_src_internal', }, @@ -1846,7 +1846,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'pTtXmCT6pCQDy2Z0lHJNTWGGH5n-fjbP9MSHP2JQ62YC', + 'version': 'nn5KvAAoMD72nH1CAMYRwvmbBl3GUz-LY98pkeumiT0C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 8648e65..433fa73 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -4779,7 +4779,12 @@ input_api.re.MULTILINE) extension_re = input_api.re.compile(r'\.[a-z]+$') errors = [] + config_h_file = input_api.os_path.join('build', 'build_config.h') for f in input_api.AffectedFiles(include_deletes=False): + # The build-config macros are allowed to be used in build_config.h + # without including itself. + if f.LocalPath() == config_h_file: + continue if not f.LocalPath().endswith( ('.h', '.c', '.cc', '.cpp', '.m', '.mm')): continue @@ -4882,8 +4887,11 @@ def CheckForDeprecatedOSMacros(input_api, output_api): """Check all affected files for invalid OS macros.""" bad_macros = [] + # The OS_ macros are allowed to be used in build/build_config.h. + config_h_file = input_api.os_path.join('build', 'build_config.h') for f in input_api.AffectedSourceFiles(None): - if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')): + if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \ + and f.LocalPath() != config_h_file: bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f)) if not bad_macros:
diff --git a/WATCHLISTS b/WATCHLISTS index b02a189..bd6ef14 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -2571,8 +2571,7 @@ 'drive_resource_metadata': ['hashimoto+watch@chromium.org'], 'eme': ['eme-reviews@chromium.org'], 'enterprise_connectors': ['dpr-eng@google.com'], - 'enterprise_reporting_private': ['domfc+watch@chromium.org', - 'anthonyvd+watch@chormium.org'], + 'enterprise_reporting_private': ['anthonyvd+watch@chormium.org'], 'exo': ['crostini-ui+exo@chromium.org', 'yhanada+watchexo@chromium.org'], 'explore_sites': ['chili+watch@chromium.org',
diff --git a/android_webview/browser/gfx/output_surface_provider_webview.cc b/android_webview/browser/gfx/output_surface_provider_webview.cc index a990ecc60..52c859cc 100644 --- a/android_webview/browser/gfx/output_surface_provider_webview.cc +++ b/android_webview/browser/gfx/output_surface_provider_webview.cc
@@ -29,6 +29,7 @@ #include "ui/gl/gl_context.h" #include "ui/gl/gl_share_group.h" #include "ui/gl/gl_surface_egl.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace android_webview { @@ -49,7 +50,8 @@ if (surface && context) return std::make_pair(std::move(surface), std::move(context)); - surface = gl::init::CreateOffscreenGLSurface(gfx::Size(1, 1)); + surface = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplayEGL(), + gfx::Size(1, 1)); DCHECK(surface); // Allow context and surface to be null and just fallback to // not having any real EGL context in that case instead of crashing.
diff --git a/android_webview/browser/gfx/test/fake_window.cc b/android_webview/browser/gfx/test/fake_window.cc index d9acb36..f6c7c81 100644 --- a/android_webview/browser/gfx/test/fake_window.cc +++ b/android_webview/browser/gfx/test/fake_window.cc
@@ -14,6 +14,7 @@ #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace android_webview { @@ -195,7 +196,8 @@ void FakeWindow::InitializeOnRT(base::WaitableEvent* sync) { CheckCurrentlyOnRT(); - surface_ = gl::init::CreateOffscreenGLSurface(surface_size_); + surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplayEGL(), + surface_size_); DCHECK(surface_); DCHECK(surface_->GetHandle()); context_ = gl::init::CreateGLContext(nullptr, surface_.get(),
diff --git a/android_webview/browser/gfx/test/fake_window.h b/android_webview/browser/gfx/test/fake_window.h index 7742f9d..328764a 100644 --- a/android_webview/browser/gfx/test/fake_window.h +++ b/android_webview/browser/gfx/test/fake_window.h
@@ -95,7 +95,7 @@ scoped_refptr<base::SingleThreadTaskRunner> render_thread_loop_; scoped_refptr<gl::GLSurface> surface_; scoped_refptr<gl::GLContext> context_; - bool context_current_; + bool context_current_ = false; base::WeakPtrFactory<FakeWindow> weak_ptr_factory_{this}; };
diff --git a/android_webview/browser/gfx/test/invalidate_test.cc b/android_webview/browser/gfx/test/invalidate_test.cc index 925c0c3..96943cd 100644 --- a/android_webview/browser/gfx/test/invalidate_test.cc +++ b/android_webview/browser/gfx/test/invalidate_test.cc
@@ -21,6 +21,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace android_webview { @@ -279,8 +280,8 @@ // explicitly. render_thread_manager_ = std::make_unique<RenderThreadManager>( base::ThreadTaskRunnerHandle::Get()); - - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size(100, 100)); + surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplayEGL(), + gfx::Size(100, 100)); DCHECK(surface_); DCHECK(surface_->GetHandle()); context_ = gl::init::CreateGLContext(nullptr, surface_.get(),
diff --git a/android_webview/common/aw_features.cc b/android_webview/common/aw_features.cc index 5957e3f..2e0c9e9 100644 --- a/android_webview/common/aw_features.cc +++ b/android_webview/common/aw_features.cc
@@ -110,7 +110,7 @@ // invalidates the URL after). const base::Feature kWebViewSynthesizePageLoadOnlyOnInitialMainDocumentAccess{ "WebViewSynthesizePageLoadOnlyOnInitialMainDocumentAccess", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; } // namespace features } // namespace android_webview
diff --git a/ash/app_list/test/app_list_test_helper.h b/ash/app_list/test/app_list_test_helper.h index 8adec0c..598b1856 100644 --- a/ash/app_list/test/app_list_test_helper.h +++ b/ash/app_list/test/app_list_test_helper.h
@@ -153,6 +153,7 @@ std::vector<ash::AppListSearchResultCategory>* GetOrderedResultCategories(); test::AppListTestModel* model() { return &model_; } + SearchModel* search_model() { return &search_model_; } TestAppListClient* app_list_client() { return app_list_client_.get(); } private:
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 f1bd064..4ef0c1c5 100644 --- a/ash/app_list/views/app_list_main_view_unittest.cc +++ b/ash/app_list/views/app_list_main_view_unittest.cc
@@ -7,43 +7,35 @@ #include <memory> #include <string> -#include "ash/app_list/app_list_test_view_delegate.h" +#include "ash/app_list/app_list_model_provider.h" #include "ash/app_list/model/app_list_test_model.h" +#include "ash/app_list/test/app_list_test_helper.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" #include "ash/app_list/views/contents_view.h" #include "ash/app_list/views/page_switcher.h" #include "ash/app_list/views/paged_apps_grid_view.h" #include "ash/app_list/views/search_box_view.h" #include "ash/constants/ash_features.h" -#include "ash/public/cpp/app_list/app_list_features.h" -#include "ash/public/cpp/test/test_app_list_color_provider.h" -#include "ash/style/ash_color_provider.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/test/scoped_feature_list.h" #include "ui/compositor/layer.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/events/base_event_utils.h" #include "ui/events/keycodes/keyboard_codes_posix.h" #include "ui/events/types/event_type.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/test/button_test_api.h" -#include "ui/views/test/views_test_base.h" #include "ui/views/view_model.h" -#include "ui/views/widget/widget.h" namespace ash { -namespace { - -const size_t kInitialItems = 2; - -} // namespace // Parameterized by ProductivityLauncher. -class AppListMainViewTest : public views::ViewsTestBase, +class AppListMainViewTest : public AshTestBase, public testing::WithParamInterface<bool> { public: AppListMainViewTest() { @@ -56,24 +48,22 @@ // testing::Test overrides: void SetUp() override { - views::ViewsTestBase::SetUp(); - zero_duration_mode_ = - std::make_unique<ui::ScopedAnimationDurationScaleMode>( - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION); + AshTestBase::SetUp(); - // Create, and show the app list is fullscreen apps grid state. - delegate_ = std::make_unique<test::AppListTestViewDelegate>(); - app_list_view_ = new AppListView(delegate_.get()); - app_list_view_->InitView(GetContext()); - app_list_view_->Show(AppListViewState::kFullscreenAllApps, - /*is_side_shelf=*/false); - EXPECT_TRUE(app_list_view_->GetWidget()->IsVisible()); + // Create and show the app list in fullscreen apps grid state. + auto* helper = GetAppListTestHelper(); + if (features::IsProductivityLauncherEnabled()) { + // Tablet mode uses a fullscreen AppListMainView. + Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true); + } else { + helper->Show(GetPrimaryDisplay().id()); + helper->GetAppListView()->SetState(AppListViewState::kFullscreenAllApps); + } + app_list_view_ = helper->GetAppListView(); } - void TearDown() override { - app_list_view_->GetWidget()->Close(); - zero_duration_mode_.reset(); - views::ViewsTestBase::TearDown(); + test::AppListTestModel* GetTestModel() { + return GetAppListTestHelper()->model(); } // |point| is in |grid_view|'s coordinates. @@ -88,29 +78,6 @@ : static_cast<AppListItemView*>(iter->view); } - void SimulateKeyPress(ui::KeyboardCode key_code) { - ui::KeyEvent key_press(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE); - app_list_view_->GetWidget()->OnKeyEvent(&key_press); - - ui::KeyEvent key_release(ui::ET_KEY_RELEASED, key_code, ui::EF_NONE); - app_list_view_->GetWidget()->OnKeyEvent(&key_release); - } - - void SimulateClick(views::View* view) { - gfx::Point center = view->GetLocalBounds().CenterPoint(); - views::View::ConvertPointToWidget(view, ¢er); - - ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, center, center, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_RIGHT_MOUSE_BUTTON); - view->GetWidget()->OnMouseEvent(&press_event); - - ui::MouseEvent release_event( - ui::ET_MOUSE_RELEASED, center, center, ui::EventTimeForNow(), - ui::EF_LEFT_MOUSE_BUTTON, ui::EF_RIGHT_MOUSE_BUTTON); - view->GetWidget()->OnMouseEvent(&release_event); - } - // |point| is in |grid_view|'s coordinates. AppListItemView* SimulateInitiateDrag(AppsGridView* grid_view, const gfx::Point& point) { @@ -177,11 +144,10 @@ AppListItemView* CreateAndOpenSingleItemFolder() { // Prepare single folder with a single item in it. AppListFolderItem* folder_item = - delegate_->GetTestModel()->CreateSingleItemFolder("single_item_folder", - "single"); + GetTestModel()->CreateSingleItemFolder("single_item_folder", "single"); GetRootGridView()->Layout(); EXPECT_EQ(folder_item, - delegate_->GetTestModel()->FindFolderItem("single_item_folder")); + GetTestModel()->FindFolderItem("single_item_folder")); EXPECT_EQ(AppListFolderItem::kItemType, folder_item->GetItemType()); EXPECT_EQ(1u, GetRootViewModel()->view_size()); @@ -191,7 +157,7 @@ // Click on the folder to open it. EXPECT_FALSE(GetFolderView()->GetVisible()); - SimulateClick(folder_item_view); + LeftClickOn(folder_item_view); EXPECT_TRUE(GetFolderView()->GetVisible()); @@ -229,11 +195,6 @@ return dragged; } - void PressKeyInSearchBox(ui::KeyboardCode key_code) { - ui::KeyEvent press(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE); - search_box_view()->search_box()->OnKeyEvent(&press); - } - void ClickButton(views::Button* button) { views::test::ButtonTestApi(button).NotifyClick(ui::MouseEvent( ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(), @@ -242,13 +203,7 @@ protected: base::test::ScopedFeatureList feature_list_; - TestAppListColorProvider app_list_color_provider_; // Needed by AppListView. - AshColorProvider ash_color_provider_; // Needed by ContinueContainer. - AppListView* app_list_view_ = nullptr; // Owned by native widget. - std::unique_ptr<test::AppListTestViewDelegate> delegate_; - - private: - std::unique_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_; + AppListView* app_list_view_ = nullptr; // Owned by native widget. }; INSTANTIATE_TEST_SUITE_P(ProductivityLauncher, @@ -257,39 +212,45 @@ // Tests that the close button becomes invisible after close button is clicked. TEST_P(AppListMainViewTest, CloseButtonInvisibleAfterCloseButtonClicked) { - PressKeyInSearchBox(ui::VKEY_A); + PressAndReleaseKey(ui::VKEY_A); ClickButton(search_box_view()->close_button()); EXPECT_FALSE(search_box_view()->close_button()->GetVisible()); } // Tests that the search box becomes empty after close button is clicked. TEST_P(AppListMainViewTest, SearchBoxEmptyAfterCloseButtonClicked) { - PressKeyInSearchBox(ui::VKEY_A); + PressAndReleaseKey(ui::VKEY_A); ClickButton(search_box_view()->close_button()); EXPECT_TRUE(search_box_view()->search_box()->GetText().empty()); } // Tests that the search box is no longer active after close button is clicked. TEST_P(AppListMainViewTest, SearchBoxActiveAfterCloseButtonClicked) { - PressKeyInSearchBox(ui::VKEY_A); + PressAndReleaseKey(ui::VKEY_A); ClickButton(search_box_view()->close_button()); EXPECT_FALSE(search_box_view()->is_search_box_active()); } // Tests changing the AppListModel when switching profiles. TEST_P(AppListMainViewTest, ModelChanged) { - delegate_->GetTestModel()->PopulateApps(kInitialItems); + const size_t kInitialItems = 2; + GetTestModel()->PopulateApps(kInitialItems); EXPECT_EQ(kInitialItems, GetRootViewModel()->view_size()); - // The model is owned by a profile keyed service, which is never destroyed - // until after profile switching. - std::unique_ptr<AppListModel> old_model(delegate_->ReleaseTestModel()); - std::unique_ptr<SearchModel> old_search_model( - delegate_->ReleaseTestSearchModel()); + AppListModel* old_model = GetAppListTestHelper()->model(); + SearchModel* old_search_model = GetAppListTestHelper()->search_model(); + // Simulate a profile switch (which switches the app list models). + auto search_model = std::make_unique<SearchModel>(); + auto model = std::make_unique<test::AppListTestModel>(); const size_t kReplacementItems = 5; - delegate_->ReplaceTestModel(kReplacementItems); + model->PopulateApps(kReplacementItems); + AppListModelProvider::Get()->SetActiveModel(model.get(), search_model.get()); EXPECT_EQ(kReplacementItems, GetRootViewModel()->view_size()); + + // Replace the old model so observers on `model` are removed before test + // shutdown. + AppListModelProvider::Get()->SetActiveModel(old_model, old_search_model); } // Tests dragging an item out of a single item folder and dropping it onto the @@ -301,7 +262,7 @@ // Number of apps to populate. Should provide more than 1 page of apps (5*4 = // 20). const size_t kNumApps = 30; - delegate_->GetTestModel()->PopulateApps(kNumApps); + GetTestModel()->PopulateApps(kNumApps); GetRootGridView()->Layout(); EXPECT_EQ(1u, GetFolderViewModel()->view_size()); @@ -321,7 +282,7 @@ // The folder should not be destroyed. EXPECT_EQ(kNumApps + 1, GetRootViewModel()->view_size()); AppListFolderItem* const folder_item = - delegate_->GetTestModel()->FindFolderItem("single_item_folder"); + GetTestModel()->FindFolderItem("single_item_folder"); ASSERT_TRUE(folder_item); EXPECT_EQ(1u, folder_item->item_list()->item_count()); } @@ -336,7 +297,7 @@ // Now add an item to the model, not in any folder, e.g., as if by Sync. EXPECT_TRUE(GetRootGridView()->has_dragged_item()); EXPECT_TRUE(GetFolderGridView()->has_dragged_item()); - delegate_->GetTestModel()->CreateAndAddItem("Extra"); + GetTestModel()->CreateAndAddItem("Extra"); // The drag operation should get canceled. EXPECT_FALSE(GetRootGridView()->has_dragged_item()); @@ -358,7 +319,7 @@ std::string folder_id = folder_item_view->item()->id(); // Add another top level app. - delegate_->GetTestModel()->PopulateApps(1); + GetTestModel()->PopulateApps(1); gfx::Point drag_point = folder_item_view->bounds().CenterPoint(); views::View::ConvertPointToTarget(GetRootGridView(), GetFolderGridView(), @@ -375,7 +336,7 @@ EXPECT_EQ(2u, GetRootViewModel()->view_size()); EXPECT_EQ(folder_id, GetRootGridView()->GetItemViewAt(0)->item()->id()); AppListFolderItem* const folder_item = - delegate_->GetTestModel()->FindFolderItem("single_item_folder"); + GetTestModel()->FindFolderItem("single_item_folder"); ASSERT_TRUE(folder_item); EXPECT_EQ(1u, folder_item->item_list()->item_count()); }
diff --git a/ash/app_list/views/app_list_view_unittest.cc b/ash/app_list/views/app_list_view_unittest.cc index 6ced33d9..c4b63963 100644 --- a/ash/app_list/views/app_list_view_unittest.cc +++ b/ash/app_list/views/app_list_view_unittest.cc
@@ -13,7 +13,6 @@ #include <utility> #include <vector> -#include "ash/app_list/app_list_metrics.h" #include "ash/app_list/app_list_test_view_delegate.h" #include "ash/app_list/model/app_list_test_model.h" #include "ash/app_list/model/search/search_box_model.h" @@ -36,7 +35,6 @@ #include "ash/app_list/views/search_result_container_view.h" #include "ash/app_list/views/search_result_list_view.h" #include "ash/app_list/views/search_result_page_view.h" -#include "ash/app_list/views/search_result_suggestion_chip_view.h" #include "ash/app_list/views/search_result_tile_item_list_view.h" #include "ash/app_list/views/search_result_tile_item_view.h" #include "ash/app_list/views/search_result_view.h" @@ -44,7 +42,6 @@ #include "ash/constants/ash_features.h" #include "ash/keyboard/ui/keyboard_ui_controller.h" #include "ash/public/cpp/app_list/app_list_config.h" -#include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/app_list/app_list_types.h" #include "ash/public/cpp/pagination/pagination_model.h" #include "ash/public/cpp/test/test_app_list_color_provider.h" @@ -52,14 +49,12 @@ #include "ash/style/ash_color_provider.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/test/icu_test_util.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/models/simple_menu_model.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animator.h" #include "ui/compositor/presentation_time_recorder.h" @@ -73,9 +68,12 @@ #include "ui/views/view_model.h" namespace ash { -namespace test { namespace { +using test::AppListTestModel; +using test::AppListTestViewDelegate; +using test::AppsGridViewTestApi; + constexpr int kInitialItems = 34; constexpr int kMaxItemsPerFolderPage = AppListFolderView::kMaxFolderColumns * @@ -786,8 +784,8 @@ view_->SetState(state); } - void Show(bool is_side_shelf = false) { - view_->Show(AppListViewState::kPeeking, is_side_shelf); + void Show() { + view_->Show(AppListViewState::kPeeking, /*is_side_shelf=*/false); } SearchResultTileItemListView* GetSearchResultTileItemListView() { @@ -840,7 +838,7 @@ } // Adding results will schedule Update(). - RunPendingMessages(); + base::RunLoop().RunUntilIdle(); } // Add search results for test on embedded Assistant UI. @@ -867,7 +865,7 @@ } // Adding results will schedule Update(). - RunPendingMessages(); + base::RunLoop().RunUntilIdle(); } void ClearSearchResults() { GetSearchModel()->results()->DeleteAll(); } @@ -881,7 +879,7 @@ result->SetTitle(ASCIIToUTF16(title)); result->set_best_match(true); GetSearchModel()->results()->Add(std::move(result)); - RunPendingMessages(); + base::RunLoop().RunUntilIdle(); } int GetOpenFirstSearchResultCount() { @@ -3050,7 +3048,7 @@ RegularLandscapeScreenAtMinPreferredVerticalMargin) { const int window_height = GetExpectedScreenSizeForProductivityLauncher( /*row_count=*/4, /*tile_height=*/120, /*tile_margins=*/8, - /*large_height=*/false); + /*is_large_height=*/false); EXPECT_EQ(689, window_height); const gfx::Size window_size = gfx::Size(800, window_height); GetContext()->SetBounds(gfx::Rect(window_size)); @@ -3085,7 +3083,7 @@ RegularLandscapeScreenWithRemovedRows) { const int window_height = GetExpectedScreenSizeForProductivityLauncher( /*row_count=*/4, /*tile_height=*/120, - /*tile_margins=*/8, /*large_height=*/false) - + /*tile_margins=*/8, /*is_large_height=*/false) - 4; EXPECT_EQ(685, window_height); const gfx::Size window_size = gfx::Size(800, window_height); @@ -3121,7 +3119,7 @@ RegularLandscapeScreenAtMaxPreferredVerticalMargin) { const int window_height = GetExpectedScreenSizeForProductivityLauncher( /*row_count=*/4, /*tile_height=*/120, /*tile_margins=*/96, - /*large_height=*/true); + /*is_large_height=*/true); EXPECT_EQ(1024, window_height); const gfx::Size window_size = gfx::Size(1100, window_height); GetContext()->SetBounds(gfx::Rect(window_size)); @@ -3156,7 +3154,7 @@ RegularLandscapeScreenWithAddedRows) { const int window_height = GetExpectedScreenSizeForProductivityLauncher( /*row_count=*/4, /*tile_height=*/120, - /*tile_margins=*/96, /*large_height=*/true) + + /*tile_margins=*/96, /*is_large_height=*/true) + 6; EXPECT_EQ(1030, window_height); const gfx::Size window_size = gfx::Size(1100, window_height); @@ -3222,7 +3220,7 @@ RegularPortraitScreenAtMinPreferredVerticalMargin) { int window_height = GetExpectedScreenSizeForProductivityLauncher( /*row_count=*/5, /*tile_height=*/120, /*tile_margins=*/8, - /*large_height=*/true); + /*is_large_height=*/true); // window_height = 860; EXPECT_EQ(868, window_height); const gfx::Size window_size = gfx::Size(700, window_height); @@ -3259,7 +3257,7 @@ const int window_height = GetExpectedScreenSizeForProductivityLauncher( /*row_count=*/5, /*tile_height=*/120, /*tile_margins=*/8, - /*large_height=*/true) - + /*is_large_height=*/true) - 8; EXPECT_EQ(860, window_height); const gfx::Size window_size = gfx::Size(700, window_height); @@ -3295,7 +3293,7 @@ RegularPortraitScreenAtMaxPreferredVerticalMargin) { const int window_height = GetExpectedScreenSizeForProductivityLauncher( /*row_count=*/5, /*tile_height=*/120, /*tile_margins=*/96, - /*large_height=*/true); + /*is_large_height=*/true); EXPECT_EQ(1270, window_height); const gfx::Size window_size = gfx::Size(1200, window_height); GetContext()->SetBounds(gfx::Rect(window_size)); @@ -3330,7 +3328,7 @@ const int window_height = GetExpectedScreenSizeForProductivityLauncher( /*row_count=*/5, /*tile_height=*/120, /*tile_margins=*/96, - /*large_height=*/true) + + /*is_large_height=*/true) + 4; EXPECT_EQ(1274, window_height); const gfx::Size window_size = gfx::Size(1200, window_height); @@ -3395,7 +3393,7 @@ DenseLandscapeScreenAtMinPreferredVerticalMargin) { const int window_height = GetExpectedScreenSizeForProductivityLauncher( /*row_count=*/4, /*tile_height=*/88, /*tile_margins=*/8, - /*large_height=*/false); + /*is_large_height=*/false); EXPECT_EQ(552, window_height); const gfx::Size window_size = gfx::Size(800, window_height); GetContext()->SetBounds(gfx::Rect(window_size)); @@ -4061,5 +4059,4 @@ } } // namespace -} // namespace test } // namespace ash
diff --git a/ash/components/arc/net/always_on_vpn_manager.cc b/ash/components/arc/net/always_on_vpn_manager.cc index 5a356d1..1a7abe2 100644 --- a/ash/components/arc/net/always_on_vpn_manager.cc +++ b/ash/components/arc/net/always_on_vpn_manager.cc
@@ -33,7 +33,7 @@ registrar_.prefs()->GetString(prefs::kAlwaysOnVpnPackage); bool lockdown = registrar_.prefs()->GetBoolean(prefs::kAlwaysOnVpnLockdown); if (lockdown && !package.empty()) { - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_configuration_handler() ->SetManagerProperty(shill::kAlwaysOnVpnPackageProperty, base::Value(std::string())); @@ -49,7 +49,7 @@ always_on_vpn_package = registrar_.prefs()->GetString(prefs::kAlwaysOnVpnPackage); } - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_configuration_handler() ->SetManagerProperty(shill::kAlwaysOnVpnPackageProperty, base::Value(always_on_vpn_package));
diff --git a/ash/components/arc/net/arc_net_host_impl.cc b/ash/components/arc/net/arc_net_host_impl.cc index 792dd05..bc841c9 100644 --- a/ash/components/arc/net/arc_net_host_impl.cc +++ b/ash/components/arc/net/arc_net_host_impl.cc
@@ -66,21 +66,20 @@ return !inet_ntop(family, data.data(), buf, sizeof(buf)) ? "" : buf; } -chromeos::NetworkStateHandler* GetStateHandler() { - return chromeos::NetworkHandler::Get()->network_state_handler(); +ash::NetworkStateHandler* GetStateHandler() { + return ash::NetworkHandler::Get()->network_state_handler(); } ash::ManagedNetworkConfigurationHandler* GetManagedConfigurationHandler() { - return chromeos::NetworkHandler::Get() - ->managed_network_configuration_handler(); + return ash::NetworkHandler::Get()->managed_network_configuration_handler(); } ash::NetworkConnectionHandler* GetNetworkConnectionHandler() { - return chromeos::NetworkHandler::Get()->network_connection_handler(); + return ash::NetworkHandler::Get()->network_connection_handler(); } ash::NetworkProfileHandler* GetNetworkProfileHandler() { - return chromeos::NetworkHandler::Get()->network_profile_handler(); + return ash::NetworkHandler::Get()->network_profile_handler(); } const ash::NetworkProfile* GetNetworkProfile() { @@ -407,7 +406,7 @@ // vector of mojo NetworkConfiguration objects. std::vector<arc::mojom::NetworkConfigurationPtr> TranslateNetworkStates( const std::string& arc_vpn_path, - const chromeos::NetworkStateHandler::NetworkStateList& network_states, + const ash::NetworkStateHandler::NetworkStateList& network_states, const std::map<std::string, base::Value>& shill_network_properties, const std::vector<patchpanel::NetworkDevice>& devices) { // Move the devices vector to a map keyed by its physical interface name in @@ -602,7 +601,7 @@ void ArcNetHostImpl::OnConnectionReady() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (chromeos::NetworkHandler::IsInitialized()) { + if (ash::NetworkHandler::IsInitialized()) { GetStateHandler()->AddObserver(this, FROM_HERE); GetNetworkConnectionHandler()->AddObserver(this); observing_network_state_ = true; @@ -657,7 +656,7 @@ ash::NetworkTypePattern network_pattern = ash::onc::NetworkTypePatternFromOncType(onc::network_type::kWiFi); - chromeos::NetworkStateHandler::NetworkStateList network_states; + ash::NetworkStateHandler::NetworkStateList network_states; GetStateHandler()->GetNetworkListByType( network_pattern, configured_only, !configured_only /* visible_only */, kGetNetworksListLimit, &network_states); @@ -673,7 +672,7 @@ GetNetworksCallback callback, const std::vector<patchpanel::NetworkDevice>& devices) { // Retrieve list of currently active networks. - chromeos::NetworkStateHandler::NetworkStateList network_states; + ash::NetworkStateHandler::NetworkStateList network_states; GetStateHandler()->GetActiveNetworkListByType( ash::NetworkTypePattern::Default(), &network_states); @@ -845,9 +844,9 @@ auto state = GetStateHandler()->GetTechnologyState(ash::NetworkTypePattern::WiFi()); // WiFi can't be enabled or disabled in these states. - if ((state == chromeos::NetworkStateHandler::TECHNOLOGY_PROHIBITED) || - (state == chromeos::NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) || - (state == chromeos::NetworkStateHandler::TECHNOLOGY_UNAVAILABLE)) { + if ((state == ash::NetworkStateHandler::TECHNOLOGY_PROHIBITED) || + (state == ash::NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) || + (state == ash::NetworkStateHandler::TECHNOLOGY_UNAVAILABLE)) { NET_LOG(ERROR) << "SetWifiEnabledState failed due to WiFi state: " << state; std::move(callback).Run(false); return; @@ -885,7 +884,7 @@ } std::string ArcNetHostImpl::LookupArcVpnServicePath() { - chromeos::NetworkStateHandler::NetworkStateList state_list; + ash::NetworkStateHandler::NetworkStateList state_list; GetStateHandler()->GetNetworkListByType( ash::NetworkTypePattern::VPN(), true /* configured_only */, false /* visible_only */, kGetNetworksListLimit, &state_list); @@ -1305,7 +1304,7 @@ if (!IsActiveNetworkState(network)) return; - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_configuration_handler() ->GetShillProperties( network->path(),
diff --git a/ash/components/arc/net/arc_net_host_impl.h b/ash/components/arc/net/arc_net_host_impl.h index 03351e6..7eb77ea 100644 --- a/ash/components/arc/net/arc_net_host_impl.h +++ b/ash/components/arc/net/arc_net_host_impl.h
@@ -213,7 +213,7 @@ base::OnceCallback<void(const std::string&)> callback, const std::string& error_name); - // Callback for chromeos::NetworkHandler::GetShillProperties + // Callback for ash::NetworkHandler::GetShillProperties void ReceiveShillProperties(const std::string& service_path, absl::optional<base::Value> shill_properties);
diff --git a/ash/components/audio/cros_audio_config_impl.cc b/ash/components/audio/cros_audio_config_impl.cc index 93809b76..9ded779 100644 --- a/ash/components/audio/cros_audio_config_impl.cc +++ b/ash/components/audio/cros_audio_config_impl.cc
@@ -96,6 +96,17 @@ } }; +void CrosAudioConfigImpl::SetOutputVolumePercent(int8_t volume) { + CrasAudioHandler* audio_handler = CrasAudioHandler::Get(); + audio_handler->SetOutputVolumePercent(volume); + + // If the volume is above certain level and it's muted, it should be unmuted. + if (audio_handler->IsOutputMuted() && + volume > audio_handler->GetOutputDefaultVolumeMuteThreshold()) { + audio_handler->SetOutputMute(false); + } +} + void CrosAudioConfigImpl::OnOutputNodeVolumeChanged(uint64_t node_id, int volume) { NotifyObserversAudioSystemPropertiesChanged();
diff --git a/ash/components/audio/cros_audio_config_impl.h b/ash/components/audio/cros_audio_config_impl.h index 06f9319..3c0eb340 100644 --- a/ash/components/audio/cros_audio_config_impl.h +++ b/ash/components/audio/cros_audio_config_impl.h
@@ -25,6 +25,7 @@ mojom::MuteState GetOutputMuteState() const override; void GetAudioDevices( std::vector<mojom::AudioDevicePtr>* output_devices_out) const override; + void SetOutputVolumePercent(int8_t volume) override; // CrasAudioHandler::AudioObserver: void OnOutputNodeVolumeChanged(uint64_t node_id, int volume) override;
diff --git a/ash/components/audio/cros_audio_config_impl_unittest.cc b/ash/components/audio/cros_audio_config_impl_unittest.cc index a9776c1..a7b6827f 100644 --- a/ash/components/audio/cros_audio_config_impl_unittest.cc +++ b/ash/components/audio/cros_audio_config_impl_unittest.cc
@@ -21,6 +21,9 @@ namespace ash::audio_config { const uint8_t kTestOutputVolumePercent = 80u; +const uint8_t kTestUnderMuteThreshholdVolumePercent = 0u; +const uint8_t kTestOverMaxOutputVolumePercent = 105u; +const int8_t kTestUnderMinOutputVolumePercent = -5; const int8_t kDefaultOutputVolumePercent = AudioDevicesPrefHandler::kDefaultOutputVolumePercent; @@ -101,7 +104,7 @@ } void SetOutputVolumePercent(uint8_t volume_percent) { - cras_audio_handler_->SetOutputVolumePercent(volume_percent); + remote_->SetOutputVolumePercent(volume_percent); base::RunLoop().RunUntilIdle(); } @@ -170,7 +173,7 @@ FakeCrasAudioClient* fake_cras_audio_client_; }; -TEST_F(CrosAudioConfigImplTest, GetOutputVolumePercent) { +TEST_F(CrosAudioConfigImplTest, GetSetOutputVolumePercent) { std::unique_ptr<FakeAudioSystemPropertiesObserver> fake_observer = Observe(); // |fake_observer| count is first incremented in Observe() method. ASSERT_EQ(1u, fake_observer->num_properties_updated_calls_); @@ -186,6 +189,75 @@ ->output_volume_percent); } +TEST_F(CrosAudioConfigImplTest, GetSetOutputVolumePercentMuteThresholdTest) { + std::unique_ptr<FakeAudioSystemPropertiesObserver> fake_observer = Observe(); + + // |fake_observer| count is first incremented in Observe() method. + ASSERT_EQ(1u, fake_observer->num_properties_updated_calls_); + ASSERT_TRUE(fake_observer->last_audio_system_properties_.has_value()); + ASSERT_EQ(kDefaultOutputVolumePercent, + fake_observer->last_audio_system_properties_.value() + ->output_volume_percent); + + // Test setting volume over mute threshold when muted. + SetOutputMuteState(mojom::MuteState::kMutedByUser); + ASSERT_EQ(2u, fake_observer->num_properties_updated_calls_); + EXPECT_EQ( + mojom::MuteState::kMutedByUser, + fake_observer->last_audio_system_properties_.value()->output_mute_state); + + SetOutputVolumePercent(kDefaultOutputVolumePercent); + + // |fake_observer| should be notified twice due to mute state changing when + // setting volume over the mute threshold. + ASSERT_EQ(4u, fake_observer->num_properties_updated_calls_); + EXPECT_EQ( + mojom::MuteState::kNotMuted, + fake_observer->last_audio_system_properties_.value()->output_mute_state); + EXPECT_EQ(kDefaultOutputVolumePercent, + fake_observer->last_audio_system_properties_.value() + ->output_volume_percent); + + // Test setting volume under mute threshold when muted. + SetOutputMuteState(mojom::MuteState::kMutedByUser); + ASSERT_EQ(5u, fake_observer->num_properties_updated_calls_); + EXPECT_EQ( + mojom::MuteState::kMutedByUser, + fake_observer->last_audio_system_properties_.value()->output_mute_state); + + SetOutputVolumePercent(kTestUnderMuteThreshholdVolumePercent); + ASSERT_EQ(6u, fake_observer->num_properties_updated_calls_); + EXPECT_EQ( + mojom::MuteState::kMutedByUser, + fake_observer->last_audio_system_properties_.value()->output_mute_state); + EXPECT_EQ(kTestUnderMuteThreshholdVolumePercent, + fake_observer->last_audio_system_properties_.value() + ->output_volume_percent); +} + +TEST_F(CrosAudioConfigImplTest, GetSetOutputVolumePercentVolumeBoundariesTest) { + std::unique_ptr<FakeAudioSystemPropertiesObserver> fake_observer = Observe(); + + // |fake_observer| count is first incremented in Observe() method. + ASSERT_EQ(1u, fake_observer->num_properties_updated_calls_); + ASSERT_TRUE(fake_observer->last_audio_system_properties_.has_value()); + ASSERT_EQ(kDefaultOutputVolumePercent, + fake_observer->last_audio_system_properties_.value() + ->output_volume_percent); + + // Test setting volume over max volume. + SetOutputVolumePercent(kTestOverMaxOutputVolumePercent); + ASSERT_EQ(2u, fake_observer->num_properties_updated_calls_); + EXPECT_EQ(100u, fake_observer->last_audio_system_properties_.value() + ->output_volume_percent); + + // Test setting volume under min volume. + SetOutputVolumePercent(kTestUnderMinOutputVolumePercent); + ASSERT_EQ(3u, fake_observer->num_properties_updated_calls_); + EXPECT_EQ(0u, fake_observer->last_audio_system_properties_.value() + ->output_volume_percent); +} + TEST_F(CrosAudioConfigImplTest, GetOutputMuteState) { std::unique_ptr<FakeAudioSystemPropertiesObserver> fake_observer = Observe(); ASSERT_EQ(1u, fake_observer->num_properties_updated_calls_);
diff --git a/ash/components/audio/public/mojom/cros_audio_config.mojom b/ash/components/audio/public/mojom/cros_audio_config.mojom index e39bd11..f5cd72e 100644 --- a/ash/components/audio/public/mojom/cros_audio_config.mojom +++ b/ash/components/audio/public/mojom/cros_audio_config.mojom
@@ -87,4 +87,8 @@ // To stop observing, disconnect |observer|. ObserveAudioSystemProperties( pending_remote<AudioSystemPropertiesObserver> observer); + + // Sets the volume of the active output device. If |volume| is above a + // threshold and the device is muted, it's unmuted. + SetOutputVolumePercent(int8 volume); }; \ No newline at end of file
diff --git a/ash/components/device_activity/device_activity_controller.cc b/ash/components/device_activity/device_activity_controller.cc index 18ca7d2..f376c3e 100644 --- a/ash/components/device_activity/device_activity_controller.cc +++ b/ash/components/device_activity/device_activity_controller.cc
@@ -243,8 +243,8 @@ psm_device_active_secret, chrome_passed_device_params_, local_state)); da_client_network_ = std::make_unique<DeviceActivityClient>( - chromeos::NetworkHandler::Get()->network_state_handler(), - url_loader_factory, std::make_unique<PsmDelegateImpl>(), + NetworkHandler::Get()->network_state_handler(), url_loader_factory, + std::make_unique<PsmDelegateImpl>(), std::make_unique<base::RepeatingTimer>(), kFresnelBaseUrl, google_apis::GetFresnelAPIKey(), std::move(use_cases)); }
diff --git a/ash/components/hid_detection/bluetooth_hid_detector_impl.cc b/ash/components/hid_detection/bluetooth_hid_detector_impl.cc index 5a3248b3..8f90bc1 100644 --- a/ash/components/hid_detection/bluetooth_hid_detector_impl.cc +++ b/ash/components/hid_detection/bluetooth_hid_detector_impl.cc
@@ -6,6 +6,7 @@ #include "ash/public/cpp/bluetooth_config_service.h" #include "base/strings/utf_string_conversions.h" #include "components/device_event_log/device_event_log.h" +#include "hid_detection_utils.h" namespace ash::hid_detection { namespace { @@ -116,6 +117,7 @@ << input_devices_status.keyboard_is_missing; input_devices_status_ = input_devices_status; state_ = kStarting; + num_pairing_attempts_ = 0; GetBluetoothConfigService( cros_bluetooth_config_remote_.BindNewPipeAndPassReceiver()); cros_bluetooth_config_remote_->ObserveSystemProperties( @@ -129,6 +131,7 @@ << "HID detection is inactive."; HID_LOG(EVENT) << "Stopping Bluetooth HID detection, |is_using_bluetooth|: " << is_using_bluetooth; + hid_detection::RecordBluetoothPairingAttempts(num_pairing_attempts_); state_ = kNotStarted; cros_bluetooth_config_remote_->SetBluetoothHidDetectionInactive( is_using_bluetooth); @@ -350,6 +353,7 @@ HID_LOG(EVENT) << "Pairing with device with id: " << current_pairing_device_.value()->id; + ++num_pairing_attempts_; device_pairing_handler_remote_->PairDevice( current_pairing_device_.value()->id, device_pairing_delegate_receiver_.BindNewPipeAndPassRemote(),
diff --git a/ash/components/hid_detection/bluetooth_hid_detector_impl.h b/ash/components/hid_detection/bluetooth_hid_detector_impl.h index c41183a..63efb3b 100644 --- a/ash/components/hid_detection/bluetooth_hid_detector_impl.h +++ b/ash/components/hid_detection/bluetooth_hid_detector_impl.h
@@ -135,6 +135,11 @@ InputDevicesStatus input_devices_status_; State state_ = kNotStarted; + // This is a counter used to emit a count of the number of pairing attempts + // that occur while HID detection is active. The count is reset to zero each + // time a HID detection session is started. + size_t num_pairing_attempts_ = 0; + mojo::Remote<chromeos::bluetooth_config::mojom::CrosBluetoothConfig> cros_bluetooth_config_remote_; mojo::Receiver<chromeos::bluetooth_config::mojom::SystemPropertiesObserver>
diff --git a/ash/components/hid_detection/bluetooth_hid_detector_impl_unittest.cc b/ash/components/hid_detection/bluetooth_hid_detector_impl_unittest.cc index e5fd156..648b8e19 100644 --- a/ash/components/hid_detection/bluetooth_hid_detector_impl_unittest.cc +++ b/ash/components/hid_detection/bluetooth_hid_detector_impl_unittest.cc
@@ -6,6 +6,7 @@ #include "ash/constants/ash_features.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "chromeos/services/bluetooth_config/fake_adapter_state_controller.h" @@ -201,6 +202,15 @@ } } + void AssertBluetoothPairingAttemptsCount(int bucket, + int count, + int total_count) { + histogram_tester_.ExpectBucketCount( + "OOBE.HidDetectionScreen.BluetoothPairingAttempts", bucket, count); + histogram_tester_.ExpectTotalCount( + "OOBE.HidDetectionScreen.BluetoothPairingAttempts", total_count); + } + private: void UpdateDiscoveredDevicesProviderDevices() { std::vector<BluetoothDevicePropertiesPtr> unpaired_devices; @@ -222,6 +232,7 @@ base::test::TaskEnvironment task_environment_; base::test::ScopedFeatureList scoped_feature_list_; + base::HistogramTester histogram_tester_; std::vector<BluetoothDevicePropertiesPtr> unpaired_devices_; size_t num_devices_created_ = 0u; @@ -261,6 +272,8 @@ StopBluetoothHidDetection(/*is_using_bluetooth=*/false); EXPECT_FALSE(IsDiscoverySessionActive()); EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState()); + AssertBluetoothPairingAttemptsCount(/*bucket=*/0, /*count=*/1, + /*total_count=*/1); // Trigger an OnPropertiesUpdated() call. Nothing should happen. TriggerOnPropertiesUpdatedCall(); @@ -403,6 +416,10 @@ AssertBluetoothHidDetectionStatus( BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard), /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, AddDevices_TypeNotMissing) { @@ -424,6 +441,10 @@ AssertBluetoothHidDetectionStatus( BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard), /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, AddDevices_NoTypeMissing) { @@ -459,6 +480,10 @@ AssertBluetoothHidDetectionStatus( BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer), /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, @@ -511,6 +536,10 @@ AssertBluetoothHidDetectionStatus( BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard), /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, AddDevices_BatchAfterStartingDetection) { @@ -557,6 +586,10 @@ AssertBluetoothHidDetectionStatus( BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboardPointerCombo), /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, @@ -610,6 +643,10 @@ AssertBluetoothHidDetectionStatus( /*current_pairing_device=*/absl::nullopt, /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, DisconnectDevice) { @@ -654,6 +691,10 @@ AssertBluetoothHidDetectionStatus( BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer), /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, ConnectDeviceTypeDuringPairing) { @@ -704,6 +745,10 @@ AssertBluetoothHidDetectionStatus( BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard), /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, @@ -746,6 +791,10 @@ AssertBluetoothHidDetectionStatus( /*current_pairing_device=*/absl::nullopt, /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, AdapterDisablesDuringPairing) { @@ -804,6 +853,10 @@ AssertBluetoothHidDetectionStatus( BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer), BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u)); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, DetectionStopsStartsDuringPairing) { @@ -835,6 +888,8 @@ // Stop detection. StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1, + /*total_count=*/1); EXPECT_FALSE(IsDiscoverySessionActive()); EXPECT_EQ(3u, delegate1->num_bluetooth_hid_status_changed_calls()); AssertBluetoothHidDetectionStatus( @@ -861,6 +916,10 @@ AssertBluetoothHidDetectionStatus( BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer), BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u)); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/2, + /*total_count=*/2); } TEST_F(BluetoothHidDetectorImplTest, AddDevices_UnsupportedAuthorizations) { @@ -914,6 +973,10 @@ AssertBluetoothHidDetectionStatus( /*current_pairing_device=*/absl::nullopt, /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/3, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, AddDevice_AuthorizePairingAuth) { @@ -954,6 +1017,10 @@ AssertBluetoothHidDetectionStatus( /*current_pairing_device=*/absl::nullopt, /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1, + /*total_count=*/1); } TEST_F(BluetoothHidDetectorImplTest, AddDevice_DisplayCodeAuths) { @@ -1049,6 +1116,10 @@ EXPECT_EQ(18u, delegate->num_bluetooth_hid_status_changed_calls()); AssertBluetoothHidDetectionStatus(/*current_pairing_device=*/absl::nullopt, /*pairing_state=*/absl::nullopt); + + StopBluetoothHidDetection(/*is_using_bluetooth=*/false); + AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1, + /*total_count=*/1); } } // namespace ash::hid_detection
diff --git a/ash/components/phonehub/tether_controller_impl_unittest.cc b/ash/components/phonehub/tether_controller_impl_unittest.cc index 287d58cc..9fc386e 100644 --- a/ash/components/phonehub/tether_controller_impl_unittest.cc +++ b/ash/components/phonehub/tether_controller_impl_unittest.cc
@@ -183,7 +183,7 @@ void TearDown() override { controller_->RemoveObserver(&fake_observer_); - chromeos::NetworkHandler::Shutdown(); + NetworkHandler::Shutdown(); testing::Test::TearDown(); }
diff --git a/ash/components/tether/active_host_network_state_updater.h b/ash/components/tether/active_host_network_state_updater.h index ecd3279..cfd248d 100644 --- a/ash/components/tether/active_host_network_state_updater.h +++ b/ash/components/tether/active_host_network_state_updater.h
@@ -7,11 +7,11 @@ #include "ash/components/tether/active_host.h" #include "base/memory/weak_ptr.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" namespace ash { +class NetworkStateHandler; + namespace tether { // Observes changes to the status of the active host, and relays these updates
diff --git a/ash/components/tether/asynchronous_shutdown_object_container_impl.h b/ash/components/tether/asynchronous_shutdown_object_container_impl.h index a87c08e..1bda3554 100644 --- a/ash/components/tether/asynchronous_shutdown_object_container_impl.h +++ b/ash/components/tether/asynchronous_shutdown_object_container_impl.h
@@ -13,8 +13,6 @@ #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h" #include "base/callback.h" #include "base/memory/ref_counted.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" class PrefService; @@ -26,6 +24,7 @@ class ManagedNetworkConfigurationHandler; class NetworkConnectionHandler; +class NetworkStateHandler; namespace tether {
diff --git a/ash/components/tether/connection_preserver_impl.h b/ash/components/tether/connection_preserver_impl.h index ff292e3..f4aaf58 100644 --- a/ash/components/tether/connection_preserver_impl.h +++ b/ash/components/tether/connection_preserver_impl.h
@@ -17,11 +17,11 @@ #include "ash/services/secure_channel/public/mojom/secure_channel.mojom.h" #include "base/timer/timer.h" #include "base/unguessable_token.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" namespace ash { +class NetworkStateHandler; + namespace tether { class SecureChannelClient;
diff --git a/ash/components/tether/crash_recovery_manager_impl.h b/ash/components/tether/crash_recovery_manager_impl.h index b76cdc4..1cad66c 100644 --- a/ash/components/tether/crash_recovery_manager_impl.h +++ b/ash/components/tether/crash_recovery_manager_impl.h
@@ -10,12 +10,12 @@ #include "ash/components/tether/active_host.h" #include "ash/components/tether/crash_recovery_manager.h" #include "base/callback.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace ash { +class NetworkStateHandler; + namespace tether { class HostScanCache;
diff --git a/ash/components/tether/host_scan_scheduler_impl.h b/ash/components/tether/host_scan_scheduler_impl.h index a3c6d6a..53cffa0d 100644 --- a/ash/components/tether/host_scan_scheduler_impl.h +++ b/ash/components/tether/host_scan_scheduler_impl.h
@@ -14,8 +14,6 @@ #include "base/time/clock.h" #include "base/time/time.h" #include "base/timer/timer.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" #include "chromeos/ash/components/network/network_state_handler_observer.h" #include "components/session_manager/core/session_manager_observer.h" @@ -29,6 +27,7 @@ namespace ash { +class NetworkStateHandler; class NetworkTypePattern; namespace tether {
diff --git a/ash/components/tether/network_host_scan_cache.h b/ash/components/tether/network_host_scan_cache.h index 979471d..d47afb28 100644 --- a/ash/components/tether/network_host_scan_cache.h +++ b/ash/components/tether/network_host_scan_cache.h
@@ -12,11 +12,11 @@ #include "ash/components/tether/host_scan_cache.h" #include "ash/components/tether/tether_host_response_recorder.h" #include "base/memory/weak_ptr.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" namespace ash { +class NetworkStateHandler; + namespace tether { class DeviceIdTetherNetworkGuidMap;
diff --git a/ash/components/tether/notification_remover.h b/ash/components/tether/notification_remover.h index bb3c4f3..2cf531a7 100644 --- a/ash/components/tether/notification_remover.h +++ b/ash/components/tether/notification_remover.h
@@ -7,12 +7,12 @@ #include "ash/components/tether/active_host.h" #include "ash/components/tether/host_scan_cache.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" #include "chromeos/ash/components/network/network_state_handler_observer.h" namespace ash { +class NetworkStateHandler; + namespace tether { class NotificationPresenter;
diff --git a/ash/components/tether/synchronous_shutdown_object_container_impl.h b/ash/components/tether/synchronous_shutdown_object_container_impl.h index 71f4067..798f878 100644 --- a/ash/components/tether/synchronous_shutdown_object_container_impl.h +++ b/ash/components/tether/synchronous_shutdown_object_container_impl.h
@@ -10,8 +10,6 @@ #include "ash/components/tether/synchronous_shutdown_object_container.h" // TODO(https://crbug.com/1164001): move to forward declaration #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" class PrefService; @@ -27,6 +25,7 @@ class NetworkConnect; class NetworkConnectionHandler; +class NetworkStateHandler; namespace tether {
diff --git a/ash/components/tether/tether_component_impl.h b/ash/components/tether/tether_component_impl.h index 07659792..9d14a17 100644 --- a/ash/components/tether/tether_component_impl.h +++ b/ash/components/tether/tether_component_impl.h
@@ -12,8 +12,6 @@ #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" #include "components/prefs/pref_registry_simple.h" #include "device/bluetooth/bluetooth_adapter.h" @@ -36,6 +34,7 @@ class ManagedNetworkConfigurationHandler; class NetworkConnect; class NetworkConnectionHandler; +class NetworkStateHandler; namespace tether {
diff --git a/ash/components/tether/tether_connector_impl.h b/ash/components/tether/tether_connector_impl.h index 13fb0c98..f4574a0 100644 --- a/ash/components/tether/tether_connector_impl.h +++ b/ash/components/tether/tether_connector_impl.h
@@ -13,8 +13,6 @@ #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h" #include "base/memory/weak_ptr.h" #include "chromeos/ash/components/network/network_connection_handler.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace ash { @@ -23,6 +21,8 @@ class DeviceSyncClient; } +class NetworkStateHandler; + namespace tether { class ActiveHost;
diff --git a/ash/components/tether/tether_network_disconnection_handler.h b/ash/components/tether/tether_network_disconnection_handler.h index 7e2a6a1..e085a24 100644 --- a/ash/components/tether/tether_network_disconnection_handler.h +++ b/ash/components/tether/tether_network_disconnection_handler.h
@@ -7,8 +7,6 @@ #include "ash/components/tether/active_host.h" #include "base/memory/weak_ptr.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" #include "chromeos/ash/components/network/network_state_handler_observer.h" namespace base { @@ -17,6 +15,8 @@ namespace ash { +class NetworkStateHandler; + namespace tether { class ActiveHost;
diff --git a/ash/components/tether/wifi_hotspot_connector.h b/ash/components/tether/wifi_hotspot_connector.h index 9926a06..6a02353 100644 --- a/ash/components/tether/wifi_hotspot_connector.h +++ b/ash/components/tether/wifi_hotspot_connector.h
@@ -13,8 +13,6 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "base/values.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" #include "chromeos/ash/components/network/network_state_handler_observer.h" namespace base { @@ -25,6 +23,7 @@ class NetworkConnect; class NetworkState; +class NetworkStateHandler; namespace tether {
diff --git a/ash/components/tether/wifi_hotspot_disconnector_impl.h b/ash/components/tether/wifi_hotspot_disconnector_impl.h index 656055fa..484f50f 100644 --- a/ash/components/tether/wifi_hotspot_disconnector_impl.h +++ b/ash/components/tether/wifi_hotspot_disconnector_impl.h
@@ -7,8 +7,6 @@ #include "ash/components/tether/wifi_hotspot_disconnector.h" #include "base/memory/weak_ptr.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" class PrefRegistrySimple; class PrefService; @@ -16,6 +14,7 @@ namespace ash { class NetworkConnectionHandler; +class NetworkStateHandler; namespace tether {
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index aae51979..1658ca5 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -1596,6 +1596,10 @@ const base::Feature kVirtualKeyboardBorderedKey{ "VirtualKeyboardBorderedKey", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enable or disable multitouch for virtual keyboard on ChromeOS. +const base::Feature kVirtualKeyboardMultitouch{ + "VirtualKeyboardMultitouch", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enable or disable round corners for virtual keyboard on ChromeOS. const base::Feature kVirtualKeyboardRoundCorners{ "VirtualKeyboardRoundCorners", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index c68186f..afeb36b 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -645,6 +645,8 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kVirtualKeyboardBorderedKey; COMPONENT_EXPORT(ASH_CONSTANTS) +extern const base::Feature kVirtualKeyboardMultitouch; +COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kVirtualKeyboardRoundCorners; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kWakeOnWifiAllowed;
diff --git a/ash/public/cpp/system/toast_data.h b/ash/public/cpp/system/toast_data.h index 13d4623..485a29e2 100644 --- a/ash/public/cpp/system/toast_data.h +++ b/ash/public/cpp/system/toast_data.h
@@ -56,6 +56,7 @@ base::RepeatingClosure dismiss_callback; base::RepeatingClosure expired_callback; base::TimeTicks time_created; + base::TimeTicks time_shown; }; } // namespace ash
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_impl.cc b/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_impl.cc index 7e71c9b..c7de878 100644 --- a/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_impl.cc +++ b/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_impl.cc
@@ -92,13 +92,12 @@ found_callback_(std::move(found_callback)), lost_callback_(std::move(lost_callback)) { observation_.Observe(scanner_.get()); - chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver( - this, FROM_HERE); + NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); } FastPairDiscoverableScannerImpl::~FastPairDiscoverableScannerImpl() { - chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( - this, FROM_HERE); + NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, + FROM_HERE); } void FastPairDiscoverableScannerImpl::OnDeviceFound(
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_impl_unittest.cc b/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_impl_unittest.cc index 0e7cbd9f..b5ecbbbc 100644 --- a/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_impl_unittest.cc +++ b/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_impl_unittest.cc
@@ -98,7 +98,7 @@ class FastPairDiscoverableScannerImplTest : public testing::Test { public: void SetUp() override { - chromeos::NetworkHandler::Initialize(); + NetworkHandler::Initialize(); repository_ = std::make_unique<FakeFastPairRepository>(); nearby::fastpair::Device metadata; @@ -131,7 +131,7 @@ process_manager_.reset(); testing::Test::TearDown(); discoverable_scanner_.reset(); - chromeos::NetworkHandler::Shutdown(); + NetworkHandler::Shutdown(); } MockQuickPairProcessManager* mock_process_manager() {
diff --git a/ash/services/cellular_setup/esim_manager.h b/ash/services/cellular_setup/esim_manager.h index 372efa1a..1732ff39 100644 --- a/ash/services/cellular_setup/esim_manager.h +++ b/ash/services/cellular_setup/esim_manager.h
@@ -11,8 +11,6 @@ #include "chromeos/ash/components/dbus/hermes/hermes_manager_client.h" #include "chromeos/ash/components/dbus/hermes/hermes_profile_client.h" #include "chromeos/ash/components/network/cellular_esim_profile_handler.h" -// TODO(https://crbug.com/1164001): move to forward declaration. -#include "chromeos/ash/components/network/network_state_handler.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/remote_set.h" @@ -28,6 +26,7 @@ class CellularESimUninstallHandler; class CellularInhibitor; class NetworkConnectionHandler; +class NetworkStateHandler; namespace cellular_setup {
diff --git a/ash/services/cellular_setup/esim_test_base.h b/ash/services/cellular_setup/esim_test_base.h index de3cb38..7d0966e 100644 --- a/ash/services/cellular_setup/esim_test_base.h +++ b/ash/services/cellular_setup/esim_test_base.h
@@ -8,8 +8,6 @@ #include "ash/services/cellular_setup/public/cpp/esim_manager_test_observer.h" #include "ash/services/cellular_setup/public/mojom/esim_manager.mojom.h" #include "base/test/task_environment.h" -// TODO(https://crbug.com/1164001): move to forward declaration. -#include "chromeos/ash/components/network/network_state_handler.h" #include "mojo/public/cpp/bindings/remote.h" #include "testing/gtest/include/gtest/gtest.h" @@ -22,6 +20,7 @@ class NetworkConfigurationHandler; class NetworkDeviceHandler; class NetworkProfileHandler; +class NetworkStateHandler; class FakeNetworkConnectionHandler; class TestCellularESimProfileHandler;
diff --git a/ash/services/cellular_setup/ota_activator_impl.h b/ash/services/cellular_setup/ota_activator_impl.h index 618dedaa..2a29319 100644 --- a/ash/services/cellular_setup/ota_activator_impl.h +++ b/ash/services/cellular_setup/ota_activator_impl.h
@@ -15,8 +15,6 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "base/timer/timer.h" -// TODO(https://crbug.com/1164001): move to forward declaration. -#include "chromeos/ash/components/network/network_state_handler.h" #include "chromeos/ash/components/network/network_state_handler_observer.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" @@ -24,6 +22,7 @@ namespace ash { class NetworkState; +class NetworkStateHandler; class NetworkActivationHandler; class NetworkConnectionHandler;
diff --git a/ash/services/device_sync/cryptauth_scheduler_impl.h b/ash/services/device_sync/cryptauth_scheduler_impl.h index 0ee2cd9..2799465 100644 --- a/ash/services/device_sync/cryptauth_scheduler_impl.h +++ b/ash/services/device_sync/cryptauth_scheduler_impl.h
@@ -18,8 +18,6 @@ #include "base/time/default_clock.h" #include "base/timer/timer.h" #include "chromeos/ash/components/network/network_handler.h" -// TODO(https://crbug.com/1164001): move to forward declaration -#include "chromeos/ash/components/network/network_state_handler.h" #include "chromeos/ash/components/network/network_state_handler_observer.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -28,6 +26,8 @@ namespace ash { +class NetworkStateHandler; + namespace device_sync { // CryptAuthScheduler implementation which stores scheduling metadata
diff --git a/ash/system/accessibility/tray_accessibility.cc b/ash/system/accessibility/tray_accessibility.cc index b8fcafd..7a83079 100644 --- a/ash/system/accessibility/tray_accessibility.cc +++ b/ash/system/accessibility/tray_accessibility.cc
@@ -626,8 +626,9 @@ MaybeShowSodaMessage(SodaFeature::kLiveCaption, language_code, message); } -void AccessibilityDetailedView::OnSodaError( - speech::LanguageCode language_code) { +void AccessibilityDetailedView::OnSodaInstallError( + speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) { std::u16string message = l10n_util::GetStringUTF16( IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR); MaybeShowSodaMessage(SodaFeature::kDictation, language_code, message);
diff --git a/ash/system/accessibility/tray_accessibility.h b/ash/system/accessibility/tray_accessibility.h index 1f02066..30abb8872 100644 --- a/ash/system/accessibility/tray_accessibility.h +++ b/ash/system/accessibility/tray_accessibility.h
@@ -79,7 +79,8 @@ // SodaInstaller::Observer: void OnSodaInstalled(speech::LanguageCode language_code) override; - void OnSodaError(speech::LanguageCode language_code) override; + void OnSodaInstallError(speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) override; void OnSodaProgress(speech::LanguageCode language_code, int combined_progress) override;
diff --git a/ash/system/audio/audio_detailed_view.cc b/ash/system/audio/audio_detailed_view.cc index be585e89..8612503 100644 --- a/ash/system/audio/audio_detailed_view.cc +++ b/ash/system/audio/audio_detailed_view.cc
@@ -358,7 +358,9 @@ MaybeShowSodaMessage(language_code, message); } -void AudioDetailedView::OnSodaError(speech::LanguageCode language_code) { +void AudioDetailedView::OnSodaInstallError( + speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) { std::u16string message = l10n_util::GetStringUTF16( IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR); MaybeShowSodaMessage(language_code, message);
diff --git a/ash/system/audio/audio_detailed_view.h b/ash/system/audio/audio_detailed_view.h index 6370206..6127f6c 100644 --- a/ash/system/audio/audio_detailed_view.h +++ b/ash/system/audio/audio_detailed_view.h
@@ -74,7 +74,8 @@ // SodaInstaller::Observer: void OnSodaInstalled(speech::LanguageCode language_code) override; - void OnSodaError(speech::LanguageCode language_code) override; + void OnSodaInstallError(speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) override; void OnSodaProgress(speech::LanguageCode language_code, int combined_progress) override;
diff --git a/ash/system/network/active_network_icon_unittest.cc b/ash/system/network/active_network_icon_unittest.cc index ad805bfc..a64bdf6 100644 --- a/ash/system/network/active_network_icon_unittest.cc +++ b/ash/system/network/active_network_icon_unittest.cc
@@ -150,7 +150,7 @@ NetworkStateTestHelper& network_state_helper() { return network_config_helper_.network_state_helper(); } - chromeos::NetworkStateHandler* network_state_handler() { + NetworkStateHandler* network_state_handler() { return network_state_helper().network_state_handler(); } ActiveNetworkIcon* active_network_icon() {
diff --git a/ash/system/network/auto_connect_notifier.cc b/ash/system/network/auto_connect_notifier.cc index db7c8df9..a754d1eb 100644 --- a/ash/system/network/auto_connect_notifier.cc +++ b/ash/system/network/auto_connect_notifier.cc
@@ -21,8 +21,6 @@ #include "chromeos/ash/components/network/network_type_pattern.h" #include "ui/base/l10n/l10n_util.h" -using chromeos::NetworkHandler; - namespace ash { namespace {
diff --git a/ash/system/network/auto_connect_notifier_unittest.cc b/ash/system/network/auto_connect_notifier_unittest.cc index 6ee0ffb..4ea99ba 100644 --- a/ash/system/network/auto_connect_notifier_unittest.cc +++ b/ash/system/network/auto_connect_notifier_unittest.cc
@@ -50,7 +50,7 @@ NetworkCertLoader::Initialize(); NetworkCertLoader::ForceAvailableForNetworkAuthForTesting(); network_handler_test_helper_ = std::make_unique<NetworkHandlerTestHelper>(); - CHECK(chromeos::NetworkHandler::Get()->auto_connect_handler()); + CHECK(NetworkHandler::Get()->auto_connect_handler()); network_config_helper_ = std::make_unique< chromeos::network_config::CrosNetworkConfigTestHelper>(); @@ -119,7 +119,7 @@ }; TEST_F(AutoConnectNotifierTest, NoExplicitConnectionRequested) { - chromeos::NetworkHandler::Get() + NetworkHandler::Get() ->auto_connect_handler() ->NotifyAutoConnectInitiatedForTest( AutoConnectHandler::AUTO_CONNECT_REASON_POLICY_APPLIED); @@ -131,7 +131,7 @@ TEST_F(AutoConnectNotifierTest, AutoConnectDueToLoginOnly) { NotifyConnectToNetworkRequested(); - chromeos::NetworkHandler::Get() + NetworkHandler::Get() ->auto_connect_handler() ->NotifyAutoConnectInitiatedForTest( AutoConnectHandler::AUTO_CONNECT_REASON_LOGGED_IN); @@ -143,7 +143,7 @@ TEST_F(AutoConnectNotifierTest, NoConnectionBeforeTimerExpires) { NotifyConnectToNetworkRequested(); - chromeos::NetworkHandler::Get() + NetworkHandler::Get() ->auto_connect_handler() ->NotifyAutoConnectInitiatedForTest( AutoConnectHandler::AUTO_CONNECT_REASON_POLICY_APPLIED); @@ -164,7 +164,7 @@ SuccessfullyJoinWifiNetwork(); NotifyConnectToNetworkRequested(); - chromeos::NetworkHandler::Get() + NetworkHandler::Get() ->auto_connect_handler() ->NotifyAutoConnectInitiatedForTest( AutoConnectHandler::AUTO_CONNECT_REASON_POLICY_APPLIED); @@ -176,7 +176,7 @@ TEST_F(AutoConnectNotifierTest, ToastDisplayed) { NotifyConnectToNetworkRequested(); - chromeos::NetworkHandler::Get() + NetworkHandler::Get() ->auto_connect_handler() ->NotifyAutoConnectInitiatedForTest( AutoConnectHandler::AUTO_CONNECT_REASON_POLICY_APPLIED);
diff --git a/ash/system/network/cellular_setup_notifier_unittest.cc b/ash/system/network/cellular_setup_notifier_unittest.cc index 7d54995..ed92205 100644 --- a/ash/system/network/cellular_setup_notifier_unittest.cc +++ b/ash/system/network/cellular_setup_notifier_unittest.cc
@@ -47,7 +47,7 @@ NetworkCertLoader::Initialize(); chromeos::shill_clients::InitializeFakes(); hermes_clients::InitializeFakes(); - chromeos::NetworkHandler::Initialize(); + NetworkHandler::Initialize(); network_config_helper_ = std::make_unique< chromeos::network_config::CrosNetworkConfigTestHelper>(); @@ -66,7 +66,7 @@ void TearDown() override { AshTestBase::TearDown(); network_config_helper_.reset(); - chromeos::NetworkHandler::Shutdown(); + NetworkHandler::Shutdown(); hermes_clients::Shutdown(); chromeos::shill_clients::Shutdown(); NetworkCertLoader::Shutdown();
diff --git a/ash/system/network/network_detailed_view_controller_unittest.cc b/ash/system/network/network_detailed_view_controller_unittest.cc index 8b026ae..f128233 100644 --- a/ash/system/network/network_detailed_view_controller_unittest.cc +++ b/ash/system/network/network_detailed_view_controller_unittest.cc
@@ -91,7 +91,7 @@ network_config_helper_ = std::make_unique< chromeos::network_config::CrosNetworkConfigTestHelper>(); - chromeos::NetworkHandler::Initialize(); + NetworkHandler::Initialize(); base::RunLoop().RunUntilIdle(); // Creating a service here, since we would be testing that wifi, @@ -120,7 +120,7 @@ network_detailed_view_controller_.reset(); AshTestBase::TearDown(); NetworkConnect::Shutdown(); - chromeos::NetworkHandler::Shutdown(); + NetworkHandler::Shutdown(); network_connect_delegate_.reset(); } @@ -187,13 +187,12 @@ base::RunLoop().RunUntilIdle(); } - chromeos::NetworkStateHandler::TechnologyState GetTechnologyState( + NetworkStateHandler::TechnologyState GetTechnologyState( const NetworkTypePattern& network) { return network_state_handler()->GetTechnologyState(network); } - void SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState state) { + void SetTetherTechnologyState(NetworkStateHandler::TechnologyState state) { network_state_handler()->SetTetherTechnologyState(state); base::RunLoop().RunUntilIdle(); } @@ -231,7 +230,7 @@ // hotspot, and associates the two networks. void AddTetherDevice() { network_state_handler()->SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); + NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); network_state_handler()->AddTetherNetworkState( kTetherGuid, kTetherName, kTetherCarrier, /*battery_percentage=*/100, kSignalStrength, /*has_connected_to_host=*/false); @@ -255,7 +254,7 @@ } private: - chromeos::NetworkStateHandler* network_state_handler() { + NetworkStateHandler* network_state_handler() { return network_state_helper()->network_state_handler(); } @@ -502,7 +501,7 @@ TEST_F(NetworkDetailedViewControllerTest, WifiStateChange) { // By default ash test instantiates WiFi networks and enables them. - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, GetTechnologyState(NetworkTypePattern::WiFi())); CheckNetworkTypeToggledHistogramBuckets( /*network_type=*/kNetworkTechnologyWiFi, @@ -516,9 +515,8 @@ /*network_type=*/kNetworkTechnologyWiFi, /*new_state=*/false, /*count=*/1u, /*total_count=*/1u); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - GetTechnologyState(NetworkTypePattern::WiFi())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + GetTechnologyState(NetworkTypePattern::WiFi())); // Renable wifi. ToggleWifiState(/*new_state=*/true); @@ -527,7 +525,7 @@ /*network_type=*/kNetworkTechnologyWiFi, /*new_state=*/true, /*count=*/1u, /*total_count=*/2u); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, GetTechnologyState(NetworkTypePattern::WiFi())); } @@ -538,7 +536,7 @@ /*network_type=*/kNetworkTechnologyMobile, /*new_state=*/false, /*count=*/0u, /*total_count=*/0u); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, GetTechnologyState(NetworkTypePattern::Cellular())); ToggleMobileState(/*new_state=*/false); @@ -547,9 +545,8 @@ /*network_type=*/kNetworkTechnologyMobile, /*new_state=*/false, /*count=*/1u, /*total_count=*/1u); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - GetTechnologyState(NetworkTypePattern::Cellular())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + GetTechnologyState(NetworkTypePattern::Cellular())); EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count()); // When SIM is locked and new state is being toggled on show SIM unlock @@ -557,9 +554,8 @@ SetCellularSimLockStatus(shill::kSIMLockPin, /*sim_locked=*/true); ToggleMobileState(/*new_state=*/true); EXPECT_EQ(1, GetSystemTrayClient()->show_sim_unlock_settings_count()); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - GetTechnologyState(NetworkTypePattern::Cellular())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + GetTechnologyState(NetworkTypePattern::Cellular())); CheckNetworkTypeToggledHistogramBuckets( /*network_type=*/kNetworkTechnologyMobile, /*new_state=*/true, /*count=*/1u, @@ -568,20 +564,19 @@ // When Cellular and Tether are both available toggle should control cellular. AddTetherDevice(); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, GetTechnologyState(NetworkTypePattern::Tether())); // Set Tether to available and check toggle updates Cellular. SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE); + NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE); SetCellularSimLockStatus(/*lock_type=*/"", /*sim_locked=*/false); ToggleMobileState(/*new_state=*/true); EXPECT_EQ(1, GetSystemTrayClient()->show_sim_unlock_settings_count()); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - GetTechnologyState(NetworkTypePattern::Tether())); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + GetTechnologyState(NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, GetTechnologyState(NetworkTypePattern::Cellular())); CheckNetworkTypeToggledHistogramBuckets( /*network_type=*/kNetworkTechnologyMobile, @@ -592,14 +587,13 @@ AddTetherDevice(); // Toggle now controls Tether since there are no Cellular devices. - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, GetTechnologyState(NetworkTypePattern::Tether())); ToggleMobileState(/*new_state=*/false); EXPECT_EQ(1, GetSystemTrayClient()->show_sim_unlock_settings_count()); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - GetTechnologyState(NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + GetTechnologyState(NetworkTypePattern::Tether())); CheckNetworkTypeToggledHistogramBuckets( /*network_type=*/kNetworkTechnologyMobile, /*new_state=*/false, /*count=*/2u, @@ -608,15 +602,14 @@ // When Tether is uninitialized and Bluetooth is disabled, toggling Mobile on // should enable Bluetooth. SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED); + NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED); SetBluetoothAdapterState(BluetoothSystemState::kDisabled); ToggleMobileState(/*new_state=*/true); EXPECT_EQ(BluetoothSystemState::kEnabling, GetBluetoothAdapterState()); EXPECT_EQ(1, GetSystemTrayClient()->show_sim_unlock_settings_count()); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED, - GetTechnologyState(NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED, + GetTechnologyState(NetworkTypePattern::Tether())); CheckNetworkTypeToggledHistogramBuckets( /*network_type=*/kNetworkTechnologyMobile, /*new_state=*/true, /*count=*/3u, @@ -627,11 +620,11 @@ // adapter state. Enabling Bluetooth will also change Tether state to // available. SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE); + NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE); SetBluetoothAdapterState(BluetoothSystemState::kEnabled); EXPECT_EQ(BluetoothSystemState::kEnabled, GetBluetoothAdapterState()); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, GetTechnologyState(NetworkTypePattern::Tether())); }
diff --git a/ash/system/network/network_feature_pod_controller_unittest.cc b/ash/system/network/network_feature_pod_controller_unittest.cc index 385594b..b654d70 100644 --- a/ash/system/network/network_feature_pod_controller_unittest.cc +++ b/ash/system/network/network_feature_pod_controller_unittest.cc
@@ -106,7 +106,7 @@ shill::kTypeEthernet, "stub_eth_device"); network_state_handler()->SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); + NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); base::RunLoop().RunUntilIdle(); } @@ -248,7 +248,7 @@ return &network_config_helper_.network_state_helper(); } - chromeos::NetworkStateHandler* network_state_handler() { + NetworkStateHandler* network_state_handler() { return network_state_helper()->network_state_handler(); }
diff --git a/ash/system/network/network_icon_unittest.cc b/ash/system/network/network_icon_unittest.cc index e245ed76..0627bbb 100644 --- a/ash/system/network/network_icon_unittest.cc +++ b/ash/system/network/network_icon_unittest.cc
@@ -139,10 +139,9 @@ base::RunLoop().RunUntilIdle(); - ASSERT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - helper().network_state_handler()->GetTechnologyState( - NetworkTypePattern::Cellular())); + ASSERT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + helper().network_state_handler()->GetTechnologyState( + NetworkTypePattern::Cellular())); } NetworkStateTestHelper& helper() {
diff --git a/ash/system/network/network_list_view_controller_unittest.cc b/ash/system/network/network_list_view_controller_unittest.cc index 763338c..37e2abd 100644 --- a/ash/system/network/network_list_view_controller_unittest.cc +++ b/ash/system/network/network_list_view_controller_unittest.cc
@@ -433,7 +433,7 @@ // hotspot, and associates the two networks. void AddTetherNetworkState() { network_state_handler()->SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); + NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); network_state_handler()->AddTetherNetworkState( kTetherGuid, kTetherName, kTetherCarrier, /*battery_percentage=*/100, kSignalStrength, /*has_connected_to_host=*/false); @@ -528,7 +528,7 @@ .IsRunning(); } - chromeos::NetworkStateHandler* network_state_handler() { + NetworkStateHandler* network_state_handler() { return network_state_helper()->network_state_handler(); } @@ -606,7 +606,7 @@ // Tether device is prohibited. network_state_handler()->SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_PROHIBITED); + NetworkStateHandler::TechnologyState::TECHNOLOGY_PROHIBITED); base::RunLoop().RunUntilIdle(); EXPECT_EQ(nullptr, GetMobileSubHeader()); histogram_tester.ExpectBucketCount("ChromeOS.SystemTray.Network.SectionShown", @@ -614,7 +614,7 @@ // Tether device is uninitialized but is primary user. network_state_handler()->SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED); + NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED); base::RunLoop().RunUntilIdle(); EXPECT_NE(nullptr, GetMobileSubHeader()); histogram_tester.ExpectBucketCount("ChromeOS.SystemTray.Network.SectionShown", @@ -1004,7 +1004,7 @@ // Tether is enabled but no devices are added. network_state_handler()->SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); + NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); base::RunLoop().RunUntilIdle(); EXPECT_NE(nullptr, GetMobileStatusMessage()); @@ -1017,7 +1017,7 @@ // Tether network is uninitialized and Bluetooth state enabling. network_state_handler()->SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED); + NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED); base::RunLoop().RunUntilIdle(); SetBluetoothAdapterState(BluetoothSystemState::kEnabling);
diff --git a/ash/system/network/sms_observer.cc b/ash/system/network/sms_observer.cc index a4e04849..5ae8666 100644 --- a/ash/system/network/sms_observer.cc +++ b/ash/system/network/sms_observer.cc
@@ -18,8 +18,6 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/message_center/message_center.h" -using chromeos::NetworkHandler; - namespace ash { const char SmsObserver::kNotificationPrefix[] = "chrome://network/sms";
diff --git a/ash/system/status_area_widget_unittest.cc b/ash/system/status_area_widget_unittest.cc index 6417d07..cc46cac 100644 --- a/ash/system/status_area_widget_unittest.cc +++ b/ash/system/status_area_widget_unittest.cc
@@ -314,7 +314,7 @@ void TearDown() override { // This roughly matches production shutdown order. - chromeos::NetworkHandler::Get()->ShutdownPrefServices(); + NetworkHandler::Get()->ShutdownPrefServices(); AshTestBase::TearDown(); }
diff --git a/ash/system/toast/toast_manager_impl.cc b/ash/system/toast/toast_manager_impl.cc index 6d3d74c..972776e 100644 --- a/ash/system/toast/toast_manager_impl.cc +++ b/ash/system/toast/toast_manager_impl.cc
@@ -11,11 +11,30 @@ #include "base/bind.h" #include "base/location.h" #include "base/metrics/histogram_functions.h" +#include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" namespace ash { +namespace { + +constexpr char NotifierFrameworkToastHistogram[] = + "Ash.NotifierFramework.Toast"; + +// Used in histogram names. +std::string GetToastDismissedTimeRange(const base::TimeDelta& time) { + if (time <= base::Seconds(2)) + return "Within2s"; + // Toast default duration is 6s, but with animation it's usually + // around ~6.2s, so recording 7s as the default case. + if (time <= base::Seconds(7)) + return "Within7s"; + return "After7s"; +} + +} // namespace + ToastManagerImpl::ToastManagerImpl() : locked_(Shell::Get()->session_controller()->IsScreenLocked()) {} @@ -82,6 +101,14 @@ } void ToastManagerImpl::OnClosed() { + const base::TimeDelta user_journey_time = + base::TimeTicks::Now() - current_toast_data_->time_shown; + const std::string time_range = GetToastDismissedTimeRange(user_journey_time); + base::UmaHistogramEnumeration( + base::StringPrintf("%s.Dismissed.%s", NotifierFrameworkToastHistogram, + time_range.c_str()), + current_toast_data_->catalog_name); + overlay_.reset(); current_toast_data_.reset(); @@ -124,6 +151,7 @@ current_toast_data_->duration); } + current_toast_data_->time_shown = base::TimeTicks::Now(); base::UmaHistogramEnumeration("Ash.NotifierFramework.Toast.ShownCount", current_toast_data_->catalog_name); base::UmaHistogramMediumTimes(
diff --git a/ash/system/toast/toast_manager_unittest.cc b/ash/system/toast/toast_manager_unittest.cc index c69d1b9..a4c59c4 100644 --- a/ash/system/toast/toast_manager_unittest.cc +++ b/ash/system/toast/toast_manager_unittest.cc
@@ -34,6 +34,25 @@ #include "ui/views/controls/button/label_button.h" #include "ui/views/widget/widget.h" +namespace { + +constexpr char kToastShownCountHistogramName[] = + "Ash.NotifierFramework.Toast.ShownCount"; + +constexpr char kToastTimeInQueueHistogramName[] = + "Ash.NotifierFramework.Toast.TimeInQueue"; + +constexpr char kToastDismissedWithin2s[] = + "Ash.NotifierFramework.Toast.Dismissed.Within2s"; + +constexpr char kToastDismissedWithin7s[] = + "Ash.NotifierFramework.Toast.Dismissed.Within7s"; + +constexpr char kToastDismissedAfter7s[] = + "Ash.NotifierFramework.Toast.Dismissed.After7s"; + +} // namespace + namespace ash { class ToastManagerImplTest : public AshTestBase { @@ -660,56 +679,105 @@ GetCurrentDismissText()); } -TEST_F(ToastManagerImplTest, NotifierFrameworkMetrics) { +TEST_F(ToastManagerImplTest, ShownCountMetric) { base::HistogramTester histogram_tester; - constexpr char kToastShownCountHistogramName[] = - "Ash.NotifierFramework.Toast.ShownCount"; - constexpr char kToastTimeInQueueHistogramName[] = - "Ash.NotifierFramework.Toast.TimeInQueue"; const ToastCatalogName catalog_name_1 = static_cast<ToastCatalogName>(1); const ToastCatalogName catalog_name_2 = static_cast<ToastCatalogName>(2); - const base::TimeDelta duration = base::Seconds(3); + const base::TimeDelta duration = base::Seconds(2); + constexpr char text[] = "sample text"; // Show Toast with catalog_name_1. - std::string id1 = ShowToast("TEXT1", duration, + std::string id1 = ShowToast(text, duration, /*visible_on_lock_screen=*/false, catalog_name_1); histogram_tester.ExpectBucketCount(kToastShownCountHistogramName, catalog_name_1, 1); - // Expect "TimeInQueue" metric to record zero since there were no toasts in - // the queue. - histogram_tester.ExpectTimeBucketCount(kToastTimeInQueueHistogramName, - base::Seconds(0), 1); - // Replace existing toast a couple of times. - ReplaceToast(id1, "TEXT1_UPDATED", duration, + ReplaceToast(id1, text, duration, /*visible_on_lock_screen=*/false, catalog_name_1); - ReplaceToast(id1, "TEXT1_UPDATED", duration, + ReplaceToast(id1, text, duration, /*visible_on_lock_screen=*/false, catalog_name_1); histogram_tester.ExpectBucketCount(kToastShownCountHistogramName, catalog_name_1, 3); - // Expect "TimeInQueue" metric to record zero since the same toast was shown, - // so it wasn't queued. - histogram_tester.ExpectTimeBucketCount(kToastTimeInQueueHistogramName, - base::Seconds(0), 3); - // Try to show toast with catalog_name_2 right after last toast was shown. - ShowToast("TEXT2", duration, /*visible_on_lock_screen=*/false, - catalog_name_2); + ShowToast(text, duration, /*visible_on_lock_screen=*/false, catalog_name_2); // Fast forward the toast's duration so the queued toast is shown. task_environment()->FastForwardBy(duration); histogram_tester.ExpectBucketCount(kToastShownCountHistogramName, catalog_name_2, 1); +} - // Expect "TimeInQueue" metric to record the toast's duration since the second - // toast was queued right after the first one was shown. +TEST_F(ToastManagerImplTest, TimeInQueueMetric) { + base::HistogramTester histogram_tester; + + const ToastCatalogName catalog_name_1 = static_cast<ToastCatalogName>(1); + const ToastCatalogName catalog_name_2 = static_cast<ToastCatalogName>(2); + const base::TimeDelta duration = base::Seconds(2); + constexpr char text[] = "sample text"; + + // Show Toast with catalog_name_1. + std::string id1 = ShowToast(text, duration, /*visible_on_lock_screen=*/false, + catalog_name_1); + + // 'TimeInQueue' is zero since there were no toasts in the queue. + histogram_tester.ExpectTimeBucketCount(kToastTimeInQueueHistogramName, + base::Seconds(0), 1); + + // Replace existing toast a couple of times. + ReplaceToast(id1, text, duration, + /*visible_on_lock_screen=*/false, catalog_name_1); + ReplaceToast(id1, text, duration, + /*visible_on_lock_screen=*/false, catalog_name_1); + + // 'TimeInQueue' is zero since the same toast was replaced. + histogram_tester.ExpectTimeBucketCount(kToastTimeInQueueHistogramName, + base::Seconds(0), 3); + + // Try to show toast with catalog_name_2 right after last toast was shown. + ShowToast(text, duration, /*visible_on_lock_screen=*/false, catalog_name_2); + + // Fast forward the toast's duration so the queued toast is shown. + task_environment()->FastForwardBy(duration); + + // 'TimeInQueue' records the toast's duration since the second toast was + // queued right after the first one was shown. histogram_tester.ExpectTimeBucketCount(kToastTimeInQueueHistogramName, duration, 1); } +TEST_F(ToastManagerImplTest, UserJourneyTimeMetric) { + base::HistogramTester histogram_tester; + + const ToastCatalogName catalog_name = ToastCatalogName::kToastManagerUnittest; + const base::TimeDelta duration = base::Seconds(6); + constexpr char text[] = "sample text"; + + // Show Toast and wait for it to dismiss by time-out. + ShowToast(text, duration); + task_environment()->FastForwardBy(duration); + histogram_tester.ExpectBucketCount(kToastDismissedWithin7s, catalog_name, 1); + + // Show toast and replace it right after. + std::string id = ShowToast(text, duration); + ReplaceToast(id, text, duration); + task_environment()->FastForwardBy(duration); + + // Replaced toast was dismissed within 2s. + histogram_tester.ExpectBucketCount(kToastDismissedWithin2s, catalog_name, 1); + histogram_tester.ExpectBucketCount(kToastDismissedWithin7s, catalog_name, 2); + + // Show a toast with infinite duration. + ShowToastWithDismiss(text, ToastData::kInfiniteDuration); + task_environment()->FastForwardBy(duration + base::Seconds(2)); + ClickDismissButton(); + + // Toast with dismiss button was dismissed after 7s. + histogram_tester.ExpectBucketCount(kToastDismissedAfter7s, catalog_name, 1); +} + // Table-driven test that checks that a toast's expired callback is run when a // toast is closed when the toast manager cancels the toast, when the toast // duration cancels the toast, and when the dismiss button is pressed.
diff --git a/ash/webui/os_feedback_ui/resources/file_attachment.js b/ash/webui/os_feedback_ui/resources/file_attachment.js index b0f9d14..bffed1b 100644 --- a/ash/webui/os_feedback_ui/resources/file_attachment.js +++ b/ash/webui/os_feedback_ui/resources/file_attachment.js
@@ -6,7 +6,7 @@ import './os_feedback_shared_css.js'; import 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; import 'chrome://resources/cr_elements/icons.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
diff --git a/ash/webui/os_feedback_ui/resources/share_data_page.js b/ash/webui/os_feedback_ui/resources/share_data_page.js index 9b58f96..822dc74 100644 --- a/ash/webui/os_feedback_ui/resources/share_data_page.js +++ b/ash/webui/os_feedback_ui/resources/share_data_page.js
@@ -6,7 +6,7 @@ import './file_attachment.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/policy/cr_tooltip_icon.m.js'; import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js';
diff --git a/ash/webui/scanning/resources/multi_page_checkbox.js b/ash/webui/scanning/resources/multi_page_checkbox.js index 1a7e18b..9bc851df 100644 --- a/ash/webui/scanning/resources/multi_page_checkbox.js +++ b/ash/webui/scanning/resources/multi_page_checkbox.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import './scan_settings_section.js'; import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service.cc b/ash/webui/shimless_rma/backend/shimless_rma_service.cc index 039fda04..ae6b5f4 100644 --- a/ash/webui/shimless_rma/backend/shimless_rma_service.cc +++ b/ash/webui/shimless_rma/backend/shimless_rma_service.cc
@@ -54,8 +54,8 @@ // Metered networks are excluded for RMA to avoid any cost to the owner who // does not have control of the device during RMA. bool HaveAllowedNetworkConnection() { - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + NetworkStateHandler* network_state_handler = + NetworkHandler::Get()->network_state_handler(); const NetworkState* network = network_state_handler->DefaultNetwork(); // TODO(gavindodd): Confirm that metered networks should be excluded. This // should only be true for cellular networks which are already blocked.
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc b/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc index ec201be..79537823 100644 --- a/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc +++ b/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc
@@ -295,7 +295,7 @@ return cros_network_config_test_helper_->network_state_helper(); } - chromeos::NetworkStateHandler* network_state_handler() { + NetworkStateHandler* network_state_handler() { return network_state_helper().network_state_handler(); }
diff --git a/ash/webui/shimless_rma/backend/version_updater.cc b/ash/webui/shimless_rma/backend/version_updater.cc index 1a44a15..705c83d 100644 --- a/ash/webui/shimless_rma/backend/version_updater.cc +++ b/ash/webui/shimless_rma/backend/version_updater.cc
@@ -42,8 +42,8 @@ // the appropriate status. |interactive| indicates whether the user is actively // checking for updates. bool IsUpdateAllowed() { - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + NetworkStateHandler* network_state_handler = + NetworkHandler::Get()->network_state_handler(); const NetworkState* network = network_state_handler->DefaultNetwork(); // Don't allow an update if device is currently offline or connected // to a network for which data is metered.
diff --git a/ash/webui/shimless_rma/resources/calibration_component_chip.js b/ash/webui/shimless_rma/resources/calibration_component_chip.js index 8bcc280..dd5e0c5 100644 --- a/ash/webui/shimless_rma/resources/calibration_component_chip.js +++ b/ash/webui/shimless_rma/resources/calibration_component_chip.js
@@ -58,12 +58,27 @@ value: false, observer: 'onIsFirstClickableComponentChanged_', }, + + /** @type {number} */ + uniqueId: { + reflectToAttribute: true, + type: Number, + value: '', + }, }; } /** @protected */ onComponentButtonClicked_() { this.checked = !this.checked; + + // Notify the page that the component chip was clicked, so that the page can + // put the focus on it. + this.dispatchEvent(new CustomEvent('click-calibration-component-button', { + bubbles: true, + composed: true, + detail: this.uniqueId, + })); } click() {
diff --git a/ash/webui/shimless_rma/resources/fake_data.js b/ash/webui/shimless_rma/resources/fake_data.js index 668d6f3..80585a4 100644 --- a/ash/webui/shimless_rma/resources/fake_data.js +++ b/ash/webui/shimless_rma/resources/fake_data.js
@@ -248,13 +248,13 @@ progress: 1.0, }, { - component: ComponentType.kBaseAccelerometer, - status: CalibrationStatus.kCalibrationInProgress, + component: ComponentType.kLidAccelerometer, + status: CalibrationStatus.kCalibrationFailed, progress: 1.0, }, { - component: ComponentType.kLidAccelerometer, - status: CalibrationStatus.kCalibrationFailed, + component: ComponentType.kBaseAccelerometer, + status: CalibrationStatus.kCalibrationInProgress, progress: 1.0, }, { @@ -262,6 +262,16 @@ status: CalibrationStatus.kCalibrationSkip, progress: 0.0, }, + { + component: ComponentType.kScreen, + status: CalibrationStatus.kCalibrationFailed, + progress: 1.0, + }, + { + component: ComponentType.kScreen, + status: CalibrationStatus.kCalibrationFailed, + progress: 1.0, + }, ]; /** @type {!Array<!CalibrationComponentStatus>} */
diff --git a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.html b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.html index e391f73d..4a89fed 100644 --- a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.html +++ b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.html
@@ -10,9 +10,10 @@ </div> <div slot="right-pane"> <div class="scroll-container"> - <div class="component-grid calibration"> + <div id="componentList" class="component-grid calibration"> <template is="dom-repeat" items="{{componentCheckboxes_}}" as="component"> <calibration-component-chip id="[[component.id]]" + unique-id="[[component.uniqueId]]" checked="{{component.checked}}" failed="[[component.failed]]" component-name="[[component.name]]"
diff --git a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js index 3ca6b5c..fe2eb0cf 100644 --- a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js +++ b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js
@@ -12,7 +12,7 @@ import {assert} from 'chrome://resources/js/assert.m.js'; import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; -import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {afterNextRender, html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ComponentTypeToId} from './data.js'; import {getShimlessRmaService} from './mojo_interface_provider.js'; @@ -30,6 +30,7 @@ /** * @typedef {{ * component: !ComponentType, + * uniqueId: number, * id: string, * name: string, * checked: boolean, @@ -38,6 +39,8 @@ */ let ComponentCheckbox; +const NUM_COLUMNS = 1; + /** * @constructor * @extends {PolymerElement} @@ -70,6 +73,16 @@ type: Array, value: () => [], }, + + /** + * The index into componentCheckboxes_ for keyboard navigation between + * components. + * @private + */ + focusedComponentIndex_: { + type: Number, + value: -1, + }, }; } @@ -86,6 +99,92 @@ this.shimlessRmaService_ = getShimlessRmaService(); /** + * The componentClickedCallback_ callback is used to capture events when + * components are clicked, so that the page can put the focus on the + * component that was clicked. + * @private {?Function} + */ + this.componentClicked_ = (event) => { + const componentIndex = this.componentCheckboxes_.findIndex( + component => component.uniqueId === event.detail); + + if (componentIndex === -1 || + this.componentCheckboxes_[componentIndex].disabled) { + return; + } + + this.focusedComponentIndex_ = componentIndex; + this.focusOnCurrentComponent_(); + }; + + /** + * Handles keyboard navigation over the list of components. + * TODO(240717594): Find a way to avoid duplication of this code in the + * repair components page. + * @private {?Function} + */ + this.HandleKeyDownEvent = (event) => { + if (event.key !== 'ArrowRight' && event.key !== 'ArrowDown' && + event.key !== 'ArrowLeft' && event.key !== 'ArrowUp') { + return; + } + + // If there are no selectable components, do nothing. + if (this.focusedComponentIndex_ === -1) { + return; + } + + // Don't use keyboard navigation if the user tabbed out of the + // component list. + if (!this.shadowRoot.activeElement || + this.shadowRoot.activeElement.tagName !== + 'CALIBRATION-COMPONENT-CHIP') { + return; + } + + if (event.key === 'ArrowRight' || event.key === 'ArrowDown') { + // The Down button should send you down the column, so we go forward + // by two components, which is the size of the row. + let step = 1; + if (event.key === 'ArrowDown') { + step = NUM_COLUMNS; + } + + let newIndex = this.focusedComponentIndex_ + step; + // Keep skipping disabled components until we encounter one that is + // not disabled. + while (newIndex < this.componentCheckboxes_.length && + this.componentCheckboxes_[newIndex].disabled) { + newIndex += step; + } + // Check that we haven't ended up outside of the array before + // applying the changes. + if (newIndex < this.componentCheckboxes_.length) { + this.focusedComponentIndex_ = newIndex; + } + } + + // The left and up arrows work similarly to down and right, but go + // backwards. + if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') { + let step = 1; + if (event.key === 'ArrowUp') { + step = NUM_COLUMNS; + } + + let newIndex = this.focusedComponentIndex_ - step; + while (newIndex >= 0 && this.componentCheckboxes_[newIndex].disabled) { + newIndex -= step; + } + if (newIndex >= 0) { + this.focusedComponentIndex_ = newIndex; + } + } + + this.focusOnCurrentComponent_(); + }; + + /** * The "Skip calibration" button on this page is styled and positioned like * a exit button. So we use the common exit button from shimless_rma.js * This function needs to be public, because it's invoked by @@ -130,9 +229,10 @@ return; } - this.componentCheckboxes_ = result.components.map(item => { + this.componentCheckboxes_ = result.components.map((item, index) => { return { component: item.component, + uniqueId: index, id: ComponentTypeToId[item.component], name: this.i18n(ComponentTypeToId[item.component]), checked: false, @@ -142,9 +242,45 @@ disabled: item.status !== CalibrationStatus.kCalibrationFailed, }; }); + + // Focus on the first clickable component at the beginning. + this.focusedComponentIndex_ = + this.componentCheckboxes_.findIndex(component => !component.disabled); + afterNextRender(this, () => { + this.focusOnCurrentComponent_(); + }); }); } + /** @override */ + connectedCallback() { + super.connectedCallback(); + window.addEventListener('keydown', this.HandleKeyDownEvent); + window.addEventListener( + 'click-calibration-component-button', this.componentClicked_); + } + + /** @override */ + disconnectedCallback() { + super.disconnectedCallback(); + window.removeEventListener('keydown', this.HandleKeyDownEvent); + window.removeEventListener( + 'click-calibration-component-button', this.componentClicked_); + } + + /** + * Make the page focus on the component at focusedComponentIndex_. + * @private + */ + focusOnCurrentComponent_() { + if (this.focusedComponentIndex_ != -1) { + const componentChip = this.shadowRoot.querySelector(`[unique-id="${ + this.componentCheckboxes_[this.focusedComponentIndex_].uniqueId}"]`); + componentChip.shadowRoot.querySelector('#componentButton').focus(); + } + } + + /** * @return {!Array<!CalibrationComponentStatus>} * @private
diff --git a/ash/wm/desks/OWNERS b/ash/wm/desks/OWNERS index 111b3ba..dbaf9f1b8 100644 --- a/ash/wm/desks/OWNERS +++ b/ash/wm/desks/OWNERS
@@ -1 +1,2 @@ afakhry@chromium.org +dandersson@chromium.org
diff --git a/ash/wm/desks/templates/saved_desk_item_view.cc b/ash/wm/desks/templates/saved_desk_item_view.cc index 75cdf6a8..615b9c5e 100644 --- a/ash/wm/desks/templates/saved_desk_item_view.cc +++ b/ash/wm/desks/templates/saved_desk_item_view.cc
@@ -592,12 +592,12 @@ }, weak_ptr_factory_.GetWeakPtr())) .Once() - .SetOpacity(std::move(layer_to_show), 0.0f) - .SetOpacity(std::move(layer_to_hide), 1.0f) + .SetOpacity(layer_to_show, 0.0f) + .SetOpacity(layer_to_hide, 1.0f) .Then() .SetDuration(base::Milliseconds(kFadeDurationMs)) - .SetOpacity(std::move(layer_to_show), 1.0f) - .SetOpacity(std::move(layer_to_hide), 0.0f); + .SetOpacity(layer_to_show, 1.0f) + .SetOpacity(layer_to_hide, 0.0f); } void SavedDeskItemView::ContentsChanged(views::Textfield* sender,
diff --git a/base/BUILD.gn b/base/BUILD.gn index de7ba75..a707f0b 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -737,6 +737,8 @@ "task/sequence_manager/enqueue_order_generator.h", "task/sequence_manager/fence.cc", "task/sequence_manager/fence.h", + "task/sequence_manager/hierarchical_timing_wheel.cc", + "task/sequence_manager/hierarchical_timing_wheel.h", "task/sequence_manager/lazily_deallocated_deque.h", "task/sequence_manager/sequence_manager.cc", "task/sequence_manager/sequence_manager.h", @@ -3293,6 +3295,7 @@ "task/post_job_unittest.cc", "task/scoped_set_task_priority_for_current_thread_unittest.cc", "task/sequence_manager/atomic_flag_set_unittest.cc", + "task/sequence_manager/hierarchical_timing_wheel_unittest.cc", "task/sequence_manager/lazily_deallocated_deque_unittest.cc", "task/sequence_manager/sequence_manager_impl_unittest.cc", "task/sequence_manager/task_order_unittest.cc",
diff --git a/base/feature_list.cc b/base/feature_list.cc index 0885a9a..857322c 100644 --- a/base/feature_list.cc +++ b/base/feature_list.cc
@@ -28,6 +28,7 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/task/sequence_manager/work_queue.h" #include "build/build_config.h" namespace base { @@ -508,6 +509,8 @@ ConfigureRandBytesFieldTrial(); #endif + base::sequence_manager::internal::WorkQueue::ConfigureCapacityFieldTrial(); + #if BUILDFLAG(DCHECK_IS_CONFIGURABLE) // Update the behaviour of LOGGING_DCHECK to match the Feature configuration. // DCHECK is also forced to be FATAL if we are running a death-test.
diff --git a/base/logging.cc b/base/logging.cc index 80dab7d..412084c 100644 --- a/base/logging.cc +++ b/base/logging.cc
@@ -25,6 +25,11 @@ #include "base/trace_event/base_tracing.h" #include "build/build_config.h" +#if !BUILDFLAG(IS_NACL) +#include "base/auto_reset.h" +#include "base/debug/crash_logging.h" +#endif // !BUILDFLAG(IS_NACL) + #if defined(LEAK_SANITIZER) && !BUILDFLAG(IS_NACL) #include "base/debug/leak_annotations.h" #endif // defined(LEAK_SANITIZER) && !BUILDFLAG(IS_NACL) @@ -456,6 +461,39 @@ } } +void SetLogFatalCrashKey(LogMessage* log_message) { +#if !BUILDFLAG(IS_NACL) + // In case of an out-of-memory condition, this code could be reentered when + // constructing and storing the key. Using a static is not thread-safe, but if + // multiple threads are in the process of a fatal crash at the same time, this + // should work. + static bool guarded = false; + if (guarded) + return; + + base::AutoReset<bool> guard(&guarded, true); + + static auto* const crash_key = base::debug::AllocateCrashKeyString( + "LOG_FATAL", base::debug::CrashKeySize::Size1024); + base::debug::SetCrashKeyString(crash_key, log_message->BuildCrashString()); + +#endif // !BUILDFLAG(IS_NACL) +} + +std::string BuildCrashString(const char* file, + int line, + const char* message_without_prefix) { + // Only log last path component. + if (file) { + const char* slash = strrchr(file, '/'); + if (slash) { + file = slash + 1; + } + } + + return base::StringPrintf("%s:%d: %s", file, line, message_without_prefix); +} + } // namespace #if BUILDFLAG(DCHECK_IS_CONFIGURABLE) @@ -685,6 +723,9 @@ TRACE_LOG_MESSAGE( file_, base::StringPiece(str_newline).substr(message_start_), line_); + if (severity_ == LOGGING_FATAL) + SetLogFatalCrashKey(this); + // Give any log message handler first dibs on the message. if (g_log_message_handler && g_log_message_handler(severity_, file_, line_, message_start_, @@ -907,21 +948,8 @@ } std::string LogMessage::BuildCrashString() const { - return BuildCrashString(file(), line(), str().c_str() + message_start_); -} - -std::string LogMessage::BuildCrashString(const char* file, - int line, - const char* message_without_prefix) { - // Only log last path component. - if (file) { - const char* slash = strrchr(file, '/'); - if (slash) { - file = slash + 1; - } - } - - return base::StringPrintf("%s:%d: %s", file, line, message_without_prefix); + return logging::BuildCrashString(file(), line(), + str().c_str() + message_start_); } // writes the common header info to the stream
diff --git a/base/logging.h b/base/logging.h index acef975e..9cef63f2 100644 --- a/base/logging.h +++ b/base/logging.h
@@ -653,9 +653,6 @@ // Gets file:line: message in a format suitable for crash reporting. std::string BuildCrashString() const; - static std::string BuildCrashString(const char* file, - int line, - const char* message_without_prefix); private: void Init(const char* file, int line);
diff --git a/base/native_library_fuchsia.cc b/base/native_library_fuchsia.cc index a58c0f2..a1ccb86 100644 --- a/base/native_library_fuchsia.cc +++ b/base/native_library_fuchsia.cc
@@ -26,6 +26,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_restrictions.h" +#include "base_paths.h" namespace base { @@ -45,13 +46,13 @@ } FilePath computed_path; - base::PathService::Get(DIR_SOURCE_ROOT, &computed_path); + base::PathService::Get(DIR_ASSETS, &computed_path); computed_path = computed_path.AppendASCII("lib").Append(components[0]); // Use fdio_open_fd (a Fuchsia-specific API) here so we can pass the // appropriate FS rights flags to request executability. - // TODO(1018538): Teach base::File about FLAG_WIN_EXECUTE on Fuchsia, and then - // use it here instead of using fdio_open_fd() directly. + // TODO(crbug.com/1018538): Teach base::File about FLAG_WIN_EXECUTE on + // Fuchsia, and then use it here instead of using fdio_open_fd() directly. base::ScopedFD fd; zx_status_t status = fdio_open_fd( computed_path.value().c_str(),
diff --git a/base/task/sequence_manager/hierarchical_timing_wheel.cc b/base/task/sequence_manager/hierarchical_timing_wheel.cc new file mode 100644 index 0000000..0b429229 --- /dev/null +++ b/base/task/sequence_manager/hierarchical_timing_wheel.cc
@@ -0,0 +1,83 @@ +// Copyright 2022 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/task/sequence_manager/hierarchical_timing_wheel.h" + +namespace base::sequence_manager { + +//////////////////////////////////////////////////////////////////////////////// +// HierarchicalTimingWheelHandle + +HierarchicalTimingWheelHandle::HierarchicalTimingWheelHandle() = default; + +HierarchicalTimingWheelHandle::HierarchicalTimingWheelHandle( + HierarchicalTimingWheelHandle&& other) noexcept + : timing_wheel_handle_(std::move(other.timing_wheel_handle_)), + heap_handle_(std::move(other.heap_handle_)), + hierarchy_index_(std::exchange(other.hierarchy_index_, kInvalidIndex)) {} + +HierarchicalTimingWheelHandle& HierarchicalTimingWheelHandle::operator=( + HierarchicalTimingWheelHandle&& other) noexcept { + timing_wheel_handle_ = std::move(other.timing_wheel_handle_); + heap_handle_ = std::move(other.heap_handle_); + hierarchy_index_ = std::exchange(other.hierarchy_index_, kInvalidIndex); + return *this; +} + +HierarchicalTimingWheelHandle::~HierarchicalTimingWheelHandle() = default; + +internal::TimingWheelHandle +HierarchicalTimingWheelHandle::GetTimingWheelHandle() const { + return timing_wheel_handle_; +} + +void HierarchicalTimingWheelHandle::SetTimingWheelHandle( + internal::TimingWheelHandle timing_wheel_handle) { + DCHECK(timing_wheel_handle.IsValid()); + DCHECK(!heap_handle_.IsValid()); + timing_wheel_handle_ = timing_wheel_handle; +} + +void HierarchicalTimingWheelHandle::ClearTimingWheelHandle() { + timing_wheel_handle_.Reset(); +} + +HeapHandle HierarchicalTimingWheelHandle::GetHeapHandle() { + return heap_handle_; +} + +void HierarchicalTimingWheelHandle::SetHeapHandle(HeapHandle heap_handle) { + DCHECK(heap_handle.IsValid()); + DCHECK(!timing_wheel_handle_.IsValid()); + heap_handle_ = heap_handle; +} + +void HierarchicalTimingWheelHandle::ClearHeapHandle() { + heap_handle_.reset(); +} + +size_t HierarchicalTimingWheelHandle::GetHierarchyIndex() const { + return hierarchy_index_; +} + +void HierarchicalTimingWheelHandle::SetHierarchyIndex(size_t hierarchy_index) { + DCHECK(hierarchy_index != kInvalidIndex); + hierarchy_index_ = hierarchy_index; +} + +void HierarchicalTimingWheelHandle::ClearHierarchyIndex() { + hierarchy_index_ = kInvalidIndex; +} + +// static +HierarchicalTimingWheelHandle HierarchicalTimingWheelHandle::Invalid() { + return HierarchicalTimingWheelHandle(); +} + +bool HierarchicalTimingWheelHandle::IsValid() const { + return (timing_wheel_handle_.IsValid() || heap_handle_.IsValid()) && + hierarchy_index_ != kInvalidIndex; +} + +} // namespace base::sequence_manager
diff --git a/base/task/sequence_manager/hierarchical_timing_wheel.h b/base/task/sequence_manager/hierarchical_timing_wheel.h new file mode 100644 index 0000000..d8a52e9 --- /dev/null +++ b/base/task/sequence_manager/hierarchical_timing_wheel.h
@@ -0,0 +1,433 @@ +// Copyright 2022 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 BASE_TASK_SEQUENCE_MANAGER_HIERARCHICAL_TIMING_WHEEL_H_ +#define BASE_TASK_SEQUENCE_MANAGER_HIERARCHICAL_TIMING_WHEEL_H_ + +#include <algorithm> +#include <array> +#include <numeric> +#include <vector> + +#include "base/containers/intrusive_heap.h" +#include "base/task/sequence_manager/timing_wheel.h" +#include "base/time/time.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace base::sequence_manager { + +// A union of |TimingWheelHandle| and |HeapHandle|. At any given +// time it holds a value of one of its alternative types. It can only +// have either. This class is maintained by the hierarchical timing +// wheel as the object moves around within it. It can be used to subsequently +// remove the element. +class BASE_EXPORT HierarchicalTimingWheelHandle { + public: + enum : size_t { kInvalidIndex = std::numeric_limits<size_t>::max() }; + + HierarchicalTimingWheelHandle(); + + HierarchicalTimingWheelHandle(const HierarchicalTimingWheelHandle& other) = + default; + HierarchicalTimingWheelHandle(HierarchicalTimingWheelHandle&& other) noexcept; + + HierarchicalTimingWheelHandle& operator=( + const HierarchicalTimingWheelHandle& other) = default; + HierarchicalTimingWheelHandle& operator=( + HierarchicalTimingWheelHandle&& other) noexcept; + + ~HierarchicalTimingWheelHandle(); + + // TimingWheel contract + internal::TimingWheelHandle GetTimingWheelHandle() const; + void SetTimingWheelHandle(internal::TimingWheelHandle timing_wheel_handle); + void ClearTimingWheelHandle(); + + // IntrusiveHeap contract + HeapHandle GetHeapHandle(); + void SetHeapHandle(HeapHandle handle); + void ClearHeapHandle(); + + size_t GetHierarchyIndex() const; + void SetHierarchyIndex(size_t hierarchy_index); + void ClearHierarchyIndex(); + + // Gets a default constructed HierarchicalTimingWheelHandle. + static HierarchicalTimingWheelHandle Invalid(); + + bool IsValid() const; + + private: + // The handle of the timing wheel in the hierarchical timing wheel where the + // element is in. + internal::TimingWheelHandle timing_wheel_handle_; + + // The handle of the heap in the hierarchical timing wheel where the element + // is in. + HeapHandle heap_handle_; + + // The index in the hierarchy of timing wheels and heaps, this handle belongs + // to. + size_t hierarchy_index_ = kInvalidIndex; +}; + +// The default HierarchicalTimingWheelHandleAccessor, which simply forwards +// calls to the underlying type. It assumes |T| provides +// HierarchicalTimingWheelHandle storage and will simply forward calls to +// equivalent member function. +template <typename T> +struct DefaultHierarchicalTimingWheelHandleAccessor { + void SetTimingWheelHandle(T* element, + internal::TimingWheelHandle handle) const { + HierarchicalTimingWheelHandle* htw_handle = element->handle(); + htw_handle->SetTimingWheelHandle(handle); + } + + void ClearTimingWheelHandle(T* element) const { + HierarchicalTimingWheelHandle* htw_handle = element->handle(); + htw_handle->ClearTimingWheelHandle(); + } + + HeapHandle GetHeapHandle(const T* element) const { + HierarchicalTimingWheelHandle* htw_handle = element->handle(); + return htw_handle->GetHeapHandle(); + } + + void SetHeapHandle(T* element, HeapHandle handle) const { + HierarchicalTimingWheelHandle* htw_handle = element->handle(); + htw_handle->SetHeapHandle(handle); + } + + void ClearHeapHandle(T* element) const { + HierarchicalTimingWheelHandle* htw_handle = element->handle(); + htw_handle->ClearHeapHandle(); + } + + void SetHierarchyIndex(T* element, size_t hierarchy_index) const { + HierarchicalTimingWheelHandle* htw_handle = element->handle(); + htw_handle->SetHierarchyIndex(hierarchy_index); + } + + void ClearHierarchyIndex(T* element) const { + HierarchicalTimingWheelHandle* htw_handle = element->handle(); + htw_handle->ClearHierarchyIndex(); + } +}; + +// Gets the delayed run time of the |element|. Assumes the |element| has a +// public |delayed_run_time| member variable. +template <typename T> +struct GetDelayedRunTime { + TimeTicks operator()(const T& element) { return element.delayed_run_time; } +}; + +// Used for ordering elements in the IntrusiveHeap in the hierarchy. +template <typename T> +struct Compare { + bool operator()(const T& lhs, const T& rhs) const { + return lhs.delayed_run_time > rhs.delayed_run_time; + } +}; + +// This class is made to optimize the data structure IntrusiveHeap. Timers are +// implemented by scheduling the user task using TaskRunner::PostDelayedTask(). +// The elements are then inserted in an InstrusiveHeap. It suffers from its time +// complexity of O(LgN) removal and insertion. +// +// This class is an implementation of timing wheel technique. It contains a +// hierarchy which is a sequence of timing wheels and heaps with different +// granularities used to span a greater range of intervals. There are two heaps +// in the hierarchy, each placed on the two ends of the sequence of timing +// wheels. +// +// |T| is a typename for the intervals that are inserted in this class. +// |TotalWheels| is the number of timing wheels to be constructed in the +// hierarchy. |WheelSize| is the number of buckets in each of the timing wheel. +// |SmallestBucketDeltaInMicroseconds| corresponds to the time delta per +// bucket for the smallest timing wheel in the hierarchy. The time delta per +// bucket for the following timing wheels are WheelSize * +// |time_delta_per_bucket| of previous timing wheel. +// |HierarchicalTimingWheelHandleAccessor| is the type of the object which under +// the hood manages the HierarchicalTimingWheelHandle. |GetDelayedRunTime| is a +// function which returns the time when the element is due at. +// +// Example: +// Note: The number enclosing in the curly brackets "{}" are the data +// structure's hierarchy number. It exists to understand their order in the +// hierarchy. +// +// TotalWheels = 4 +// WheelSize = 100 +// SmallestBucketDeltaInMicroseconds = 500 microseconds +// +// Heap{0} - all elements with delays below 500 microseconds +// +// Wheel{1} - each bucket of 500microseconds = 0.5ms. +// bucket0 contains 0 <= delta < 0.5ms +// bucket1 contains 0.5 <= delta < 1ms +// Wheel1 contains 0.5 <= delta < 50ms +// +// Wheel{2} - each bucket of 50ms. +// bucket0 contains 0 <= delta < 50ms +// bucket1 contains 50ms <= delta < 100ms +// Wheel1 contains 50ms <= delta < 5s +// +// Wheel{3} - each bucket of 5s. +// bucket0 contains 0 <= delta < 5s +// bucket1 contains 5s <= delta < 10s +// Wheel1 contains 5s <= delta < 500s +// +// Wheel{4} - each bucket of 500s. +// bucket0 contains 0 <= delta < 500s +// bucket1 contains 500s <= delta < 1000s +// Wheel1 contains 500s <= delta < 50000s +// +// Heap{5} - all elements with delay above or equals to 500microseconds * +// (100^4) +// +// This class takes O(1) time to insert and cancel timers. However, if a element +// has a very small or big timer interval, then it's placed in a heap. This +// means, the removal and insertion won't be as efficient. However, the +// expectation is that such elements with very small or very big intervals would +// be very few. + +template <typename T, + size_t TotalWheels, + size_t WheelSize, + size_t SmallestBucketDeltaInMicroseconds, + typename HierarchicalTimingWheelHandleAccessor = + DefaultHierarchicalTimingWheelHandleAccessor<T>, + typename GetDelayedRunTime = GetDelayedRunTime<T>, + typename Compare = Compare<T>> +class HierarchicalTimingWheel { + public: + // Construct a HierarchicalTimingWheel instance where |last_wakeup| + // corresponds to the last time it was updated. + explicit HierarchicalTimingWheel( + TimeTicks last_wakeup, + const HierarchicalTimingWheelHandleAccessor& + hierarchical_timing_wheel_handle_accessor = + HierarchicalTimingWheelHandleAccessor(), + const GetDelayedRunTime& get_delayed_run_time = GetDelayedRunTime(), + const Compare compare = Compare()) + : small_delay_heap_(compare, hierarchical_timing_wheel_handle_accessor), + large_delay_heap_(compare, hierarchical_timing_wheel_handle_accessor), + last_wakeup_(last_wakeup), + hierarchical_timing_wheel_handle_accessor_( + hierarchical_timing_wheel_handle_accessor), + get_delayed_run_time_(get_delayed_run_time) {} + + HierarchicalTimingWheel(HierarchicalTimingWheel&&) = delete; + HierarchicalTimingWheel& operator=(HierarchicalTimingWheel&&) = delete; + + HierarchicalTimingWheel(const HierarchicalTimingWheel&) = delete; + HierarchicalTimingWheel& operator=(const HierarchicalTimingWheel&) = delete; + + ~HierarchicalTimingWheel() = default; + + size_t Size() { + return small_delay_heap_.size() + large_delay_heap_.size() + + std::accumulate(std::begin(wheels_), std::end(wheels_), 0, + [](size_t i, auto& wheel) { + return wheel.total_elements() + i; + }); + } + + // Inserts the |element| based on its delayed run time into one of the + // |wheels_|. + typename std::vector<T>::const_iterator Insert(T element) { + DCHECK(get_delayed_run_time_(element) > last_wakeup_); + + const TimeDelta delay = get_delayed_run_time_(element) - last_wakeup_; + const size_t hierarchy_index = FindHierarchyIndex(delay); + + if (IsHeap(hierarchy_index)) { + auto& heap = GetHeapForHierarchyIndex(hierarchy_index); + hierarchical_timing_wheel_handle_accessor_.SetHierarchyIndex( + &element, hierarchy_index); + auto it = heap.insert(std::move(element)); + return it; + } else { + auto& wheel = GetTimingWheelForHierarchyIndex(hierarchy_index); + hierarchical_timing_wheel_handle_accessor_.SetHierarchyIndex( + &element, hierarchy_index); + auto it = wheel.Insert(std::move(element), delay); + return it; + } + } + + // Updates the hierarchy and reassigns the elements that need to be + // placed in a different timing wheel or heap to reflect their respective + // delay. It returns the elements that are expired. + std::vector<T> Update(TimeTicks now) { + DCHECK(now >= last_wakeup_); + std::vector<T> expired_elements; + + // Check for expired elements in the small delay heap. + while (!small_delay_heap_.empty() && + get_delayed_run_time_(small_delay_heap_.top()) <= now) { + T element = small_delay_heap_.take_top(); + + // Clear the hierarchy index since the |element| will be returned. + hierarchical_timing_wheel_handle_accessor_.ClearHierarchyIndex(&element); + + expired_elements.push_back(std::move(element)); + } + + // Look into the timing wheels for elements which have either expired or + // need to be moved down the hierarchy. + std::vector<T> elements; + const TimeDelta time_delta = now - last_wakeup_; + const size_t timing_wheels_delay_upperbound = + SmallestBucketDeltaInMicroseconds * Pow(WheelSize, TotalWheels); + const TimeTicks timing_wheels_maximum_delayed_run_time = + now + Milliseconds(timing_wheels_delay_upperbound); + last_wakeup_ = now; + + for (size_t wheel_index = 0; wheel_index < TotalWheels; wheel_index++) { + wheels_[wheel_index].AdvanceTimeAndRemoveExpiredElements(time_delta, + elements); + } + + // Keep on removing the top elements from the |large_delay_heap_| which + // could be either moved down the hierarchy or are expired. + while (!large_delay_heap_.empty() && + get_delayed_run_time_(large_delay_heap_.top()) < + timing_wheels_maximum_delayed_run_time) { + elements.push_back(std::move(large_delay_heap_.take_top())); + } + + // Re-insert elements which haven't expired yet. + for (auto& element : elements) { + if (now >= get_delayed_run_time_(element)) { + hierarchical_timing_wheel_handle_accessor_.ClearHierarchyIndex( + &element); + expired_elements.emplace_back(std::move(element)); + } else { + // Doesn't clear hierarchy index since the element will have their + // hierarchy index overwritten when re-inserted. + Insert(std::move(element)); + } + } + + return expired_elements; + } + + // Removes the |element|. This is considered as the element getting cancelled + // and will never be run. + void Remove(HierarchicalTimingWheelHandle& handle) { + DCHECK(handle.IsValid()); + if (handle.GetTimingWheelHandle().IsValid()) { + auto& wheel = GetTimingWheelForHierarchyIndex(handle.GetHierarchyIndex()); + wheel.Remove(handle.GetTimingWheelHandle()); + } else { + auto& heap = GetHeapForHierarchyIndex(handle.GetHierarchyIndex()); + heap.erase(handle.GetHeapHandle()); + } + } + + // Returns the earliest due element in all of the hierarchy. This method + // should only called when the HierarchicalTimingWheel is not empty. + typename std::vector<T>::const_reference Top() { + DCHECK_NE(Size(), 0u); + + // Check for smallest elements heap first. + if (!small_delay_heap_.empty()) { + return small_delay_heap_.top(); + } + + // Iterate from smallest to biggest element wheel. + for (size_t i = 0; i < TotalWheels; i++) { + if (wheels_[i].total_elements() != 0) { + return wheels_[i].Top(); + } + } + + // The result must be in the biggest elements heap. + return large_delay_heap_.top(); + } + + private: + bool IsHeap(size_t hierarchy_index) { + return hierarchy_index == 0 or hierarchy_index == TotalWheels + 1; + } + + auto& GetHeapForHierarchyIndex(size_t hierarchy_index) { + DCHECK(hierarchy_index == 0 || hierarchy_index == TotalWheels + 1); + return hierarchy_index == 0 ? small_delay_heap_ : large_delay_heap_; + } + + auto& GetTimingWheelForHierarchyIndex(size_t hierarchy_index) { + DCHECK(hierarchy_index > 0); + DCHECK(hierarchy_index < TotalWheels + 1); + return wheels_[hierarchy_index - 1]; + } + + // Calculates the hierarchy index at which a element with |delay| should be + // appended in. + size_t FindHierarchyIndex(TimeDelta delay) { + DCHECK(!delay.is_zero()); + + if (delay < Microseconds(SmallestBucketDeltaInMicroseconds)) + return 0; + + for (size_t i = 0; i < TotalWheels; i++) { + if (delay < (wheels_[i].time_delta_per_bucket() * WheelSize)) { + return i + 1; + } + } + + // Return the index of the heap placed at the end of the hierarchy. + return TotalWheels + 1; + } + + // Computes |a| to the power of |b| at compile time. This is used to compute + // the parameter for |TimingWheel| when generating |wheels_| at compile + // time. + constexpr static std::size_t Pow(size_t a, size_t b) { + size_t res = 1; + for (size_t i = 0; i < b; i++) { + res *= a; + } + return res; + } + + using Wheel = + typename internal::TimingWheel<T, + WheelSize, + HierarchicalTimingWheelHandleAccessor, + GetDelayedRunTime>; + + // Generates |wheels_| at compile time. + template <size_t... I> + static std::array<Wheel, TotalWheels> MakeWheels(std::index_sequence<I...>) { + return {(Wheel(Microseconds(SmallestBucketDeltaInMicroseconds * + Pow(WheelSize, I))))...}; + } + + // The timing wheels where the elements are added according to their delay. + std::array<Wheel, TotalWheels> wheels_ = + MakeWheels(std::make_index_sequence<TotalWheels>{}); + + // There are two heaps enclosing the sequence of timing wheels. The first one + // contains elements whose delay is too small to enter a timing wheel. The + // second one contains elements whose delay is too big to enter a timing + // wheel. + IntrusiveHeap<T, Compare, HierarchicalTimingWheelHandleAccessor> + small_delay_heap_; + IntrusiveHeap<T, Compare, HierarchicalTimingWheelHandleAccessor> + large_delay_heap_; + + // The last time when the timing wheels were updated. + TimeTicks last_wakeup_; + + HierarchicalTimingWheelHandleAccessor + hierarchical_timing_wheel_handle_accessor_; + + GetDelayedRunTime get_delayed_run_time_; +}; + +} // namespace base::sequence_manager + +#endif
diff --git a/base/task/sequence_manager/hierarchical_timing_wheel_unittest.cc b/base/task/sequence_manager/hierarchical_timing_wheel_unittest.cc new file mode 100644 index 0000000..e22eb21 --- /dev/null +++ b/base/task/sequence_manager/hierarchical_timing_wheel_unittest.cc
@@ -0,0 +1,302 @@ +// Copyright 2022 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/task/sequence_manager/hierarchical_timing_wheel.h" + +#include <math.h> + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base::sequence_manager { + +namespace { + +// Custom comparator for testing. +template <typename T> +struct CustomCompare { + bool operator()(const T& lhs, const T& rhs) const { + return std::tie(lhs.delayed_run_time, lhs.name) > + std::tie(rhs.delayed_run_time, rhs.name); + } +}; + +class Task { + public: + enum : size_t { kInvalidIndex = std::numeric_limits<size_t>::max() }; + + explicit Task(TimeTicks delayed_run_time, std::string name = std::string()) + : delayed_run_time(delayed_run_time), + name(name), + handle_(std::make_unique<HierarchicalTimingWheelHandle>()) {} + + HierarchicalTimingWheelHandle* handle() const { return handle_.get(); } + + TimeTicks delayed_run_time; + + // Used as a second comparator key to test the custom comparator + // functionality. + std::string name; + + private: + std::unique_ptr<HierarchicalTimingWheelHandle> handle_; +}; + +} // namespace + +// Tests the construction of the object. +TEST(HierarchicalTimingWheelTest, SimpleTest) { + const TimeTicks baseline = TimeTicks::Now(); + HierarchicalTimingWheel<Task, 4, 100, 500> hierarchical_timing_wheel{ + baseline}; + + EXPECT_EQ(hierarchical_timing_wheel.Size(), 0u); + + auto* handle = + hierarchical_timing_wheel.Insert(Task{baseline + Microseconds(100)}) + ->handle(); + EXPECT_EQ(hierarchical_timing_wheel.Size(), 1u); + + hierarchical_timing_wheel.Remove(*handle); + EXPECT_EQ(hierarchical_timing_wheel.Size(), 0u); +} + +// Tests whether an element can be added in all the places in the hierarchy. +TEST(HierarchicalTimingWheelTest, InsertAllDistinctElements) { + const size_t kHierarchyCount = 6; + const TimeTicks baseline = TimeTicks::Now(); + HierarchicalTimingWheel<Task, 4, 100, 500> hierarchical_timing_wheel{ + baseline}; + + // Create time delta to insert a task in each of the hierarchy. The element's + // index represents the hierarchy index in which it will be inserted. The + // delays are chosen as per the example given in the class's header file. + const TimeDelta kDelay[kHierarchyCount] = { + Microseconds(100), Microseconds(500), Milliseconds(50), + Seconds(5), Seconds(500), Seconds(50000)}; + + HierarchicalTimingWheelHandle* handles[kHierarchyCount]; + for (size_t i = 0; i < kHierarchyCount; i++) { + handles[i] = + hierarchical_timing_wheel.Insert(Task{baseline + kDelay[i]})->handle(); + } + + for (size_t i = 0; i < kHierarchyCount; i++) { + EXPECT_EQ(handles[i]->GetHierarchyIndex(), i); + + const bool is_heap_handle = i == 0 || i == kHierarchyCount - 1; + EXPECT_EQ(handles[i]->GetHeapHandle().IsValid(), is_heap_handle); + EXPECT_EQ(handles[i]->GetTimingWheelHandle().IsValid(), !is_heap_handle); + } +} + +// Tests whether multiple elements can be added in the same place in the +// hierarchy. +TEST(HierarchicalTimingWheelTest, InsertSimilarElements) { + const size_t kTotalElements = 3; + const size_t kExpectedHierarchyIndex = 1; + const TimeTicks baseline = TimeTicks::Now(); + HierarchicalTimingWheel<Task, 4, 100, 500> hierarchical_timing_wheel{ + baseline}; + + // Create time delta to insert a task in the second hierarchy. + const TimeDelta kDelay[kTotalElements] = {Microseconds(500), Milliseconds(21), + Milliseconds(49)}; + + HierarchicalTimingWheelHandle* handles[kTotalElements]; + for (size_t i = 0; i < kTotalElements; i++) { + handles[i] = + hierarchical_timing_wheel.Insert(Task{baseline + kDelay[i]})->handle(); + } + + for (auto* handle : handles) { + EXPECT_EQ(handle->GetHierarchyIndex(), kExpectedHierarchyIndex); + EXPECT_EQ(handle->GetHeapHandle().IsValid(), false); + EXPECT_EQ(handle->GetTimingWheelHandle().IsValid(), true); + } +} + +// Tests whether the hierarchy can be updated and cascading take place from one +// hierarchy to another for an element. +TEST(HierarchicalTimingWheelTest, UpdateOneElement) { + const size_t kHierarchyCount = 6; + TimeTicks baseline = TimeTicks::Now(); + HierarchicalTimingWheel<Task, 4, 100, 500> hierarchical_timing_wheel{ + baseline}; + + // An array of deltas which cascades an element from the biggest + // hierarchy to the smallest sequentially, and then finally expiring the + // element. + const TimeDelta kTimeDelta[] = {Seconds(50000) - Seconds(500), + Seconds(500) - Seconds(5), + Seconds(5) - Milliseconds(50), + Milliseconds(50) - Microseconds(500), + Microseconds(500) - Microseconds(100), + Microseconds(100)}; + + // Create time delta to insert a task at the end of the hierarchy. + const TimeTicks delayed_run_time = baseline + Seconds(50000); + + HierarchicalTimingWheelHandle* handle = + hierarchical_timing_wheel.Insert(Task{delayed_run_time})->handle(); + + std::vector<Task> expired_tasks; + for (size_t i = 0; i < kHierarchyCount; i++) { + const size_t expected_hierarchy_index = kHierarchyCount - i - 1; + EXPECT_EQ(handle->GetHierarchyIndex(), expected_hierarchy_index); + baseline += kTimeDelta[i]; + expired_tasks = hierarchical_timing_wheel.Update(baseline); + + // An element will be returned as expired on the last Update. + const bool expired = i == kHierarchyCount - 1; + + // We expect one element to be returned, once. + EXPECT_EQ(expired_tasks.size() == 0, !expired); + EXPECT_EQ(expired_tasks.size() == 1, expired); + } +} + +// Tests whether the hierarchy can be updated and cascading take place of +// multiple existing elements in the hierarchy. +TEST(HierarchicalTimingWheelTest, UpdateMultipleElements) { + const size_t kHierarchyCount = 6; + TimeTicks baseline = TimeTicks::Now(); + HierarchicalTimingWheel<Task, 4, 100, 500> hierarchical_timing_wheel{ + baseline}; + + // Create time delta to insert a task in each of the hierarchy. The element's + // index represents the hierarchy index in which it will be inserted. + const TimeDelta kDelay[kHierarchyCount] = { + Microseconds(100), Microseconds(500), Milliseconds(50), + Seconds(5), Seconds(500), Seconds(50000)}; + + HierarchicalTimingWheelHandle* handles[kHierarchyCount]; + for (size_t i = 0; i < kHierarchyCount; i++) { + handles[i] = + hierarchical_timing_wheel.Insert(Task{baseline + kDelay[i]})->handle(); + } + + // This update expires all the inserted elements except the last two. + baseline += Seconds(499); + std::vector<Task> expired_tasks = hierarchical_timing_wheel.Update(baseline); + EXPECT_EQ(expired_tasks.size(), 4u); + EXPECT_EQ(handles[kHierarchyCount - 2]->GetHierarchyIndex(), 2u); + EXPECT_EQ(handles[kHierarchyCount - 1]->GetHierarchyIndex(), 4u); + + // Expires the last two elements by updating much more than latest delay + // element. + baseline += Seconds(100000); + expired_tasks = hierarchical_timing_wheel.Update(baseline); + EXPECT_EQ(expired_tasks.size(), 2u); +} + +// Tests whether an element can be removed from each hierarchy. +TEST(HierarchicalTimingWheelTest, RemoveElements) { + const size_t kHierarchyCount = 6; + const TimeTicks baseline = TimeTicks::Now(); + HierarchicalTimingWheel<Task, 4, 100, 500> hierarchical_timing_wheel{ + baseline}; + + // Create time delta to insert a task in each of the hierarchy. The element's + // index represents the hierarchy index in which it will be inserted. + const TimeDelta kDelay[kHierarchyCount] = { + Microseconds(100), Microseconds(500), Milliseconds(50), + Seconds(5), Seconds(500), Seconds(50000)}; + + HierarchicalTimingWheelHandle* handles[kHierarchyCount]; + for (size_t i = 0; i < kHierarchyCount; i++) { + handles[i] = + hierarchical_timing_wheel.Insert(Task{baseline + kDelay[i]})->handle(); + } + + for (auto* handle : handles) { + hierarchical_timing_wheel.Remove(*handle); + } + + // The biggest delay was Seconds(50000). Hence, this would remove any leftover + // element, which there aren't supposed to be. + std::vector<Task> expired_tasks = + hierarchical_timing_wheel.Update(baseline + Seconds(50000)); + EXPECT_EQ(expired_tasks.empty(), true); +} + +// Tests whether the top element of the hierarchy returned is correct when all +// distinct elements exist in the hierarchy. +TEST(HierarchicalTimingWheelTest, TopDifferentElements) { + const size_t kHierarchyCount = 6; + const TimeTicks baseline = TimeTicks::Now(); + HierarchicalTimingWheel<Task, 4, 100, 500> hierarchical_timing_wheel{ + baseline}; + + // Create time delta to insert a task in each of the hierarchy. The element's + // index represents the hierarchy index in which it will be inserted. + const TimeDelta kDelay[kHierarchyCount] = { + Microseconds(100), Microseconds(500), Milliseconds(50), + Seconds(5), Seconds(500), Seconds(50000)}; + + HierarchicalTimingWheelHandle* handles[kHierarchyCount]; + for (size_t i = 0; i < kHierarchyCount; i++) { + handles[i] = + hierarchical_timing_wheel.Insert(Task{baseline + kDelay[i]})->handle(); + const Task& task = hierarchical_timing_wheel.Top(); + EXPECT_EQ(task.delayed_run_time, baseline + kDelay[0]); + } + + for (size_t i = 0; i < kHierarchyCount; i++) { + const Task& task = hierarchical_timing_wheel.Top(); + EXPECT_EQ(task.delayed_run_time, baseline + kDelay[i]); + hierarchical_timing_wheel.Remove(*handles[i]); + } +} + +// Tests whether the top element of the hierarchy returned is correct when +// multiple similar elements are in the hierarchy. +TEST(HierarchicalTimingWheelTest, TopSimilarElements) { + const size_t kTotalElements = 3; + const TimeTicks baseline = TimeTicks::Now(); + HierarchicalTimingWheel<Task, 4, 100, 500> hierarchical_timing_wheel{ + baseline}; + + // Create time delta to insert a task in the first hierarchy. + const TimeDelta kDelay[kTotalElements] = { + Microseconds(100), Microseconds(200), Microseconds(300)}; + + HierarchicalTimingWheelHandle* handles[kTotalElements]; + for (size_t i = 0; i < kTotalElements; i++) { + handles[i] = + hierarchical_timing_wheel.Insert(Task{baseline + kDelay[i]})->handle(); + const Task& task = hierarchical_timing_wheel.Top(); + EXPECT_EQ(task.delayed_run_time, baseline + kDelay[0]); + } + + for (size_t i = 0; i < kTotalElements; i++) { + const Task& task = hierarchical_timing_wheel.Top(); + EXPECT_EQ(task.delayed_run_time, baseline + kDelay[i]); + hierarchical_timing_wheel.Remove(*handles[i]); + } +} + +// Tests whether the |Compare| functor is correctly used. +TEST(HierarchicalTimingWheelTest, CustomComparator) { + const std::string expectedTopTaskName = "a"; + const TimeTicks baseline = TimeTicks::Now(); + HierarchicalTimingWheel<Task, 4, 100, 500, + DefaultHierarchicalTimingWheelHandleAccessor<Task>, + GetDelayedRunTime<Task>, CustomCompare<Task>> + hierarchical_timing_wheel{baseline}; + + // Create time delta to insert a task in the first hierarchy. + const TimeDelta kDelay = Microseconds(100); + + // Inserts two elements in the same bucket. + hierarchical_timing_wheel.Insert(Task{baseline + kDelay, "z"}); + hierarchical_timing_wheel.Insert(Task{baseline + kDelay, "a"}); + const Task& task = hierarchical_timing_wheel.Top(); + + // The custom comparator orders by the name's lexicographical order, + // since both the elements have the same delayed run time. + EXPECT_EQ(task.name, expectedTopTaskName); +} + +} // namespace base::sequence_manager
diff --git a/base/task/sequence_manager/work_queue.cc b/base/task/sequence_manager/work_queue.cc index 1bb4ebb..9c8512b6 100644 --- a/base/task/sequence_manager/work_queue.cc +++ b/base/task/sequence_manager/work_queue.cc
@@ -4,8 +4,11 @@ #include "base/task/sequence_manager/work_queue.h" +#include <atomic> + #include "base/containers/stack_container.h" #include "base/debug/alias.h" +#include "base/metrics/field_trial_params.h" #include "base/task/sequence_manager/fence.h" #include "base/task/sequence_manager/sequence_manager_impl.h" #include "base/task/sequence_manager/task_order.h" @@ -17,6 +20,39 @@ namespace sequence_manager { namespace internal { +namespace { + +const Feature kDifferentWorkQueueCapacities{"DifferentWorkQueueCapacities", + FEATURE_DISABLED_BY_DEFAULT}; + +std::atomic<bool> g_different_work_queue_capacities_feature_enabled(false); + +} // namespace + +// static +void WorkQueue::ConfigureCapacityFieldTrial() { + g_different_work_queue_capacities_feature_enabled.store( + FeatureList::IsEnabled(kDifferentWorkQueueCapacities), + std::memory_order_relaxed); +} + +// static +bool WorkQueue::IsDifferentWorkQueueCapacitiesEnabled() { + return g_different_work_queue_capacities_feature_enabled.load( + std::memory_order_relaxed); +} + +// static +size_t WorkQueue::GetStackCapacityChoice() { + static const size_t kStackCapacityChoice = + IsDifferentWorkQueueCapacitiesEnabled() + ? static_cast<size_t>(GetFieldTrialParamByFeatureAsInt( + kDifferentWorkQueueCapacities, "StackCapacity", + StackCapacity::kDefault)) + : StackCapacity::kDefault; + return kStackCapacityChoice; +} + WorkQueue::WorkQueue(TaskQueueImpl* task_queue, const char* name, QueueType queue_type) @@ -219,14 +255,12 @@ return pending_task; } -bool WorkQueue::RemoveAllCanceledTasksFromFront() { - if (!work_queue_sets_) - return false; - +template <size_t stack_capacity> +bool WorkQueue::RemoveAllCancelledTasksFromFrontImpl() { // Since task destructors could have a side-effect of deleting this task queue // we move cancelled tasks into a temporary container which can be emptied // without accessing |this|. - StackVector<Task, 8> tasks_to_delete; + StackVector<Task, stack_capacity> tasks_to_delete; while (!tasks_.empty()) { const auto& pending_task = tasks_.front(); @@ -256,6 +290,31 @@ return !tasks_to_delete->empty(); } +template bool WorkQueue::RemoveAllCancelledTasksFromFrontImpl< + WorkQueue::StackCapacity::kSmall>(); +template bool WorkQueue::RemoveAllCancelledTasksFromFrontImpl< + WorkQueue::StackCapacity::kMedium>(); +template bool WorkQueue::RemoveAllCancelledTasksFromFrontImpl< + WorkQueue::StackCapacity::kLarge>(); +template bool WorkQueue::RemoveAllCancelledTasksFromFrontImpl< + WorkQueue::StackCapacity::kDefault>(); + +bool WorkQueue::RemoveAllCanceledTasksFromFront() { + if (!work_queue_sets_) + return false; + + switch (GetStackCapacityChoice()) { + case StackCapacity::kSmall: + return RemoveAllCancelledTasksFromFrontImpl<StackCapacity::kSmall>(); + case StackCapacity::kMedium: + return RemoveAllCancelledTasksFromFrontImpl<StackCapacity::kMedium>(); + case StackCapacity::kLarge: + return RemoveAllCancelledTasksFromFrontImpl<StackCapacity::kLarge>(); + default: + return RemoveAllCancelledTasksFromFrontImpl<StackCapacity::kDefault>(); + } +} + void WorkQueue::AssignToWorkQueueSets(WorkQueueSets* work_queue_sets) { work_queue_sets_ = work_queue_sets; }
diff --git a/base/task/sequence_manager/work_queue.h b/base/task/sequence_manager/work_queue.h index d236666..082cb1a10 100644 --- a/base/task/sequence_manager/work_queue.h +++ b/base/task/sequence_manager/work_queue.h
@@ -163,7 +163,29 @@ void CollectTasksOlderThan(TaskOrder reference, std::vector<const Task*>* result) const; + // This is for an experiment where we try different WorkQueue capacities + // when deleting tasks in RemoveAllCanceledTasksFromFront() (see + // crbug.com/1347892). Tests spawn threads around the time FeatureList is + // initialized, which creates race conditions as WorkQueue is trying to read + // the Feature while threads spawn. To solve this, we store the value of the + // Feature in a std::atomic<bool> and initialize it once in SetInstance(), and + // read this atomic value instead of calling IsEnabled(). + static void ConfigureCapacityFieldTrial(); + static bool IsDifferentWorkQueueCapacitiesEnabled(); + private: + enum StackCapacity : size_t { + kSmall = 4, + kMedium = 16, + kLarge = 24, + kDefault = 8, + }; + + static size_t GetStackCapacityChoice(); + + template <size_t stack_capacity> + bool RemoveAllCancelledTasksFromFrontImpl(); + bool InsertFenceImpl(Fence fence); TaskQueueImpl::TaskDeque tasks_;
diff --git a/base/test/launcher/test_launcher_unittest.cc b/base/test/launcher/test_launcher_unittest.cc index 3c9bc2ad..46b98f9 100644 --- a/base/test/launcher/test_launcher_unittest.cc +++ b/base/test/launcher/test_launcher_unittest.cc
@@ -8,6 +8,7 @@ #include "base/base64.h" #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/command_line.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" @@ -809,7 +810,8 @@ // Validate delegate produces correct command line. TEST_F(UnitTestLauncherDelegateTester, GetCommandLine) { - UnitTestLauncherDelegate launcher_delegate(&defaultPlatform, 10u, true); + UnitTestLauncherDelegate launcher_delegate(&defaultPlatform, 10u, true, + DoNothing()); TestLauncherDelegate* delegate_ptr = &launcher_delegate; std::vector<std::string> test_names(5, "Tests"); @@ -1049,7 +1051,8 @@ // Validate delegate sets batch size correctly. TEST_F(UnitTestLauncherDelegateTester, BatchSize) { - UnitTestLauncherDelegate launcher_delegate(&defaultPlatform, 15u, true); + UnitTestLauncherDelegate launcher_delegate(&defaultPlatform, 15u, true, + DoNothing()); TestLauncherDelegate* delegate_ptr = &launcher_delegate; EXPECT_EQ(delegate_ptr->GetBatchSize(), 15u); }
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc index f58381d..58f05f20 100644 --- a/base/test/launcher/unit_test_launcher.cc +++ b/base/test/launcher/unit_test_launcher.cc
@@ -151,6 +151,7 @@ int default_batch_limit, size_t retry_limit, bool use_job_objects, + RepeatingClosure timeout_callback, OnceClosure gtest_init) { base::test::AllowCheckIsTestToBeCalled(); @@ -218,7 +219,7 @@ DefaultUnitTestPlatformDelegate platform_delegate; UnitTestLauncherDelegate delegate(&platform_delegate, batch_limit, - use_job_objects); + use_job_objects, timeout_callback); TestLauncher launcher(&delegate, parallel_jobs, retry_limit); bool success = launcher.Run(); @@ -277,6 +278,7 @@ } return LaunchUnitTestsInternal(std::move(run_test_suite), parallel_jobs, kDefaultTestBatchLimit, retry_limit, true, + DoNothing(), BindOnce(&InitGoogleTestChar, &argc, argv)); } @@ -285,7 +287,7 @@ RunTestSuiteCallback run_test_suite) { CommandLine::Init(argc, argv); return LaunchUnitTestsInternal(std::move(run_test_suite), 1U, - kDefaultTestBatchLimit, 1U, true, + kDefaultTestBatchLimit, 1U, true, DoNothing(), BindOnce(&InitGoogleTestChar, &argc, argv)); } @@ -294,10 +296,12 @@ size_t parallel_jobs, int default_batch_limit, bool use_job_objects, + RepeatingClosure timeout_callback, RunTestSuiteCallback run_test_suite) { CommandLine::Init(argc, argv); return LaunchUnitTestsInternal(std::move(run_test_suite), parallel_jobs, default_batch_limit, 1U, use_job_objects, + timeout_callback, BindOnce(&InitGoogleTestChar, &argc, argv)); } @@ -314,6 +318,7 @@ } return LaunchUnitTestsInternal(std::move(run_test_suite), parallel_jobs, kDefaultTestBatchLimit, 1U, use_job_objects, + DoNothing(), BindOnce(&InitGoogleTestWChar, &argc, argv)); } #endif // BUILDFLAG(IS_WIN) @@ -369,10 +374,12 @@ UnitTestLauncherDelegate::UnitTestLauncherDelegate( UnitTestPlatformDelegate* platform_delegate, size_t batch_limit, - bool use_job_objects) + bool use_job_objects, + RepeatingClosure timeout_callback) : platform_delegate_(platform_delegate), batch_limit_(batch_limit), - use_job_objects_(use_job_objects) {} + use_job_objects_(use_job_objects), + timeout_callback_(timeout_callback) {} UnitTestLauncherDelegate::~UnitTestLauncherDelegate() { DCHECK(thread_checker_.CalledOnValidThread()); @@ -416,4 +423,8 @@ return batch_limit_; } +void UnitTestLauncherDelegate::OnTestTimedOut(const CommandLine& cmd_line) { + timeout_callback_.Run(); +} + } // namespace base
diff --git a/base/test/launcher/unit_test_launcher.h b/base/test/launcher/unit_test_launcher.h index 75a6c8a..4e867e6 100644 --- a/base/test/launcher/unit_test_launcher.h +++ b/base/test/launcher/unit_test_launcher.h
@@ -40,11 +40,15 @@ // |default_batch_limit| is the default size of test batch // (use 0 to disable batching). // |use_job_objects| determines whether to use job objects. +// |timeout_callback| is called each time a test batch times out. It can be used +// as a cue to print additional debugging information about the test system, +// such as log files or the names of running processes. int LaunchUnitTestsWithOptions(int argc, char** argv, size_t parallel_jobs, int default_batch_limit, bool use_job_objects, + RepeatingClosure timeout_callback, RunTestSuiteCallback run_test_suite); #if BUILDFLAG(IS_WIN) @@ -128,7 +132,8 @@ public: UnitTestLauncherDelegate(UnitTestPlatformDelegate* delegate, size_t batch_limit, - bool use_job_objects); + bool use_job_objects, + RepeatingClosure timeout_callback); UnitTestLauncherDelegate(const UnitTestLauncherDelegate&) = delete; UnitTestLauncherDelegate& operator=(const UnitTestLauncherDelegate&) = delete; @@ -151,6 +156,8 @@ size_t GetBatchSize() override; + void OnTestTimedOut(const CommandLine& cmd_line) override; + ThreadChecker thread_checker_; raw_ptr<UnitTestPlatformDelegate> platform_delegate_; @@ -160,6 +167,9 @@ // Determines whether we use job objects on Windows. bool use_job_objects_; + + // Callback to invoke when a test process times out. + RepeatingClosure timeout_callback_; }; // We want to stop throwing away duplicate test filter file flags, but we're
diff --git a/base/values.cc b/base/values.cc index 9dc7ff6..c6f102d 100644 --- a/base/values.cc +++ b/base/values.cc
@@ -12,6 +12,7 @@ #include "base/as_const.h" #include "base/bit_cast.h" +#include "base/check.h" #include "base/check_op.h" #include "base/containers/checked_iterators.h" #include "base/containers/cxx20_erase_vector.h" @@ -345,10 +346,12 @@ } bool Value::GetBool() const { + DCHECK(is_bool()); return absl::get<bool>(data_); } int Value::GetInt() const { + DCHECK(is_int()); return absl::get<int>(data_); } @@ -362,30 +365,37 @@ } const std::string& Value::GetString() const { + DCHECK(is_string()); return absl::get<std::string>(data_); } std::string& Value::GetString() { + DCHECK(is_string()); return absl::get<std::string>(data_); } const Value::BlobStorage& Value::GetBlob() const { + DCHECK(is_blob()); return absl::get<BlobStorage>(data_); } const Value::Dict& Value::GetDict() const { + DCHECK(is_dict()); return absl::get<Dict>(data_); } Value::Dict& Value::GetDict() { + DCHECK(is_dict()); return absl::get<Dict>(data_); } const Value::List& Value::GetList() const { + DCHECK(is_list()); return absl::get<List>(data_); } Value::List& Value::GetList() { + DCHECK(is_list()); return absl::get<List>(data_); }
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc index 5cabfb3f..e4b64ff 100644 --- a/build/sanitizers/tsan_suppressions.cc +++ b/build/sanitizers/tsan_suppressions.cc
@@ -104,6 +104,7 @@ // https://crbug.com/794920 "race:base::debug::SetCrashKeyString\n" + "race:crash_reporter::internal::CrashKeyStringImpl::Clear\n" "race:crash_reporter::internal::CrashKeyStringImpl::Set\n" // http://crbug.com/927330
diff --git a/build/util/version.gni b/build/util/version.gni deleted file mode 100644 index eec226e..0000000 --- a/build/util/version.gni +++ /dev/null
@@ -1,6 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# TODO(crbug.com/1347803): Delete this file. -import("//chrome/version.gni")
diff --git a/cc/paint/image_transfer_cache_entry_unittest.cc b/cc/paint/image_transfer_cache_entry_unittest.cc index 817d311..b18eb55 100644 --- a/cc/paint/image_transfer_cache_entry_unittest.cc +++ b/cc/paint/image_transfer_cache_entry_unittest.cc
@@ -36,6 +36,7 @@ #include "ui/gl/gl_context_egl.h" #include "ui/gl/gl_share_group.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/create_gr_gl_interface.h" #include "ui/gl/init/gl_factory.h" @@ -86,7 +87,8 @@ public: void SetUp() override { // Initialize a GL GrContext for Skia. - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), + gfx::Size()); ASSERT_TRUE(surface_); share_group_ = base::MakeRefCounted<gl::GLShareGroup>(); gl_context_ = base::MakeRefCounted<gl::GLContextEGL>(share_group_.get()); @@ -94,9 +96,9 @@ ASSERT_TRUE( gl_context_->Initialize(surface_.get(), gl::GLContextAttribs())); ASSERT_TRUE(gl_context_->MakeCurrent(surface_.get())); - sk_sp<GrGLInterface> interface(gl::init::CreateGrGLInterface( + sk_sp<GrGLInterface> gl_interface(gl::init::CreateGrGLInterface( *gl_context_->GetVersionInfo(), false /* use_version_es2 */)); - gr_context_ = GrDirectContext::MakeGL(std::move(interface)); + gr_context_ = GrDirectContext::MakeGL(std::move(gl_interface)); ASSERT_TRUE(gr_context_); }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 3867c5f8..d6d99fc 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -1770,6 +1770,7 @@ "//services/device/public/java:geolocation_java", "//services/device/public/java:geolocation_java_test_support", "//services/device/public/mojom:mojom_java", + "//services/media_session/public/mojom:mojom_java", "//services/network/public/mojom:mojom_java", "//services/network/public/mojom:mojom_proxy_config_java", "//services/network/public/mojom:url_loader_base_java",
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni index 7e3ed53..631f2f3 100644 --- a/chrome/android/chrome_java_resources.gni +++ b/chrome/android/chrome_java_resources.gni
@@ -504,6 +504,7 @@ "java/res/layout/custom_tabs_control_container.xml", "java/res/layout/custom_tabs_handle_view.xml", "java/res/layout/custom_tabs_navigation_bar.xml", + "java/res/layout/custom_tabs_toast_branding_layout.xml", "java/res/layout/custom_tabs_toolbar.xml", "java/res/layout/custom_tabs_toolbar_button.xml", "java/res/layout/custom_tabs_topbar.xml",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java index d764e78..9681207 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
@@ -402,6 +402,10 @@ mMediator.softCleanup(); } + void hardCleanup() { + mMediator.hardCleanup(); + } + void prepareTabSwitcherView() { if (mGlobalLayoutListener != null) { mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener); @@ -409,6 +413,7 @@ registerLayoutChangeListener(); mRecyclerView.prepareTabSwitcherView(); mMediator.prepareTabSwitcherView(); + mMediator.registerOnScrolledListener(mRecyclerView); } private void registerLayoutChangeListener() {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java index cbb6eb1..08ca85c 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -33,6 +33,8 @@ import androidx.appcompat.content.res.AppCompatResources; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.OnScrollListener; import org.chromium.base.Callback; import org.chromium.base.Log; @@ -99,8 +101,10 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** * Mediator for business logic for the tab grid. This class should be initialized with a list of @@ -362,6 +366,7 @@ private static final String TAG = "TabListMediator"; private static Map<Integer, Integer> sTabClosedFromMapTabClosedFromMap = new HashMap<>(); + private static Set<Integer> sViewedTabIds = new HashSet<>(); private final Context mContext; private final TabListModel mModel; @@ -384,6 +389,10 @@ private @UiType int mUiType; private int mSearchChipIconDrawableId; private GridLayoutManager mGridLayoutManager; + // mRecyclerView and mOnScrollListener are null, unless the the price drop IPH or badge is + // enabled. + private @Nullable RecyclerView mRecyclerView; + private @Nullable OnScrollListener mOnScrollListener; private final TabActionListener mTabSelectedListener = new TabActionListener() { @Override @@ -1231,8 +1240,20 @@ return false; } + /** + * Add the tab id of a {@Tab} that has been viewed to the sViewedTabIds set. + * @param tabIndex The tab index of a {@Tab} the user has viewed. + */ + private void addViewedTabId(int tabIndex) { + assert !mTabModelSelector.getCurrentModel().isIncognito(); + int tabId = mModel.get(tabIndex).model.get(TabProperties.TAB_ID); + assert TabModelUtils.getTabById(mTabModelSelector.getCurrentModel(), tabId) != null; + sViewedTabIds.add(tabId); + } + void postHiding() { mVisible = false; + unregisterOnScrolledListener(); } private boolean isSelectedTab(PseudoTab tab, int tabModelSelectedTabId) { @@ -1256,6 +1277,33 @@ } } + void hardCleanup() { + assert !mVisible; + if (PriceTrackingUtilities.isTrackPricesOnTabsEnabled() + && (PriceTrackingFeatures.isPriceDropIphEnabled() + || PriceTrackingFeatures.isPriceDropBadgeEnabled())) { + saveSeenPriceDrops(); + } + sViewedTabIds.clear(); + } + + /** + * While leaving the tab switcher grid this update whether a tab's current price drop has or has + * not been seen. + */ + private void saveSeenPriceDrops() { + for (Integer tabId : sViewedTabIds) { + Tab tab = TabModelUtils.getTabById(mTabModelSelector.getModel(false), tabId); + if (tab != null && isUngroupedTab(tab.getId())) { + ShoppingPersistedTabData.from(tab, (sptd) -> { + if (sptd != null && sptd.getPriceDrop() != null) { + sptd.setIsCurrentPriceDropSeen(true); + } + }); + } + } + } + private void updateTab(int index, PseudoTab pseudoTab, boolean isSelected, boolean isUpdatingId, boolean quickMode) { if (index < 0 || index >= mModel.size()) return; @@ -1329,6 +1377,11 @@ return getRelatedTabsForId(tabId).size() == 1; } + @VisibleForTesting + public Set<Integer> getViewedTabIdsForTesting() { + return sViewedTabIds; + } + /** * @return The callback that hosts the logic for swipe and drag related actions. */ @@ -1380,6 +1433,40 @@ } /** + * Adds an on scroll listener to {@link TabListRecyclerView} that determines whether a tab + * thumbnail is within view after a scroll is completed. + * @param recyclerView the {@link TabListRecyclerView} to add the listener too. + */ + void registerOnScrolledListener(RecyclerView recyclerView) { + if (PriceTrackingUtilities.isTrackPricesOnTabsEnabled() + && (PriceTrackingFeatures.isPriceDropIphEnabled() + || PriceTrackingFeatures.isPriceDropBadgeEnabled())) { + mRecyclerView = recyclerView; + mOnScrollListener = new OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + if (!mTabModelSelector.isIncognitoSelected()) { + for (int i = 0; i < mRecyclerView.getChildCount(); i++) { + if (mRecyclerView.getLayoutManager().isViewPartiallyVisible( + mRecyclerView.getChildAt(i), false, true)) { + addViewedTabId(i); + } + } + } + } + }; + mRecyclerView.addOnScrollListener(mOnScrollListener); + } + } + + private void unregisterOnScrolledListener() { + if (mRecyclerView != null && mOnScrollListener != null) { + mRecyclerView.removeOnScrollListener(mOnScrollListener); + mOnScrollListener = null; + } + } + + /** * Span count is computed based on screen width for tablets and orientation for phones. * When in multi-window mode on phone, the span count is fixed to 2 to keep tab card size * reasonable. @@ -1478,6 +1565,7 @@ if (mTemplateUrlObserver != null) { TemplateUrlServiceFactory.get().removeObserver(mTemplateUrlObserver); } + unregisterOnScrolledListener(); } private void addTabInfoToModel(final PseudoTab pseudoTab, int index, boolean isSelected) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java index eec795c9..2bd0f054 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -805,6 +805,11 @@ mTabListCoordinator.softCleanup(); } + @Override + public void hardCleanup() { + mTabListCoordinator.hardCleanup(); + } + // ResetHandler implementation. @Override public void onDestroy() {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java index 7e271d6..8052cc0f 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
@@ -188,6 +188,13 @@ * Release the thumbnail {@link Bitmap} but keep the {@link TabGridView}. */ void softCleanup(); + + /** + * Check to see if there are any not viewed price drops when the user leaves the tab + * switcher. This is done only before the coordinator is destroyed to reduce the amount of + * calls to ShoppingPersistedTabData. + */ + void hardCleanup(); } /** @@ -434,8 +441,10 @@ mContainerView = containerView; mSoftClearTabListRunnable = mResetHandler::softCleanup; - mClearTabListRunnable = - () -> mResetHandler.resetWithTabList(null, false, mShowTabsInMruOrder); + mClearTabListRunnable = () -> { + mResetHandler.hardCleanup(); + mResetHandler.resetWithTabList(null, false, mShowTabsInMruOrder); + }; mHandler = new Handler(); mTabContentManager = tabContentManager;
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java index 9faf173..ff9d13c 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -169,6 +169,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * Tests for {@link TabListMediator}. */ @@ -253,6 +254,8 @@ @Mock RecyclerView mRecyclerView; @Mock + TabListRecyclerView mTabListRecyclerView; + @Mock RecyclerView.Adapter mAdapter; @Mock TabGroupModelFilter mTabGroupModelFilter; @@ -305,6 +308,8 @@ ArgumentCaptor<ComponentCallbacks> mComponentCallbacksCaptor; @Captor ArgumentCaptor<TemplateUrlService.TemplateUrlServiceObserver> mTemplateUrlServiceObserver; + @Captor + ArgumentCaptor<RecyclerView.OnScrollListener> mOnScrollListenerCaptor; @Mock EndpointFetcher.Natives mEndpointFetcherJniMock; @Mock @@ -3145,6 +3150,31 @@ -1)); } + @Test + public void testPriceDropSeen() throws TimeoutException { + setPriceTrackingEnabledForTesting(true); + PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(true); + PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeBoolean( + PriceTrackingUtilities.TRACK_PRICES_ON_TABS, true); + + doReturn(false).when(mTab1).isIncognito(); + doReturn(false).when(mTab2).isIncognito(); + + List<Tab> tabs = new ArrayList<>(); + tabs.add(mTabModel.getTabAt(0)); + tabs.add(mTabModel.getTabAt(1)); + + mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), + /*quickMode =*/false, /*mruMode =*/false); + + prepareRecyclerViewForScroll(); + mMediator.registerOnScrolledListener(mRecyclerView); + verify(mRecyclerView).addOnScrollListener(mOnScrollListenerCaptor.capture()); + mOnScrollListenerCaptor.getValue().onScrolled( + mRecyclerView, /*dx =*/mTabModel.getCount(), /*dy =*/0); + assertEquals(2, mMediator.getViewedTabIdsForTesting().size()); + } + private void setUpCloseButtonDescriptionString(boolean isGroup) { if (isGroup) { doAnswer(invocation -> { @@ -3400,11 +3430,23 @@ doReturn(mPriceDrop).when(mShoppingPersistedTabData).getPriceDrop(); } + private void prepareRecyclerViewForScroll() { + View seenView = mock(View.class); + for (int i = 0; i < mTabModel.getCount(); i++) { + when(mRecyclerView.getChildAt(i)).thenReturn(seenView); + } + + doReturn(true).when(mGridLayoutManager).isViewPartiallyVisible(seenView, false, true); + doReturn(mTabModel.getCount()).when(mRecyclerView).getChildCount(); + } + private static void setPriceTrackingEnabledForTesting(boolean value) { FeatureList.TestValues testValues = new FeatureList.TestValues(); testValues.addFeatureFlagOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, true); testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, PriceTrackingFeatures.PRICE_TRACKING_PARAM, String.valueOf(value)); + testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, + PriceTrackingFeatures.PRICE_DROP_IPH_ENABLED_PARAM, String.valueOf(value)); FeatureList.setTestValues(testValues); } }
diff --git a/chrome/android/java/res/layout/custom_tabs_toast_branding_layout.xml b/chrome/android/java/res/layout/custom_tabs_toast_branding_layout.xml new file mode 100644 index 0000000..3e600b3 --- /dev/null +++ b/chrome/android/java/res/layout/custom_tabs_toast_branding_layout.xml
@@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2022 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. --> + +<org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="44dp" + android:gravity="center" + android:maxLines="1" + android:drawableStart="@mipmap/app_icon" + android:drawablePadding="@dimen/custom_tabs_menu_footer_margin_horizontal" + android:background="@drawable/custom_toast_background" + app:drawableWidth="@dimen/chip_icon_size" + app:drawableHeight="@dimen/chip_icon_size" + style="@style/TextAppearance.TextSmall.Primary.Baseline" /> \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/OWNERS index e31c9547..ab4c0db 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/OWNERS
@@ -3,3 +3,4 @@ per-file ContextualSearchSceneLayer.java=donnd@chromium.org per-file ContextualSearchSceneLayer.java=twellington@chromium.org +per-file TabStripSceneLayer.java=skavuluru@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingChecker.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingChecker.java index 170155e..137b740 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingChecker.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingChecker.java
@@ -109,9 +109,9 @@ private @BrandingDecision int makeBrandingDecisionFromLaunchTime( long startTime, long lastBrandingShowTime) { - // TODO(crrev.com/c/3769601): Support toast branding. - if (lastBrandingShowTime == BRANDING_TIME_NOT_FOUND - || startTime - lastBrandingShowTime >= mBrandingCadence) { + if (lastBrandingShowTime == BRANDING_TIME_NOT_FOUND) { + return BrandingDecision.TOAST; + } else if (startTime - lastBrandingShowTime >= mBrandingCadence) { return BrandingDecision.TOOLBAR; } else { return BrandingDecision.NONE;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingController.java index 9528cfa..8dbcce8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingController.java
@@ -6,17 +6,22 @@ import android.content.Context; import android.os.SystemClock; +import android.view.LayoutInflater; +import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.chromium.base.CallbackController; import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; +import org.chromium.chrome.R; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.IntCachedFieldTrialParameter; import org.chromium.content_public.browser.UiThreadTaskTraits; +import org.chromium.ui.widget.Toast; import java.util.concurrent.TimeUnit; @@ -53,8 +58,10 @@ private final @BrandingDecision OneshotSupplierImpl<Integer> mBrandingDecision = new OneshotSupplierImpl<>(); private final BrandingChecker mBrandingChecker; + private final Context mContext; private ToolbarBrandingDelegate mToolbarBrandingDelegate; + private @Nullable Toast mToast; private long mToolbarInitializedTime; private boolean mIsBrandingShowing; @@ -64,12 +71,13 @@ * @param packageName The package name for the embedded app. */ public BrandingController(Context context, String packageName) { + mContext = context; mBrandingDecision.onAvailable((decision) -> maybeMakeBrandingDecision()); // TODO(https://crbug.com/1350661): Start branding checker during CCT warm up. mBrandingChecker = new BrandingChecker(context, packageName, SharedPreferencesBrandingTimeStorage.getInstance(), mBrandingDecision::set, - BRANDING_CADENCE_MS.getValue(), BrandingDecision.TOOLBAR); + BRANDING_CADENCE_MS.getValue(), BrandingDecision.TOAST); mBrandingChecker.executeWithTaskTraits(TaskTraits.USER_VISIBLE_MAY_BLOCK); } @@ -105,13 +113,20 @@ @BrandingDecision int brandingDecision = mBrandingDecision.get(); - if (BrandingDecision.NONE == brandingDecision) { - mToolbarBrandingDelegate.showRegularToolbar(); - return; + switch (brandingDecision) { + case BrandingDecision.NONE: + mToolbarBrandingDelegate.showRegularToolbar(); + break; + case BrandingDecision.TOOLBAR: + showToolbarBranding(remainingBrandingTime); + break; + case BrandingDecision.TOAST: + mToolbarBrandingDelegate.showRegularToolbar(); + showToastBranding(remainingBrandingTime); + break; + default: + assert false : "Unreachable state!"; } - - // TODO(wenyufu): Support toast branding. - showToolbarBranding(remainingBrandingTime); } private void showToolbarBranding(long durationMs) { @@ -126,9 +141,24 @@ mCallbackController.makeCancelable(hideToolbarBranding), durationMs); } + private void showToastBranding(long durationMs) { + String appName = mContext.getResources().getString(R.string.app_name); + String toastText = + mContext.getResources().getString(R.string.twa_running_in_chrome_template, appName); + TextView runInChromeTextView = (TextView) LayoutInflater.from(mContext).inflate( + R.layout.custom_tabs_toast_branding_layout, null, false); + runInChromeTextView.setText(toastText); + mToast = new Toast(mContext, /*toastView*/ runInChromeTextView); + mToast.setDuration((int) durationMs); + mToast.show(); + } + /** Destroy this instance an cancel all scheduled callbacks */ public void destroy() { mCallbackController.destroy(); + if (mToast != null) { + mToast.cancel(); + } } @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingDecision.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingDecision.java index 91379ac3..1b6d509 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingDecision.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingDecision.java
@@ -13,13 +13,9 @@ * Class used to indicate what branding decision needs to make for the embedded app. */ @Retention(RetentionPolicy.SOURCE) -@IntDef({ - BrandingDecision.NONE, BrandingDecision.TOOLBAR, - // BrandingDecision.TOAST -}) +@IntDef({BrandingDecision.NONE, BrandingDecision.TOOLBAR, BrandingDecision.TOAST}) @interface BrandingDecision { int NONE = 1; int TOOLBAR = 2; - // TODO(crrev.com/c/3769601): Support toast branding. - // int TOAST = 3; // Default. + int TOAST = 3; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java index 2f6058a..16d1fde 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java
@@ -16,6 +16,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Icon; import android.os.Build; @@ -106,20 +108,56 @@ private MediaSessionBroadcastReceiver mMediaSessionReceiver; - private MediaActionButtonsManager mMediaActionsButtonsManager; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + MediaActionButtonsManager mMediaActionsButtonsManager; /** * A helper class for managing media action buttons in PictureInPicture window. */ - private class MediaActionButtonsManager { - private final RemoteAction mPreviousTrack; - private final RemoteAction mPlay; - private final RemoteAction mPause; - private final RemoteAction mReplay; - private final RemoteAction mNextTrack; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + class MediaActionButtonsManager { + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + final RemoteAction mPreviousTrack; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + final RemoteAction mPlay; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + final RemoteAction mPause; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + final RemoteAction mReplay; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + final RemoteAction mNextTrack; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + final RemoteAction mHangUp; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + final ToggleRemoteAction mMicrophone; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + final ToggleRemoteAction mCamera; private @PlaybackState int mPlaybackState; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + class ToggleRemoteAction { + private final RemoteAction mActionOn; + private final RemoteAction mActionOff; + private boolean mState; + + private ToggleRemoteAction( + RemoteAction actionOn, RemoteAction actionOff) { + mActionOn = actionOn; + mActionOff = actionOff; + mState = false; + } + + private void setState(boolean on) { + mState = on; + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + RemoteAction getAction() { + return mState ? mActionOn : mActionOff; + } + } + /** A set of {@link MediaSessionAction}. */ private HashSet<Integer> mVisibleActions; @@ -134,35 +172,85 @@ R.string.accessibility_replay); mNextTrack = createRemoteAction(MediaSessionAction.NEXT_TRACK, R.drawable.ic_skip_next_white_36dp, R.string.accessibility_next_track); + mHangUp = createRemoteAction(MediaSessionAction.HANG_UP, + R.drawable.ic_call_end_white_36dp, R.string.accessibility_hang_up); + mMicrophone = new ToggleRemoteAction( + createRemoteAction(MediaSessionAction.TOGGLE_MICROPHONE, + R.drawable.ic_mic_white_36dp, R.string.accessibility_mute_microphone), + createRemoteAction(MediaSessionAction.TOGGLE_MICROPHONE, + R.drawable.ic_mic_off_white_36dp, + R.string.accessibility_unmute_microphone)); + mCamera = new ToggleRemoteAction(createRemoteAction(MediaSessionAction.TOGGLE_CAMERA, + R.drawable.ic_videocam_white_36dp, + R.string.accessibility_turn_off_camera), + createRemoteAction(MediaSessionAction.TOGGLE_CAMERA, + R.drawable.ic_videocam_off_white_36dp, + R.string.accessibility_turn_on_camera)); mPlaybackState = PlaybackState.END_OF_VIDEO; mVisibleActions = new HashSet<>(); } + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @SuppressLint("NewApi") - private ArrayList<RemoteAction> getActionsForPictureInPictureParams() { + ArrayList<RemoteAction> getActionsForPictureInPictureParams() { ArrayList<RemoteAction> actions = new ArrayList<>(); - mPreviousTrack.setEnabled(mVisibleActions.contains(MediaSessionAction.PREVIOUS_TRACK)); - actions.add(mPreviousTrack); - - RemoteAction playPauseAction = null; - switch (mPlaybackState) { - case PlaybackState.PLAYING: - playPauseAction = mPause; - break; - case PlaybackState.PAUSED: - playPauseAction = mPlay; - break; - case PlaybackState.END_OF_VIDEO: - playPauseAction = mReplay; - break; + boolean shouldShowPreviousNextTrack = + mVisibleActions.contains(MediaSessionAction.PREVIOUS_TRACK) + || mVisibleActions.contains(MediaSessionAction.NEXT_TRACK); + if (shouldShowPreviousNextTrack) { + mPreviousTrack.setEnabled( + mVisibleActions.contains(MediaSessionAction.PREVIOUS_TRACK)); + actions.add(mPreviousTrack); } - playPauseAction.setEnabled(mVisibleActions.contains(MediaSessionAction.PLAY)); - actions.add(playPauseAction); - mNextTrack.setEnabled(mVisibleActions.contains(MediaSessionAction.NEXT_TRACK)); - actions.add(mNextTrack); + if (mVisibleActions.contains(MediaSessionAction.PLAY)) { + switch (mPlaybackState) { + case PlaybackState.PLAYING: + actions.add(mPause); + break; + case PlaybackState.PAUSED: + actions.add(mPlay); + break; + case PlaybackState.END_OF_VIDEO: + actions.add(mReplay); + break; + } + } + + if (shouldShowPreviousNextTrack) { + mNextTrack.setEnabled(mVisibleActions.contains(MediaSessionAction.NEXT_TRACK)); + actions.add(mNextTrack); + } + + if (mVisibleActions.contains(MediaSessionAction.TOGGLE_MICROPHONE)) { + actions.add(mMicrophone.getAction()); + } + + if (mVisibleActions.contains(MediaSessionAction.TOGGLE_CAMERA)) { + actions.add(mCamera.getAction()); + } + + if (mVisibleActions.contains(MediaSessionAction.HANG_UP)) { + actions.add(mHangUp); + } + + // Insert a disabled dummy remote action with transparent icon if action list is empty. + // This is a workaround of the issue that android picture-in-picture will fallback to + // default MediaSession when action list given is empty. + // TODO (jazzhsu): Remove this when android picture-in-picture can accept empty list and + // not fallback to default MediaSession. + if (actions.isEmpty()) { + RemoteAction dummyAction = new RemoteAction( + Icon.createWithBitmap(Bitmap.createBitmap( + new int[] {Color.TRANSPARENT}, 1, 1, Bitmap.Config.ARGB_8888)), + "", "", + PendingIntent.getBroadcast(getApplicationContext(), -1, + new Intent(MEDIA_ACTION), PendingIntent.FLAG_IMMUTABLE)); + dummyAction.setEnabled(false); + actions.add(dummyAction); + } return actions; } @@ -180,8 +268,16 @@ mPlaybackState = playbackState; } + private void setMicrophoneMuted(boolean muted) { + mMicrophone.setState(!muted); + } + + private void setCameraOn(boolean cameraOn) { + mCamera.setState(cameraOn); + } + /** - * Create a disabled remote action for picture-in-picture window. + * Create a remote action for picture-in-picture window. * * @param action {@link MediaSessionAction} that the action button is corresponding to. * @param iconResourceId used for getting icon associated with the id. @@ -198,13 +294,10 @@ PendingIntent.getBroadcast(getApplicationContext(), action, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); - RemoteAction remoteAction = new RemoteAction( + return new RemoteAction( Icon.createWithResource(getApplicationContext(), iconResourceId), getApplicationContext().getResources().getText(titleResourceId), "", pendingIntent); - - remoteAction.setEnabled(false); - return remoteAction; } } @@ -235,6 +328,15 @@ case MediaSessionAction.NEXT_TRACK: PictureInPictureActivityJni.get().nextTrack(nativeOverlayWindowAndroid); return; + case MediaSessionAction.TOGGLE_MICROPHONE: + PictureInPictureActivityJni.get().toggleMicrophone(nativeOverlayWindowAndroid); + return; + case MediaSessionAction.TOGGLE_CAMERA: + PictureInPictureActivityJni.get().toggleCamera(nativeOverlayWindowAndroid); + return; + case MediaSessionAction.HANG_UP: + PictureInPictureActivityJni.get().hangUp(nativeOverlayWindowAndroid); + return; default: return; } @@ -484,14 +586,28 @@ mAspectRatio = new Rational(width, height); } + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @CalledByNative - private void setPlaybackState(@PlaybackState int playbackState) { + void setPlaybackState(@PlaybackState int playbackState) { mMediaActionsButtonsManager.updatePlaybackState(playbackState); updatePictureInPictureParams(); } @CalledByNative - private void updateVisibleActions(int[] actions) { + private void setMicrophoneMuted(boolean muted) { + mMediaActionsButtonsManager.setMicrophoneMuted(muted); + updatePictureInPictureParams(); + } + + @CalledByNative + private void setCameraState(boolean turnedOn) { + mMediaActionsButtonsManager.setCameraOn(turnedOn); + updatePictureInPictureParams(); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + @CalledByNative + void updateVisibleActions(int[] actions) { HashSet<Integer> visibleActions = new HashSet<>(); for (int action : actions) visibleActions.add(action); mMediaActionsButtonsManager.updateVisibleActions(visibleActions); @@ -604,6 +720,9 @@ void togglePlayPause(long nativeOverlayWindowAndroid); void nextTrack(long nativeOverlayWindowAndroid); void previousTrack(long nativeOverlayWindowAndroid); + void toggleMicrophone(long nativeOverlayWindowAndroid); + void toggleCamera(long nativeOverlayWindowAndroid); + void hangUp(long nativeOverlayWindowAndroid); void compositorViewCreated(long nativeOverlayWindowAndroid, CompositorView compositorView);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/PictureInPictureActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/PictureInPictureActivityTest.java index 4e36bd0..4a7889a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/PictureInPictureActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/PictureInPictureActivityTest.java
@@ -13,6 +13,7 @@ import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE; import android.app.Activity; +import android.app.RemoteAction; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; @@ -48,9 +49,12 @@ import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.util.ActivityTestUtils; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.overlay_window.PlaybackState; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.WebContentsUtils; +import org.chromium.media_session.mojom.MediaSessionAction; +import java.util.ArrayList; import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; @@ -186,6 +190,71 @@ testExitOn(activity, () -> activity.close()); } + @Test + @MediumTest + @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) + public void testMediaActions() throws Throwable { + PictureInPictureActivity activity = startPictureInPictureActivity(); + PictureInPictureActivity.MediaActionButtonsManager manager = + activity.mMediaActionsButtonsManager; + + activity.updateVisibleActions(new int[] {MediaSessionAction.PLAY}); + activity.setPlaybackState(PlaybackState.PAUSED); + ArrayList<RemoteAction> actions = manager.getActionsForPictureInPictureParams(); + Assert.assertEquals(actions.size(), 1); + Assert.assertEquals(actions.get(0), manager.mPlay); + + activity.setPlaybackState(PlaybackState.PLAYING); + actions = manager.getActionsForPictureInPictureParams(); + Assert.assertEquals(actions.get(0), manager.mPause); + + // Both next track and previous track button should be visible when only one of them is + // enabled. The one that is not handled should be visible and disabled. + activity.updateVisibleActions( + new int[] {MediaSessionAction.PLAY, MediaSessionAction.PREVIOUS_TRACK}); + actions = manager.getActionsForPictureInPictureParams(); + Assert.assertEquals(actions.size(), 3); + Assert.assertEquals(actions.get(0), manager.mPreviousTrack); + Assert.assertEquals(actions.get(2), manager.mNextTrack); + Assert.assertTrue(actions.get(0).isEnabled()); + Assert.assertFalse(actions.get(2).isEnabled()); + + // When all actions are not handled, there should be a dummy action presented to prevent + // android picture-in-picture from using default MediaSession. + activity.updateVisibleActions(new int[] {}); + actions = manager.getActionsForPictureInPictureParams(); + Assert.assertEquals(actions.size(), 1); + Assert.assertFalse(actions.get(0).isEnabled()); + testExitOn(activity, () -> activity.close()); + } + + @Test + @MediumTest + @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) + public void testMediaActionsForVideoConferencing() throws Throwable { + PictureInPictureActivity activity = startPictureInPictureActivity(); + PictureInPictureActivity.MediaActionButtonsManager manager = + activity.mMediaActionsButtonsManager; + + activity.updateVisibleActions(new int[] {MediaSessionAction.TOGGLE_MICROPHONE}); + ArrayList<RemoteAction> actions = manager.getActionsForPictureInPictureParams(); + Assert.assertEquals(actions.size(), 1); + Assert.assertEquals(actions.get(0), manager.mMicrophone.getAction()); + + activity.updateVisibleActions(new int[] {MediaSessionAction.TOGGLE_CAMERA}); + actions = manager.getActionsForPictureInPictureParams(); + Assert.assertEquals(actions.size(), 1); + Assert.assertEquals(actions.get(0), manager.mCamera.getAction()); + + activity.updateVisibleActions(new int[] {MediaSessionAction.HANG_UP}); + actions = manager.getActionsForPictureInPictureParams(); + Assert.assertEquals(actions.size(), 1); + Assert.assertEquals(actions.get(0), manager.mHangUp); + testExitOn(activity, () -> activity.close()); + } + private WebContents getWebContents() { return mActivityTestRule.getActivity().getCurrentWebContents(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java index 24a88bb..798936b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
@@ -53,7 +53,7 @@ @RunWith(BaseJUnit4ClassRunner.class) @Batch(Batch.UNIT_TESTS) @Features.DisableFeatures({ChromeFeatureList.OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS, - ChromeFeatureList.LOCATION_BAR_MODEL_OPTIMIZATIONS}) + ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) public final class ToolbarSecurityIconTest { private static final boolean IS_SMALL_DEVICE = true; private static final boolean IS_OFFLINE_PAGE = true;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingCheckerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingCheckerUnitTest.java index 020336e..0f15a42 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingCheckerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingCheckerUnitTest.java
@@ -118,8 +118,8 @@ mainLooper().idle(); long showBrandingTime = SystemClock.elapsedRealtime(); - assertEquals("Branding is checked for new package, BrandingDecision should be TOOLBAR. ", - BrandingDecision.TOOLBAR, callbackDelegate.getBrandingDecision()); + assertEquals("Branding is checked for new package, BrandingDecision should be TOAST. ", + BrandingDecision.TOAST, callbackDelegate.getBrandingDecision()); assertEquals("Show branding time is different.", showBrandingTime, mStorage.get(NEW_APPLICATION)); } @@ -141,7 +141,7 @@ mainLooper().idle(); long showBrandingTime = SystemClock.elapsedRealtime(); assertEquals("Branding check canceled, BrandingDecision should be the test default. ", - BrandingDecision.TOOLBAR, callbackDelegate.getBrandingDecision()); + BrandingDecision.TOAST, callbackDelegate.getBrandingDecision()); assertEquals("Show branding time is different.", showBrandingTime, mStorage.get(PACKAGE_1)); } @@ -153,7 +153,7 @@ mainLooper().idle(); assertEquals("Package is invalid, BrandingDecision should be the test default. ", - BrandingDecision.TOOLBAR, callbackDelegate.getBrandingDecision()); + BrandingDecision.TOAST, callbackDelegate.getBrandingDecision()); assertEquals("Branding time should not record for invalid package.", -1, mStorage.get(INVALID_PACKAGE)); } @@ -190,7 +190,7 @@ private BrandingChecker createBrandingChecker( String packageName, CallbackDelegate callbackDelegate) { return new BrandingChecker(mContext, packageName, mStorage, callbackDelegate::notifyCalled, - TEST_BRANDING_CADENCE, BrandingDecision.TOOLBAR); + TEST_BRANDING_CADENCE, BrandingDecision.TOAST); } private ShadowLooper mainLooper() {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingControllerUnitTest.java index 688cd66..27b8937 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingControllerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/branding/BrandingControllerUnitTest.java
@@ -28,6 +28,7 @@ import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode.Mode; import org.robolectric.shadows.ShadowSystemClock; +import org.robolectric.shadows.ShadowToast; import org.chromium.base.ContextUtils; import org.chromium.base.FakeTimeTestRule; @@ -42,7 +43,8 @@ * Unit test for {@link BrandingController} and {@link SharedPreferencesBrandingTimeStorage}. */ @RunWith(BaseRobolectricTestRunner.class) -@Config(manifest = Config.NONE, shadows = {ShadowSystemClock.class, ShadowPostTask.class}) +@Config(manifest = Config.NONE, + shadows = {ShadowSystemClock.class, ShadowPostTask.class, ShadowToast.class}) @LooperMode(Mode.PAUSED) public class BrandingControllerUnitTest { private static final int TEST_BRANDING_CADENCE = 10_000; @@ -84,6 +86,7 @@ SharedPreferencesBrandingTimeStorage.getInstance().resetForTesting(); ShadowPostTask.reset(); ShadowSystemClock.reset(); + ShadowToast.reset(); } @Test @@ -92,14 +95,11 @@ .newBrandingController() .assertBrandingDecisionMade(null) .idleMainLooper() // Finish branding checker - .assertBrandingDecisionMade(BrandingDecision.TOOLBAR) + .assertBrandingDecisionMade(BrandingDecision.TOAST) .assertShownEmptyLocationBar(false) .onToolbarInitialized() .assertShownEmptyLocationBar(true) - .assertShownBrandingLocationBar(true) - .assertShownRegularLocationBar(false) - .advanceMills(BrandingController.TOTAL_BRANDING_DELAY_MS) - .idleMainLooper() // Finish toolbar branding + .assertShownBrandingLocationBar(false) .assertShownRegularLocationBar(true); } @@ -109,30 +109,28 @@ .newBrandingController() .idleMainLooper() // Finish branding checker. .onToolbarInitialized() - .advanceMills(BrandingController.TOTAL_BRANDING_DELAY_MS) - .idleMainLooper() // Finish toolbar branding. - .assertShownBrandingLocationBar(true) + .assertShownToastBranding(true) + .assertShownBrandingLocationBar(false) .assertShownRegularLocationBar(true) // Start 2nd branding immediately. .newBrandingController() .idleMainLooper() .assertBrandingDecisionMade(BrandingDecision.NONE) .onToolbarInitialized() + .assertShownToastBranding(false) .assertShownEmptyLocationBar(true) .assertShownBrandingLocationBar(false) .assertShownRegularLocationBar(true); } @Test - public void testBrandingWorkflow_ShowBrandingPassingCadence() { + public void testBrandingWorkflow_ShowToolbarBranding() { new BrandingCheckTester() .newBrandingController() .idleMainLooper() // Finish branding checker. - .assertBrandingDecisionMade(BrandingDecision.TOOLBAR) + .assertBrandingDecisionMade(BrandingDecision.TOAST) .onToolbarInitialized() - .advanceMills(BrandingController.TOTAL_BRANDING_DELAY_MS) - .idleMainLooper() // Finish toolbar branding. - .assertShownBrandingLocationBar(true) + .assertShownToastBranding(true) .assertShownRegularLocationBar(true) // Start 2nd branding with delay. .advanceMills(TEST_BRANDING_CADENCE + 1) @@ -140,7 +138,11 @@ .idleMainLooper() // Finish branding checker. .assertBrandingDecisionMade(BrandingDecision.TOOLBAR) .onToolbarInitialized() - .assertShownBrandingLocationBar(true); + .assertShownBrandingLocationBar(true) + .assertShownToastBranding(false) + .advanceMills(BrandingController.TOTAL_BRANDING_DELAY_MS + 1) + .idleMainLooper() // Finish toolbar branding + .assertShownRegularLocationBar(true); } @Test @@ -153,11 +155,8 @@ .assertShownBrandingLocationBar(false) .advanceMills(300) .idleMainLooper() // Finish branding checker. - .assertBrandingDecisionMade(BrandingDecision.TOOLBAR) - .assertShownBrandingLocationBar(true) - .assertShownRegularLocationBar(false) - .advanceMills(1501) // BrandingController.TOTAL_BRANDING_DELAY_MS = 1800 - 300 + 1 - .idleMainLooper() + .assertBrandingDecisionMade(BrandingDecision.TOAST) + .assertShownToastBranding(true) .assertShownRegularLocationBar(true); } @@ -167,18 +166,18 @@ .newBrandingController() .onToolbarInitialized() .idleMainLooper() - .assertBrandingDecisionMade(BrandingDecision.TOOLBAR) + .assertBrandingDecisionMade(BrandingDecision.TOAST) + .assertShownToastBranding(true) .newBrandingController() .onToolbarInitialized() .advanceMills(TEST_MAX_TOOLBAR_BLANK_TIMEOUT) .idleMainLooper() // Branding checker is finished, but timed out comes first. - .assertBrandingDecisionMade(BrandingDecision.TOOLBAR) - .assertShownBrandingLocationBar(true) - .assertShownRegularLocationBar(false) - .advanceMills(801) // BrandingController.TOTAL_BRANDING_DELAY_MS - - // TEST_MAX_TOOLBAR_BLANK_TIMEOUT + 1 = 801 - .idleMainLooper() + .assertBrandingDecisionMade(BrandingDecision.TOAST) .assertShownRegularLocationBar(true); + + // BrandingController.TOTAL_BRANDING_DELAY_MS - TEST_MAX_TOOLBAR_BLANK_TIMEOUT = 800 + assertEquals( + "Toast duration is different.", 800, ShadowToast.getLatestToast().getDuration()); } class BrandingCheckTester { @@ -188,6 +187,7 @@ // Always initialize a new mock, as some tests were testing multiple branding runs. mToolbarBrandingDelegate = mock(ToolbarBrandingDelegate.class); + ShadowToast.reset(); // Reset the shadow toast so the toast shown count resets. return this; } @@ -212,6 +212,12 @@ return this; } + public BrandingCheckTester assertShownToastBranding(boolean shown) { + assertEquals("Toast shown count does not match.", shown ? 1 : 0, + ShadowToast.shownToastCount()); + return this; + } + public BrandingCheckTester onToolbarInitialized() { mBrandingController.onToolbarInitialized(mToolbarBrandingDelegate); return this;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java index d02125f..38b68f5 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java
@@ -65,7 +65,7 @@ */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE, shadows = {ShadowGURL.class, ShadowTrustedCdn.class}) -@DisableFeatures({ChromeFeatureList.LOCATION_BAR_MODEL_OPTIMIZATIONS}) +@DisableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) @SuppressWarnings("DoNotMock") // Mocks GURL public class LocationBarModelUnitTest { @Implements(TrustedCdn.class) @@ -299,7 +299,7 @@ verify(mLocationBarDataObserver).onSecurityStateChanged(); } - @EnableFeatures({ChromeFeatureList.LOCATION_BAR_MODEL_OPTIMIZATIONS}) + @EnableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) @Test @MediumTest public void testSpannableCache() {
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 3679db7..f7fd2499 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1227,6 +1227,8 @@ "policy/value_provider/value_provider_util.h", "policy/webusb_allow_devices_for_urls_policy_handler.cc", "policy/webusb_allow_devices_for_urls_policy_handler.h", + "power_bookmarks/power_bookmark_service_factory.cc", + "power_bookmarks/power_bookmark_service_factory.h", "predictors/autocomplete_action_predictor.cc", "predictors/autocomplete_action_predictor.h", "predictors/autocomplete_action_predictor_factory.cc", @@ -2197,6 +2199,7 @@ "//components/policy/content/", "//components/policy/core/browser", "//components/policy/proto", + "//components/power_bookmarks/core", "//components/pref_registry", "//components/prefs", "//components/privacy_sandbox",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index 6f51568..0d9d09b 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -123,6 +123,8 @@ "+components/desks_storage", "+components/dbus", "+components/device_event_log", + "+components/device_signals/core/browser", + "+components/device_signals/core/common", "+components/digital_asset_links", "+components/digital_goods", "+components/domain_reliability",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index c227b37e..28dfe74 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -4861,7 +4861,7 @@ {"enable-cros-virtual-keyboard-multitouch", flag_descriptions::kVirtualKeyboardMultitouchName, flag_descriptions::kVirtualKeyboardMultitouchDescription, kOsCrOS, - FEATURE_VALUE_TYPE(features::kVirtualKeyboardMultitouch)}, + FEATURE_VALUE_TYPE(chromeos::features::kVirtualKeyboardMultitouch)}, {"enable-cros-virtual-keyboard-round-corners", flag_descriptions::kVirtualKeyboardRoundCornersName, flag_descriptions::kVirtualKeyboardRoundCornersDescription, kOsCrOS, @@ -6790,11 +6790,6 @@ kLensCameraAssistedSearchVariations, "LensCameraAssistedSearch")}, - {"location-bar-model-optimizations", - flag_descriptions::kLocationBarModelOptimizationsName, - flag_descriptions::kLocationBarModelOptimizationsDescription, kOsAndroid, - FEATURE_VALUE_TYPE(chrome::android::kLocationBarModelOptimizations)}, - {"enable-iph", flag_descriptions::kEnableIphName, flag_descriptions::kEnableIphDescription, kOsAndroid, FEATURE_VALUE_TYPE(feature_engagement::kEnableIPH)},
diff --git a/chrome/browser/accessibility/soda_installer_impl.cc b/chrome/browser/accessibility/soda_installer_impl.cc index 02b6ed4..d633efa 100644 --- a/chrome/browser/accessibility/soda_installer_impl.cc +++ b/chrome/browser/accessibility/soda_installer_impl.cc
@@ -157,7 +157,8 @@ base::UmaHistogramBoolean(kSodaBinaryInstallationResult, false); } - NotifyOnSodaError(language_code); + NotifyOnSodaInstallError( + language_code, speech::SodaInstaller::ErrorCode::kUnspecifiedError); break; case Events::COMPONENT_CHECKING_FOR_UPDATES: case Events::COMPONENT_UPDATED:
diff --git a/chrome/browser/android/compositor/OWNERS b/chrome/browser/android/compositor/OWNERS index 57fa9d4..7accf24 100644 --- a/chrome/browser/android/compositor/OWNERS +++ b/chrome/browser/android/compositor/OWNERS
@@ -1,6 +1,7 @@ dtrainor@chromium.org mdjones@chromium.org +per-file *tab_strip*=file://chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/OWNERS per-file *contextual_search*=gangwu@chromium.org # Secondary
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc index 8197d9d..1431402 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -43,13 +43,7 @@ Profile* profile = ProfileManager::GetActiveUserProfile(); delegate_ = std::make_unique<ContextualSearchDelegate>( profile->GetURLLoaderFactory(), - TemplateURLServiceFactory::GetForProfile(profile), - base::BindRepeating( - &ContextualSearchManager::OnSearchTermResolutionResponse, - base::Unretained(this)), - base::BindRepeating( - &ContextualSearchManager::OnTextSurroundingSelectionAvailable, - base::Unretained(this))); + TemplateURLServiceFactory::GetForProfile(profile)); } ContextualSearchManager::~ContextualSearchManager() { @@ -74,8 +68,11 @@ NativeContextualSearchContext::FromJavaContextualSearchContext( j_contextual_search_context); // Calls back to OnSearchTermResolutionResponse. - delegate_->StartSearchTermResolutionRequest(contextual_search_context, - base_web_contents); + delegate_->StartSearchTermResolutionRequest( + contextual_search_context, base_web_contents, + base::BindRepeating( + &ContextualSearchManager::OnSearchTermResolutionResponse, + base::Unretained(this))); } void ContextualSearchManager::GatherSurroundingText( @@ -89,8 +86,11 @@ base::WeakPtr<NativeContextualSearchContext> contextual_search_context = NativeContextualSearchContext::FromJavaContextualSearchContext( j_contextual_search_context); - delegate_->GatherAndSaveSurroundingText(contextual_search_context, - base_web_contents); + delegate_->GatherAndSaveSurroundingText( + contextual_search_context, base_web_contents, + base::BindRepeating( + &ContextualSearchManager::OnTextSurroundingSelectionAvailable, + base::Unretained(this))); } void ContextualSearchManager::OnSearchTermResolutionResponse(
diff --git a/chrome/browser/android/vr/gvr_graphics_delegate.cc b/chrome/browser/android/vr/gvr_graphics_delegate.cc index 2c6f08c8..5b128d8 100644 --- a/chrome/browser/android/vr/gvr_graphics_delegate.cc +++ b/chrome/browser/android/vr/gvr_graphics_delegate.cc
@@ -27,6 +27,7 @@ #include "ui/gl/gl_context.h" #include "ui/gl/gl_fence_egl.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace vr { @@ -167,22 +168,25 @@ // TODO(crbug.com/1170580): support ANGLE with cardboard? gl::init::DisableANGLE(); - if (gl::GetGLImplementation() == gl::kGLImplementationNone && - !gl::init::InitializeGLOneOff(/*system_device_id=*/0)) { - LOG(ERROR) << "gl::init::InitializeGLOneOff failed"; - browser_->ForceExitVr(); - return; + gl::GLDisplay* display = nullptr; + if (gl::GetGLImplementation() == gl::kGLImplementationNone) { + display = gl::init::InitializeGLOneOff(/*system_device_id=*/0); + if (!display) { + LOG(ERROR) << "gl::init::InitializeGLOneOff failed"; + browser_->ForceExitVr(); + return; + } + } else { + display = gl::GetDefaultDisplayEGL(); } - DCHECK(gl::GetGLImplementation() != gl::kGLImplementationEGLANGLE); - scoped_refptr<gl::GLSurface> surface; if (window) { DCHECK(!surfaceless_rendering_); - surface = gl::init::CreateViewGLSurface(window); + surface = gl::init::CreateViewGLSurface(display, window); } else { DCHECK(surfaceless_rendering_); - surface = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface = gl::init::CreateOffscreenGLSurface(display, gfx::Size()); } if (!surface.get()) { LOG(ERROR) << "gl::init::CreateOffscreenGLSurface failed";
diff --git a/chrome/browser/apps/app_service/publishers/crostini_apps.cc b/chrome/browser/apps/app_service/publishers/crostini_apps.cc index dc873f1..dcc4c95 100644 --- a/chrome/browser/apps/app_service/publishers/crostini_apps.cc +++ b/chrome/browser/apps/app_service/publishers/crostini_apps.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/apps/app_service/publishers/crostini_apps.h" #include <utility> +#include <vector> #include "ash/constants/ash_features.h" #include "ash/public/cpp/app_menu_constants.h" @@ -20,6 +21,7 @@ #include "chrome/browser/ash/crostini/crostini_pref_names.h" #include "chrome/browser/ash/crostini/crostini_shelf_utils.h" #include "chrome/browser/ash/crostini/crostini_util.h" +#include "chrome/browser/ash/file_manager/fileapi_util.h" #include "chrome/browser/ash/guest_os/guest_os_registry_service_factory.h" #include "chrome/browser/ash/guest_os/guest_os_terminal.h" #include "chrome/browser/profiles/profile.h" @@ -31,6 +33,7 @@ #include "components/services/app_service/public/cpp/intent_util.h" #include "components/services/app_service/public/mojom/types.mojom.h" #include "mojo/public/cpp/bindings/callback_helpers.h" +#include "storage/browser/file_system/file_system_context.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/strings/grit/ui_strings.h" @@ -71,7 +74,10 @@ std::vector<std::string> mime_types_vector(mime_types.begin(), mime_types.end()); apps::IntentFilterPtr intent_filter = apps_util::CreateFileFilter( - {apps_util::kIntentActionView}, mime_types_vector, {}); + {apps_util::kIntentActionView}, mime_types_vector, {}, + // TODO(crbug/1349974): Remove activity_name when default file handling + // preferences for Files App are migrated. + /*activity_name=*/apps_util::kGuestOsActivityName); intent_filters.push_back(std::move(intent_filter)); return intent_filters; } @@ -144,10 +150,21 @@ LaunchSource launch_source, WindowInfoPtr window_info, base::OnceCallback<void(bool)> callback) { + // Retrieve URLs from the files in the intent. + std::vector<crostini::LaunchArg> args; + if (intent && intent->files.size() > 0) { + args.reserve(intent->files.size()); + storage::FileSystemContext* file_system_context = + file_manager::util::GetFileManagerFileSystemContext(profile_); + for (auto& file : intent->files) { + args.emplace_back( + file_system_context->CrackURLInFirstPartyContext(file->url)); + } + } crostini::LaunchCrostiniAppWithIntent( profile_, app_id, window_info ? window_info->display_id : display::kInvalidDisplayId, - std::move(intent), /*args=*/{}, + std::move(intent), args, base::BindOnce( [](LaunchAppWithIntentCallback callback, bool success, const std::string& failure_reason) { @@ -217,10 +234,21 @@ apps::mojom::LaunchSource launch_source, apps::mojom::WindowInfoPtr window_info, LaunchAppWithIntentCallback callback) { + // Retrieve URLs from the files in the intent. + std::vector<crostini::LaunchArg> args; + if (intent && intent->files.has_value()) { + storage::FileSystemContext* file_system_context = + file_manager::util::GetFileManagerFileSystemContext(profile_); + args.reserve(intent->files.value().size()); + for (auto& file : intent->files.value()) { + args.emplace_back( + file_system_context->CrackURLInFirstPartyContext(file->url)); + } + } crostini::LaunchCrostiniAppWithIntent( profile_, app_id, window_info ? window_info->display_id : display::kInvalidDisplayId, - ConvertMojomIntentToIntent(intent), /*args=*/{}, + ConvertMojomIntentToIntent(intent), args, base::BindOnce( [](LaunchAppWithIntentCallback callback, bool success, const std::string& failure_reason) {
diff --git a/chrome/browser/apps/app_service/publishers/crostini_apps_unittest.cc b/chrome/browser/apps/app_service/publishers/crostini_apps_unittest.cc index cea1de60..8e6ab45 100644 --- a/chrome/browser/apps/app_service/publishers/crostini_apps_unittest.cc +++ b/chrome/browser/apps/app_service/publishers/crostini_apps_unittest.cc
@@ -9,10 +9,14 @@ #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/ash/crostini/crostini_test_helper.h" +#include "chrome/browser/ash/guest_os/guest_os_registry_service_factory.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/test/base/testing_profile.h" #include "chromeos/ash/components/dbus/cicerone/cicerone_client.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "components/prefs/scoped_user_pref_update.h" #include "components/services/app_service/public/cpp/app_registry_cache.h" +#include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/app_update.h" #include "components/services/app_service/public/cpp/intent_filter.h" #include "components/services/app_service/public/cpp/intent_util.h" @@ -30,6 +34,8 @@ AppServiceProxy* app_service_proxy() { return app_service_proxy_; } + TestingProfile* profile() { return profile_.get(); } + void SetUp() override { ash::CiceroneClient::InitializeFake(); profile_ = std::make_unique<TestingProfile>(); @@ -107,4 +113,41 @@ } } +TEST_F(CrostiniAppsTest, AppReadinessUpdatesWhenCrostiniDisabled) { + // Install a Crostini app. + vm_tools::apps::App app; + app.set_desktop_file_id("app_id"); + vm_tools::apps::App::LocaleString::Entry* entry = + app.mutable_name()->add_values(); + entry->set_locale(std::string()); + entry->set_value("app_name"); + test_helper()->AddApp(app); + + // Get the app ID so that we can find the Crostini app in App Service later. + std::string app_service_id = crostini::CrostiniTestHelper::GenerateAppId( + app.desktop_file_id(), crostini::kCrostiniDefaultVmName, + crostini::kCrostiniDefaultContainerName); + + // Check that the app is ready. + apps::Readiness readiness_before; + app_service_proxy()->AppRegistryCache().ForOneApp( + app_service_id, [&readiness_before](const AppUpdate& update) { + readiness_before = update.Readiness(); + }); + ASSERT_EQ(readiness_before, Readiness::kReady); + + // Disable Crostini. This call uninstalls all Crostini apps. + guest_os::GuestOsRegistryServiceFactory::GetForProfile(profile()) + ->ClearApplicationList(guest_os::VmType::TERMINA, + crostini::kCrostiniDefaultVmName, ""); + + // Check that the app is now disabled. + apps::Readiness readiness_after; + app_service_proxy()->AppRegistryCache().ForOneApp( + app_service_id, [&readiness_after](const AppUpdate& update) { + readiness_after = update.Readiness(); + }); + ASSERT_EQ(readiness_after, Readiness::kUninstalledByUser); +} + } // namespace apps
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn index 1f9b3e69..caaf08f 100644 --- a/chrome/browser/ash/BUILD.gn +++ b/chrome/browser/ash/BUILD.gn
@@ -1011,6 +1011,8 @@ "file_manager/speedometer.h", "file_manager/trash_common_util.cc", "file_manager/trash_common_util.h", + "file_manager/trash_info_validator.cc", + "file_manager/trash_info_validator.h", "file_manager/trash_io_task.cc", "file_manager/trash_io_task.h", "file_manager/url_util.cc",
diff --git a/chrome/browser/ash/accessibility/accessibility_manager.cc b/chrome/browser/ash/accessibility/accessibility_manager.cc index 3315703..1828dd3 100644 --- a/chrome/browser/ash/accessibility/accessibility_manager.cc +++ b/chrome/browser/ash/accessibility/accessibility_manager.cc
@@ -2114,7 +2114,9 @@ OnSodaInstallUpdated(100); } -void AccessibilityManager::OnSodaError(speech::LanguageCode language_code) { +void AccessibilityManager::OnSodaInstallError( + speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) { if (language_code != speech::LanguageCode::kNone && language_code != GetDictationLanguageCode()) { return;
diff --git a/chrome/browser/ash/accessibility/accessibility_manager.h b/chrome/browser/ash/accessibility/accessibility_manager.h index a5f7419..c27a24e 100644 --- a/chrome/browser/ash/accessibility/accessibility_manager.h +++ b/chrome/browser/ash/accessibility/accessibility_manager.h
@@ -365,7 +365,8 @@ // SodaInstaller::Observer: void OnSodaInstalled(speech::LanguageCode language_code) override; - void OnSodaError(speech::LanguageCode language_code) override; + void OnSodaInstallError(speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) override; void OnSodaProgress(speech::LanguageCode language_code, int progress) override;
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc index 0b5162b..9c725fc 100644 --- a/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc +++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
@@ -254,7 +254,7 @@ // automatically unregisters a callback when it's destructed. base::CallbackListSubscription default_zoom_level_subscription_; - base::ScopedObservation<chromeos::NetworkStateHandler, + base::ScopedObservation<ash::NetworkStateHandler, ash::NetworkStateHandlerObserver> network_state_handler_observer_{this}; @@ -434,7 +434,7 @@ TimezoneSettings::GetInstance()->AddObserver(this); network_state_handler_observer_.Observe( - chromeos::NetworkHandler::Get()->network_state_handler()); + ash::NetworkHandler::Get()->network_state_handler()); } void ArcSettingsServiceImpl::StopObservingSettingsChanges() {
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc index ff305f9..7a5a31d 100644 --- a/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc +++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc
@@ -302,9 +302,9 @@ void SetProxyConfigForNetworkService(const std::string& service_path, base::Value proxy_config) { ProxyConfigDictionary proxy_config_dict(std::move(proxy_config)); - const ash::NetworkState* network = chromeos::NetworkHandler::Get() - ->network_state_handler() - ->GetNetworkState(service_path); + const ash::NetworkState* network = + ash::NetworkHandler::Get()->network_state_handler()->GetNetworkState( + service_path); ASSERT_TRUE(network); ash::proxy_config::SetProxyConfigForNetwork(proxy_config_dict, *network); } @@ -603,9 +603,8 @@ proxy_config.SetKey("mode", base::Value(ProxyPrefs::kAutoDetectProxyModeName)); ProxyConfigDictionary proxy_config_dict(std::move(proxy_config)); - const ash::NetworkState* network = chromeos::NetworkHandler::Get() - ->network_state_handler() - ->DefaultNetwork(); + const ash::NetworkState* network = + ash::NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); ASSERT_TRUE(network); ash::proxy_config::SetProxyConfigForNetwork(proxy_config_dict, *network); RunUntilIdle();
diff --git a/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.h b/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.h index fff36e92..157a124 100644 --- a/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.h +++ b/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.h
@@ -114,8 +114,7 @@ bool is_observing_network_ = false; KerberosFilesHandler kerberos_files_handler_; - base::ScopedObservation<chromeos::NetworkStateHandler, - NetworkStateHandlerObserver> + base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver> network_state_handler_observer_{this}; // Stores message ids of shown notifications. Each notification is shown at
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h index f879376..e82abb9 100644 --- a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h +++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h
@@ -20,8 +20,6 @@ #include "chrome/browser/ash/cert_provisioning/cert_provisioning_platform_keys_helpers.h" #include "chrome/browser/ash/platform_keys/platform_keys_service.h" #include "chrome/browser/platform_keys/platform_keys.h" -// TODO(https://crbug.com/1164001): forward declare NetworkStateHandler -// after //chromeos/network is moved to ash. #include "chromeos/ash/components/network/network_state_handler.h" #include "chromeos/ash/components/network/network_state_handler_observer.h" #include "components/prefs/pref_change_registrar.h" @@ -225,8 +223,7 @@ // |platform_keys_service_| can be nullptr if it has been shut down. platform_keys::PlatformKeysService* platform_keys_service_ = nullptr; NetworkStateHandler* network_state_handler_ = nullptr; - base::ScopedObservation<chromeos::NetworkStateHandler, - NetworkStateHandlerObserver> + base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver> network_state_handler_observer_{this}; PrefChangeRegistrar pref_change_registrar_;
diff --git a/chrome/browser/ash/crosapi/extension_info_private_ash.cc b/chrome/browser/ash/crosapi/extension_info_private_ash.cc index f28a17c..fab7cc4 100644 --- a/chrome/browser/ash/crosapi/extension_info_private_ash.cc +++ b/chrome/browser/ash/crosapi/extension_info_private_ash.cc
@@ -38,7 +38,7 @@ #include "extensions/common/error_utils.h" #include "third_party/cros_system_api/dbus/service_constants.h" -using chromeos::NetworkHandler; +using ash::NetworkHandler; namespace crosapi {
diff --git a/chrome/browser/ash/crosapi/network_settings_service_ash.cc b/chrome/browser/ash/crosapi/network_settings_service_ash.cc index bfa4bab..bca85948 100644 --- a/chrome/browser/ash/crosapi/network_settings_service_ash.cc +++ b/chrome/browser/ash/crosapi/network_settings_service_ash.cc
@@ -51,9 +51,9 @@ profile_manager_->AddObserver(this); } // Uninitialized in unit_tests. - if (chromeos::NetworkHandler::IsInitialized()) { + if (ash::NetworkHandler::IsInitialized()) { network_state_handler_observer_.Observe( - chromeos::NetworkHandler::Get()->network_state_handler()); + ash::NetworkHandler::Get()->network_state_handler()); } observers_.set_disconnect_handler(base::BindRepeating( &NetworkSettingsServiceAsh::OnDisconnect, base::Unretained(this)));
diff --git a/chrome/browser/ash/crosapi/network_settings_service_ash.h b/chrome/browser/ash/crosapi/network_settings_service_ash.h index ab5a529..fd288d9 100644 --- a/chrome/browser/ash/crosapi/network_settings_service_ash.h +++ b/chrome/browser/ash/crosapi/network_settings_service_ash.h
@@ -97,7 +97,7 @@ PrefService* local_state_; ProfileManager* profile_manager_ = nullptr; - base::ScopedObservation<chromeos::NetworkStateHandler, + base::ScopedObservation<ash::NetworkStateHandler, ash::NetworkStateHandlerObserver> network_state_handler_observer_{this};
diff --git a/chrome/browser/ash/crosapi/networking_attributes_ash.cc b/chrome/browser/ash/crosapi/networking_attributes_ash.cc index ecdd159..7c5da17a 100644 --- a/chrome/browser/ash/crosapi/networking_attributes_ash.cc +++ b/chrome/browser/ash/crosapi/networking_attributes_ash.cc
@@ -47,8 +47,8 @@ return; } - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler* network_state_handler = + ash::NetworkHandler::Get()->network_state_handler(); const chromeos::NetworkState* network = network_state_handler->DefaultNetwork(); if (!network) {
diff --git a/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc b/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc index 12a8a0b..c00b69f 100644 --- a/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc
@@ -183,9 +183,8 @@ testing::Mock::VerifyAndClearExpectations(&observer); const ash::DeviceState* device_state = - chromeos::NetworkHandler::Get() - ->network_state_handler() - ->GetDeviceState(kWifiDevicePath); + ash::NetworkHandler::Get()->network_state_handler()->GetDeviceState( + kWifiDevicePath); EXPECT_EQ(device_state->mac_address(), kFormattedMacAddress); EXPECT_EQ(device_state->GetIpAddressByType(shill::kTypeIPv4), kIpv4Address); EXPECT_EQ(device_state->GetIpAddressByType(shill::kTypeIPv6), kIpv6Address);
diff --git a/chrome/browser/ash/crosapi/networking_private_ash.cc b/chrome/browser/ash/crosapi/networking_private_ash.cc index e3f399e..a5d8bcb 100644 --- a/chrome/browser/ash/crosapi/networking_private_ash.cc +++ b/chrome/browser/ash/crosapi/networking_private_ash.cc
@@ -17,9 +17,9 @@ #include "extensions/browser/api/networking_private/networking_private_delegate_factory.h" #include "third_party/cros_system_api/dbus/shill/dbus-constants.h" +using ::ash::NetworkHandler; using ::ash::NetworkState; -using chromeos::NetworkHandler; -using chromeos::NetworkStateHandler; +using ::ash::NetworkStateHandler; namespace crosapi {
diff --git a/chrome/browser/ash/crosapi/networking_private_ash.h b/chrome/browser/ash/crosapi/networking_private_ash.h index a0a51802..78cc89b 100644 --- a/chrome/browser/ash/crosapi/networking_private_ash.h +++ b/chrome/browser/ash/crosapi/networking_private_ash.h
@@ -108,7 +108,7 @@ // Lacros observers to be notified of relevant events. mojo::RemoteSet<mojom::NetworkingPrivateDelegateObserver> observers_; // We observe network state to forward its events to our Lacros observers. - base::ScopedObservation<chromeos::NetworkStateHandler, + base::ScopedObservation<ash::NetworkStateHandler, ash::NetworkStateHandlerObserver> network_state_observation_{this}; base::ScopedObservation<ash::NetworkCertificateHandler,
diff --git a/chrome/browser/ash/crosapi/vpn_service_ash.cc b/chrome/browser/ash/crosapi/vpn_service_ash.cc index de3ae59..1d38fb8 100644 --- a/chrome/browser/ash/crosapi/vpn_service_ash.cc +++ b/chrome/browser/ash/crosapi/vpn_service_ash.cc
@@ -178,7 +178,7 @@ const std::string& extension_id) : extension_id_(extension_id) { network_configuration_observer_.Observe( - chromeos::NetworkHandler::Get()->network_configuration_handler()); + ash::NetworkHandler::Get()->network_configuration_handler()); } VpnServiceForExtensionAsh::~VpnServiceForExtensionAsh() = default; @@ -209,7 +209,7 @@ // Since the API is only designed to be used with the primary profile, it's // safe to get the hash of the primary profile here. const ash::NetworkProfile* profile = - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_profile_handler() ->GetProfileForUserhash(ash::ProfileHelper::GetUserIdHashFromProfile( ProfileManager::GetPrimaryUserProfile())); @@ -232,7 +232,7 @@ properties.Set(shill::kGuidProperty, base::GenerateGUID()); auto [success, failure] = AdaptCallback(std::move(callback)); - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_configuration_handler() ->CreateShillConfiguration( base::Value(std::move(properties)), @@ -274,7 +274,7 @@ DestroyConfigurationInternal(configuration); auto [success, failure] = AdaptCallback(std::move(callback)); - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_configuration_handler() ->RemoveConfiguration( *service_path, @@ -546,12 +546,12 @@ VpnServiceAsh::VpnServiceAsh() { // Can be false in unit tests. - if (!chromeos::NetworkHandler::IsInitialized()) { + if (!ash::NetworkHandler::IsInitialized()) { return; } network_state_handler_observer_.Observe( - chromeos::NetworkHandler::Get()->network_state_handler()); + ash::NetworkHandler::Get()->network_state_handler()); vpn_providers_observer_ = std::make_unique<VpnProvidersObserver>(this); } @@ -589,9 +589,9 @@ } void VpnServiceAsh::NetworkListChanged() { - chromeos::NetworkStateHandler::NetworkStateList network_list; + ash::NetworkStateHandler::NetworkStateList network_list; - auto* network_handler = chromeos::NetworkHandler::Get(); + auto* network_handler = ash::NetworkHandler::Get(); network_handler->network_state_handler()->GetVisibleNetworkListByType( ash::NetworkTypePattern::VPN(), &network_list);
diff --git a/chrome/browser/ash/crosapi/vpn_service_ash.h b/chrome/browser/ash/crosapi/vpn_service_ash.h index 91f2acb..ceaece1a 100644 --- a/chrome/browser/ash/crosapi/vpn_service_ash.h +++ b/chrome/browser/ash/crosapi/vpn_service_ash.h
@@ -264,7 +264,7 @@ // Ids of enabled vpn extensions. base::flat_set<std::string> vpn_extensions_; - base::ScopedObservation<chromeos::NetworkStateHandler, + base::ScopedObservation<ash::NetworkStateHandler, ash::NetworkStateHandlerObserver> network_state_handler_observer_{this};
diff --git a/chrome/browser/ash/crostini/crostini_manager.cc b/chrome/browser/ash/crostini/crostini_manager.cc index 705b1ab..70f8343 100644 --- a/chrome/browser/ash/crostini/crostini_manager.cc +++ b/chrome/browser/ash/crostini/crostini_manager.cc
@@ -46,11 +46,13 @@ #include "chrome/browser/ash/drive/drive_integration_service.h" #include "chrome/browser/ash/file_manager/path_util.h" #include "chrome/browser/ash/guest_os/guest_os_pref_names.h" +#include "chrome/browser/ash/guest_os/guest_os_session_tracker.h" #include "chrome/browser/ash/guest_os/guest_os_share_path.h" #include "chrome/browser/ash/guest_os/guest_os_stability_monitor.h" #include "chrome/browser/ash/guest_os/public/guest_os_service.h" #include "chrome/browser/ash/guest_os/public/guest_os_service_factory.h" #include "chrome/browser/ash/guest_os/public/guest_os_wayland_server.h" +#include "chrome/browser/ash/guest_os/public/types.h" #include "chrome/browser/ash/policy/handlers/powerwash_requirements_checker.h" #include "chrome/browser/ash/scheduler_configuration_manager.h" #include "chrome/browser/browser_process.h" @@ -567,8 +569,10 @@ // are finished. Also, a lot of unit tests don't inject a fake container so // it's possible in tests to end up here without a running container. Don't // try mounting sshfs in that case. - auto info = crostini_manager_->GetContainerInfo(container_id_); - if (container_id_ == DefaultContainerId() && info) { + bool running = + guest_os::GuestOsSessionTracker::GetForProfile(profile_)->IsRunning( + container_id_); + if (container_id_ == DefaultContainerId() && running) { crostini_manager_->MountCrostiniFiles(container_id_, base::DoNothing(), true); } @@ -1190,23 +1194,17 @@ is_unclean_startup_ = is_unclean_startup; } -absl::optional<ContainerInfo> CrostiniManager::GetContainerInfo( - const guest_os::GuestId& container_id) { - if (!IsVmRunning(container_id.vm_name)) { - return absl::nullopt; - } - auto range = running_containers_.equal_range(container_id.vm_name); - for (auto it = range.first; it != range.second; ++it) { - if (it->second.name == container_id.container_name) { - return it->second; - } - } - return absl::nullopt; -} - void CrostiniManager::AddRunningContainerForTesting(std::string vm_name, ContainerInfo info) { - running_containers_.emplace(std::move(vm_name), info); + auto* tracker = guest_os::GuestOsSessionTracker::GetForProfile(profile_); + guest_os::GuestId id{guest_os::VmType::TERMINA, vm_name, info.name}; + guest_os::GuestInfo guest_info{id, + 0, + info.username, + info.homedir, + info.ipv4_address, + info.sftp_vsock_port}; + tracker->AddGuestForTesting(id, guest_info); // IN-TEST } void CrostiniManager::UpdateLaunchMetricsForEnterpriseReporting() { @@ -1230,9 +1228,9 @@ if (ash::AnomalyDetectorClient::Get()) { // May be null in tests. ash::AnomalyDetectorClient::Get()->AddObserver(this); } - if (chromeos::NetworkHandler::IsInitialized()) { + if (ash::NetworkHandler::IsInitialized()) { network_state_handler_observer_.Observe( - chromeos::NetworkHandler::Get()->network_state_handler()); + ash::NetworkHandler::Get()->network_state_handler()); } if (chromeos::PowerManagerClient::Get()) { chromeos::PowerManagerClient::Get()->AddObserver(this); @@ -2523,7 +2521,6 @@ LOG(ERROR) << "Failed to start VM: " << response->failure_reason(); // If we thought vms and containers were running before, they aren't now. running_vms_.erase(vm_name); - running_containers_.erase(vm_name); std::move(callback).Run(/*success=*/false); return; } @@ -2537,7 +2534,6 @@ VmInfo{VmState::STARTING, std::move(response->vm_info())}; // If we thought a container was running for this VM, we're wrong. This can // happen if the vm was formerly running, then stopped via crosh. - running_containers_.erase(vm_name); if (wait_for_tremplin) { VLOG(1) << "Awaiting TremplinStartedSignal for " << owner_id_ << ", " @@ -2657,7 +2653,6 @@ // Remove from running_vms_, and other vm-keyed state. running_vms_.erase(vm_name); - running_containers_.erase(vm_name); InvokeAndErasePendingCallbacks( &export_lxd_container_callbacks_, vm_name, CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED, 0, 0); @@ -2702,11 +2697,6 @@ } VLOG(1) << "Container " << signal.container_name() << " started"; - running_containers_.emplace( - signal.vm_name(), - ContainerInfo(signal.container_name(), signal.container_username(), - signal.container_homedir(), signal.ipv4_address(), - signal.sftp_vsock_port())); InvokeAndErasePendingContainerCallbacks( &start_container_callbacks_, container_id, CrostiniResult::SUCCESS); @@ -2757,7 +2747,7 @@ } shutdown_container_callbacks_.erase(range_callbacks.first, range_callbacks.second); - RemoveStoppedContainer(container_id); + HandleContainerShutdown(container_id); } void CrostiniManager::OnInstallLinuxPackageProgress( @@ -3039,7 +3029,7 @@ break; case vm_tools::cicerone::StopLxdContainerResponse::STOPPED: - RemoveStoppedContainer(container_id); + HandleContainerShutdown(container_id); std::move(callback).Run(CrostiniResult::SUCCESS); break; @@ -3266,8 +3256,10 @@ (version != ContainerOsVersion::kOtherOs && version != ContainerOsVersion::kUnknown); - if (result == CrostiniResult::SUCCESS && !GetContainerInfo(container_id) && - is_garcon_required) { + bool running = + guest_os::GuestOsSessionTracker::GetForProfile(profile_)->IsRunning( + container_id); + if (result == CrostiniResult::SUCCESS && !running && is_garcon_required) { VLOG(1) << "Awaiting ContainerStarted signal from Garcon, did not yet have " "information for container " << container_id.container_name; @@ -3297,7 +3289,7 @@ result = CrostiniResult::CONTAINER_STOP_CANCELLED; break; case vm_tools::cicerone::LxdContainerStoppingSignal::STOPPED: - RemoveStoppedContainer(container_id); + HandleContainerShutdown(container_id); result = CrostiniResult::SUCCESS; break; case vm_tools::cicerone::LxdContainerStoppingSignal::STOPPING: @@ -3782,8 +3774,8 @@ // TODO(danielng): Consider handling instant tethering. void CrostiniManager::ActiveNetworksChanged( const std::vector<const ash::NetworkState*>& active_networks) { - chromeos::NetworkStateHandler::NetworkStateList active_physical_networks; - chromeos::NetworkHandler::Get() + ash::NetworkStateHandler::NetworkStateList active_physical_networks; + ash::NetworkHandler::Get() ->network_state_handler() ->GetActiveNetworkListByType(ash::NetworkTypePattern::Physical(), &active_physical_networks); @@ -3793,7 +3785,7 @@ if (!network) return; const ash::DeviceState* device = - chromeos::NetworkHandler::Get()->network_state_handler()->GetDeviceState( + ash::NetworkHandler::Get()->network_state_handler()->GetDeviceState( network->device_path()); if (!device) return; @@ -3809,7 +3801,6 @@ void CrostiniManager::SuspendImminent( power_manager::SuspendImminent::Reason reason) { - auto info = GetContainerInfo(DefaultContainerId()); if (!crostini_sshfs_->IsSshfsMounted(DefaultContainerId())) { return; } @@ -3827,7 +3818,10 @@ // https://crbug.com/968060. Sshfs is unmounted before suspend, // call RestartCrostini to force remount if container is running. guest_os::GuestId container_id = DefaultContainerId(); - if (GetContainerInfo(container_id)) { + bool running = + guest_os::GuestOsSessionTracker::GetForProfile(profile_)->IsRunning( + container_id); + if (running) { // TODO(crbug/1142321): Double-check if anything breaks if we change this // to just remount the sshfs mounts, in particular check 9p mounts. RestartCrostini(container_id, base::DoNothing()); @@ -3956,21 +3950,13 @@ restarter_it->second->StartLxdContainerFinished(result); } -void CrostiniManager::RemoveStoppedContainer( +void CrostiniManager::HandleContainerShutdown( const guest_os::GuestId& container_id) { // Run all ContainerShutdown observers for (auto& observer : container_shutdown_observers_) { observer.OnContainerShutdown(container_id); } - // Remove from running containers multimap. - auto range_containers = running_containers_.equal_range(container_id.vm_name); - for (auto it = range_containers.first; it != range_containers.second; ++it) { - if (it->second.name == container_id.container_name) { - running_containers_.erase(it); - break; - } - } - if (running_containers_.empty()) { + if (!IsVmRunning(kCrostiniDefaultVmName)) { auto* engagement_metrics_service = CrostiniEngagementMetricsService::Factory::GetForProfile(profile_); // This is null in unit tests.
diff --git a/chrome/browser/ash/crostini/crostini_manager.h b/chrome/browser/ash/crostini/crostini_manager.h index 4a5d9697..2e588cb 100644 --- a/chrome/browser/ash/crostini/crostini_manager.h +++ b/chrome/browser/ash/crostini/crostini_manager.h
@@ -565,9 +565,6 @@ const vm_tools::cicerone::OsRelease& os_release); const vm_tools::cicerone::OsRelease* GetContainerOsRelease( const guest_os::GuestId& container_id) const; - // Returns null if VM or container is not running. - absl::optional<ContainerInfo> GetContainerInfo( - const guest_os::GuestId& container_id); void AddRunningContainerForTesting(std::string vm_name, ContainerInfo info); // If the Crostini reporting policy is set, save the last app launch @@ -808,8 +805,9 @@ // metric logging the type. Mostly happens async and best-effort. void EmitVmDiskTypeMetric(const std::string vm_name); - // Removes specified container id from running_containers list. - void RemoveStoppedContainer(const guest_os::GuestId& container_id); + // Runs things that should happened whenever a container shutdowns e.g. + // triggering observers. + void HandleContainerShutdown(const guest_os::GuestId& container_id); // Registers a container with GuestOsService's registries. No-op if it's // already registered. @@ -860,9 +858,6 @@ std::map<std::string, VmInfo> running_vms_; - // Running containers as keyed by vm name. - std::multimap<std::string, ContainerInfo> running_containers_; - // OsRelease protos keyed by guest_os::GuestId. We populate this map even if a // container fails to start normally. std::map<guest_os::GuestId, vm_tools::cicerone::OsRelease> @@ -930,7 +925,7 @@ guest_os::GuestOsTerminalProviderRegistry::Id> terminal_provider_ids_; - base::ScopedObservation<chromeos::NetworkStateHandler, + base::ScopedObservation<ash::NetworkStateHandler, ash::NetworkStateHandlerObserver> network_state_handler_observer_{this};
diff --git a/chrome/browser/ash/crostini/crostini_manager_unittest.cc b/chrome/browser/ash/crostini/crostini_manager_unittest.cc index a29b5ac..3502bd7 100644 --- a/chrome/browser/ash/crostini/crostini_manager_unittest.cc +++ b/chrome/browser/ash/crostini/crostini_manager_unittest.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/ash/crostini/crostini_util.h" #include "chrome/browser/ash/crostini/fake_crostini_features.h" #include "chrome/browser/ash/guest_os/guest_os_pref_names.h" +#include "chrome/browser/ash/guest_os/guest_os_session_tracker.h" #include "chrome/browser/ash/guest_os/public/guest_os_service.h" #include "chrome/browser/ash/guest_os/public/guest_os_wayland_server.h" #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" @@ -889,11 +890,10 @@ EXPECT_GE(fake_concierge_client_->create_disk_image_call_count(), 1); EXPECT_GE(fake_concierge_client_->start_vm_call_count(), 1); EXPECT_EQ(1, restart_crostini_callback_count_); - - absl::optional<ContainerInfo> container_info = - crostini_manager()->GetContainerInfo(container_id()); - EXPECT_EQ(container_info.value().username, + auto req = fake_cicerone_client_->get_setup_lxd_container_user_request(); + EXPECT_EQ(req.container_username(), DefaultContainerUserNameForProfile(profile())); + ExpectRestarterUmaCount(1); histogram_tester_.ExpectTotalCount("Crostini.RestarterTimeInState2.Start", 1); histogram_tester_.ExpectTotalCount( @@ -929,10 +929,6 @@ EXPECT_GE(fake_concierge_client_->start_vm_call_count(), 1); EXPECT_EQ(1, restart_crostini_callback_count_); - absl::optional<ContainerInfo> container_info = - crostini_manager()->GetContainerInfo(container_id()); - EXPECT_EQ(container_info.value().username, - DefaultContainerUserNameForProfile(profile())); histogram_tester_.ExpectTotalCount("Crostini.Restarter.Started", 1); histogram_tester_.ExpectTotalCount("Crostini.RestarterResult", 1); histogram_tester_.ExpectTotalCount("Crostini.Installer.Started", 0); @@ -958,10 +954,6 @@ EXPECT_GE(fake_concierge_client_->start_vm_call_count(), 1); EXPECT_EQ(1, restart_crostini_callback_count_); - absl::optional<ContainerInfo> container_info = - crostini_manager()->GetContainerInfo(container_id()); - EXPECT_EQ(container_info.value().username, - DefaultContainerUserNameForProfile(profile())); ExpectRestarterUmaCount(1); } @@ -977,10 +969,8 @@ EXPECT_GE(fake_concierge_client_->create_disk_image_call_count(), 1); EXPECT_GE(fake_concierge_client_->start_vm_call_count(), 1); EXPECT_EQ(1, restart_crostini_callback_count_); - - absl::optional<ContainerInfo> container_info = - crostini_manager()->GetContainerInfo(container_id()); - EXPECT_EQ(container_info.value().username, "helloworld"); + auto req = fake_cicerone_client_->get_setup_lxd_container_user_request(); + EXPECT_EQ(req.container_username(), "helloworld"); ExpectRestarterUmaCount(1); } @@ -1521,7 +1511,6 @@ EXPECT_EQ(1, restart_crostini_callback_count_); EXPECT_TRUE(crostini_manager()->IsVmRunning(kVmName)); - EXPECT_TRUE(crostini_manager()->GetContainerInfo(container_id())); // Now call StartTerminaVm again. The default response state is "STARTING", // so no container should be considered running. @@ -1534,7 +1523,6 @@ run_loop2.Run(); EXPECT_GE(fake_concierge_client_->start_vm_call_count(), 1); EXPECT_TRUE(crostini_manager()->IsVmRunning(kVmName)); - EXPECT_FALSE(crostini_manager()->GetContainerInfo(container_id())); ExpectRestarterUmaCount(1); }
diff --git a/chrome/browser/ash/crostini/crostini_mount_provider.cc b/chrome/browser/ash/crostini/crostini_mount_provider.cc index 44915b3..bfa70e3 100644 --- a/chrome/browser/ash/crostini/crostini_mount_provider.cc +++ b/chrome/browser/ash/crostini/crostini_mount_provider.cc
@@ -6,8 +6,10 @@ #include <memory> +#include "base/bind.h" #include "chrome/browser/ash/crostini/crostini_manager.h" #include "chrome/browser/ash/crostini/crostini_util.h" +#include "chrome/browser/ash/guest_os/guest_os_session_tracker.h" #include "chrome/browser/ash/guest_os/public/types.h" #include "chrome/browser/ash/profiles/profile_helper.h" @@ -51,15 +53,23 @@ return; } auto* manager = CrostiniManager::GetForProfile(profile_); - auto vm_info = manager->GetVmInfo(container_id_.vm_name); - auto container_info = manager->GetContainerInfo(container_id_); if (!container_shutdown_observer_.IsObserving()) { container_shutdown_observer_.Observe(manager); } - - std::move(callback).Run(true, vm_info->info.cid(), - container_info->sftp_vsock_port, - container_info->homedir); + // The container's finished booting but we need to wait for the session + // tracker to update which races against CrostiniManager calling us. + subscription_ = + guest_os::GuestOsSessionTracker::GetForProfile(profile_) + ->RunOnceContainerStarted(container_id_, + base::BindOnce( + [](PrepareCallback callback, + guest_os::GuestInfo container_info) { + std::move(callback).Run( + true, container_info.cid, + container_info.sftp_vsock_port, + container_info.homedir); + }, + std::move(callback))); } std::unique_ptr<guest_os::GuestOsFileWatcher>
diff --git a/chrome/browser/ash/crostini/crostini_mount_provider.h b/chrome/browser/ash/crostini/crostini_mount_provider.h index ca5b89bc..f4660e1c4 100644 --- a/chrome/browser/ash/crostini/crostini_mount_provider.h +++ b/chrome/browser/ash/crostini/crostini_mount_provider.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_ASH_CROSTINI_CROSTINI_MOUNT_PROVIDER_H_ #define CHROME_BROWSER_ASH_CROSTINI_CROSTINI_MOUNT_PROVIDER_H_ +#include "base/callback_list.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/ash/crostini/crostini_manager.h" #include "chrome/browser/ash/crostini/crostini_simple_types.h" @@ -55,6 +56,7 @@ &CrostiniManager::AddContainerShutdownObserver, &CrostiniManager::RemoveContainerShutdownObserver> container_shutdown_observer_{this}; + base::CallbackListSubscription subscription_; // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed.
diff --git a/chrome/browser/ash/crostini/crostini_port_forwarder.cc b/chrome/browser/ash/crostini/crostini_port_forwarder.cc index 076e135..c079614 100644 --- a/chrome/browser/ash/crostini/crostini_port_forwarder.cc +++ b/chrome/browser/ash/crostini/crostini_port_forwarder.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/ash/crostini/crostini_pref_names.h" #include "chrome/browser/ash/crostini/crostini_util.h" #include "chrome/browser/ash/guest_os/guest_os_pref_names.h" +#include "chrome/browser/ash/guest_os/guest_os_session_tracker.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h" #include "chromeos/dbus/permission_broker/permission_broker_client.h" @@ -154,8 +155,8 @@ const PortRuleKey& key, const guest_os::GuestId& container_id, base::OnceCallback<void(bool)> result_callback) { - auto info = - CrostiniManager::GetForProfile(profile_)->GetContainerInfo(container_id); + auto info = guest_os::GuestOsSessionTracker::GetForProfile(profile_)->GetInfo( + container_id); if (!info) { LOG(ERROR) << "Inactive container to make port rules for."; std::move(result_callback).Run(false); @@ -201,9 +202,10 @@ const PortRuleKey& key, const guest_os::GuestId& container_id, base::OnceCallback<void(bool)> result_callback) { - auto info = - CrostiniManager::GetForProfile(profile_)->GetContainerInfo(container_id); - if (!info) { + bool running = + guest_os::GuestOsSessionTracker::GetForProfile(profile_)->IsRunning( + container_id); + if (!running) { LOG(ERROR) << "Inactive container to make port rules for."; std::move(result_callback).Run(false); return;
diff --git a/chrome/browser/ash/crostini/crostini_sshfs.cc b/chrome/browser/ash/crostini/crostini_sshfs.cc index 92761c21..11962c0 100644 --- a/chrome/browser/ash/crostini/crostini_sshfs.cc +++ b/chrome/browser/ash/crostini/crostini_sshfs.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/ash/crostini/crostini_util.h" #include "chrome/browser/ash/file_manager/path_util.h" #include "chrome/browser/ash/file_manager/volume_manager.h" +#include "chrome/browser/ash/guest_os/guest_os_session_tracker.h" #include "chrome/browser/profiles/profile.h" #include "chromeos/ash/components/dbus/cros_disks/cros_disks_client.h" #include "content/public/browser/browser_thread.h" @@ -105,8 +106,10 @@ } auto* manager = CrostiniManagerFactory::GetForProfile(profile_); - absl::optional<ContainerInfo> info = manager->GetContainerInfo(container_id); - if (!info) { + bool running = + guest_os::GuestOsSessionTracker::GetForProfile(profile_)->IsRunning( + in_progress_mount_->container_id); + if (!running) { LOG(ERROR) << "Unable to mount files for a container that's not running"; Finish(CrostiniSshfsResult::kContainerNotRunning); return; @@ -129,9 +132,8 @@ return; } - auto* manager = CrostiniManagerFactory::GetForProfile(profile_); - absl::optional<ContainerInfo> info = - manager->GetContainerInfo(in_progress_mount_->container_id); + auto info = guest_os::GuestOsSessionTracker::GetForProfile(profile_)->GetInfo( + in_progress_mount_->container_id); if (!info) { LOG(ERROR) << "Got ssh keys for a container that's not running. Aborting."; Finish(CrostiniSshfsResult::kGetContainerInfoFailed); @@ -141,18 +143,14 @@ // Add ourselves as an observer so we can continue once the path is mounted. auto* dmgr = ash::disks::DiskMountManager::GetInstance(); - // Construct sshfs:// source path. - in_progress_mount_->source_path = base::StringPrintf( - "sshfs://%s@%s:", info->username.c_str(), hostname.c_str()); - - // If we have a vsock port and cid, use sftp:// over vsock instead. if (info->sftp_vsock_port != 0) { - absl::optional<VmInfo> vm_info = - manager->GetVmInfo(in_progress_mount_->container_id.vm_name); - if (vm_info) { - in_progress_mount_->source_path = base::StringPrintf( - "sftp://%" PRId64 ":%u", vm_info->info.cid(), info->sftp_vsock_port); - } + // If we have a vsock port and cid, use sftp:// over vsock instead. + in_progress_mount_->source_path = base::StringPrintf( + "sftp://%" PRId64 ":%u", info->cid, info->sftp_vsock_port); + } else { + // otherwise construct sshfs:// source path. + in_progress_mount_->source_path = base::StringPrintf( + "sshfs://%s@%s:", info->username.c_str(), hostname.c_str()); } in_progress_mount_->container_homedir = info->homedir;
diff --git a/chrome/browser/ash/crostini/crostini_util.cc b/chrome/browser/ash/crostini/crostini_util.cc index daf96d8..df122223 100644 --- a/chrome/browser/ash/crostini/crostini_util.cc +++ b/chrome/browser/ash/crostini/crostini_util.cc
@@ -26,6 +26,7 @@ #include "chrome/browser/ash/guest_os/guest_os_pref_names.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/browser/ash/guest_os/guest_os_session_tracker.h" #include "chrome/browser/ash/guest_os/guest_os_share_path.h" #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/profiles/profile.h" @@ -500,7 +501,7 @@ guest_os::GetContainers(profile, kCrostiniDefaultVmType)) { if (container.container_name != container_id.container_name && container.vm_name == container_id.vm_name) { - if (CrostiniManager::GetForProfile(profile)->GetContainerInfo( + if (guest_os::GuestOsSessionTracker::GetForProfile(profile)->IsRunning( container)) { return false; }
diff --git a/chrome/browser/ash/cryptauth/client_app_metadata_provider_service.h b/chrome/browser/ash/cryptauth/client_app_metadata_provider_service.h index 61001df..191609e 100644 --- a/chrome/browser/ash/cryptauth/client_app_metadata_provider_service.h +++ b/chrome/browser/ash/cryptauth/client_app_metadata_provider_service.h
@@ -13,8 +13,6 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/system/sys_info.h" -// TODO(https://crbug.com/1164001): move to forward declaration. -#include "chromeos/ash/components/network/network_state_handler.h" #include "components/gcm_driver/instance_id/instance_id.h" #include "components/keyed_service/core/keyed_service.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -33,6 +31,8 @@ namespace ash { +class NetworkStateHandler; + // Concrete ClientAppMetadataProvider implementation, which lazily computes the // ClientAppMetadata when GetClientAppMetadata() is called. Once the // ClientAppMetadata has been successfully computed once, the same instance is
diff --git a/chrome/browser/ash/file_manager/app_service_file_tasks.cc b/chrome/browser/ash/file_manager/app_service_file_tasks.cc index 5e71982b..a9592b3 100644 --- a/chrome/browser/ash/file_manager/app_service_file_tasks.cc +++ b/chrome/browser/ash/file_manager/app_service_file_tasks.cc
@@ -69,8 +69,9 @@ // because both are executed through App Service, which can tell the // difference itself. return TASK_TYPE_FILE_HANDLER; - case apps::AppType::kUnknown: case apps::AppType::kCrostini: + return TASK_TYPE_CROSTINI_APP; + case apps::AppType::kUnknown: case apps::AppType::kBuiltIn: case apps::AppType::kMacOs: case apps::AppType::kPluginVm: @@ -98,6 +99,24 @@ return true; } +// Check if the file URLs can be mapped to a path inside VMs for +// GuestOS apps to access. +bool FilesCanBeSharedToVm(Profile* profile, std::vector<GURL> file_urls) { + storage::FileSystemContext* file_system_context = + util::GetFileManagerFileSystemContext(profile); + base::FilePath placeholder_vm_mount("/"); + base::FilePath not_used; + for (const GURL& file_url : file_urls) { + if (!file_manager::util::ConvertFileSystemURLToPathInsideVM( + profile, file_system_context->CrackURLInFirstPartyContext(file_url), + placeholder_vm_mount, + /*map_crostini_home=*/false, ¬_used)) { + return false; + } + } + return true; +} + Profile* GetProfileWithAppService(Profile* profile) { if (apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) { return profile; @@ -144,11 +163,16 @@ // the base profile in these cases (see crbug.com/1111695). Profile* profile_with_app_service = GetProfileWithAppService(profile); if (!profile_with_app_service) { + LOG(WARNING) << "Unexpected profile type"; return; } + apps::AppServiceProxy* proxy = apps::AppServiceProxyFactory::GetForProfile(profile_with_app_service); + bool files_shareable_to_vm = + FilesCanBeSharedToVm(profile_with_app_service, file_urls); + std::vector<apps::IntentFilePtr> intent_files; intent_files.reserve(entries.size()); for (size_t i = 0; i < entries.size(); i++) { @@ -169,6 +193,7 @@ apps::AppType::kStandaloneBrowserExtension}; if (ash::features::ShouldArcAndGuestOsFileTasksUseAppService()) { supported_app_types.push_back(apps::AppType::kArc); + supported_app_types.push_back(apps::AppType::kCrostini); } for (auto& launch_entry : intent_launch_info) { auto app_type = proxy->AppRegistryCache().GetAppType(launch_entry.app_id); @@ -213,6 +238,10 @@ continue; } + if (app_type == apps::AppType::kCrostini && !files_shareable_to_vm) { + continue; + } + constexpr int kIconSize = 32; GURL icon_url = apps::AppIconSource::GetIconURL(launch_entry.app_id, kIconSize); @@ -265,7 +294,8 @@ if (ash::features::ShouldArcAndGuestOsFileTasksUseAppService()) { DCHECK(task.task_type == TASK_TYPE_ARC_APP || task.task_type == TASK_TYPE_WEB_APP || - task.task_type == TASK_TYPE_FILE_HANDLER); + task.task_type == TASK_TYPE_FILE_HANDLER || + task.task_type == TASK_TYPE_CROSTINI_APP); } else { DCHECK(task.task_type == TASK_TYPE_WEB_APP || task.task_type == TASK_TYPE_FILE_HANDLER);
diff --git a/chrome/browser/ash/file_manager/app_service_file_tasks_unittest.cc b/chrome/browser/ash/file_manager/app_service_file_tasks_unittest.cc index b6035f4..43445bd 100644 --- a/chrome/browser/ash/file_manager/app_service_file_tasks_unittest.cc +++ b/chrome/browser/ash/file_manager/app_service_file_tasks_unittest.cc
@@ -9,15 +9,18 @@ #include <vector> #include "ash/constants/ash_features.h" +#include "base/strings/escape.h" #include "base/test/scoped_feature_list.h" #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/app_service_test.h" #include "chrome/browser/apps/app_service/intent_util.h" +#include "chrome/browser/ash/crostini/crostini_test_helper.h" #include "chrome/browser/ash/file_manager/file_tasks.h" #include "chrome/browser/ash/file_manager/path_util.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" #include "chrome/test/base/testing_profile.h" +#include "components/prefs/scoped_user_pref_update.h" #include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/intent_filter.h" #include "components/services/app_service/public/cpp/intent_test_util.h" @@ -26,6 +29,7 @@ #include "content/public/test/browser_task_environment.h" #include "extensions/browser/entry_info.h" #include "extensions/common/extension_builder.h" +#include "storage/browser/file_system/external_mount_points.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/features.h" @@ -54,13 +58,6 @@ const char kActivityLabelAny[] = "some_any_file"; const char kActivityLabelTextWild[] = "some_text_wild_file"; -GURL test_url(const std::string& file_name) { - GURL url = - GURL("filesystem:chrome-extension://extensionid/external/" + file_name); - EXPECT_TRUE(url.is_valid()); - return url; -} - } // namespace namespace file_manager { @@ -75,6 +72,10 @@ app_service_proxy_ = apps::AppServiceProxyFactory::GetForProfile(profile_.get()); ASSERT_TRUE(app_service_proxy_); + storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( + util::GetDownloadsMountPointName(profile_.get()), + storage::kFileSystemTypeLocal, storage::FileSystemMountOption(), + util::GetMyFilesFolderForProfile(profile_.get())); } Profile* profile() { return profile_.get(); } @@ -83,8 +84,19 @@ std::string file_name; std::string mime_type; bool is_directory = false; + GURL file_url; }; + GURL test_url(const std::string& file_name) { + GURL url = + GURL("filesystem:chrome-extension://id/external/" + + base::EscapeUrlEncodedData( + util::GetDownloadsMountPointName(profile()) + "/" + file_name, + /*use_plus=*/false)); + EXPECT_TRUE(url.is_valid()); + return url; + } + std::vector<FullTaskDescriptor> FindAppServiceTasks( const std::vector<FakeFile>& files) { std::vector<extensions::EntryInfo> entries; @@ -94,7 +106,11 @@ util::GetMyFilesFolderForProfile(profile()).AppendASCII( fake_file.file_name), fake_file.mime_type, fake_file.is_directory); - file_urls.push_back(test_url(fake_file.file_name)); + if (fake_file.file_url.is_empty()) { + file_urls.push_back(test_url(fake_file.file_name)); + } else { + file_urls.push_back(fake_file.file_url); + } } std::vector<FullTaskDescriptor> tasks; @@ -297,8 +313,8 @@ apps::AppType::kChromeApp, true); } - apps::IntentFilterPtr CreateArcFileIntentFilter(std::string action, - std::string mime_type) { + apps::IntentFilterPtr CreateFileIntentFilter(std::string action, + std::string mime_type) { auto intent_filter = std::make_unique<apps::IntentFilter>(); intent_filter->AddSingleValueCondition(apps::ConditionType::kAction, action, apps::PatternMatchType::kLiteral); @@ -319,6 +335,14 @@ return app_id; } + void AddCrostiniAppWithIntentFilter(std::string app_id, + apps::IntentFilterPtr intent_filter) { + std::vector<apps::IntentFilterPtr> filters; + filters.push_back(std::move(intent_filter)); + AddFakeAppWithIntentFilters(app_id, std::move(filters), + apps::AppType::kCrostini, true); + } + base::test::ScopedFeatureList feature_list_; content::BrowserTaskEnvironment task_environment_; std::unique_ptr<TestingProfile> profile_; @@ -365,13 +389,28 @@ std::string text_activity = "TextViewerActivity"; std::string text_app_id = AddArcAppWithIntentFilter( text_package_name, text_activity, - CreateArcFileIntentFilter(apps_util::kIntentActionView, text_mime_type)); + CreateFileIntentFilter(apps_util::kIntentActionView, text_mime_type)); std::vector<FullTaskDescriptor> tasks = FindAppServiceTasks({{"foo.txt", text_mime_type}}); ASSERT_EQ(0U, tasks.size()); } +// Crostini apps should not be found when kArcAndGuestOsFileTasksUseAppService +// is disabled. +TEST_F(AppServiceFileTasksTestDisabled, FindAppServiceCrostiniApp) { + std::string text_mime_type = "text/plain"; + std::string file_name = "foo.txt"; + std::string text_app_id = "Text app"; + AddCrostiniAppWithIntentFilter( + text_app_id, + CreateFileIntentFilter(apps_util::kIntentActionView, text_mime_type)); + + std::vector<FullTaskDescriptor> tasks = + FindAppServiceTasks({{file_name, text_mime_type}}); + ASSERT_EQ(0U, tasks.size()); +} + // An app which does not handle intents should not be found even if the filters // match. TEST_F(AppServiceFileTasksTestEnabled, FindAppServiceFileTasksHandlesIntent) { @@ -647,14 +686,14 @@ std::string text_activity = "TextViewerActivity"; std::string text_app_id = AddArcAppWithIntentFilter( text_package_name, text_activity, - CreateArcFileIntentFilter(apps_util::kIntentActionView, text_mime_type)); + CreateFileIntentFilter(apps_util::kIntentActionView, text_mime_type)); // Create an app with an image file filter. std::string image_package_name = "com.example.imageViewer"; std::string image_activity = "ImageViewerActivity"; std::string image_app_id = AddArcAppWithIntentFilter( image_package_name, image_activity, - CreateArcFileIntentFilter(apps_util::kIntentActionView, image_mime_type)); + CreateFileIntentFilter(apps_util::kIntentActionView, image_mime_type)); // Check if only the text ARC app appears as a result. std::vector<FullTaskDescriptor> tasks = @@ -665,5 +704,67 @@ EXPECT_FALSE(tasks[0].is_file_extension_match); } +TEST_F(AppServiceFileTasksTestEnabled, FindAppServiceCrostiniApp) { + std::string file_name = "foo.txt"; + std::string text_app_id = "Text app"; + AddCrostiniAppWithIntentFilter( + text_app_id, + CreateFileIntentFilter(apps_util::kIntentActionView, kMimeTypeText)); + + // Check if the text Crostini app is returned. + std::vector<FullTaskDescriptor> tasks = + FindAppServiceTasks({{file_name, kMimeTypeText}}); + ASSERT_EQ(1U, tasks.size()); + EXPECT_EQ(text_app_id, tasks[0].task_descriptor.app_id); + EXPECT_FALSE(tasks[0].is_generic_file_handler); + EXPECT_FALSE(tasks[0].is_file_extension_match); +} + +TEST_F(AppServiceFileTasksTestEnabled, CrostiniCheckPathsCanBeShared) { + std::string file_name = "foo.txt"; + std::string text_app_id = "Text app"; + AddCrostiniAppWithIntentFilter( + text_app_id, + CreateFileIntentFilter(apps_util::kIntentActionView, kMimeTypeText)); + + // Possible to share path. + std::vector<FullTaskDescriptor> tasks = + FindAppServiceTasks({{file_name, kMimeTypeText}}); + ASSERT_EQ(1U, tasks.size()); + EXPECT_EQ(text_app_id, tasks[0].task_descriptor.app_id); + + // Should not be possible to share path. + GURL invalid_url = GURL("broken:url"); + tasks = + FindAppServiceTasks({{file_name, kMimeTypeText, /*is_directory=*/false, + /*file_url=*/invalid_url}}); + ASSERT_EQ(0U, tasks.size()); +} + +TEST_F(AppServiceFileTasksTestEnabled, FindMultipleAppServiceCrostiniApps) { + std::string file_name = "foo.txt"; + std::string app_id_1 = "Text app 1"; + std::string app_id_2 = "Text app 2"; + AddCrostiniAppWithIntentFilter( + app_id_1, + CreateFileIntentFilter(apps_util::kIntentActionView, kMimeTypeText)); + AddCrostiniAppWithIntentFilter( + app_id_2, + CreateFileIntentFilter(apps_util::kIntentActionView, kMimeTypeText)); + + // Check if both Crostini apps are returned. + std::vector<FullTaskDescriptor> tasks = + FindAppServiceTasks({{file_name, kMimeTypeText}}); + ASSERT_EQ(2U, tasks.size()); + + EXPECT_EQ(app_id_1, tasks[0].task_descriptor.app_id); + EXPECT_FALSE(tasks[0].is_generic_file_handler); + EXPECT_FALSE(tasks[0].is_file_extension_match); + + EXPECT_EQ(app_id_2, tasks[1].task_descriptor.app_id); + EXPECT_FALSE(tasks[1].is_generic_file_handler); + EXPECT_FALSE(tasks[1].is_file_extension_match); +} + } // namespace file_tasks } // namespace file_manager.
diff --git a/chrome/browser/ash/file_manager/file_tasks.cc b/chrome/browser/ash/file_manager/file_tasks.cc index 17943d7..f99da98 100644 --- a/chrome/browser/ash/file_manager/file_tasks.cc +++ b/chrome/browser/ash/file_manager/file_tasks.cc
@@ -717,10 +717,12 @@ return true; } - // ARC apps and web apps need mime types for launching. Retrieve them first. + // Apps from App Service need mime types for launching. Retrieve them first. if (task.task_type == TASK_TYPE_ARC_APP || task.task_type == TASK_TYPE_WEB_APP || - task.task_type == TASK_TYPE_FILE_HANDLER) { + task.task_type == TASK_TYPE_FILE_HANDLER || + (ash::features::ShouldArcAndGuestOsFileTasksUseAppService() && + task.task_type == TASK_TYPE_CROSTINI_APP)) { // TODO(petermarshall): Implement GetProfileForExtensionTask in Lacros if // necessary, for Chrome Apps. extensions::app_file_handler_util::MimeTypeCollector* mime_collector = @@ -732,8 +734,9 @@ return true; } - if (task.task_type == TASK_TYPE_CROSTINI_APP || - task.task_type == TASK_TYPE_PLUGIN_VM_APP) { + if (!ash::features::ShouldArcAndGuestOsFileTasksUseAppService() && + (task.task_type == TASK_TYPE_CROSTINI_APP || + task.task_type == TASK_TYPE_PLUGIN_VM_APP)) { DCHECK_EQ(kGuestOsAppActionID, task.action_id); ExecuteGuestOsTask(profile, task, file_urls, std::move(done)); return true; @@ -817,9 +820,11 @@ new std::vector<FullTaskDescriptor>); if (ash::features::ShouldArcAndGuestOsFileTasksUseAppService()) { - // Skip FindArcTasks since ARC tasks are now found in App Service. - FindExtensionAndAppTasks(profile, entries, file_urls, std::move(callback), - std::move(result_list)); + // Skip FindArcTasks and FindGuestOsTasks since these tasks are now found in + // App Service. + FindAppServiceTasks(profile, entries, file_urls, result_list.get()); + PostProcessFoundTasks(profile, entries, std::move(callback), + std::move(result_list)); } else { // 1. Find and append ARC handler tasks. FindArcTasks(profile, entries, file_urls, std::move(result_list),
diff --git a/chrome/browser/ash/file_manager/path_util.cc b/chrome/browser/ash/file_manager/path_util.cc index 15deb3f..964f829 100644 --- a/chrome/browser/ash/file_manager/path_util.cc +++ b/chrome/browser/ash/file_manager/path_util.cc
@@ -33,6 +33,7 @@ #include "chrome/browser/ash/file_manager/app_id.h" #include "chrome/browser/ash/file_manager/fileapi_util.h" #include "chrome/browser/ash/file_manager/volume_manager.h" +#include "chrome/browser/ash/guest_os/guest_os_session_tracker.h" #include "chrome/browser/ash/guest_os/public/guest_os_mount_provider.h" #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/ash/smb_client/smb_service.h" @@ -493,8 +494,8 @@ } else if (id == GetCrostiniMountPointName(profile)) { // Crostini. if (map_crostini_home) { - absl::optional<crostini::ContainerInfo> container_info = - crostini::CrostiniManager::GetForProfile(profile)->GetContainerInfo( + auto container_info = + guest_os::GuestOsSessionTracker::GetForProfile(profile)->GetInfo( crostini::DefaultContainerId()); if (!container_info) { return false; @@ -548,8 +549,8 @@ base::FilePath relative_path; if (map_crostini_home) { - absl::optional<crostini::ContainerInfo> container_info = - crostini::CrostiniManager::GetForProfile(profile)->GetContainerInfo( + auto container_info = + guest_os::GuestOsSessionTracker::GetForProfile(profile)->GetInfo( crostini::DefaultContainerId()); if (container_info && AppendRelativePath(container_info->homedir, inside, &relative_path)) {
diff --git a/chrome/browser/ash/file_manager/restore_io_task.cc b/chrome/browser/ash/file_manager/restore_io_task.cc index 961ee5c3..5f92bd17c 100644 --- a/chrome/browser/ash/file_manager/restore_io_task.cc +++ b/chrome/browser/ash/file_manager/restore_io_task.cc
@@ -7,7 +7,6 @@ #include "base/callback.h" #include "base/files/file.h" #include "base/files/file_util.h" -#include "base/strings/string_piece.h" #include "base/task/bind_post_task.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" @@ -78,13 +77,10 @@ return; } - enabled_trash_locations_ = - GenerateEnabledTrashLocationsForProfile(profile_, base_path_); progress_.state = State::kInProgress; - - parser_ = std::make_unique<chromeos::trash_service::TrashInfoParser>( - base::BindOnce(&RestoreIOTask::Complete, weak_ptr_factory_.GetWeakPtr(), - State::kError)); + validator_ = std::make_unique<TrashInfoValidator>(profile_, base_path_); + validator_->SetDisconnectHandler(base::BindOnce( + &RestoreIOTask::Complete, weak_ptr_factory_.GetWeakPtr(), State::kError)); ValidateTrashInfo(0); } @@ -104,101 +100,32 @@ (base_path_.empty()) ? progress_.sources[idx].url.path() : base_path_.Append(progress_.sources[idx].url.path()); - if (trash_info.FinalExtension() != kTrashInfoExtension) { - progress_.sources[idx].error = base::File::FILE_ERROR_INVALID_URL; - Complete(State::kError); - return; - } - // Ensures the trash location is parented at an enabled trash location. - base::FilePath trash_folder_location; - base::FilePath mount_point_path; - for (const auto& [parent_path, info] : enabled_trash_locations_) { - if (parent_path.Append(info.relative_folder_path).IsParent(trash_info)) { - trash_folder_location = parent_path.Append(info.relative_folder_path); - mount_point_path = info.mount_point_path; - break; - } - } - - if (mount_point_path.empty() || trash_folder_location.empty()) { - progress_.sources[idx].error = base::File::FILE_ERROR_INVALID_OPERATION; - Complete(State::kError); - return; - } - - // Ensure the corresponding file that this metadata file refers to actually - // exists. - base::FilePath trashed_file_location = - trash_folder_location.Append(kFilesFolderName) - .Append(trash_info.BaseName().RemoveFinalExtension()); - - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::MayBlock()}, - base::BindOnce(&base::PathExists, trashed_file_location), - base::BindOnce(&RestoreIOTask::OnTrashedFileExists, - weak_ptr_factory_.GetWeakPtr(), idx, mount_point_path, - trashed_file_location)); -} - -void RestoreIOTask::OnTrashedFileExists( - size_t idx, - const base::FilePath& mount_point_path, - const base::FilePath& trashed_file_location, - bool exists) { - if (!exists) { - progress_.sources[idx].error = base::File::FILE_ERROR_NOT_FOUND; - Complete(State::kError); - return; - } - - auto complete_callback = base::BindPostTask( - base::SequencedTaskRunnerHandle::Get(), + auto on_parsed_callback = base::BindOnce(&RestoreIOTask::EnsureParentRestorePathExists, - weak_ptr_factory_.GetWeakPtr(), idx, mount_point_path, - trashed_file_location)); + weak_ptr_factory_.GetWeakPtr(), idx); - base::FilePath trashinfo_path = - (base_path_.empty()) - ? progress_.sources[idx].url.path() - : base_path_.Append(progress_.sources[idx].url.path()); - - parser_->ParseTrashInfoFile(std::move(trashinfo_path), - std::move(complete_callback)); + validator_->ValidateAndParseTrashInfo(std::move(trash_info), + std::move(on_parsed_callback)); } void RestoreIOTask::EnsureParentRestorePathExists( size_t idx, - const base::FilePath& mount_point_path, - const base::FilePath& trashed_file_location, - base::File::Error status, - const base::FilePath& restore_path, - base::Time deletion_date) { - if (status != base::File::FILE_OK) { - progress_.sources[idx].error = status; + base::FileErrorOr<ParsedTrashInfoData> parsed_data) { + if (parsed_data.is_error()) { + progress_.sources[idx].error = parsed_data.error(); Complete(State::kError); return; } - if (restore_path.empty() || - restore_path.value()[0] != base::FilePath::kSeparators[0]) { - progress_.sources[idx].error = base::File::FILE_ERROR_INVALID_URL; - Complete(State::kError); - return; - } - - // Remove the leading "/" character to make the restore path relative from the - // known trash parent path. - base::StringPiece relative_path = - base::StringPiece(restore_path.value()).substr(1); - base::FilePath absolute_restore_path = mount_point_path.Append(relative_path); - base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock()}, - base::BindOnce(&CreateNestedPath, absolute_restore_path.DirName()), + base::BindOnce(&CreateNestedPath, + parsed_data.value().absolute_restore_path.DirName()), base::BindOnce(&RestoreIOTask::OnParentRestorePathExists, - weak_ptr_factory_.GetWeakPtr(), idx, trashed_file_location, - absolute_restore_path)); + weak_ptr_factory_.GetWeakPtr(), idx, + parsed_data.value().trashed_file_path, + parsed_data.value().absolute_restore_path)); } void RestoreIOTask::OnParentRestorePathExists(
diff --git a/chrome/browser/ash/file_manager/restore_io_task.h b/chrome/browser/ash/file_manager/restore_io_task.h index ac9b6b28..b0d4656 100644 --- a/chrome/browser/ash/file_manager/restore_io_task.h +++ b/chrome/browser/ash/file_manager/restore_io_task.h
@@ -11,7 +11,7 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/ash/file_manager/io_task.h" #include "chrome/browser/ash/file_manager/trash_common_util.h" -#include "chromeos/ash/components/trash_service/public/cpp/trash_info_parser.h" +#include "chrome/browser/ash/file_manager/trash_info_validator.h" #include "storage/browser/file_system/file_system_context.h" #include "storage/browser/file_system/file_system_operation_runner.h" #include "storage/browser/file_system/file_system_url.h" @@ -46,27 +46,15 @@ // Finalises the RestoreIOTask with the `state`. void Complete(State state); - // Ensure the metadata file conforms to the following: - // - Has a .trashinfo suffix - // - Resides in an enabled trash directory - // - The file resides in the info directory - // - Has an identical item in the files directory with no .trashinfo suffix + // Calls the underlying TrashInfoValidator to perform validation on the + // supplied .trashinfo file. void ValidateTrashInfo(size_t idx); - void OnTrashedFileExists(size_t idx, - const base::FilePath& mount_point_path, - const base::FilePath& trashed_file_location, - bool exists); - // Make sure the enclosing folder where the trashed file to be restored to // actually exists. In the event the file path has been removed, recreate it. void EnsureParentRestorePathExists( size_t idx, - const base::FilePath& mount_point_path, - const base::FilePath& trashed_file_location, - base::File::Error status, - const base::FilePath& restore_path, - base::Time deletion_date); + base::FileErrorOr<ParsedTrashInfoData> parsed_data); void OnParentRestorePathExists(size_t idx, const base::FilePath& trashed_file_location, @@ -107,16 +95,12 @@ // only in testing. base::FilePath base_path_; - // A map containing paths which are enabled for trashing. - TrashPathsMap enabled_trash_locations_; - // Stores the id of the restore operation if one is in progress. Used so the // restore can be cancelled. absl::optional<storage::FileSystemOperationRunner::OperationID> operation_id_; - // Holds the connection open to the `TrashService`. This is a sandboxed - // process that performs parsing of the trashinfo files. - std::unique_ptr<chromeos::trash_service::TrashInfoParser> parser_ = nullptr; + // Validates and parses .trashinfo files. + std::unique_ptr<TrashInfoValidator> validator_ = nullptr; ProgressCallback progress_callback_; CompleteCallback complete_callback_;
diff --git a/chrome/browser/ash/file_manager/trash_info_validator.cc b/chrome/browser/ash/file_manager/trash_info_validator.cc new file mode 100644 index 0000000..f35e6ca --- /dev/null +++ b/chrome/browser/ash/file_manager/trash_info_validator.cc
@@ -0,0 +1,146 @@ +// Copyright 2022 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/file_manager/trash_info_validator.h" + +#include "base/files/file.h" +#include "base/files/file_util.h" +#include "base/strings/string_piece.h" +#include "base/task/bind_post_task.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "base/threading/sequenced_task_runner_handle.h" + +class Profile; + +namespace file_manager { + +namespace { + +void RunCallbackWithError(base::File::Error error, + ValidateAndParseTrashInfoCallback callback) { + std::move(callback).Run(base::FileErrorOr<ParsedTrashInfoData>(error)); +} + +} // namespace + +TrashInfoValidator::TrashInfoValidator(Profile* profile, + const base::FilePath& base_path) { + enabled_trash_locations_ = + io_task::GenerateEnabledTrashLocationsForProfile(profile, base_path); + + parser_ = std::make_unique<chromeos::trash_service::TrashInfoParser>(); +} + +TrashInfoValidator::~TrashInfoValidator() = default; + +void TrashInfoValidator::SetDisconnectHandler( + base::OnceCallback<void()> disconnect_callback) { + DCHECK(parser_) << "Parser should not be null here"; + if (parser_) { + parser_->SetDisconnectHandler(std::move(disconnect_callback)); + } +} + +void TrashInfoValidator::ValidateAndParseTrashInfo( + const base::FilePath& trash_info_path, + ValidateAndParseTrashInfoCallback callback) { + // Validates the supplied file ends in a .trashinfo extension. + if (trash_info_path.FinalExtension() != io_task::kTrashInfoExtension) { + RunCallbackWithError(base::File::FILE_ERROR_INVALID_URL, + std::move(callback)); + return; + } + + // Validate the .trashinfo file belongs in an enabled trash location. + base::FilePath trash_folder_location; + base::FilePath mount_point_path; + for (const auto& [parent_path, info] : enabled_trash_locations_) { + if (parent_path.Append(info.relative_folder_path) + .IsParent(trash_info_path)) { + trash_folder_location = parent_path.Append(info.relative_folder_path); + mount_point_path = info.mount_point_path; + break; + } + } + + if (mount_point_path.empty() || trash_folder_location.empty()) { + RunCallbackWithError(base::File::FILE_ERROR_INVALID_OPERATION, + std::move(callback)); + return; + } + + // Ensure the corresponding file that this metadata file refers to actually + // exists. + base::FilePath trashed_file_location = + trash_folder_location.Append(io_task::kFilesFolderName) + .Append(trash_info_path.BaseName().RemoveFinalExtension()); + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&base::PathExists, trashed_file_location), + base::BindOnce(&TrashInfoValidator::OnTrashedFileExists, + weak_ptr_factory_.GetWeakPtr(), mount_point_path, + trashed_file_location, std::move(trash_info_path), + std::move(callback))); +} + +void TrashInfoValidator::OnTrashedFileExists( + const base::FilePath& mount_point_path, + const base::FilePath& trashed_file_location, + const base::FilePath& trash_info_path, + ValidateAndParseTrashInfoCallback callback, + bool exists) { + if (!exists) { + RunCallbackWithError(base::File::FILE_ERROR_NOT_FOUND, std::move(callback)); + return; + } + + auto complete_callback = base::BindPostTask( + base::SequencedTaskRunnerHandle::Get(), + base::BindOnce(&TrashInfoValidator::OnTrashInfoParsed, + weak_ptr_factory_.GetWeakPtr(), mount_point_path, + trashed_file_location, std::move(callback))); + + parser_->ParseTrashInfoFile(std::move(trash_info_path), + std::move(complete_callback)); +} + +void TrashInfoValidator::OnTrashInfoParsed( + const base::FilePath& mount_point_path, + const base::FilePath& trashed_file_location, + ValidateAndParseTrashInfoCallback callback, + base::File::Error status, + const base::FilePath& restore_path, + base::Time deletion_date) { + if (status != base::File::FILE_OK) { + RunCallbackWithError(status, std::move(callback)); + return; + } + + // The restore path that was parsed could be empty or not have a leading "/". + if (restore_path.empty() || + restore_path.value()[0] != base::FilePath::kSeparators[0]) { + RunCallbackWithError(base::File::FILE_ERROR_INVALID_URL, + std::move(callback)); + return; + } + + // Remove the leading "/" character to make the restore path relative from the + // known trash parent path. + base::StringPiece relative_path = + base::StringPiece(restore_path.value()).substr(1); + base::FilePath absolute_restore_path = mount_point_path.Append(relative_path); + + ParsedTrashInfoData parsed_data = { + .trashed_file_path = std::move(trashed_file_location), + .absolute_restore_path = std::move(absolute_restore_path), + .deletion_date = std::move(deletion_date), + }; + + std::move(callback).Run( + base::FileErrorOr<ParsedTrashInfoData>(std::move(parsed_data))); +} + +} // namespace file_manager
diff --git a/chrome/browser/ash/file_manager/trash_info_validator.h b/chrome/browser/ash/file_manager/trash_info_validator.h new file mode 100644 index 0000000..25b3295e --- /dev/null +++ b/chrome/browser/ash/file_manager/trash_info_validator.h
@@ -0,0 +1,108 @@ +// Copyright 2022 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_FILE_MANAGER_TRASH_INFO_VALIDATOR_H_ +#define CHROME_BROWSER_ASH_FILE_MANAGER_TRASH_INFO_VALIDATOR_H_ + +#include <utility> + +#include "base/callback.h" +#include "base/files/file_error_or.h" +#include "base/files/file_path.h" +#include "base/time/time.h" +#include "chrome/browser/ash/file_manager/trash_common_util.h" +#include "chromeos/ash/components/trash_service/public/cpp/trash_info_parser.h" + +namespace file_manager { + +// On a successful parse of .trashinfo files, returns the restoration path, +// deletion date and actual location of the trashed file. +struct ParsedTrashInfoData { + // The actual on-disk location of the trashed file, e.g. .Trash/files/foo.txt. + base::FilePath trashed_file_path; + + // The path to restore the file back to. The basename here and the basename + // for the `trashed_file_path` may differ as the path may conflict with + // another in the trash. + base::FilePath absolute_restore_path; + + // The date/time the file was trashed. + base::Time deletion_date; +}; + +// Helper alias to define the callback type that is returned from the validator. +using ValidateAndParseTrashInfoCallback = + base::OnceCallback<void(base::FileErrorOr<ParsedTrashInfoData>)>; + +// Validates and parses individual .trashinfo files to ensure they conform to +// the XDG specification. This is exposed here as we need to get a file handler +// and ensure files exist prior to parsing them. This can be done in a +// privileged context, but the parsing cannot. To use this: +// 1. Initialize a `TrashInfoValidator` like: +// auto parser = std::make_unique<TrashInfoValidator>(profile, +// base_path); +// 2. Set your disconnect handler in the event the underlying trash service +// disconnects errorenously. +// parser->SetDisconnectHandler(base::BindOnce(&Method, WeakPtr())); +// 3. For every file to validate and parse, call the ValidateAndParseTrashInfo +// method, e.g. +// parser->ValidateAndParseTrashInfo(trash_info_path, +// base::BindOnce(&OnParsed, WeakPtr())); +class TrashInfoValidator { + public: + // The `base_path` here is used primarily for testing purposes to identify the + // enabled trash locations. + TrashInfoValidator(Profile* profile, const base::FilePath& base_path); + ~TrashInfoValidator(); + + TrashInfoValidator(const TrashInfoValidator&) = delete; + TrashInfoValidator& operator=(const TrashInfoValidator&) = delete; + + // Ensure the metadata file conforms to the following: + // - Has a .trashinfo suffix + // - Resides in an enabled trash directory + // - The file resides in the info directory + // - Has an identical item in the files directory with no .trashinfo suffix + // On confirming the above it then calls the TrashService to retrieve the + // parsed trashinfo data. The `trash_info_path` must be absolute. + void ValidateAndParseTrashInfo(const base::FilePath& trash_info_path, + ValidateAndParseTrashInfoCallback callback); + + // Set the disconnect handler for the underlying TrashService. + // TODO(b/238946031): Potentially centralize this by calling the `callback` + // instead of having a separate disconnect callback. + void SetDisconnectHandler(base::OnceCallback<void()> disconnect_callback); + + private: + // Invoked after verifying if the on-disk file exists. The `mount_point_path` + // represents the location where the .Trash folder resides (e.g. ~/MyFiles), + // the `trashed_file_location` is the on-disk file that should be restored and + // the `trash_info_path` represents the location of the .trashinfo file. + void OnTrashedFileExists(const base::FilePath& mount_point_path, + const base::FilePath& trashed_file_location, + const base::FilePath& trash_info_path, + ValidateAndParseTrashInfoCallback callback, + bool exists); + + // Invoked when the TrashService has finished parsing the .trashinfo file. + void OnTrashInfoParsed(const base::FilePath& mount_point_path, + const base::FilePath& trashed_file_location, + ValidateAndParseTrashInfoCallback callback, + base::File::Error status, + const base::FilePath& restore_path, + base::Time deletion_date); + + // A map containing paths which are enabled for trashing. + io_task::TrashPathsMap enabled_trash_locations_; + + // Holds the connection open to the `TrashService`. This is a sandboxed + // process that performs parsing of the trashinfo files. + std::unique_ptr<chromeos::trash_service::TrashInfoParser> parser_ = nullptr; + + base::WeakPtrFactory<TrashInfoValidator> weak_ptr_factory_{this}; +}; + +} // namespace file_manager + +#endif // CHROME_BROWSER_ASH_FILE_MANAGER_TRASH_INFO_VALIDATOR_H_
diff --git a/chrome/browser/ash/guest_os/guest_os_session_tracker.cc b/chrome/browser/ash/guest_os/guest_os_session_tracker.cc index 70c95ff..0cadeb99 100644 --- a/chrome/browser/ash/guest_os/guest_os_session_tracker.cc +++ b/chrome/browser/ash/guest_os/guest_os_session_tracker.cc
@@ -132,6 +132,10 @@ return iter->second; } +bool GuestOsSessionTracker::IsRunning(const GuestId& id) { + return guests_.contains(id); +} + // ash::ConciergeClient::VmObserver overrides. void GuestOsSessionTracker::OnVmStarted( const vm_tools::concierge::VmStartedSignal& signal) {
diff --git a/chrome/browser/ash/guest_os/guest_os_session_tracker.h b/chrome/browser/ash/guest_os/guest_os_session_tracker.h index 652f41a..2a2f9bb3 100644 --- a/chrome/browser/ash/guest_os/guest_os_session_tracker.h +++ b/chrome/browser/ash/guest_os/guest_os_session_tracker.h
@@ -57,9 +57,13 @@ base::OnceCallback<void(GuestInfo)> callback); // Returns information about a running guest. Returns nullopt if the guest - // isn't recognised e.g. it's not running. + // isn't recognised e.g. it's not running. If you just want to check if a + // guest is running or not and don't need the info, use `IsRunning` instead absl::optional<GuestInfo> GetInfo(const GuestId& id); + // Returns true if a guest is running, false otherwise. + bool IsRunning(const GuestId& id); + void AddGuestForTesting(const GuestId& id, const GuestInfo& info); protected:
diff --git a/chrome/browser/ash/login/helper.cc b/chrome/browser/ash/login/helper.cc index bffde6a..9191f49 100644 --- a/chrome/browser/ash/login/helper.cc +++ b/chrome/browser/ash/login/helper.cc
@@ -87,20 +87,17 @@ } bool NetworkStateHelper::IsConnected() const { - chromeos::NetworkStateHandler* nsh = - chromeos::NetworkHandler::Get()->network_state_handler(); + NetworkStateHandler* nsh = NetworkHandler::Get()->network_state_handler(); return nsh->ConnectedNetworkByType(NetworkTypePattern::Default()) != nullptr; } bool NetworkStateHelper::IsConnectedToEthernet() const { - chromeos::NetworkStateHandler* nsh = - chromeos::NetworkHandler::Get()->network_state_handler(); + NetworkStateHandler* nsh = NetworkHandler::Get()->network_state_handler(); return nsh->ConnectedNetworkByType(NetworkTypePattern::Ethernet()) != nullptr; } bool NetworkStateHelper::IsConnecting() const { - chromeos::NetworkStateHandler* nsh = - chromeos::NetworkHandler::Get()->network_state_handler(); + NetworkStateHandler* nsh = NetworkHandler::Get()->network_state_handler(); return nsh->ConnectingNetworkByType(NetworkTypePattern::Default()) != nullptr; }
diff --git a/chrome/browser/ash/login/screens/network_screen.h b/chrome/browser/ash/login/screens/network_screen.h index dd6fc91..09fc84e 100644 --- a/chrome/browser/ash/login/screens/network_screen.h +++ b/chrome/browser/ash/login/screens/network_screen.h
@@ -154,8 +154,7 @@ ScreenExitCallback exit_callback_; std::unique_ptr<login::NetworkStateHelper> network_state_helper_; - base::ScopedObservation<chromeos::NetworkStateHandler, - NetworkStateHandlerObserver> + base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver> network_state_handler_observer_{this}; base::WeakPtrFactory<NetworkScreen> weak_ptr_factory_{this};
diff --git a/chrome/browser/ash/login/screens/update_required_screen.h b/chrome/browser/ash/login/screens/update_required_screen.h index 6055b458..7f9db0d 100644 --- a/chrome/browser/ash/login/screens/update_required_screen.h +++ b/chrome/browser/ash/login/screens/update_required_screen.h
@@ -121,8 +121,7 @@ base::RepeatingClosure exit_callback_; std::unique_ptr<ErrorScreensHistogramHelper> histogram_helper_; - base::ScopedObservation<chromeos::NetworkStateHandler, - NetworkStateHandlerObserver> + base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver> network_state_handler_observer_{this}; // Whether the screen is shown.
diff --git a/chrome/browser/ash/login/security_token_login_browsertest.cc b/chrome/browser/ash/login/security_token_login_browsertest.cc index 4294d2c..9156a0c 100644 --- a/chrome/browser/ash/login/security_token_login_browsertest.cc +++ b/chrome/browser/ash/login/security_token_login_browsertest.cc
@@ -25,7 +25,9 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" #include "chrome/browser/ash/login/existing_user_controller.h" +#include "chrome/browser/ash/login/lock/screen_locker_tester.h" #include "chrome/browser/ash/login/saml/security_token_saml_test.h" +#include "chrome/browser/ash/login/security_token_session_controller.h" #include "chrome/browser/ash/login/test/cryptohome_mixin.h" #include "chrome/browser/ash/login/test/js_checker.h" #include "chrome/browser/ash/login/test/login_manager_mixin.h" @@ -244,8 +246,13 @@ void WaitForChromeTerminating() { termination_loop_.Run(); } + bool is_chrome_terminating() const { return is_chrome_terminating_; } + // SessionObserver - void OnChromeTerminating() override { termination_loop_.Quit(); } + void OnChromeTerminating() override { + is_chrome_terminating_ = true; + termination_loop_.Quit(); + } void OnSessionStateChanged(session_manager::SessionState state) override { if (state == session_manager::SessionState::LOCKED) @@ -253,6 +260,7 @@ } private: + bool is_chrome_terminating_ = false; base::RunLoop session_locked_loop_; base::RunLoop termination_loop_; }; @@ -566,6 +574,14 @@ GetChallengeResponseAccountId()); } + void Lock() { + ScreenLockerTester().Lock(); + // Mimic the behavior of real-world smart card middleware extensions, which + // stop talking to smart cards in-session while at the lock screen. + SetSecurityTokenAvailability(/*available_on_login_screen=*/true, + /*available_in_session=*/false); + } + // Configures and installs the user session certificate provider extension. void PrepareUserCertificateProviderExtension() { user_extension_mixin_.InitWithMockPolicyProvider(profile(), @@ -574,13 +590,20 @@ test_certificate_provider_extension_mixin_.ForceInstall(profile())); } - // Makes the user session extension call certificateProvider.setCertificates() - // without providing any certificates, thus simulating the removal of a - // security token. - void SimulateSecurityTokenRemoval() { + // Makes the extensions call certificateProvider.setCertificates(). Depending + // on the passed flags, extensions will pass empty or non-empty sets of + // certificates. + void SetSecurityTokenAvailability(bool available_on_login_screen, + bool available_in_session) { + // Configure the sign-in screen extension. + ASSERT_TRUE(certificate_provider_extension()); + certificate_provider_extension()->set_should_provide_certificates( + available_on_login_screen); + certificate_provider_extension()->TriggerSetCertificates(); + // Configure the in-session extension. ASSERT_TRUE(user_certificate_provider_extension()); user_certificate_provider_extension()->set_should_provide_certificates( - false); + available_in_session); user_certificate_provider_extension()->TriggerSetCertificates(); } @@ -605,6 +628,14 @@ return has_notification; } + bool GetNotificationDisplayedKnownUserFlag() const { + return user_manager::KnownUser(g_browser_process->local_state()) + .FindBoolPath(GetChallengeResponseAccountId(), + login::SecurityTokenSessionController:: + kNotificationDisplayedKnownUserKey) + .value_or(false); + } + Profile* profile() const { return profile_; } TestCertificateProviderExtension* user_certificate_provider_extension() { @@ -623,35 +654,39 @@ // Tests the SecurityTokenSessionBehavior policy with value "LOCK". IN_PROC_BROWSER_TEST_P(SecurityTokenSessionBehaviorTest, Lock) { Login(); - profile()->GetPrefs()->SetString(prefs::kSecurityTokenSessionBehavior, - "LOCK"); + g_browser_process->local_state()->SetString( + prefs::kSecurityTokenSessionBehavior, "LOCK"); PrepareUserCertificateProviderExtension(); + SetSecurityTokenAvailability(/*available_on_login_screen=*/false, + /*available_in_session=*/true); ChromeSessionObserver chrome_session_observer; - SimulateSecurityTokenRemoval(); + SetSecurityTokenAvailability(/*available_on_login_screen=*/false, + /*available_in_session=*/false); chrome_session_observer.WaitForSessionLocked(); EXPECT_TRUE(ProfileHasNotification( profile(), "security_token_session_controller_notification")); - EXPECT_TRUE(profile()->GetPrefs()->GetBoolean( - prefs::kSecurityTokenSessionNotificationDisplayed)); + EXPECT_TRUE(GetNotificationDisplayedKnownUserFlag()); } // Tests the SecurityTokenSessionBehavior policy with value "LOGOUT". IN_PROC_BROWSER_TEST_P(SecurityTokenSessionBehaviorTest, PRE_Logout) { Login(); ChromeSessionObserver chrome_session_observer; - profile()->GetPrefs()->SetString(prefs::kSecurityTokenSessionBehavior, - "LOGOUT"); + g_browser_process->local_state()->SetString( + prefs::kSecurityTokenSessionBehavior, "LOGOUT"); PrepareUserCertificateProviderExtension(); + SetSecurityTokenAvailability(/*available_on_login_screen=*/false, + /*available_in_session=*/true); // Removal of the certificate should lead to the end of the current session. - SimulateSecurityTokenRemoval(); + SetSecurityTokenAvailability(/*available_on_login_screen=*/false, + /*available_in_session=*/false); chrome_session_observer.WaitForChromeTerminating(); // Check login screen notification is scheduled. - EXPECT_TRUE(profile()->GetPrefs()->GetBoolean( - prefs::kSecurityTokenSessionNotificationDisplayed)); + EXPECT_TRUE(GetNotificationDisplayedKnownUserFlag()); } IN_PROC_BROWSER_TEST_P(SecurityTokenSessionBehaviorTest, Logout) { @@ -661,12 +696,54 @@ "security_token_session_controller_notification")); } +// Test that entering the Lock Screen doesn't cause the logout if the policy is +// set to LOGOUT. This is a regression test for crbug.com/1349140. +IN_PROC_BROWSER_TEST_P(SecurityTokenSessionBehaviorTest, + LockScreenWhileLogoutPolicy) { + Login(); + g_browser_process->local_state()->SetString( + prefs::kSecurityTokenSessionBehavior, "LOGOUT"); + PrepareUserCertificateProviderExtension(); + SetSecurityTokenAvailability(/*available_on_login_screen=*/false, + /*available_in_session=*/true); + ChromeSessionObserver chrome_session_observer; + Lock(); + + // We want to check that the user session doesn't get terminated erroneously + // here. There's no good way of testing something not to happen if the exact + // timing is unknown, so we're doing a best-effort here: + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(chrome_session_observer.is_chrome_terminating()); + EXPECT_FALSE(GetNotificationDisplayedKnownUserFlag()); +} + +// Test that removing the security token while at the Lock Screen causes the +// logout if the policy is set to LOGOUT. +IN_PROC_BROWSER_TEST_P(SecurityTokenSessionBehaviorTest, LogoutFromLockScreen) { + Login(); + g_browser_process->local_state()->SetString( + prefs::kSecurityTokenSessionBehavior, "LOGOUT"); + PrepareUserCertificateProviderExtension(); + SetSecurityTokenAvailability(/*available_on_login_screen=*/false, + /*available_in_session=*/true); + ChromeSessionObserver chrome_session_observer; + Lock(); + + // Removal of the certificate should lead to the end of the current session. + SetSecurityTokenAvailability(/*available_on_login_screen=*/false, + /*available_in_session=*/false); + chrome_session_observer.WaitForChromeTerminating(); + + // Check login screen notification is scheduled. + EXPECT_TRUE(GetNotificationDisplayedKnownUserFlag()); +} + // Tests the SecurityTokenSessionNotificationSeconds policy. IN_PROC_BROWSER_TEST_P(SecurityTokenSessionBehaviorTest, NotificationSeconds) { Login(); - profile()->GetPrefs()->SetString(prefs::kSecurityTokenSessionBehavior, - "LOCK"); - profile()->GetPrefs()->SetInteger( + g_browser_process->local_state()->SetString( + prefs::kSecurityTokenSessionBehavior, "LOCK"); + g_browser_process->local_state()->SetInteger( prefs::kSecurityTokenSessionNotificationSeconds, 1); PrepareUserCertificateProviderExtension(); ChromeSessionObserver chrome_session_observer; @@ -675,7 +752,8 @@ views::test::AnyWidgetTestPasskey{}, "SecurityTokenSessionRestrictionView"); - SimulateSecurityTokenRemoval(); + SetSecurityTokenAvailability(/*available_on_login_screen=*/false, + /*available_in_session=*/false); views::Widget* notification = notification_waiter.WaitIfNeededAndGet(); views::test::WidgetDestroyedWaiter notification_closing_observer( @@ -743,8 +821,8 @@ Profile* profile = ProfileHelper::Get()->GetProfileByUser( user_manager::UserManager::Get()->GetActiveUser()); PrepareUserCertificateProviderExtension(profile); - profile->GetPrefs()->SetString(prefs::kSecurityTokenSessionBehavior, - "LOGOUT"); + g_browser_process->local_state()->SetString( + prefs::kSecurityTokenSessionBehavior, "LOGOUT"); // Removal of the certificate should lead to the end of the current session. ChromeSessionObserver chrome_session_observer;
diff --git a/chrome/browser/ash/login/security_token_session_controller.cc b/chrome/browser/ash/login/security_token_session_controller.cc index 7065d215..cf392d1 100644 --- a/chrome/browser/ash/login/security_token_session_controller.cc +++ b/chrome/browser/ash/login/security_token_session_controller.cc
@@ -36,6 +36,8 @@ #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" +#include "components/session_manager/core/session_manager.h" +#include "components/session_manager/session_manager_types.h" #include "components/user_manager/known_user.h" #include "components/user_manager/user.h" #include "extensions/common/extension_id.h" @@ -159,29 +161,34 @@ } // namespace +const char* const + SecurityTokenSessionController::kNotificationDisplayedKnownUserKey = + "security_token_session_notification_displayed"; + SecurityTokenSessionController::SecurityTokenSessionController( + bool is_user_profile, PrefService* local_state, - PrefService* profile_prefs, - const user_manager::User* user, + const user_manager::User* primary_user, chromeos::CertificateProviderService* certificate_provider_service) - : local_state_(local_state), - profile_prefs_(profile_prefs), - user_(user), - certificate_provider_service_(certificate_provider_service) { + : is_user_profile_(is_user_profile), + local_state_(local_state), + primary_user_(primary_user), + certificate_provider_service_(certificate_provider_service), + session_manager_(session_manager::SessionManager::Get()) { DCHECK(local_state_); - DCHECK(profile_prefs_); - DCHECK(user_); + DCHECK(primary_user_); DCHECK(certificate_provider_service_); + session_manager_observation_.Observe(session_manager_); certificate_provider_ = certificate_provider_service_->CreateCertificateProvider(); LoadStoredChallengeResponseSpkiKeysForUser( - local_state_, user_->GetAccountId(), &extension_to_spkis_, + local_state_, primary_user_->GetAccountId(), &extension_to_spkis_, &observed_extensions_); UpdateNotificationPref(); - behavior_ = GetBehaviorFromPref(); - pref_change_registrar_.Init(profile_prefs_); + behavior_ = GetBehaviorFromPrefAndSessionState(); + pref_change_registrar_.Init(local_state_); base::RepeatingClosure behavior_pref_changed_callback = - base::BindRepeating(&SecurityTokenSessionController::UpdateBehaviorPref, + base::BindRepeating(&SecurityTokenSessionController::UpdateBehavior, weak_ptr_factory_.GetWeakPtr()); base::RepeatingClosure notification_pref_changed_callback = base::BindRepeating( @@ -206,7 +213,7 @@ extension_to_spkis_.clear(); observed_extensions_.clear(); LoadStoredChallengeResponseSpkiKeysForUser( - local_state_, user_->GetAccountId(), &extension_to_spkis_, + local_state_, primary_user_->GetAccountId(), &extension_to_spkis_, &observed_extensions_); } @@ -247,22 +254,33 @@ } } -// static -void SecurityTokenSessionController::RegisterLocalStatePrefs( - PrefRegistrySimple* registry) { - registry->RegisterStringPref( - prefs::kSecurityTokenSessionNotificationScheduledDomain, ""); +void SecurityTokenSessionController::OnSessionStateChanged() { + if (session_manager_->session_state() == + session_manager::SessionState::LOCKED) { + had_lock_screen_transition_ = true; + } + + // Reset the flag, so that after the certificates are collected from all + // extensions we know whether the absence of some should be tolerated. + all_required_certificates_were_observed_ = false; + + UpdateBehavior(); } // static -void SecurityTokenSessionController::RegisterProfilePrefs( +void SecurityTokenSessionController::RegisterLocalStatePrefs( PrefRegistrySimple* registry) { + // Prefs that contain policy values. We use the Local State for these, so that + // the values are available for the controller regardless of the profile it's + // attached to (the policy stack has code to automatically copy the primary + // profile's policies into the Local State). registry->RegisterStringPref(prefs::kSecurityTokenSessionBehavior, kIgnorePrefValue); registry->RegisterIntegerPref(prefs::kSecurityTokenSessionNotificationSeconds, 0); - registry->RegisterBooleanPref( - prefs::kSecurityTokenSessionNotificationDisplayed, false); + // Prefs that contain state that needs to be persisted across Chrome restarts. + registry->RegisterStringPref( + prefs::kSecurityTokenSessionNotificationScheduledDomain, ""); } // static @@ -294,9 +312,9 @@ base::UTF8ToUTF16(sanitized_domain))); } -void SecurityTokenSessionController::UpdateBehaviorPref() { +void SecurityTokenSessionController::UpdateBehavior() { Behavior previous_behavior = behavior_; - behavior_ = GetBehaviorFromPref(); + behavior_ = GetBehaviorFromPrefAndSessionState(); if (behavior_ == Behavior::kIgnore) { Reset(); } else if (previous_behavior == Behavior::kIgnore) { @@ -307,14 +325,49 @@ } void SecurityTokenSessionController::UpdateNotificationPref() { - notification_seconds_ = base::Seconds(profile_prefs_->GetInteger( + notification_seconds_ = base::Seconds(local_state_->GetInteger( prefs::kSecurityTokenSessionNotificationSeconds)); } +bool SecurityTokenSessionController::ShouldApplyPolicyInCurrentSessionState() + const { + switch (session_manager_->session_state()) { + case session_manager::SessionState::UNKNOWN: + case session_manager::SessionState::OOBE: + case session_manager::SessionState::LOGIN_PRIMARY: + case session_manager::SessionState::LOGGED_IN_NOT_ACTIVE: + case session_manager::SessionState::LOGIN_SECONDARY: + case session_manager::SessionState::RMA: + return false; + case session_manager::SessionState::ACTIVE: + if (!is_user_profile_) { + // Inside the user session, only the controller that's tied to the user + // profile should work. + return false; + } + return true; + case session_manager::SessionState::LOCKED: + if (is_user_profile_) { + // On the lock screen, only the controller that's tied to the sign-in + // profile should work. + return false; + } + return true; + } + NOTREACHED(); + return false; +} + SecurityTokenSessionController::Behavior -SecurityTokenSessionController::GetBehaviorFromPref() const { +SecurityTokenSessionController::GetBehaviorFromPrefAndSessionState() const { + // First determine if we're in a session state in which our instance should do + // nothing (ignore the policy). + if (!ShouldApplyPolicyInCurrentSessionState()) + return Behavior::kIgnore; + // After passing the session state checks, use the policy value as the desired + // behavior. return ParseBehaviorPrefValue( - profile_prefs_->GetString(prefs::kSecurityTokenSessionBehavior)); + local_state_->GetString(prefs::kSecurityTokenSessionBehavior)); } void SecurityTokenSessionController::TriggerAction() { @@ -341,17 +394,30 @@ void SecurityTokenSessionController::ExtensionProvidesAllRequiredCertificates( const extensions::ExtensionId& extension_id) { extensions_missing_required_certificates_.erase(extension_id); - if (extensions_missing_required_certificates_.empty()) + if (extensions_missing_required_certificates_.empty()) { + all_required_certificates_were_observed_ = true; Reset(); + } } void SecurityTokenSessionController::ExtensionStopsProvidingCertificate( const extensions::ExtensionId& extension_id) { extensions_missing_required_certificates_.insert(extension_id); - if (fullscreen_notification_) + if (!all_required_certificates_were_observed_ && + had_lock_screen_transition_) { + // When transitioning to/from the Lock Screen, we delay applying the policy + // until we saw the full list of the required certificates at least once. + // This is needed because the extensions report a spuriously empty list of + // certificates shortly after such session state transition, due to the USB + // access conflicts between two profiles. + return; + } + + if (fullscreen_notification_) { // There was already a security token missing. return; + } // Schedule session lock / logout. action_timer_.Start( @@ -367,24 +433,21 @@ weak_ptr_factory_.GetWeakPtr()), behavior_, chrome::enterprise_util::GetDomainFromEmail( - user_->GetDisplayEmail())), + primary_user_->GetDisplayEmail())), nullptr, nullptr); fullscreen_notification_->Show(); } } -void SecurityTokenSessionController::AddLockNotification() const { +void SecurityTokenSessionController::AddLockNotification() { // A user should see the notification only the first time their session is // locked. - if (profile_prefs_->GetBoolean( - prefs::kSecurityTokenSessionNotificationDisplayed)) { + if (GetNotificationDisplayedKnownUserFlag()) return; - } - profile_prefs_->SetBoolean(prefs::kSecurityTokenSessionNotificationDisplayed, - true); + SetNotificationDisplayedKnownUserFlag(); - std::string domain = - chrome::enterprise_util::GetDomainFromEmail(user_->GetDisplayEmail()); + std::string domain = chrome::enterprise_util::GetDomainFromEmail( + primary_user_->GetDisplayEmail()); DisplayNotification( l10n_util::GetStringFUTF16(IDS_SECURITY_TOKEN_SESSION_LOCK_MESSAGE_TITLE, ui::GetChromeOSDeviceName()), @@ -392,21 +455,18 @@ base::UTF8ToUTF16(domain))); } -void SecurityTokenSessionController::ScheduleLogoutNotification() const { +void SecurityTokenSessionController::ScheduleLogoutNotification() { // The notification can not be created directly, since it will not persist // after the session is ended. Instead, use local state to schedule the // creation of a notification. - if (profile_prefs_->GetBoolean( - prefs::kSecurityTokenSessionNotificationDisplayed)) { - // A user should see the notification only the first time they are logged - // out. + if (GetNotificationDisplayedKnownUserFlag()) return; - } - profile_prefs_->SetBoolean(prefs::kSecurityTokenSessionNotificationDisplayed, - true); + SetNotificationDisplayedKnownUserFlag(); + local_state_->SetString( prefs::kSecurityTokenSessionNotificationScheduledDomain, - chrome::enterprise_util::GetDomainFromEmail(user_->GetDisplayEmail())); + chrome::enterprise_util::GetDomainFromEmail( + primary_user_->GetDisplayEmail())); } void SecurityTokenSessionController::Reset() { @@ -421,5 +481,23 @@ } } +bool SecurityTokenSessionController::GetNotificationDisplayedKnownUserFlag() + const { + return user_manager::KnownUser(local_state_) + .FindBoolPath(primary_user_->GetAccountId(), + kNotificationDisplayedKnownUserKey) + .value_or(false); +} + +void SecurityTokenSessionController::SetNotificationDisplayedKnownUserFlag() { + // The reason we use `KnownUser` (i.e., the Local State) here is because the + // flag needs to be readable/writable from the instance of our class that's + // tied to the sign-in profile. There's no direct/safe way to access a + // profile's pref service from a keyed service tied to a different profile. + user_manager::KnownUser(local_state_) + .SetBooleanPref(primary_user_->GetAccountId(), + kNotificationDisplayedKnownUserKey, true); +} + } // namespace login } // namespace ash
diff --git a/chrome/browser/ash/login/security_token_session_controller.h b/chrome/browser/ash/login/security_token_session_controller.h index b6e89714..d68a72bc 100644 --- a/chrome/browser/ash/login/security_token_session_controller.h +++ b/chrome/browser/ash/login/security_token_session_controller.h
@@ -11,6 +11,7 @@ #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "chrome/browser/certificate_provider/certificate_provider_service.h" @@ -18,6 +19,8 @@ #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" +#include "components/session_manager/core/session_manager.h" +#include "components/session_manager/core/session_manager_observer.h" #include "components/user_manager/user.h" #include "extensions/common/extension_id.h" @@ -39,14 +42,18 @@ // is getting informed what is going to happen when the certificate vanishes. class SecurityTokenSessionController : public KeyedService, - public chromeos::CertificateProviderService::Observer { + public chromeos::CertificateProviderService::Observer, + public session_manager::SessionManagerObserver { public: enum class Behavior { kIgnore, kLogout, kLock }; + // A key in the known_user database that stores the boolean flag: whether the + // notification has been shown or not. + static const char* const kNotificationDisplayedKnownUserKey; SecurityTokenSessionController( + bool is_user_profile, PrefService* local_state, - PrefService* profile_prefs, - const user_manager::User* user, + const user_manager::User* primary_user, chromeos::CertificateProviderService* certificate_provider_service); SecurityTokenSessionController(const SecurityTokenSessionController& other) = delete; @@ -58,7 +65,6 @@ void Shutdown() override; static void RegisterLocalStatePrefs(PrefRegistrySimple* registry); - static void RegisterProfilePrefs(PrefRegistrySimple* registry); // If this controller logged the user out just before, display a notification // explaining why this happened. This is only done the first time this @@ -71,15 +77,19 @@ // providing certificates are not yet initialized. void OnChallengeResponseKeysUpdated(); - // CertificateProviderService::Observer + // CertificateProviderService::Observer: void OnCertificatesUpdated( const std::string& extension_id, const std::vector<chromeos::certificate_provider::CertificateInfo>& certificate_infos) override; + // session_manager::SessionManagerObserver: + void OnSessionStateChanged() override; + private: - Behavior GetBehaviorFromPref() const; - void UpdateBehaviorPref(); + bool ShouldApplyPolicyInCurrentSessionState() const; + Behavior GetBehaviorFromPrefAndSessionState() const; + void UpdateBehavior(); void UpdateNotificationPref(); void ExtensionProvidesAllRequiredCertificates( @@ -87,13 +97,21 @@ void ExtensionStopsProvidingCertificate( const extensions::ExtensionId& extension_id); void TriggerAction(); - void AddLockNotification() const; - void ScheduleLogoutNotification() const; + void AddLockNotification(); + void ScheduleLogoutNotification(); void Reset(); + bool GetNotificationDisplayedKnownUserFlag() const; + void SetNotificationDisplayedKnownUserFlag(); + + const bool is_user_profile_; PrefService* const local_state_; - PrefService* const profile_prefs_; - const user_manager::User* const user_; + const user_manager::User* const primary_user_; + chromeos::CertificateProviderService* certificate_provider_service_ = nullptr; + session_manager::SessionManager* const session_manager_; + base::ScopedObservation<session_manager::SessionManager, + session_manager::SessionManagerObserver> + session_manager_observation_{this}; PrefChangeRegistrar pref_change_registrar_; Behavior behavior_ = Behavior::kIgnore; base::TimeDelta notification_seconds_; @@ -104,8 +122,13 @@ extensions_missing_required_certificates_; views::Widget* fullscreen_notification_ = nullptr; base::OneShotTimer action_timer_; - chromeos::CertificateProviderService* certificate_provider_service_ = nullptr; std::unique_ptr<chromeos::CertificateProvider> certificate_provider_; + // Whether all of the user's certificates have been provided at least once by + // the extensions. This field is reset every time the session state changes. + bool all_required_certificates_were_observed_ = false; + // Whether the session state has transitioned into the `LOCKED` session state + // at least once. + bool had_lock_screen_transition_ = false; base::WeakPtrFactory<SecurityTokenSessionController> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ash/login/security_token_session_controller_factory.cc b/chrome/browser/ash/login/security_token_session_controller_factory.cc index 362aa54..d4d12c1e 100644 --- a/chrome/browser/ash/login/security_token_session_controller_factory.cc +++ b/chrome/browser/ash/login/security_token_session_controller_factory.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ash/login/security_token_session_controller_factory.h" +#include "base/check_is_test.h" #include "chrome/browser/ash/login/challenge_response_auth_keys_loader.h" #include "chrome/browser/ash/login/security_token_session_controller.h" #include "chrome/browser/ash/profiles/profile_helper.h" @@ -43,24 +44,33 @@ KeyedService* SecurityTokenSessionControllerFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - // The service should only exist for the primary profile. + // The service should only exist for the primary and the sign-in profiles. Profile* profile = Profile::FromBrowserContext(context); - if (!ProfileHelper::IsPrimaryProfile(profile)) + if (!profile) + return nullptr; + const bool is_primary_profile = ProfileHelper::IsPrimaryProfile(profile); + const bool is_signin_profile = ProfileHelper::IsSigninProfile(profile); + if (!is_primary_profile && !is_signin_profile) return nullptr; PrefService* local_state = g_browser_process->local_state(); if (!local_state) { // This can happen in tests that do not have local state. + CHECK_IS_TEST(); return nullptr; } - user_manager::User* user = ProfileHelper::Get()->GetUserByProfile( - Profile::FromBrowserContext(context)); + auto* const user_manager = user_manager::UserManager::Get(); + DCHECK(user_manager); + const user_manager::User* primary_user = user_manager->GetPrimaryUser(); + DCHECK(primary_user); + chromeos::CertificateProviderService* certificate_provider_service = chromeos::CertificateProviderServiceFactory::GetForBrowserContext( context); - return new SecurityTokenSessionController(local_state, profile->GetPrefs(), - user, certificate_provider_service); + return new SecurityTokenSessionController(is_primary_profile, local_state, + primary_user, + certificate_provider_service); } bool SecurityTokenSessionControllerFactory::ServiceIsCreatedWithBrowserContext()
diff --git a/chrome/browser/ash/login/session/user_session_manager.cc b/chrome/browser/ash/login/session/user_session_manager.cc index 2ccd617d..de08e50 100644 --- a/chrome/browser/ash/login/session/user_session_manager.cc +++ b/chrome/browser/ash/login/session/user_session_manager.cc
@@ -1694,6 +1694,9 @@ login::SecurityTokenSessionControllerFactory::GetForBrowserContext( profile) ->OnChallengeResponseKeysUpdated(); + login::SecurityTokenSessionControllerFactory::GetForBrowserContext( + ProfileHelper::GetSigninProfile()) + ->OnChallengeResponseKeysUpdated(); } if (user_context_.GetSyncTrustedVaultKeys().has_value()) {
diff --git a/chrome/browser/ash/mobile/mobile_activator.h b/chrome/browser/ash/mobile/mobile_activator.h index 0f170df..83ffe7c 100644 --- a/chrome/browser/ash/mobile/mobile_activator.h +++ b/chrome/browser/ash/mobile/mobile_activator.h
@@ -255,8 +255,7 @@ // Cellular plan payment time. base::Time cellular_plan_payment_time_; - base::ScopedObservation<chromeos::NetworkStateHandler, - NetworkStateHandlerObserver> + base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver> network_state_handler_observer_{this}; base::ObserverList<Observer>::Unchecked observers_;
diff --git a/chrome/browser/ash/net/network_portal_detector_impl.h b/chrome/browser/ash/net/network_portal_detector_impl.h index 0094c185..8286877 100644 --- a/chrome/browser/ash/net/network_portal_detector_impl.h +++ b/chrome/browser/ash/net/network_portal_detector_impl.h
@@ -229,8 +229,7 @@ content::NotificationRegistrar registrar_; - base::ScopedObservation<chromeos::NetworkStateHandler, - NetworkStateHandlerObserver> + base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver> network_state_handler_observer_{this}; // Test time ticks used by unit tests.
diff --git a/chrome/browser/ash/net/rollback_network_config/rollback_network_config.cc b/chrome/browser/ash/net/rollback_network_config/rollback_network_config.cc index d972807..bc589d0 100644 --- a/chrome/browser/ash/net/rollback_network_config/rollback_network_config.cc +++ b/chrome/browser/ash/net/rollback_network_config/rollback_network_config.cc
@@ -349,17 +349,16 @@ RollbackNetworkConfig::Importer::Importer() { DeviceSettingsService::Get()->AddObserver(this); - chromeos::NetworkHandler::Get() - ->managed_network_configuration_handler() - ->AddObserver(this); + NetworkHandler::Get()->managed_network_configuration_handler()->AddObserver( + this); } RollbackNetworkConfig::Importer::~Importer() { if (DeviceSettingsService::Get()) { DeviceSettingsService::Get()->RemoveObserver(this); } - if (chromeos::NetworkHandler::Get()) { - chromeos::NetworkHandler::Get() + if (NetworkHandler::Get()) { + NetworkHandler::Get() ->managed_network_configuration_handler() ->RemoveObserver(this); }
diff --git a/chrome/browser/ash/net/rollback_network_config/rollback_network_config_unittest.cc b/chrome/browser/ash/net/rollback_network_config/rollback_network_config_unittest.cc index 64229d73b..e3448f1 100644 --- a/chrome/browser/ash/net/rollback_network_config/rollback_network_config_unittest.cc +++ b/chrome/browser/ash/net/rollback_network_config/rollback_network_config_unittest.cc
@@ -162,21 +162,20 @@ FAIL(); } -chromeos::NetworkStateHandler* network_state_handler() { - return chromeos::NetworkHandler::Get()->network_state_handler(); +NetworkStateHandler* network_state_handler() { + return NetworkHandler::Get()->network_state_handler(); } ash::ManagedNetworkConfigurationHandler* managed_network_configuration_handler() { - return chromeos::NetworkHandler::Get() - ->managed_network_configuration_handler(); + return NetworkHandler::Get()->managed_network_configuration_handler(); } ShillServiceClient* shill_service_client() { return ShillServiceClient::Get(); } -const ash::NetworkState* GetNetworkState(const std::string& guid) { +const NetworkState* GetNetworkState(const std::string& guid) { return network_state_handler()->GetNetworkStateFromGuid(guid); }
diff --git a/chrome/browser/ash/net/secure_dns_manager.cc b/chrome/browser/ash/net/secure_dns_manager.cc index 0eb0424..9da2b27 100644 --- a/chrome/browser/ash/net/secure_dns_manager.cc +++ b/chrome/browser/ash/net/secure_dns_manager.cc
@@ -94,9 +94,8 @@ registrar_.prefs()->GetString(prefs::kDnsOverHttpsMode), registrar_.prefs()->GetString(prefs::kDnsOverHttpsTemplates)); - chromeos::NetworkHandler::Get() - ->network_configuration_handler() - ->SetManagerProperty(shill::kDNSProxyDOHProvidersProperty, doh_providers); + NetworkHandler::Get()->network_configuration_handler()->SetManagerProperty( + shill::kDNSProxyDOHProvidersProperty, doh_providers); } } // namespace ash
diff --git a/chrome/browser/ash/net/system_proxy_manager.h b/chrome/browser/ash/net/system_proxy_manager.h index 797a0f9..d34618a 100644 --- a/chrome/browser/ash/net/system_proxy_manager.h +++ b/chrome/browser/ash/net/system_proxy_manager.h
@@ -277,8 +277,7 @@ std::unique_ptr<PrefChangeRegistrar> local_state_pref_change_registrar_; std::unique_ptr<PrefChangeRegistrar> profile_pref_change_registrar_; - base::ScopedObservation<chromeos::NetworkStateHandler, - NetworkStateHandlerObserver> + base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver> network_state_handler_observer_{this}; base::RepeatingClosure send_auth_details_closure_for_test_;
diff --git a/chrome/browser/ash/network_change_manager_client.h b/chrome/browser/ash/network_change_manager_client.h index 2cadcf3..5730bf0 100644 --- a/chrome/browser/ash/network_change_manager_client.h +++ b/chrome/browser/ash/network_change_manager_client.h
@@ -114,8 +114,7 @@ // Service path for the current default network. std::string service_path_; - base::ScopedObservation<chromeos::NetworkStateHandler, - NetworkStateHandlerObserver> + base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver> network_state_handler_observer_{this}; net::NetworkChangeNotifierPosix* network_change_notifier_;
diff --git a/chrome/browser/ash/note_taking_helper_unittest.cc b/chrome/browser/ash/note_taking_helper_unittest.cc index faa98536..ffcfad0 100644 --- a/chrome/browser/ash/note_taking_helper_unittest.cc +++ b/chrome/browser/ash/note_taking_helper_unittest.cc
@@ -27,6 +27,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/values.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" @@ -37,6 +38,7 @@ #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/test_extension_system.h" +#include "chrome/browser/media/router/media_router_feature.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_list/arc/arc_app_test.h" @@ -173,6 +175,9 @@ void SetUp() override { SessionManagerClient::InitializeFakeInMemory(); FakeSessionManagerClient::Get()->set_arc_available(true); + // `media_router::kMediaRouter` is disabled because it has unmet + // dependencies and is unrelated to this unit test. + feature_list_.InitAndDisableFeature(media_router::kMediaRouter); BrowserWithTestWindowTest::SetUp(); InitExtensionService(profile()); @@ -486,6 +491,7 @@ ArcAppTest arc_test_; std::unique_ptr<arc::FakeIntentHelperHost> intent_helper_host_; + base::test::ScopedFeatureList feature_list_; }; TEST_F(NoteTakingHelperTest, PaletteNotEnabled) {
diff --git a/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc b/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc index 0d66e62..707cf01 100644 --- a/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc +++ b/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc
@@ -251,9 +251,8 @@ device_network_configuration_updater_ = DeviceNetworkConfigurationUpdaterAsh::CreateForDevicePolicy( GetPolicyService(), - chromeos::NetworkHandler::Get() - ->managed_network_configuration_handler(), - chromeos::NetworkHandler::Get()->network_device_handler(), + ash::NetworkHandler::Get()->managed_network_configuration_handler(), + ash::NetworkHandler::Get()->network_device_handler(), ash::CrosSettings::Get(), DeviceNetworkConfigurationUpdaterAsh::DeviceAssetIDFetcher()); // NetworkCertLoader may be not initialized in tests. @@ -279,7 +278,7 @@ device_dock_mac_address_source_handler_ = std::make_unique<DeviceDockMacAddressHandler>( ash::CrosSettings::Get(), - chromeos::NetworkHandler::Get()->network_device_handler()); + ash::NetworkHandler::Get()->network_device_handler()); device_wifi_allowed_handler_ = std::make_unique<DeviceWiFiAllowedHandler>(ash::CrosSettings::Get()); @@ -291,7 +290,7 @@ device_scheduled_update_checker_ = std::make_unique<DeviceScheduledUpdateChecker>( ash::CrosSettings::Get(), - chromeos::NetworkHandler::Get()->network_state_handler(), + ash::NetworkHandler::Get()->network_state_handler(), std::make_unique<ScheduledTaskExecutorImpl>( update_checker_internal::kUpdateCheckTimerTag));
diff --git a/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.cc b/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.cc index 817ba005..900c67e 100644 --- a/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.cc +++ b/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.cc
@@ -39,12 +39,12 @@ : DeviceNamePolicyHandlerImpl( cros_settings, chromeos::system::StatisticsProvider::GetInstance(), - chromeos::NetworkHandler::Get()->network_state_handler()) {} + ash::NetworkHandler::Get()->network_state_handler()) {} DeviceNamePolicyHandlerImpl::DeviceNamePolicyHandlerImpl( ash::CrosSettings* cros_settings, chromeos::system::StatisticsProvider* statistics_provider, - chromeos::NetworkStateHandler* handler) + ash::NetworkStateHandler* handler) : cros_settings_(cros_settings), statistics_provider_(statistics_provider), handler_(handler), @@ -61,7 +61,7 @@ weak_factory_.GetWeakPtr())); network_state_handler_observer_.Observe( - chromeos::NetworkHandler::Get()->network_state_handler()); + ash::NetworkHandler::Get()->network_state_handler()); // Fire it once so we're sure we get an invocation on startup. OnDeviceHostnamePropertyChanged();
diff --git a/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.h b/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.h index a8e1e418..0d93b20 100644 --- a/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.h +++ b/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.h
@@ -45,7 +45,7 @@ DeviceNamePolicyHandlerImpl( ash::CrosSettings* cros_settings, chromeos::system::StatisticsProvider* statistics_provider, - chromeos::NetworkStateHandler* handler); + ash::NetworkStateHandler* handler); // NetworkStateHandlerObserver overrides void DefaultNetworkChanged(const ash::NetworkState* network) override; @@ -71,8 +71,8 @@ ash::CrosSettings* cros_settings_; chromeos::system::StatisticsProvider* statistics_provider_; - chromeos::NetworkStateHandler* handler_; - base::ScopedObservation<chromeos::NetworkStateHandler, + ash::NetworkStateHandler* handler_; + base::ScopedObservation<ash::NetworkStateHandler, ash::NetworkStateHandlerObserver> network_state_handler_observer_{this};
diff --git a/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl_unittest.cc b/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl_unittest.cc index 61428de..46d36fb 100644 --- a/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl_unittest.cc +++ b/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl_unittest.cc
@@ -99,7 +99,7 @@ handler_ = base::WrapUnique(new DeviceNamePolicyHandlerImpl( ash::CrosSettings::Get(), &fake_statistics_provider_, - chromeos::NetworkHandler::Get()->network_state_handler())); + ash::NetworkHandler::Get()->network_state_handler())); handler_->AddObserver(&fake_observer_); base::RunLoop().RunUntilIdle(); }
diff --git a/chrome/browser/ash/policy/handlers/device_wifi_allowed_handler.cc b/chrome/browser/ash/policy/handlers/device_wifi_allowed_handler.cc index 0faf3e21..4f04745 100644 --- a/chrome/browser/ash/policy/handlers/device_wifi_allowed_handler.cc +++ b/chrome/browser/ash/policy/handlers/device_wifi_allowed_handler.cc
@@ -40,11 +40,11 @@ bool wifi_allowed = true; cros_settings_->GetBoolean(ash::kDeviceWiFiAllowed, &wifi_allowed); if (!wifi_allowed) { - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->prohibited_technologies_handler() ->AddGloballyProhibitedTechnology(shill::kTypeWifi); } else { - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->prohibited_technologies_handler() ->RemoveGloballyProhibitedTechnology(shill::kTypeWifi); }
diff --git a/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc b/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc index e818e61f..4d8f7aa 100644 --- a/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc +++ b/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc
@@ -51,8 +51,8 @@ } MinimumVersionPolicyHandler::NetworkStatus GetCurrentNetworkStatus() { - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler* network_state_handler = + ash::NetworkHandler::Get()->network_state_handler(); const ash::NetworkState* current_network = network_state_handler->DefaultNetwork(); if (!current_network || !current_network->IsConnectedState()) @@ -514,8 +514,8 @@ std::move(close_callback)); if (!eol_reached_) { - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler* network_state_handler = + ash::NetworkHandler::Get()->network_state_handler(); if (!network_state_handler->HasObserver(this)) network_state_handler_observer_.Observe(network_state_handler); }
diff --git a/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h b/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h index 37208285..1bc420e 100644 --- a/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h +++ b/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h
@@ -313,7 +313,7 @@ // current network and time to reach the deadline. std::unique_ptr<ash::UpdateRequiredNotification> notification_handler_; - base::ScopedObservation<chromeos::NetworkStateHandler, + base::ScopedObservation<ash::NetworkStateHandler, ash::NetworkStateHandlerObserver> network_state_handler_observer_{this};
diff --git a/chrome/browser/ash/policy/handlers/system_proxy_handler_unittest.cc b/chrome/browser/ash/policy/handlers/system_proxy_handler_unittest.cc index 686fcda..1296713 100644 --- a/chrome/browser/ash/policy/handlers/system_proxy_handler_unittest.cc +++ b/chrome/browser/ash/policy/handlers/system_proxy_handler_unittest.cc
@@ -62,8 +62,8 @@ system_proxy_handler_->SetSystemProxyManagerForTesting( system_proxy_manager_.get()); - chromeos::NetworkHandler::Get()->InitializePrefServices( - profile_->GetPrefs(), local_state_.Get()); + ash::NetworkHandler::Get()->InitializePrefServices(profile_->GetPrefs(), + local_state_.Get()); } void TearDown() override {
diff --git a/chrome/browser/ash/policy/networking/euicc_status_uploader.cc b/chrome/browser/ash/policy/networking/euicc_status_uploader.cc index 754f81c..0592968 100644 --- a/chrome/browser/ash/policy/networking/euicc_status_uploader.cc +++ b/chrome/browser/ash/policy/networking/euicc_status_uploader.cc
@@ -84,7 +84,7 @@ local_state_(local_state), is_device_managed_callback_(std::move(is_device_active_callback)), retry_entry_(&kBackOffPolicy) { - if (!chromeos::NetworkHandler::IsInitialized()) { + if (!ash::NetworkHandler::IsInitialized()) { LOG(WARNING) << "NetworkHandler is not initialized."; return; } @@ -93,7 +93,7 @@ hermes_euicc_observation_.Observe(ash::HermesEuiccClient::Get()); cloud_policy_client_observation_.Observe(client_); - auto* network_handler = chromeos::NetworkHandler::Get(); + auto* network_handler = ash::NetworkHandler::Get(); network_handler->managed_cellular_pref_handler()->AddObserver(this); managed_network_configuration_handler_ = network_handler->managed_network_configuration_handler(); @@ -101,10 +101,9 @@ } EuiccStatusUploader::~EuiccStatusUploader() { - if (chromeos::NetworkHandler::IsInitialized()) - chromeos::NetworkHandler::Get() - ->managed_cellular_pref_handler() - ->RemoveObserver(this); + if (ash::NetworkHandler::IsInitialized()) + ash::NetworkHandler::Get()->managed_cellular_pref_handler()->RemoveObserver( + this); OnManagedNetworkConfigurationHandlerShuttingDown(); } @@ -191,7 +190,7 @@ base::Value esim_profiles(base::Value::Type::LIST); - for (const auto& esim_profile : chromeos::NetworkHandler::Get() + for (const auto& esim_profile : ash::NetworkHandler::Get() ->cellular_esim_profile_handler() ->GetESimProfiles()) { // Do not report non-provisioned cellular networks. @@ -199,7 +198,7 @@ continue; const std::string* smdp_address = - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->managed_cellular_pref_handler() ->GetSmdpAddressFromIccid(esim_profile.iccid()); // Report only managed profiles with a SMDP address.
diff --git a/chrome/browser/ash/policy/networking/euicc_status_uploader_unittest.cc b/chrome/browser/ash/policy/networking/euicc_status_uploader_unittest.cc index 569b26b..e1d1057 100644 --- a/chrome/browser/ash/policy/networking/euicc_status_uploader_unittest.cc +++ b/chrome/browser/ash/policy/networking/euicc_status_uploader_unittest.cc
@@ -224,7 +224,7 @@ kAddProfileWithService); if (test_profile.managed) { - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->managed_cellular_pref_handler() ->AddIccidSmdpPair(test_profile.iccid, test_profile.smdp_address); } @@ -472,14 +472,14 @@ // NetworkHandler::Shutdown() has already been called before // EuiccStatusUploader is deleted - chromeos::NetworkHandler::Shutdown(); + ash::NetworkHandler::Shutdown(); // No requests made as NetworkHandler is not available. UpdateUploader(status_uploader.get()); EXPECT_EQ(GetRequestCount(), 2); // Need to reinitialize before exiting test. - chromeos::NetworkHandler::Initialize(); + ash::NetworkHandler::Initialize(); } } // namespace policy
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_reset_euicc_job.cc b/chrome/browser/ash/policy/remote_commands/device_command_reset_euicc_job.cc index 2a7565b74..fcd6854 100644 --- a/chrome/browser/ash/policy/remote_commands/device_command_reset_euicc_job.cc +++ b/chrome/browser/ash/policy/remote_commands/device_command_reset_euicc_job.cc
@@ -77,7 +77,7 @@ SYSLOG(INFO) << "Executing EUICC reset memory remote command"; ash::CellularESimUninstallHandler* uninstall_handler = - chromeos::NetworkHandler::Get()->cellular_esim_uninstall_handler(); + ash::NetworkHandler::Get()->cellular_esim_uninstall_handler(); uninstall_handler->ResetEuiccMemory( *euicc_path, base::BindOnce(
diff --git a/chrome/browser/ash/policy/reporting/install_event_log_collector_base.cc b/chrome/browser/ash/policy/reporting/install_event_log_collector_base.cc index 7606870..1a1a364 100644 --- a/chrome/browser/ash/policy/reporting/install_event_log_collector_base.cc +++ b/chrome/browser/ash/policy/reporting/install_event_log_collector_base.cc
@@ -30,12 +30,10 @@ } bool InstallEventLogCollectorBase::GetOnlineState() { - chromeos::NetworkStateHandler::NetworkStateList network_state_list; - chromeos::NetworkHandler::Get() - ->network_state_handler() - ->GetNetworkListByType( - ash::NetworkTypePattern::Default(), true /* configured_only */, - false /* visible_only */, 0 /* limit */, &network_state_list); + ash::NetworkStateHandler::NetworkStateList network_state_list; + ash::NetworkHandler::Get()->network_state_handler()->GetNetworkListByType( + ash::NetworkTypePattern::Default(), true /* configured_only */, + false /* visible_only */, 0 /* limit */, &network_state_list); for (const ash::NetworkState* network_state : network_state_list) { if (network_state->connection_state() == shill::kStateOnline) {
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.cc b/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.cc index 5f8246c..6ba3d7b 100644 --- a/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.cc +++ b/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.cc
@@ -46,7 +46,7 @@ // so it's safe to use "this" with any callbacks. DeviceScheduledUpdateChecker::DeviceScheduledUpdateChecker( ash::CrosSettings* cros_settings, - chromeos::NetworkStateHandler* network_state_handler, + ash::NetworkStateHandler* network_state_handler, std::unique_ptr<ScheduledTaskExecutor> update_check_executor) : cros_settings_(cros_settings), cros_settings_subscription_(cros_settings_->AddSettingsObserver(
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.h b/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.h index 32a1963..56feb96 100644 --- a/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.h +++ b/chrome/browser/ash/policy/scheduled_task_handler/device_scheduled_update_checker.h
@@ -29,7 +29,7 @@ public: DeviceScheduledUpdateChecker( ash::CrosSettings* cros_settings, - chromeos::NetworkStateHandler* network_state_handler, + ash::NetworkStateHandler* network_state_handler, std::unique_ptr<ScheduledTaskExecutor> update_check_executor); DeviceScheduledUpdateChecker(const DeviceScheduledUpdateChecker&) = delete;
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc index d53e6f0..601cfec 100644 --- a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc +++ b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc
@@ -15,7 +15,7 @@ namespace policy { OsAndPoliciesUpdateChecker::OsAndPoliciesUpdateChecker( - chromeos::NetworkStateHandler* network_state_handler) + ash::NetworkStateHandler* network_state_handler) : network_state_handler_(network_state_handler), update_check_task_executor_( update_checker_internal::
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.h b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.h index f86fcd6..a2e0ce9 100644 --- a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.h +++ b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.h
@@ -41,7 +41,7 @@ public ash::NetworkStateHandlerObserver { public: explicit OsAndPoliciesUpdateChecker( - chromeos::NetworkStateHandler* network_state_handler); + ash::NetworkStateHandler* network_state_handler); OsAndPoliciesUpdateChecker(const OsAndPoliciesUpdateChecker&) = delete; OsAndPoliciesUpdateChecker& operator=(const OsAndPoliciesUpdateChecker&) = @@ -116,8 +116,8 @@ UpdateCheckCompletionCallback update_check_completion_cb_; // Not owned. - chromeos::NetworkStateHandler* const network_state_handler_; - base::ScopedObservation<chromeos::NetworkStateHandler, + ash::NetworkStateHandler* const network_state_handler_; + base::ScopedObservation<ash::NetworkStateHandler, ash::NetworkStateHandlerObserver> network_state_handler_observer_{this};
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_update_checker_unittest.cc b/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_update_checker_unittest.cc index 06ab501..771cbd2 100644 --- a/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_update_checker_unittest.cc +++ b/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_update_checker_unittest.cc
@@ -73,7 +73,7 @@ public: DeviceScheduledUpdateCheckerForTest( ash::CrosSettings* cros_settings, - chromeos::NetworkStateHandler* network_state_handler, + ash::NetworkStateHandler* network_state_handler, std::unique_ptr<ScheduledTaskExecutor> task_executor) : DeviceScheduledUpdateChecker(cros_settings, network_state_handler,
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector.cc b/chrome/browser/ash/policy/status_collector/device_status_collector.cc index 26094b7..4039276 100644 --- a/chrome/browser/ash/policy/status_collector/device_status_collector.cc +++ b/chrome/browser/ash/policy/status_collector/device_status_collector.cc
@@ -2316,13 +2316,13 @@ }, }; - chromeos::NetworkStateHandler::DeviceStateList device_list; - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler::DeviceStateList device_list; + ash::NetworkStateHandler* network_state_handler = + ash::NetworkHandler::Get()->network_state_handler(); network_state_handler->GetDeviceList(&device_list); bool anything_reported = false; - chromeos::NetworkStateHandler::DeviceStateList::const_iterator device; + ash::NetworkStateHandler::DeviceStateList::const_iterator device; for (device = device_list.begin(); device != device_list.end(); ++device) { // Determine the type enum constant for |device|. size_t type_idx = 0; @@ -2391,8 +2391,8 @@ }; bool anything_reported = false; - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler* network_state_handler = + ash::NetworkHandler::Get()->network_state_handler(); user_manager::UserManager* user_manager = user_manager::UserManager::Get(); const user_manager::User* const primary_user = user_manager->GetPrimaryUser(); @@ -2403,7 +2403,7 @@ } // Walk the various networks and store their state in the status report. - chromeos::NetworkStateHandler::NetworkStateList state_list; + ash::NetworkStateHandler::NetworkStateList state_list; network_state_handler->GetNetworkListByType( ash::NetworkTypePattern::Default(), true, // configured_only
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc index b2a0842..7395127 100644 --- a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc +++ b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
@@ -3954,9 +3954,9 @@ // Flush out pending state updates. base::RunLoop().RunUntilIdle(); - chromeos::NetworkStateHandler::NetworkStateList state_list; - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler::NetworkStateList state_list; + ash::NetworkStateHandler* network_state_handler = + ash::NetworkHandler::Get()->network_state_handler(); network_state_handler->GetNetworkListByType( ash::NetworkTypePattern::Default(), true, // configured_only
diff --git a/chrome/browser/ash/tether/fake_tether_service.cc b/chrome/browser/ash/tether/fake_tether_service.cc index b441f3dc9..3cbcbfa 100644 --- a/chrome/browser/ash/tether/fake_tether_service.cc +++ b/chrome/browser/ash/tether/fake_tether_service.cc
@@ -21,7 +21,7 @@ device_sync::DeviceSyncClient* device_sync_client, secure_channel::SecureChannelClient* secure_channel_client, multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client, - chromeos::NetworkStateHandler* network_state_handler, + NetworkStateHandler* network_state_handler, session_manager::SessionManager* session_manager) : TetherService(profile, power_manager_client, @@ -33,7 +33,7 @@ void FakeTetherService::StartTetherIfPossible() { if (GetTetherTechnologyState() != - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED) { + NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED) { return; }
diff --git a/chrome/browser/ash/tether/fake_tether_service.h b/chrome/browser/ash/tether/fake_tether_service.h index 8abd186..c04b1d0 100644 --- a/chrome/browser/ash/tether/fake_tether_service.h +++ b/chrome/browser/ash/tether/fake_tether_service.h
@@ -21,7 +21,7 @@ device_sync::DeviceSyncClient* device_sync_client, secure_channel::SecureChannelClient* secure_channel_client, multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client, - chromeos::NetworkStateHandler* network_state_handler, + NetworkStateHandler* network_state_handler, session_manager::SessionManager* session_manager); FakeTetherService(const FakeTetherService&) = delete; FakeTetherService& operator=(const FakeTetherService&) = delete;
diff --git a/chrome/browser/ash/tether/tether_service.cc b/chrome/browser/ash/tether/tether_service.cc index b6ff1b2e..11521e7 100644 --- a/chrome/browser/ash/tether/tether_service.cc +++ b/chrome/browser/ash/tether/tether_service.cc
@@ -96,7 +96,7 @@ device_sync::DeviceSyncClient* device_sync_client, secure_channel::SecureChannelClient* secure_channel_client, multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client, - chromeos::NetworkStateHandler* network_state_handler, + NetworkStateHandler* network_state_handler, session_manager::SessionManager* session_manager) : profile_(profile), power_manager_client_(power_manager_client), @@ -141,7 +141,7 @@ void TetherService::StartTetherIfPossible() { if (GetTetherTechnologyState() != - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED) { + NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED) { return; } @@ -155,9 +155,9 @@ notification_presenter_.get(), gms_core_notifications_state_tracker_.get(), profile_->GetPrefs(), network_state_handler_, - chromeos::NetworkHandler::Get()->managed_network_configuration_handler(), + NetworkHandler::Get()->managed_network_configuration_handler(), NetworkConnect::Get(), - chromeos::NetworkHandler::Get()->network_connection_handler(), adapter_, + NetworkHandler::Get()->network_connection_handler(), adapter_, session_manager_); } @@ -286,20 +286,20 @@ void TetherService::UpdateEnabledState() { bool was_pref_enabled = IsEnabledByPreference(); - chromeos::NetworkStateHandler::TechnologyState tether_technology_state = + NetworkStateHandler::TechnologyState tether_technology_state = network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether()); // If |was_pref_enabled| differs from the new Tether TechnologyState, the // settings toggle has been changed. Update the kInstantTetheringEnabled user // pref accordingly. bool is_enabled; - if (was_pref_enabled && tether_technology_state == - chromeos::NetworkStateHandler::TechnologyState:: - TECHNOLOGY_AVAILABLE) { + if (was_pref_enabled && + tether_technology_state == + NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE) { is_enabled = false; - } else if (!was_pref_enabled && tether_technology_state == - chromeos::NetworkStateHandler:: - TechnologyState::TECHNOLOGY_ENABLED) { + } else if (!was_pref_enabled && + tether_technology_state == + NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED) { is_enabled = true; } else { is_enabled = was_pref_enabled; @@ -367,11 +367,11 @@ if (!adapter_) return; - chromeos::NetworkStateHandler::TechnologyState new_tether_technology_state = + NetworkStateHandler::TechnologyState new_tether_technology_state = GetTetherTechnologyState(); if (new_tether_technology_state == - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED) { + NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED) { // If Tether should be enabled, notify NetworkStateHandler before starting // up the component. This ensures that it is not possible to add Tether // networks before the network stack is ready for them. @@ -389,8 +389,7 @@ } } -chromeos::NetworkStateHandler::TechnologyState -TetherService::GetTetherTechnologyState() { +NetworkStateHandler::TechnologyState TetherService::GetTetherTechnologyState() { TetherFeatureState new_feature_state = GetTetherFeatureState(); if (new_feature_state != previous_feature_state_) { PA_LOG(INFO) << "Tether state has changed. New state: " @@ -410,27 +409,22 @@ case NO_AVAILABLE_HOSTS: case CELLULAR_DISABLED: case BETTER_TOGETHER_SUITE_DISABLED: - return chromeos::NetworkStateHandler::TechnologyState:: - TECHNOLOGY_UNAVAILABLE; + return NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE; case PROHIBITED: - return chromeos::NetworkStateHandler::TechnologyState:: - TECHNOLOGY_PROHIBITED; + return NetworkStateHandler::TechnologyState::TECHNOLOGY_PROHIBITED; case BLUETOOTH_DISABLED: - return chromeos::NetworkStateHandler::TechnologyState:: - TECHNOLOGY_UNINITIALIZED; + return NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED; case USER_PREFERENCE_DISABLED: - return chromeos::NetworkStateHandler::TechnologyState:: - TECHNOLOGY_AVAILABLE; + return NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE; case ENABLED: - return chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED; + return NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED; default: - return chromeos::NetworkStateHandler::TechnologyState:: - TECHNOLOGY_UNAVAILABLE; + return NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE; } }
diff --git a/chrome/browser/ash/tether/tether_service.h b/chrome/browser/ash/tether/tether_service.h index 1d00d83..20a6011 100644 --- a/chrome/browser/ash/tether/tether_service.h +++ b/chrome/browser/ash/tether/tether_service.h
@@ -79,7 +79,7 @@ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); // Attempt to start the Tether module. Only succeeds if all conditions to - // reach chromeos::NetworkStateHandler::TechnologyState::ENABLED are reached. + // reach NetworkStateHandler::TechnologyState::ENABLED are reached. // Should only be called once a user is logged in. virtual void StartTetherIfPossible();
diff --git a/chrome/browser/ash/tether/tether_service_factory.cc b/chrome/browser/ash/tether/tether_service_factory.cc index 1178fdec..b2f37d3 100644 --- a/chrome/browser/ash/tether/tether_service_factory.cc +++ b/chrome/browser/ash/tether/tether_service_factory.cc
@@ -58,7 +58,7 @@ KeyedService* TetherServiceFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - DCHECK(chromeos::NetworkHandler::IsInitialized()); + DCHECK(NetworkHandler::IsInitialized()); if (!IsFeatureAllowed(context)) return nullptr; @@ -73,7 +73,7 @@ secure_channel::SecureChannelClientProvider::GetInstance()->GetClient(), multidevice_setup::MultiDeviceSetupClientFactory::GetForProfile( Profile::FromBrowserContext(context)), - chromeos::NetworkHandler::Get()->network_state_handler(), + NetworkHandler::Get()->network_state_handler(), session_manager::SessionManager::Get()); int num_tether_networks = 0; @@ -91,7 +91,7 @@ secure_channel::SecureChannelClientProvider::GetInstance()->GetClient(), multidevice_setup::MultiDeviceSetupClientFactory::GetForProfile( Profile::FromBrowserContext(context)), - chromeos::NetworkHandler::Get()->network_state_handler(), + NetworkHandler::Get()->network_state_handler(), session_manager::SessionManager::Get()); }
diff --git a/chrome/browser/ash/tether/tether_service_unittest.cc b/chrome/browser/ash/tether/tether_service_unittest.cc index 11a9101..a8776ce 100644 --- a/chrome/browser/ash/tether/tether_service_unittest.cc +++ b/chrome/browser/ash/tether/tether_service_unittest.cc
@@ -94,7 +94,7 @@ device_sync::DeviceSyncClient* device_sync_client, secure_channel::SecureChannelClient* secure_channel_client, multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client, - chromeos::NetworkStateHandler* network_state_handler, + NetworkStateHandler* network_state_handler, session_manager::SessionManager* session_manager) : TetherService(profile, power_manager_client, @@ -153,7 +153,7 @@ GmsCoreNotificationsStateTrackerImpl* gms_core_notifications_state_tracker, PrefService* pref_service, - chromeos::NetworkStateHandler* network_state_handler, + NetworkStateHandler* network_state_handler, ManagedNetworkConfigurationHandler* managed_network_configuration_handler, NetworkConnect* network_connect, NetworkConnectionHandler* network_connection_handler, @@ -425,10 +425,9 @@ // Ensure that TetherService does not prematurely update its // TechnologyState before it fetches the BluetoothAdapter. - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); if (!fake_device_sync_client_->is_ready()) { @@ -446,10 +445,8 @@ void SetTetherTechnologyStateEnabled(bool enabled) { network_state_handler()->SetTetherTechnologyState( - enabled - ? chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED - : chromeos::NetworkStateHandler::TechnologyState:: - TECHNOLOGY_AVAILABLE); + enabled ? NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED + : NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE); } void SetCellularTechnologyStateEnabled(bool enabled) { @@ -510,8 +507,8 @@ return network_handler_test_helper_.manager_test(); } - chromeos::NetworkStateHandler* network_state_handler() { - return chromeos::NetworkHandler::Get()->network_state_handler(); + NetworkStateHandler* network_state_handler() { + return NetworkHandler::Get()->network_state_handler(); } const multidevice::RemoteDeviceRefList test_devices_; @@ -568,7 +565,7 @@ // The TechnologyState should not have changed due to Shutdown() being called. // If it had changed, any settings UI that was previously open would have // shown visual jank. - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); @@ -580,7 +577,7 @@ CreateTetherService(); // Tether should be ENABLED, and there should be no AsyncShutdownTask. - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -600,10 +597,9 @@ test_tether_component_factory_->active_tether_component()->status()); // Tether should be AVAILABLE. - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); // Complete the shutdown process; TetherService should delete its // TetherComponent instance. @@ -620,15 +616,14 @@ chromeos::FakePowerManagerClient::Get()->SendSuspendImminent( power_manager::SuspendImminent_Reason_OTHER); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); chromeos::FakePowerManagerClient::Get()->SendSuspendDone(); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -650,7 +645,7 @@ fake_device_sync_client_->NotifyReady(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -667,10 +662,9 @@ CreateTetherService(); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); fake_tether_host_fetcher_factory_->last_created()->set_tether_hosts( @@ -679,7 +673,7 @@ multidevice_setup::mojom::Feature::kInstantTethering, multidevice_setup::mojom::FeatureState::kEnabledByUser); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -691,7 +685,7 @@ TEST_F(TetherServiceTest, TestMultiDeviceSetupClientLosesVerifiedHost) { CreateTetherService(); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -702,10 +696,9 @@ multidevice_setup::mojom::FeatureState:: kUnavailableNoVerifiedHost_HostExistsButNotSetAndVerified); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); mock_timer_->Fire(); @@ -723,17 +716,16 @@ CreateTetherService(); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); fake_multidevice_setup_client_->SetFeatureState( multidevice_setup::mojom::Feature::kInstantTethering, multidevice_setup::mojom::FeatureState::kEnabledByUser); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -745,7 +737,7 @@ TEST_F(TetherServiceTest, TestBetterTogetherSuiteBecomesDisabled) { CreateTetherService(); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -754,10 +746,9 @@ multidevice_setup::mojom::Feature::kInstantTethering, multidevice_setup::mojom::FeatureState::kUnavailableSuiteDisabled); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); ShutdownTetherService(); @@ -850,10 +841,9 @@ fake_tether_host_fetcher_factory_->SetNoInitialDevices(); CreateTetherService(); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); // Simulate this being the final state of Tether by passing time. @@ -871,10 +861,9 @@ CreateTetherService(); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_PROHIBITED, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_PROHIBITED, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); VerifyTetherFeatureStateRecorded( @@ -886,10 +875,9 @@ CreateTetherService(); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); // Simulate this being the final state of Tether by passing time. @@ -908,17 +896,16 @@ set_is_adapter_present(true); SetIsBluetoothPowered(true); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); fake_tether_host_fetcher_factory_->last_created()->set_tether_hosts( test_devices_); fake_tether_host_fetcher_factory_->last_created()->NotifyTetherHostsUpdated(); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -946,10 +933,9 @@ CreateTetherService(); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherFeatureStateRecorded( TetherService::TetherFeatureState::WIFI_NOT_PRESENT, @@ -961,25 +947,23 @@ CreateTetherService(); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); SetIsBluetoothPowered(true); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); SetIsBluetoothPowered(false); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); VerifyTetherFeatureStateRecorded( @@ -991,23 +975,21 @@ // TODO(https://crbug.com/893878): Fix disabled test. TEST_F(TetherServiceTest, DISABLED_TestCellularIsUnavailable) { manager_test()->RemoveTechnology(shill::kTypeCellular); - ASSERT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Cellular())); + ASSERT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Cellular())); CreateTetherService(); SetTetherTechnologyStateEnabled(false); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); VerifyLastShutdownReason(TetherComponent::ShutdownReason::PREF_DISABLED); SetTetherTechnologyStateEnabled(true); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -1027,42 +1009,38 @@ // Cellular disabled SetCellularTechnologyStateEnabled(false); - ASSERT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Cellular())); + ASSERT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Cellular())); VerifyTetherActiveStatus(false /* expected_active */); SetTetherTechnologyStateEnabled(false); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); SetTetherTechnologyStateEnabled(true); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); // Cellular enabled SetCellularTechnologyStateEnabled(true); - ASSERT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + ASSERT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Cellular())); VerifyTetherActiveStatus(true /* expected_active */); SetTetherTechnologyStateEnabled(false); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); SetTetherTechnologyStateEnabled(true); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -1082,10 +1060,9 @@ CreateTetherService(); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); EXPECT_FALSE(profile_->GetPrefs()->GetBoolean( multidevice_setup::kInstantTetheringEnabledPrefName)); VerifyTetherActiveStatus(false /* expected_active */); @@ -1099,16 +1076,15 @@ TEST_F(TetherServiceTest, DISABLED_TestEnabled) { CreateTetherService(); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); SetTetherTechnologyStateEnabled(false); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); EXPECT_FALSE(profile_->GetPrefs()->GetBoolean( multidevice_setup::kInstantTetheringEnabledPrefName)); VerifyTetherActiveStatus(false /* expected_active */); @@ -1117,7 +1093,7 @@ 1u /* expected_count */); SetTetherTechnologyStateEnabled(true); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); EXPECT_TRUE(profile_->GetPrefs()->GetBoolean( @@ -1146,7 +1122,7 @@ fake_multidevice_setup_client_->SetFeatureState( multidevice_setup::mojom::Feature::kInstantTethering, multidevice_setup::mojom::FeatureState::kEnabledByUser); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -1162,10 +1138,9 @@ fake_multidevice_setup_client_->SetFeatureState( multidevice_setup::mojom::Feature::kInstantTethering, multidevice_setup::mojom::FeatureState::kDisabledByUser); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); VerifyTetherFeatureStateRecorded( TetherService::TetherFeatureState::USER_PREFERENCE_DISABLED, @@ -1180,7 +1155,7 @@ fake_multidevice_setup_client_->SetFeatureState( multidevice_setup::mojom::Feature::kInstantTethering, multidevice_setup::mojom::FeatureState::kEnabledByUser); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -1196,7 +1171,7 @@ TEST_F(TetherServiceTest, TestUserPrefChangesViaTechnologyStateChange) { CreateTetherService(); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */); @@ -1211,10 +1186,9 @@ fake_multidevice_setup_client_->SetFeatureState( multidevice_setup::mojom::Feature::kInstantTethering, multidevice_setup::mojom::FeatureState::kDisabledByUser); - EXPECT_EQ( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, - network_state_handler()->GetTechnologyState( - NetworkTypePattern::Tether())); + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, + network_state_handler()->GetTechnologyState( + NetworkTypePattern::Tether())); VerifyTetherActiveStatus(false /* expected_active */); histogram_tester_.ExpectBucketCount( "InstantTethering.UserPreference.OnToggle", false, @@ -1230,7 +1204,7 @@ fake_multidevice_setup_client_->SetFeatureState( multidevice_setup::mojom::Feature::kInstantTethering, multidevice_setup::mojom::FeatureState::kEnabledByUser); - EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, + EXPECT_EQ(NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, network_state_handler()->GetTechnologyState( NetworkTypePattern::Tether())); VerifyTetherActiveStatus(true /* expected_active */);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 0136943..2bced6c 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -204,6 +204,7 @@ #include "components/live_caption/caption_util.h" #include "components/media_router/browser/presentation/presentation_service_delegate_impl.h" #include "components/media_router/browser/presentation/receiver_presentation_service_delegate_impl.h" +#include "components/media_router/browser/presentation/web_contents_presentation_manager.h" #include "components/metrics/client_info.h" #include "components/metrics_services_manager/metrics_services_manager.h" #include "components/net_log/chrome_net_log.h" @@ -4357,6 +4358,24 @@ return nullptr; } +void ChromeContentBrowserClient::AddPresentationObserver( + content::PresentationObserver* observer, + content::WebContents* web_contents) { + if (media_router::MediaRouterEnabled(web_contents->GetBrowserContext())) { + media_router::WebContentsPresentationManager::Get(web_contents) + ->AddObserver(observer); + } +} + +void ChromeContentBrowserClient::RemovePresentationObserver( + content::PresentationObserver* observer, + content::WebContents* web_contents) { + if (media_router::MediaRouterEnabled(web_contents->GetBrowserContext())) { + media_router::WebContentsPresentationManager::Get(web_contents) + ->RemoveObserver(observer); + } +} + std::vector<std::unique_ptr<content::NavigationThrottle>> ChromeContentBrowserClient::CreateThrottlesForNavigation( content::NavigationHandle* handle) {
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 489dc30..8ad42c8 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -484,6 +484,10 @@ content::ReceiverPresentationServiceDelegate* GetReceiverPresentationServiceDelegate( content::WebContents* web_contents) override; + void AddPresentationObserver(content::PresentationObserver* observer, + content::WebContents* web_contents) override; + void RemovePresentationObserver(content::PresentationObserver* observer, + content::WebContents* web_contents) override; std::vector<std::unique_ptr<content::NavigationThrottle>> CreateThrottlesForNavigation(content::NavigationHandle* handle) override; std::vector<std::unique_ptr<content::CommitDeferringCondition>>
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/BUILD.gn b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/BUILD.gn index 09f2cd2..8dbeabc 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/BUILD.gn +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/BUILD.gn
@@ -6,6 +6,7 @@ public = [ "secure_enclave_client.h", "secure_enclave_helper.h", + "secure_enclave_signing_key.h", ] sources = [ @@ -15,9 +16,14 @@ "secure_enclave_helper.cc", "secure_enclave_helper_impl.h", "secure_enclave_helper_impl.mm", + "secure_enclave_signing_key.cc", ] - public_deps = [ "//base" ] + public_deps = [ + "//base", + "//crypto", + "//third_party/abseil-cpp:absl", + ] deps = [ "//chrome/browser/enterprise/connectors/device_trust/key_management/core:constants", @@ -54,7 +60,10 @@ source_set("unit_tests") { testonly = true - sources = [ "secure_enclave_client_unittest.mm" ] + sources = [ + "secure_enclave_client_unittest.mm", + "secure_enclave_signing_key_unittest.mm", + ] deps = [ ":mac",
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/mock_secure_enclave_client.h b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/mock_secure_enclave_client.h index baa2de43e..cd77c6c 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/mock_secure_enclave_client.h +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/mock_secure_enclave_client.h
@@ -28,6 +28,10 @@ CreateTemporaryKey, (), (override)); + MOCK_METHOD(base::ScopedCFTypeRef<SecKeyRef>, + CopyStoredKey, + (KeyType), + (override)); MOCK_METHOD(bool, MoveTemporaryKeyToPermanent, (), (override)); MOCK_METHOD(bool, DeleteKey, (KeyType), (override)); MOCK_METHOD(bool,
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/mock_secure_enclave_helper.h b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/mock_secure_enclave_helper.h index 4d08c8a..f65586c3 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/mock_secure_enclave_helper.h +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/mock_secure_enclave_helper.h
@@ -25,9 +25,12 @@ CreateSecureKey, (CFDictionaryRef), (override)); + MOCK_METHOD(base::ScopedCFTypeRef<SecKeyRef>, + CopyKey, + (CFDictionaryRef), + (override)); MOCK_METHOD(bool, Update, (CFDictionaryRef, CFDictionaryRef), (override)); MOCK_METHOD(bool, Delete, (CFDictionaryRef), (override)); - MOCK_METHOD(bool, CheckExists, (CFDictionaryRef), (override)); MOCK_METHOD(bool, CheckKeychainUnlocked, (), (override)); MOCK_METHOD(bool, IsSecureEnclaveSupported, (), (override)); };
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client.h b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client.h index 46357c6..dbaa1f4 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client.h +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client.h
@@ -39,6 +39,10 @@ // Creates a new Secure Enclave private key with a temporary key label. virtual base::ScopedCFTypeRef<SecKeyRef> CreateTemporaryKey() = 0; + // Queries for the secure key using its label determined by the key `type`. + // Returns the secure key reference or a nullptr if no key was found. + virtual base::ScopedCFTypeRef<SecKeyRef> CopyStoredKey(KeyType type) = 0; + // Updates the private key label from the temporary key label to the // non-temporary label. virtual bool MoveTemporaryKeyToPermanent() = 0;
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.h b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.h index 1683bf6f..2f4e5e5 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.h +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.h
@@ -28,6 +28,7 @@ // SecureEnclaveClient: base::ScopedCFTypeRef<SecKeyRef> CreateTemporaryKey() override; + base::ScopedCFTypeRef<SecKeyRef> CopyStoredKey(KeyType type) override; bool MoveTemporaryKeyToPermanent() override; bool DeleteKey(KeyType type) override; bool GetStoredKeyLabel(KeyType type, std::vector<uint8_t>& output) override;
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.mm b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.mm index 58ba9cc..367af64 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.mm +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.mm
@@ -14,6 +14,7 @@ #include "base/containers/span.h" #include "base/mac/scoped_cftyperef.h" #include "base/numerics/safe_conversions.h" +#include "base/strings/string_piece.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper.h" @@ -28,12 +29,25 @@ namespace { +// Returns the key label based on the key `type` if the key type is not +// supported an empty string is returned. +base::StringPiece GetLabelFromKeyType(SecureEnclaveClient::KeyType type) { + if (type == SecureEnclaveClient::KeyType::kTemporary) + return constants::kTemporaryDeviceTrustSigningKeyLabel; + if (type == SecureEnclaveClient::KeyType::kPermanent) + return constants::kDeviceTrustSigningKeyLabel; + return base::StringPiece(); +} + // Much of the Keychain API was marked deprecated as of the macOS 13 SDK. // Removal of its use is tracked in https://crbug.com/1348251 but deprecation // warnings are disabled in the meanwhile. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +// TODO(http://b/241261382): Look for alternatives in ACL creation and validate +// the new key is stored in the data protection keychain. + // Issues the SecAccessCreate API to create the ACL for the secure key. // This ACL allows all Chrome applications access to modify this key // so all Chrome applications can perform the mac key rotation process. @@ -88,13 +102,14 @@ // Creates the query used for querying the keychain for the secure key // reference. base::ScopedCFTypeRef<CFMutableDictionaryRef> CreateQueryForKey( - const std::string& label) { + SecureEnclaveClient::KeyType type) { base::ScopedCFTypeRef<CFMutableDictionaryRef> query(CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); CFDictionarySetValue(query, kSecClass, kSecClassKey); CFDictionarySetValue(query, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom); - CFDictionarySetValue(query, kSecAttrLabel, base::SysUTF8ToCFStringRef(label)); + CFDictionarySetValue(query, kSecAttrLabel, + base::SysUTF8ToCFStringRef(GetLabelFromKeyType(type))); CFDictionarySetValue(query, kSecReturnRef, @YES); return query; } @@ -119,6 +134,11 @@ return helper_->CreateSecureKey(attributes); } +base::ScopedCFTypeRef<SecKeyRef> SecureEnclaveClientImpl::CopyStoredKey( + KeyType type) { + return helper_->CopyKey(CreateQueryForKey(type)); +} + bool SecureEnclaveClientImpl::MoveTemporaryKeyToPermanent() { // Deletes an old Secure Enclave key if it exists. DeleteKey(SecureEnclaveClient::KeyType::kPermanent); @@ -131,26 +151,20 @@ attributes_to_update, kSecAttrLabel, base::SysUTF8ToCFStringRef(constants::kDeviceTrustSigningKeyLabel)); - return helper_->Update( - CreateQueryForKey(constants::kTemporaryDeviceTrustSigningKeyLabel), - attributes_to_update); + return helper_->Update(CreateQueryForKey(KeyType::kTemporary), + attributes_to_update); } bool SecureEnclaveClientImpl::DeleteKey(KeyType type) { - auto* label = (type == KeyType::kTemporary) - ? constants::kTemporaryDeviceTrustSigningKeyLabel - : constants::kDeviceTrustSigningKeyLabel; - return helper_->Delete(CreateQueryForKey(label)); + return helper_->Delete(CreateQueryForKey(type)); } bool SecureEnclaveClientImpl::GetStoredKeyLabel(KeyType type, std::vector<uint8_t>& output) { - std::string label = (type == KeyType::kTemporary) - ? constants::kTemporaryDeviceTrustSigningKeyLabel - : constants::kDeviceTrustSigningKeyLabel; - if (!helper_->CheckExists(CreateQueryForKey(label))) + if (!helper_->CopyKey(CreateQueryForKey(type))) return false; + auto label = GetLabelFromKeyType(type); output.assign(label.begin(), label.end()); return true; }
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_unittest.mm b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_unittest.mm index 000fdd0..4453395 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_unittest.mm +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_unittest.mm
@@ -112,6 +112,34 @@ EXPECT_EQ(secure_enclave_client_->CreateTemporaryKey(), test_key_); } +// Tests when the CopyStoredKey method invokes the SE helper's CopyKey method +// and a key is found using both a permanent and a temporary key type. +TEST_F(SecureEnclaveClientTest, CopyStoredKey_KeyFound) { + EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_)) + .Times(2) + .WillRepeatedly([this](CFDictionaryRef query) { return test_key_; }); + EXPECT_EQ(secure_enclave_client_->CopyStoredKey( + SecureEnclaveClient::KeyType::kPermanent), + test_key_); + EXPECT_EQ(secure_enclave_client_->CopyStoredKey( + SecureEnclaveClient::KeyType::kTemporary), + test_key_); +} + +// Tests when the CopyStoredKey method invokes the SE helper's CopyKey method +// and a key is not found using both a permanent and a temporary key type. +TEST_F(SecureEnclaveClientTest, CopyStoredKey_KeyNotFound) { + EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_)) + .Times(2) + .WillRepeatedly([](CFDictionaryRef query) { + return base::ScopedCFTypeRef<SecKeyRef>(); + }); + EXPECT_FALSE(secure_enclave_client_->CopyStoredKey( + SecureEnclaveClient::KeyType::kPermanent)); + EXPECT_FALSE(secure_enclave_client_->CopyStoredKey( + SecureEnclaveClient::KeyType::kTemporary)); +} + // Tests that the MoveTemporaryKeyToPermanent method invokes the SE helper's // Update method and that the key attributes and query are set correctly. TEST_F(SecureEnclaveClientTest, MoveTemporaryKeyToPermanent) { @@ -160,16 +188,16 @@ SecureEnclaveClient::KeyType::kPermanent)); } -// Tests that the GetStoredKeyLabel method invokes the SE helper's CheckExists +// Tests that the GetStoredKeyLabel method invokes the SE helper's CopyKey // method and that the query and output is correct for a temporary key. -TEST_F(SecureEnclaveClientTest, GetStoredKeyLabel_TempKeyLabel) { +TEST_F(SecureEnclaveClientTest, GetStoredKeyLabel_TempKeyLabelFound) { std::vector<uint8_t> output; std::string temp_label = constants::kTemporaryDeviceTrustSigningKeyLabel; - EXPECT_CALL(*mock_secure_enclave_helper_, CheckExists(_)) + EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_)) .Times(1) .WillOnce([this, &temp_label](CFDictionaryRef query) { VerifyQuery(query, base::SysUTF8ToCFStringRef(temp_label)); - return true; + return test_key_; }); EXPECT_TRUE(secure_enclave_client_->GetStoredKeyLabel( @@ -179,16 +207,16 @@ EXPECT_EQ(expected_output, output); } -// Tests that the GetStoredKeyLabel method invokes the SE helper's CheckExists +// Tests that the GetStoredKeyLabel method invokes the SE helper's CopyKey // method and that the query and output is correct for a permanent key. -TEST_F(SecureEnclaveClientTest, GetStoredKeyLabel_PermanentKeyLabel) { +TEST_F(SecureEnclaveClientTest, GetStoredKeyLabel_PermanentKeyLabelFound) { std::vector<uint8_t> output; std::string permanent_label = constants::kDeviceTrustSigningKeyLabel; - EXPECT_CALL(*mock_secure_enclave_helper_, CheckExists(_)) + EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_)) .Times(1) .WillOnce([this, &permanent_label](CFDictionaryRef query) { VerifyQuery(query, base::SysUTF8ToCFStringRef(permanent_label)); - return true; + return test_key_; }); EXPECT_TRUE(secure_enclave_client_->GetStoredKeyLabel( SecureEnclaveClient::KeyType::kPermanent, output)); @@ -197,13 +225,15 @@ EXPECT_EQ(expected_output, output); } -// Tests that the GetStoredKeyLabel method invokes the SE helper's CheckExists +// Tests that the GetStoredKeyLabel method invokes the SE helper's CopyKey // method and that the query search returns false. TEST_F(SecureEnclaveClientTest, GetStoredKeyLabel_KeyNotFound) { std::vector<uint8_t> output; - EXPECT_CALL(*mock_secure_enclave_helper_, CheckExists(_)) + EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_)) .Times(1) - .WillOnce([](CFDictionaryRef query) { return false; }); + .WillOnce([](CFDictionaryRef query) { + return base::ScopedCFTypeRef<SecKeyRef>(); + }); EXPECT_FALSE(secure_enclave_client_->GetStoredKeyLabel( SecureEnclaveClient::KeyType::kPermanent, output)); std::vector<uint8_t> expected_output;
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper.h b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper.h index 6fba910..f0c705e 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper.h +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper.h
@@ -25,26 +25,27 @@ static std::unique_ptr<SecureEnclaveHelper> Create(); - // Issues the SecKeyCreateRandomKey API to create the secure key with its key + // Uses the SecKeyCreateRandomKey API to create the secure key with its key // `attributes`. Returns the key or a nullptr on failure. virtual base::ScopedCFTypeRef<SecKeyRef> CreateSecureKey( CFDictionaryRef attributes) = 0; - // Issues the SecItemUpdate API to update the the key retrieved with the + // Uses the SecItemCopyMatching API to search the keychain using the + // `query` dictionary. Returns the reference to the secure key or a nullptr + // if the key is not found. + virtual base::ScopedCFTypeRef<SecKeyRef> CopyKey(CFDictionaryRef query) = 0; + + // Uses the SecItemUpdate API to update the the key retrieved with the // `query` with its `attributes_to_update`. Returns true if the key // attributes were updated successfully and false otherwise. virtual bool Update(CFDictionaryRef query, CFDictionaryRef attributes_to_update) = 0; - // Issues the SecItemDelete API to delete the key retrieved with the `query`. + // Uses the SecItemDelete API to delete the key retrieved with the `query`. // Returns true if the key was deleted and false otherwise. virtual bool Delete(CFDictionaryRef query) = 0; - // Issues the SecItemCopyMatching API to search the keychain using the - // `query` dictionary. Returns true if the key exists and false otherwise. - virtual bool CheckExists(CFDictionaryRef query) = 0; - - // Issues the SecKeychainCopyDefault API to check if the keychain is unlocked. + // Uses the SecKeychainCopyDefault API to check if the keychain is unlocked. // Returns true when the keychain is unlocked and false otherwise. virtual bool CheckKeychainUnlocked() = 0;
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper_impl.h b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper_impl.h index f9e1a56..0d656c7 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper_impl.h +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper_impl.h
@@ -22,10 +22,10 @@ // SecureEnclaveHelper: base::ScopedCFTypeRef<SecKeyRef> CreateSecureKey( CFDictionaryRef attributes) override; + base::ScopedCFTypeRef<SecKeyRef> CopyKey(CFDictionaryRef query) override; bool Update(CFDictionaryRef query, CFDictionaryRef attributes_to_update) override; bool Delete(CFDictionaryRef query) override; - bool CheckExists(CFDictionaryRef query) override; bool CheckKeychainUnlocked() override; bool IsSecureEnclaveSupported() override; };
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper_impl.mm b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper_impl.mm index f8bab1a..88d7958 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper_impl.mm +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper_impl.mm
@@ -35,10 +35,13 @@ return SecItemDelete(query) == errSecSuccess; } -bool SecureEnclaveHelperImpl::CheckExists(CFDictionaryRef query) { - base::ScopedCFTypeRef<CFTypeRef> key; - SecItemCopyMatching(query, key.InitializeInto()); - return key != nullptr; +base::ScopedCFTypeRef<SecKeyRef> SecureEnclaveHelperImpl::CopyKey( + CFDictionaryRef query) { + base::ScopedCFTypeRef<SecKeyRef> key; + SecItemCopyMatching( + query, const_cast<CFTypeRef*>( + reinterpret_cast<const CFTypeRef*>(key.InitializeInto()))); + return key; } // Much of the Keychain API was marked deprecated as of the macOS 13 SDK.
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key.cc b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key.cc new file mode 100644 index 0000000..fe73436b --- /dev/null +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key.cc
@@ -0,0 +1,166 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key.h" + +#include <memory> +#include <string> +#include <vector> + +#include "base/check.h" +#include "base/containers/contains.h" +#include "base/containers/span.h" +#include "base/mac/scoped_cftyperef.h" +#include "base/notreached.h" +#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client.h" +#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/shared_command_constants.h" +#include "crypto/signature_verifier.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace enterprise_connectors { + +namespace { + +// Returns the result of the comparison of the key `label` and the +// `wrapped_key_label`. +bool CheckEqual(const std::string& label, + base::span<const uint8_t> wrapped_key_label) { + auto label_span = base::as_bytes(base::make_span(label)); + return std::equal(wrapped_key_label.begin(), wrapped_key_label.end(), + label_span.begin(), label_span.end()); +} + +// Returns the key type from the `wrapped_key_label` if the `wrapped_key_label` +// matches any of the supported key labels. Otherwise a nullptr is returned. +absl::optional<SecureEnclaveClient::KeyType> GetTypeFromWrappedKey( + base::span<const uint8_t> wrapped_key_label) { + if (CheckEqual(constants::kDeviceTrustSigningKeyLabel, wrapped_key_label)) { + return SecureEnclaveClient::KeyType::kPermanent; + } + + if (CheckEqual(constants::kTemporaryDeviceTrustSigningKeyLabel, + wrapped_key_label)) { + return SecureEnclaveClient::KeyType::kTemporary; + } + + NOTREACHED(); + return absl::nullopt; +} + +// An implementation of crypto::UnexportableSigningKey. +class SecureEnclaveSigningKey : public crypto::UnexportableSigningKey { + public: + SecureEnclaveSigningKey(base::ScopedCFTypeRef<SecKeyRef> key, + std::unique_ptr<SecureEnclaveClient> client, + SecureEnclaveClient::KeyType type); + ~SecureEnclaveSigningKey() override; + + // crypto::UnexportableSigningKey: + crypto::SignatureVerifier::SignatureAlgorithm Algorithm() const override; + std::vector<uint8_t> GetSubjectPublicKeyInfo() const override; + std::vector<uint8_t> GetWrappedKey() const override; + absl::optional<std::vector<uint8_t>> SignSlowly( + base::span<const uint8_t> data) override; + + private: + base::ScopedCFTypeRef<SecKeyRef> key_; + std::unique_ptr<SecureEnclaveClient> client_; + SecureEnclaveClient::KeyType key_type_; +}; + +SecureEnclaveSigningKey::SecureEnclaveSigningKey( + base::ScopedCFTypeRef<SecKeyRef> key, + std::unique_ptr<SecureEnclaveClient> client, + SecureEnclaveClient::KeyType type) + : key_(std::move(key)), client_(std::move(client)), key_type_(type) { + DCHECK(key_); + DCHECK(client_); +} + +SecureEnclaveSigningKey::~SecureEnclaveSigningKey() = default; + +crypto::SignatureVerifier::SignatureAlgorithm +SecureEnclaveSigningKey::Algorithm() const { + return crypto::SignatureVerifier::ECDSA_SHA256; +} + +std::vector<uint8_t> SecureEnclaveSigningKey::GetSubjectPublicKeyInfo() const { + std::vector<uint8_t> pubkey; + client_->ExportPublicKey(key_, pubkey); + return pubkey; +} + +std::vector<uint8_t> SecureEnclaveSigningKey::GetWrappedKey() const { + std::vector<uint8_t> wrapped; + client_->GetStoredKeyLabel(key_type_, wrapped); + return wrapped; +} + +absl::optional<std::vector<uint8_t>> SecureEnclaveSigningKey::SignSlowly( + base::span<const uint8_t> data) { + std::vector<uint8_t> signature; + if (!client_->SignDataWithKey(key_, data, signature)) { + return absl::nullopt; + } + + return signature; +} + +} // namespace + +SecureEnclaveSigningKeyProvider::SecureEnclaveSigningKeyProvider( + SecureEnclaveClient::KeyType type) + : provider_key_type_(type) {} +SecureEnclaveSigningKeyProvider::~SecureEnclaveSigningKeyProvider() = default; + +absl::optional<crypto::SignatureVerifier::SignatureAlgorithm> +SecureEnclaveSigningKeyProvider::SelectAlgorithm( + base::span<const crypto::SignatureVerifier::SignatureAlgorithm> + acceptable_algorithms) { + const auto kAlgorithm = crypto::SignatureVerifier::ECDSA_SHA256; + if (base::Contains(acceptable_algorithms, kAlgorithm)) + return kAlgorithm; + + return absl::nullopt; +} + +std::unique_ptr<crypto::UnexportableSigningKey> +SecureEnclaveSigningKeyProvider::GenerateSigningKeySlowly( + base::span<const crypto::SignatureVerifier::SignatureAlgorithm> + acceptable_algorithms) { + if (provider_key_type_ != SecureEnclaveClient::KeyType::kTemporary) + return nullptr; + + auto algo = SelectAlgorithm(acceptable_algorithms); + if (!algo) + return nullptr; + + DCHECK_EQ(crypto::SignatureVerifier::ECDSA_SHA256, *algo); + + auto client = SecureEnclaveClient::Create(); + auto key = client->CreateTemporaryKey(); + if (!key) + return nullptr; + + return std::make_unique<SecureEnclaveSigningKey>( + std::move(key), std::move(client), provider_key_type_); +} + +std::unique_ptr<crypto::UnexportableSigningKey> +SecureEnclaveSigningKeyProvider::FromWrappedSigningKeySlowly( + base::span<const uint8_t> wrapped_key_label) { + // Verifying wrapped key label matches the provider key type. + if (provider_key_type_ != GetTypeFromWrappedKey(wrapped_key_label)) + return nullptr; + + auto client = SecureEnclaveClient::Create(); + auto key = client->CopyStoredKey(provider_key_type_); + if (!key) + return nullptr; + + return std::make_unique<SecureEnclaveSigningKey>( + std::move(key), std::move(client), provider_key_type_); +} + +} // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key.h b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key.h new file mode 100644 index 0000000..ba0a015 --- /dev/null +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key.h
@@ -0,0 +1,43 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_KEY_MANAGEMENT_CORE_MAC_SECURE_ENCLAVE_SIGNING_KEY_H_ +#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_KEY_MANAGEMENT_CORE_MAC_SECURE_ENCLAVE_SIGNING_KEY_H_ + +#include <memory> + +#include "base/containers/span.h" +#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client.h" +#include "crypto/unexportable_key.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace enterprise_connectors { + +// An implementation of crypto::UnexportableKeyProvider for mac using the +// Secure Enclave key. +class SecureEnclaveSigningKeyProvider : public crypto::UnexportableKeyProvider { + public: + // Takes a parameter of key `type` (Permanent or Temporary) that the key + // provider will represent. + explicit SecureEnclaveSigningKeyProvider(SecureEnclaveClient::KeyType type); + ~SecureEnclaveSigningKeyProvider() override; + + // crypto::UnexportableKeyProvider: + absl::optional<crypto::SignatureVerifier::SignatureAlgorithm> SelectAlgorithm( + base::span<const crypto::SignatureVerifier::SignatureAlgorithm> + acceptable_algorithms) override; + std::unique_ptr<crypto::UnexportableSigningKey> GenerateSigningKeySlowly( + base::span<const crypto::SignatureVerifier::SignatureAlgorithm> + acceptable_algorithms) override; + std::unique_ptr<crypto::UnexportableSigningKey> FromWrappedSigningKeySlowly( + base::span<const uint8_t> wrapped_key_label) override; + + private: + // The key type (Permanent or Temporary) the provider represents. + SecureEnclaveClient::KeyType provider_key_type_; +}; + +} // namespace enterprise_connectors + +#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_KEY_MANAGEMENT_CORE_MAC_SECURE_ENCLAVE_SIGNING_KEY_H_
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key_unittest.mm b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key_unittest.mm new file mode 100644 index 0000000..ac0bd94 --- /dev/null +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key_unittest.mm
@@ -0,0 +1,226 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key.h" + +#import <Foundation/Foundation.h> +#import <Security/Security.h> + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/containers/span.h" +#include "base/mac/scoped_cftyperef.h" +#include "base/strings/sys_string_conversions.h" +#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/mock_secure_enclave_client.h" +#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client.h" +#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/shared_command_constants.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using ::testing::InSequence; + +namespace enterprise_connectors { + +using test::MockSecureEnclaveClient; + +class SecureEnclaveSigningKeyTest : public testing::Test { + public: + SecureEnclaveSigningKeyTest() { + CreateTestKey(); + auto mock_secure_enclave_client = + std::make_unique<MockSecureEnclaveClient>(); + mock_secure_enclave_client_ = mock_secure_enclave_client.get(); + SecureEnclaveClient::SetInstanceForTesting( + std::move(mock_secure_enclave_client)); + } + + protected: + // Creates a temporary key. + void CreateTestKey() { + base::ScopedCFTypeRef<CFMutableDictionaryRef> test_attributes( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + CFDictionarySetValue(test_attributes, kSecAttrLabel, + base::SysUTF8ToNSString("fake-label")); + CFDictionarySetValue(test_attributes, kSecAttrKeyType, + kSecAttrKeyTypeECSECPrimeRandom); + CFDictionarySetValue(test_attributes, kSecAttrKeySizeInBits, @256); + base::ScopedCFTypeRef<CFMutableDictionaryRef> private_key_params( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + CFDictionarySetValue(private_key_params, kSecAttrIsPermanent, @NO); + CFDictionarySetValue(test_attributes, kSecPrivateKeyAttrs, + private_key_params); + test_key_ = base::ScopedCFTypeRef<SecKeyRef>( + SecKeyCreateRandomKey(test_attributes, nullptr)); + } + + // Sets the unexportable key using the test key. + void SetUnexportableKey() { + auto provider = SecureEnclaveSigningKeyProvider( + SecureEnclaveClient::KeyType::kTemporary); + EXPECT_CALL(*mock_secure_enclave_client_, CreateTemporaryKey()) + .Times(1) + .WillOnce([this]() { return test_key_; }); + auto acceptable_algorithms = {crypto::SignatureVerifier::ECDSA_SHA256}; + key_ = provider.GenerateSigningKeySlowly(acceptable_algorithms); + } + + MockSecureEnclaveClient* mock_secure_enclave_client_ = nullptr; + std::unique_ptr<crypto::UnexportableSigningKey> key_; + base::ScopedCFTypeRef<SecKeyRef> test_key_; +}; + +// Tests that the GenerateSigningKeySlowly method invokes the SE client's +// CreateTemporaryKey method only when the provider is a temporary key provider. +TEST_F(SecureEnclaveSigningKeyTest, GenerateSigningKeySlowly) { + auto acceptable_algorithms = {crypto::SignatureVerifier::ECDSA_SHA256}; + + InSequence s; + + auto provider = + SecureEnclaveSigningKeyProvider(SecureEnclaveClient::KeyType::kTemporary); + EXPECT_CALL(*mock_secure_enclave_client_, CreateTemporaryKey()) + .Times(1) + .WillOnce([this]() { return test_key_; }); + auto unexportable_key = + provider.GenerateSigningKeySlowly(acceptable_algorithms); + EXPECT_TRUE(unexportable_key); + EXPECT_EQ(crypto::SignatureVerifier::ECDSA_SHA256, + unexportable_key->Algorithm()); + + provider = + SecureEnclaveSigningKeyProvider(SecureEnclaveClient::KeyType::kPermanent); + EXPECT_CALL(*mock_secure_enclave_client_, CreateTemporaryKey()).Times(0); + unexportable_key = provider.GenerateSigningKeySlowly(acceptable_algorithms); + EXPECT_FALSE(unexportable_key); +} + +// Tests that the FromWrappedSigningKeySlowly invokes the SE client's +// CopyStoredKey method only when the wrapped key label matches the key +// provider type and the provider is a permanent key provider. +TEST_F(SecureEnclaveSigningKeyTest, + FromWrappedSigningKeySlowly_PermanentKeyProvider) { + auto permanent_key_provider = SecureEnclaveSigningKeyProvider( + (SecureEnclaveClient::KeyType::kPermanent)); + std::unique_ptr<crypto::UnexportableSigningKey> unexportable_key; + + InSequence s; + + // Permanent provider key type with a wrapped permanent key label. + EXPECT_CALL(*mock_secure_enclave_client_, CopyStoredKey(_)) + .Times(1) + .WillOnce([this](SecureEnclaveClient::KeyType type) { + EXPECT_EQ(SecureEnclaveClient::KeyType::kPermanent, type); + return test_key_; + }); + unexportable_key = permanent_key_provider.FromWrappedSigningKeySlowly( + base::as_bytes(base::make_span( + std::string(constants::kDeviceTrustSigningKeyLabel)))); + EXPECT_TRUE(unexportable_key); + EXPECT_EQ(crypto::SignatureVerifier::ECDSA_SHA256, + unexportable_key->Algorithm()); + + // Permanent key provider with a wrapped temporary key label. + EXPECT_CALL(*mock_secure_enclave_client_, CopyStoredKey(_)).Times(0); + unexportable_key = permanent_key_provider.FromWrappedSigningKeySlowly( + base::as_bytes(base::make_span( + std::string(constants::kTemporaryDeviceTrustSigningKeyLabel)))); + EXPECT_FALSE(unexportable_key); +} + +// Tests that the FromWrappedSigningKeySlowly invokes the SE client's +// CopyStoredKey method only when the wrapped key label matches the key +// provider type and the provider is a temporary key provider. +TEST_F(SecureEnclaveSigningKeyTest, + FromWrappedSigningKeySlowly_TemporaryKeyProvider) { + auto temp_key_provider = SecureEnclaveSigningKeyProvider( + (SecureEnclaveClient::KeyType::kTemporary)); + std::unique_ptr<crypto::UnexportableSigningKey> unexportable_key; + + InSequence s; + + // Temporary key provider with a wrapped temporary key label. + EXPECT_CALL(*mock_secure_enclave_client_, CopyStoredKey(_)) + .Times(1) + .WillOnce([this](SecureEnclaveClient::KeyType type) { + EXPECT_EQ(SecureEnclaveClient::KeyType::kTemporary, type); + return test_key_; + }); + unexportable_key = temp_key_provider.FromWrappedSigningKeySlowly( + base::as_bytes(base::make_span( + std::string(constants::kTemporaryDeviceTrustSigningKeyLabel)))); + EXPECT_TRUE(unexportable_key); + EXPECT_EQ(crypto::SignatureVerifier::ECDSA_SHA256, + unexportable_key->Algorithm()); + + // Temporary provider key type with a wrapped permanent key label. + EXPECT_CALL(*mock_secure_enclave_client_, CopyStoredKey(_)).Times(0); + unexportable_key = temp_key_provider.FromWrappedSigningKeySlowly( + base::as_bytes(base::make_span( + std::string(constants::kDeviceTrustSigningKeyLabel)))); + EXPECT_FALSE(unexportable_key); +} + +// Tests that the GetSubjectPublicKeyInfo method invokes the SE client's +// ExportPublicKey method and that the public key information gotten from +// this method is correct. +TEST_F(SecureEnclaveSigningKeyTest, GetSubjectPublicKeyInfo) { + SetUnexportableKey(); + std::string test_data = "data"; + EXPECT_CALL(*mock_secure_enclave_client_, ExportPublicKey(_, _)) + .WillOnce([&test_data](SecKeyRef key, std::vector<uint8_t>& output) { + output.assign(test_data.begin(), test_data.end()); + return true; + }); + + EXPECT_EQ(std::vector<uint8_t>(test_data.begin(), test_data.end()), + key_->GetSubjectPublicKeyInfo()); +} + +// Tests that the GetWrappedKey method invokes the SE client's +// GetStoredKeyLabel method and that the wrapped key label is the temporary +// key label since the SecureEnclaveSigningKey is currently a temporary key. +TEST_F(SecureEnclaveSigningKeyTest, GetWrappedKey) { + SetUnexportableKey(); + EXPECT_CALL(*mock_secure_enclave_client_, + GetStoredKeyLabel(SecureEnclaveClient::KeyType::kTemporary, _)) + .WillOnce( + [](SecureEnclaveClient::KeyType type, std::vector<uint8_t>& output) { + std::string label = + (type == SecureEnclaveClient::KeyType::kTemporary) + ? constants::kTemporaryDeviceTrustSigningKeyLabel + : constants::kDeviceTrustSigningKeyLabel; + output.assign(label.begin(), label.end()); + return true; + }); + auto wrapped = key_->GetWrappedKey(); + EXPECT_EQ(constants::kTemporaryDeviceTrustSigningKeyLabel, + std::string(wrapped.begin(), wrapped.end())); +} + +// Tests that the SignSlowly method invokes the SE client's SignDataWithKey +// method and that the signature is correct. +TEST_F(SecureEnclaveSigningKeyTest, SignSlowly) { + SetUnexportableKey(); + std::string test_data = "data"; + EXPECT_CALL(*mock_secure_enclave_client_, SignDataWithKey(_, _, _)) + .Times(1) + .WillOnce([&test_data](SecKeyRef key, base::span<const uint8_t> data, + std::vector<uint8_t>& output) { + output.assign(test_data.begin(), test_data.end()); + return true; + }); + EXPECT_EQ( + std::vector<uint8_t>(test_data.begin(), test_data.end()), + key_->SignSlowly(base::as_bytes(base::make_span("data to be sign")))); +} + +} // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.cc b/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.cc index 1fd28e0..cfe3696 100644 --- a/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.cc +++ b/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.cc
@@ -13,6 +13,8 @@ const base::Feature kExtensionEventsEnabled{"ExtensionEventsEnabled", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kBrowserCrashEventsEnabled{ + "BrowserCrashEventsEnabled", base::FEATURE_DISABLED_BY_DEFAULT}; namespace { constexpr char kReportingConnectorUrlFlag[] = "reporting-connector-url";
diff --git a/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h b/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h index 79ba5b1..ccd953f 100644 --- a/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h +++ b/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h
@@ -20,6 +20,7 @@ // Feature flags for individual event types. extern const base::Feature kExtensionEventsEnabled; +extern const base::Feature kBrowserCrashEventsEnabled; // The settings for a report service obtained from a connector policy. class ReportingServiceSettings { @@ -38,6 +39,7 @@ static constexpr char kExtensionInstallEvent[] = "browserExtensionInstallEvent"; + static constexpr char kBrowserCrashEvent[] = "browserCrashEvent"; // All events that the reporting connector supports. static const constexpr char* kAllReportingEvents[] = { @@ -50,6 +52,7 @@ extensions::SafeBrowsingPrivateEventRouter::kKeyLoginEvent, extensions::SafeBrowsingPrivateEventRouter::kKeyPasswordBreachEvent, kExtensionInstallEvent, + kBrowserCrashEvent, }; private:
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index c87c4e06..b91ea09 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -1219,6 +1219,8 @@ "api/file_browser_handler/file_browser_handler_flow_lacros.h", "api/file_manager/file_browser_handler_api_lacros.cc", "api/file_manager/file_browser_handler_api_lacros.h", + "api/file_system/chrome_file_system_delegate_lacros.cc", + "api/file_system/chrome_file_system_delegate_lacros.h", "api/file_system/volume_list_provider_lacros.cc", "api/file_system/volume_list_provider_lacros.h", "api/image_writer_private/image_writer_controller_lacros.cc",
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc index 69b42a3..edb9bfa 100644 --- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc +++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -72,6 +72,7 @@ #endif #if BUILDFLAG(IS_CHROMEOS_LACROS) +#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h" #include "chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.h" #endif @@ -391,6 +392,8 @@ FileSystemDelegate* ChromeExtensionsAPIClient::GetFileSystemDelegate() { #if BUILDFLAG(IS_CHROMEOS_ASH) using ChromeFileSystemDelegate_Use = ChromeFileSystemDelegateAsh; +#elif BUILDFLAG(IS_CHROMEOS_LACROS) + using ChromeFileSystemDelegate_Use = ChromeFileSystemDelegateLacros; #else using ChromeFileSystemDelegate_Use = ChromeFileSystemDelegate; #endif
diff --git a/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc index d34e8da..e974799 100644 --- a/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc +++ b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
@@ -35,15 +35,15 @@ #include "base/mac/foundation_util.h" #endif -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) #include "extensions/browser/event_router.h" -#endif // BUILDFLAG(IS_CHROMEOS_ASH) +#endif // BUILDFLAG(IS_CHROMEOS) namespace extensions { namespace file_system = api::file_system; -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) using file_system_api::ConsentProvider; using file_system_api::ConsentProviderDelegate; @@ -72,7 +72,7 @@ } } // namespace file_system_api -#endif // BUILDFLAG(IS_CHROMEOS_ASH) +#endif // BUILDFLAG(IS_CHROMEOS) /******** ChromeFileSystemDelegate ********/ @@ -165,7 +165,7 @@ return 0; } -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) bool ChromeFileSystemDelegate::IsGrantable( content::BrowserContext* browser_context, const Extension& extension) { @@ -189,7 +189,7 @@ content::BrowserContext* browser_context, VolumeListCallback success_callback, ErrorCallback error_callback) {} -#endif // BUILDFLAG(IS_CHROMEOS_ASH) +#endif // BUILDFLAG(IS_CHROMEOS) SavedFilesServiceInterface* ChromeFileSystemDelegate::GetSavedFilesService( content::BrowserContext* browser_context) {
diff --git a/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h index 07fba404..cde2f69 100644 --- a/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h +++ b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h
@@ -16,9 +16,9 @@ #include "extensions/browser/extension_function.h" #include "ui/shell_dialogs/select_file_dialog.h" -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) #include "chrome/browser/extensions/api/file_system/consent_provider.h" -#endif // BUILDFLAG(IS_CHROMEOS_ASH) +#endif // BUILDFLAG(IS_CHROMEOS) namespace content { class BrowserContext; @@ -26,7 +26,7 @@ namespace extensions { -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) namespace file_system_api { extern const char kConsentImpossible[]; @@ -39,7 +39,7 @@ const char* ConsentResultToError(ConsentProvider::Consent result); } // namespace file_system_api -#endif // BUILDFLAG(IS_CHROMEOS_ASH) +#endif // BUILDFLAG(IS_CHROMEOS) class ChromeFileSystemDelegate : public FileSystemDelegate { public: @@ -68,7 +68,7 @@ base::OnceClosure on_accept, base::OnceClosure on_cancel) override; int GetDescriptionIdForAcceptType(const std::string& accept_type) override; -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) bool IsGrantable(content::BrowserContext* browser_context, const Extension& extension) override; void RequestFileSystem(content::BrowserContext* browser_context, @@ -81,7 +81,7 @@ void GetVolumeList(content::BrowserContext* browser_context, VolumeListCallback success_callback, ErrorCallback error_callback) override; -#endif // BUILDFLAG(IS_CHROMEOS_ASH) +#endif // BUILDFLAG(IS_CHROMEOS) SavedFilesServiceInterface* GetSavedFilesService( content::BrowserContext* browser_context) override; };
diff --git a/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.cc b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.cc new file mode 100644 index 0000000..0898fa9 --- /dev/null +++ b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.cc
@@ -0,0 +1,349 @@ +// Copyright 2022 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/extensions/api/file_system/chrome_file_system_delegate_lacros.h" + +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/check.h" +#include "base/memory/raw_ptr.h" +#include "base/path_service.h" +#include "base/scoped_observation.h" +#include "chrome/browser/extensions/api/file_system/consent_provider.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_observer.h" +#include "chromeos/lacros/lacros_service.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" +#include "extensions/browser/api/file_handlers/app_file_handler_util.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/granted_file_entry.h" +#include "extensions/common/extension.h" + +namespace extensions { + +namespace file_system = api::file_system; + +using extensions::app_file_handler_util::CreateFileEntryWithPermissions; +using file_system_api::ConsentProvider; +using file_system_api::ConsentProviderDelegate; + +namespace { + +const char kApiUnavailableError[] = "API unavailable."; +const char kProfileGoneError[] = "Profile gone."; +const char kRenderFrameHostGoneError[] = "Render frame host gone."; +const char kRequestAbortedError[] = "Request aborted."; + +// Volume list converter that excludes volumes unsupported by lacros-chrome. +void ConvertAndFilterMojomToVolumeList( + const std::vector<crosapi::mojom::VolumePtr>& src_volume_list, + std::vector<file_system::Volume>* dst_volume_list) { + DCHECK(dst_volume_list->empty()); + for (auto& src_volume : src_volume_list) { + if (src_volume->is_available_to_lacros) { + file_system::Volume dst_volume; + dst_volume.volume_id = src_volume->volume_id; + dst_volume.writable = src_volume->writable; + dst_volume_list->emplace_back(std::move(dst_volume)); + } + } +} + +} // namespace + +namespace file_system_api { + +void DispatchVolumeListChangeEventLacros( + content::BrowserContext* browser_context, + const std::vector<crosapi::mojom::VolumePtr>& volume_list) { + DCHECK(browser_context); + EventRouter* const event_router = EventRouter::Get(browser_context); + if (!event_router) // Possible on shutdown. + return; + + ExtensionRegistry* const registry = ExtensionRegistry::Get(browser_context); + if (!registry) // Possible on shutdown. + return; + + // TODO(crbug.com/1351493): Simplify usage for IsGrantable(). + ConsentProviderDelegate consent_provider_delegate( + Profile::FromBrowserContext(browser_context)); + ConsentProvider consent_provider(&consent_provider_delegate); + + file_system::VolumeListChangedEvent event_args; + // Note: Events are still fired even if: + // * The *filtered* volume list does not change. + // * The filtered volume list is empty. + // This is done for simplicy: Detecting change in filtered volume list will + // requires caching volume list on Lacros side; preventing empty filtered + // volume list from triggering an event will lead to inconsistencies compared + // to polling via getVolumeList(). + ConvertAndFilterMojomToVolumeList(volume_list, &event_args.volumes); + for (const auto& extension : registry->enabled_extensions()) { + if (!consent_provider.IsGrantable(*extension)) + continue; + + event_router->DispatchEventToExtension( + extension->id(), + std::make_unique<Event>( + events::FILE_SYSTEM_ON_VOLUME_LIST_CHANGED, + file_system::OnVolumeListChanged::kEventName, + file_system::OnVolumeListChanged::Create(event_args))); + } +} + +} // namespace file_system_api + +namespace { + +/******** RequestFileSystemExecutor ********/ + +// Executor for chrome.requestFileSystem(), with async steps: +// 1. Crosapi call to get volume info. +// 2. (Potentially) request consent via dialog. +// Sources of complexity: +// * Lifetime: Instances are ref counted, and are kept alive via callback +// binding. +// * Profile: (2) requires |profile_|, which may disappear while awaiting (1)! +// This is handled by observing |profile_|: If it is destroyed then abort +// before (2); else proceeds with (2) and unobserve ASAP. +// * Fulfillment: To ensure the request is fulfilled, one of |success_callback| +// or |error_callback| gets called eventually (via FinishWith*()). +class RequestFileSystemExecutor + : public base::RefCountedThreadSafe<RequestFileSystemExecutor>, + public ProfileObserver { + public: + RequestFileSystemExecutor( + Profile* profile, + scoped_refptr<ExtensionFunction> requester, + const std::string& volume_id, + bool writable, + ChromeFileSystemDelegate::FileSystemCallback success_callback, + ChromeFileSystemDelegate::ErrorCallback error_callback); + RequestFileSystemExecutor(const RequestFileSystemExecutor&) = delete; + RequestFileSystemExecutor& operator=(const RequestFileSystemExecutor&) = + delete; + + // Entry point for executor flow. + void Run(chromeos::LacrosService* lacros_service); + + private: + friend class base::RefCountedThreadSafe<RequestFileSystemExecutor>; + ~RequestFileSystemExecutor() override; + + // ProfileObserver: + void OnProfileWillBeDestroyed(Profile* profile) override; + + // Callback for (1), on receiving volume info from crosapi. + void OnCrosapiGetVolumeMountInfo(crosapi::mojom::VolumePtr crosapi_volume); + + // Callback for (2), on consent granting or denial. + void OnConsentReceived(base::FilePath mount_path, + ConsentProvider::Consent result); + + // Consumes |error_callback_| to pass |error| on error. + void FinishWithError(const std::string& error); + + // Consumes |success_callback_| to pass results on success. + void FinishWithResponse(const std::string& filesystem_id, + const std::string& registered_name); + + // |profile_| can be a raw pointer since its destruction is observed. + base::raw_ptr<Profile> profile_; + base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this}; + scoped_refptr<ExtensionFunction> requester_; + const std::string volume_id_; + const bool want_writable_; + ChromeFileSystemDelegate::FileSystemCallback success_callback_; + ChromeFileSystemDelegate::ErrorCallback error_callback_; + bool responded_ = false; +}; + +RequestFileSystemExecutor::RequestFileSystemExecutor( + Profile* profile, + scoped_refptr<ExtensionFunction> requester, + const std::string& volume_id, + bool want_writable, + ChromeFileSystemDelegate::FileSystemCallback success_callback, + ChromeFileSystemDelegate::ErrorCallback error_callback) + : profile_(profile), + requester_(requester), + volume_id_(volume_id), + want_writable_(want_writable), + success_callback_(std::move(success_callback)), + error_callback_(std::move(error_callback)) { + profile_observation_.Observe(profile_); +} + +void RequestFileSystemExecutor::Run(chromeos::LacrosService* lacros_service) { + // All code path from here must lead to either |success_callback_| or + // |error_callback_| getting called. + lacros_service->GetRemote<crosapi::mojom::VolumeManager>() + ->GetVolumeMountInfo( + volume_id_, + base::BindOnce( + &RequestFileSystemExecutor::OnCrosapiGetVolumeMountInfo, this)); +} + +RequestFileSystemExecutor::~RequestFileSystemExecutor() { + if (!responded_) + FinishWithError(kRequestAbortedError); +} + +void RequestFileSystemExecutor::OnProfileWillBeDestroyed(Profile* profile) { + DCHECK_EQ(profile_, profile); + profile_observation_.Reset(); + profile_ = nullptr; +} + +void RequestFileSystemExecutor::OnCrosapiGetVolumeMountInfo( + crosapi::mojom::VolumePtr crosapi_volume) { + // Profile can be gone before this callback executes, while awaiting crosapi. + if (!profile_) { + FinishWithError(kProfileGoneError); + return; + } + if (!crosapi_volume || !crosapi_volume->is_available_to_lacros) { + FinishWithError(file_system_api::kVolumeNotFoundError); + return; + } + if (want_writable_ && !crosapi_volume->writable) { + FinishWithError(file_system_api::kSecurityError); + return; + } + + // TODO(crbug.com/1351493): Simplify usage for RequestConsent(). + ConsentProviderDelegate consent_provider_delegate(profile_); + ConsentProvider consent_provider(&consent_provider_delegate); + + ConsentProvider::ConsentCallback callback = + base::BindOnce(&RequestFileSystemExecutor::OnConsentReceived, this, + crosapi_volume->mount_path); + + consent_provider.RequestConsent( + requester_->render_frame_host(), *requester_->extension(), + crosapi_volume->volume_id, crosapi_volume->volume_label, want_writable_, + std::move(callback)); + + // Done with |profile_|, so stop observing. + profile_observation_.Reset(); + profile_ = nullptr; +} + +void RequestFileSystemExecutor::OnConsentReceived( + base::FilePath mount_path, + ConsentProvider::Consent result) { + // Render frame host can be gone before this callback executes. + if (!requester_->render_frame_host()) { + FinishWithError(kRenderFrameHostGoneError); + return; + } + + const char* consent_err_msg = file_system_api::ConsentResultToError(result); + if (consent_err_msg) { + FinishWithError(consent_err_msg); + return; + } + + const auto process_id = requester_->source_process_id(); + extensions::GrantedFileEntry granted_file_entry = + CreateFileEntryWithPermissions(process_id, mount_path, + /*can_write=*/want_writable_, + /*can_create=*/want_writable_, + /*can_delete=*/want_writable_); + FinishWithResponse(granted_file_entry.filesystem_id, + granted_file_entry.registered_name); +} + +void RequestFileSystemExecutor::FinishWithError(const std::string& error) { + std::move(error_callback_).Run(error); + responded_ = true; +} + +void RequestFileSystemExecutor::FinishWithResponse( + const std::string& filesystem_id, + const std::string& registered_name) { + std::move(success_callback_).Run(filesystem_id, registered_name); + responded_ = true; +} + +} // namespace + +/******** ChromeFileSystemDelegateLacros ********/ + +ChromeFileSystemDelegateLacros::ChromeFileSystemDelegateLacros() = default; + +ChromeFileSystemDelegateLacros::~ChromeFileSystemDelegateLacros() = default; + +void ChromeFileSystemDelegateLacros::RequestFileSystem( + content::BrowserContext* browser_context, + scoped_refptr<ExtensionFunction> requester, + const Extension& extension, + std::string volume_id, + bool writable, + FileSystemCallback success_callback, + ErrorCallback error_callback) { + Profile* profile = Profile::FromBrowserContext(browser_context); + // TODO(crbug.com/1351493): Simplify usage for IsGrantable(). + ConsentProviderDelegate consent_provider_delegate(profile); + ConsentProvider consent_provider(&consent_provider_delegate); + + if (writable && + !app_file_handler_util::HasFileSystemWritePermission(&extension)) { + std::move(error_callback) + .Run(file_system_api::kRequiresFileSystemWriteError); + return; + } + + if (!consent_provider.IsGrantable(extension)) { + std::move(error_callback) + .Run(file_system_api::kNotSupportedOnNonKioskSessionError); + return; + } + + auto* lacros_service = chromeos::LacrosService::Get(); + DCHECK(lacros_service); + if (!lacros_service->IsAvailable<crosapi::mojom::VolumeManager>()) { + std::move(error_callback).Run(kApiUnavailableError); + return; + } + + // The executor object is kept alive by its presence in callbacks, and + // deleted when callbacks are invoked or cleared. + scoped_refptr<RequestFileSystemExecutor> executor = + new RequestFileSystemExecutor(profile, requester, volume_id, writable, + std::move(success_callback), + std::move(error_callback)); + executor->Run(lacros_service); +} + +void ChromeFileSystemDelegateLacros::GetVolumeList( + content::BrowserContext* /*browser_context*/, + VolumeListCallback success_callback, + ErrorCallback error_callback) { + auto* lacros_service = chromeos::LacrosService::Get(); + DCHECK(lacros_service); + if (!lacros_service->IsAvailable<crosapi::mojom::VolumeManager>()) { + std::move(error_callback).Run(kApiUnavailableError); + return; + } + + lacros_service->GetRemote<crosapi::mojom::VolumeManager>()->GetFullVolumeList( + base::BindOnce( + [](VolumeListCallback success_callback, + std::vector<crosapi::mojom::VolumePtr> src_volume_list) { + std::vector<file_system::Volume> filtered_volume_list; + ConvertAndFilterMojomToVolumeList(src_volume_list, + &filtered_volume_list); + std::move(success_callback).Run(filtered_volume_list); + }, + std::move(success_callback))); +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h new file mode 100644 index 0000000..8fb3fbe6 --- /dev/null +++ b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h
@@ -0,0 +1,61 @@ +// Copyright 2022 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_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_LACROS_H_ +#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_LACROS_H_ + +#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h" + +#include <string> +#include <vector> + +#include "base/memory/scoped_refptr.h" +#include "chromeos/crosapi/mojom/volume_manager.mojom.h" +#include "extensions/browser/extension_function.h" + +namespace content { +class BrowserContext; +} // namespace content + +namespace extensions { + +class Extension; + +namespace file_system_api { + +// Dispatches an event about a mounted or unmounted volume in the system to +// each extension which can request it. +void DispatchVolumeListChangeEventLacros( + content::BrowserContext* browser_context, + const std::vector<crosapi::mojom::VolumePtr>& volume_list); + +} // namespace file_system_api + +class ChromeFileSystemDelegateLacros : public ChromeFileSystemDelegate { + public: + ChromeFileSystemDelegateLacros(); + + ChromeFileSystemDelegateLacros(const ChromeFileSystemDelegateLacros&) = + delete; + ChromeFileSystemDelegateLacros& operator=( + const ChromeFileSystemDelegateLacros&) = delete; + + ~ChromeFileSystemDelegateLacros() override; + + // ChromeFileSystemDelegate: + void RequestFileSystem(content::BrowserContext* browser_context, + scoped_refptr<ExtensionFunction> requester, + const Extension& extension, + std::string volume_id, + bool writable, + FileSystemCallback success_callback, + ErrorCallback error_callback) override; + void GetVolumeList(content::BrowserContext* browser_context, + VolumeListCallback success_callback, + ErrorCallback error_callback) override; +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_LACROS_H_
diff --git a/chrome/browser/extensions/api/file_system/consent_provider.h b/chrome/browser/extensions/api/file_system/consent_provider.h index 7ec3a81..1293e803 100644 --- a/chrome/browser/extensions/api/file_system/consent_provider.h +++ b/chrome/browser/extensions/api/file_system/consent_provider.h
@@ -29,8 +29,8 @@ // TestingConsentProviderDelegate. // This class may post callbacks given to it, but does not asynchronously call // itself. It is generally safe to use a temporary ConsentProvider. -// TODO(michaelpg): Make this easier to use by replacing member functions with -// static methods. +// TODO(crbug.com/1351493): Make this easier to use, perhaps by replacing member +// functions with static methods. class ConsentProvider { public: enum Consent { CONSENT_GRANTED, CONSENT_REJECTED, CONSENT_IMPOSSIBLE };
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest.cc b/chrome/browser/extensions/api/file_system/file_system_apitest.cc index 04c1dbc..43c4f0f 100644 --- a/chrome/browser/extensions/api/file_system/file_system_apitest.cc +++ b/chrome/browser/extensions/api/file_system/file_system_apitest.cc
@@ -9,7 +9,6 @@ #include "base/scoped_observation.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" -#include "build/chromeos_buildflags.h" #include "chrome/browser/apps/platform_apps/app_browsertest_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_paths.h" @@ -731,13 +730,13 @@ << message_; } -#if !BUILDFLAG(IS_CHROMEOS_ASH) +#if !BUILDFLAG(IS_CHROMEOS) IN_PROC_BROWSER_TEST_F(FileSystemApiTest, RequestFileSystem_NotChromeOS) { ASSERT_TRUE(RunExtensionTest( "api_test/file_system/request_file_system_not_chromeos", {.launch_as_platform_app = true}, {.ignore_manifest_warnings = true})) << message_; } -#endif +#endif // !BUILDFLAG(IS_CHROMEOS) } // namespace extensions
diff --git a/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.cc b/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.cc index 896ce28..fcfe9c61 100644 --- a/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.cc +++ b/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/extensions/api/file_system/volume_list_provider_lacros.h" #include "base/logging.h" +#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h" #include "chrome/browser/profiles/profile.h" #include "chromeos/lacros/lacros_service.h" @@ -26,9 +27,7 @@ void VolumeListProviderLacros::OnVolumeListChanged( std::vector<crosapi::mojom::VolumePtr> volume_list) { DCHECK(profile_); - - // TODO(crbug.com/1263204): Add and call - // file_system_api::DispatchVolumeListChangeEventLacros(). + file_system_api::DispatchVolumeListChangeEventLacros(profile_, volume_list); } } // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc index cf2a1e5..a18afaf 100644 --- a/chrome/browser/extensions/api/identity/identity_apitest.cc +++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -122,9 +122,8 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) void InitNetwork() { - const ash::NetworkState* default_network = chromeos::NetworkHandler::Get() - ->network_state_handler() - ->DefaultNetwork(); + const ash::NetworkState* default_network = + ash::NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); auto* portal_detector = new ash::NetworkPortalDetectorTestImpl(); portal_detector->SetDefaultNetworkForTesting(default_network->guid());
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc index 280b012c..31cfe8f 100644 --- a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc +++ b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
@@ -335,10 +335,10 @@ } void SetupTether() { - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler* network_state_handler = + ash::NetworkHandler::Get()->network_state_handler(); network_state_handler->SetTetherTechnologyState( - chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); + ash::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); network_state_handler->AddTetherNetworkState( "tetherGuid1", "tetherName1", "tetherCarrier1", 50 /* battery_percentage */, 75 /* signal_strength */, @@ -942,7 +942,7 @@ } IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetErrorState) { - chromeos::NetworkHandler::Get()->network_state_handler()->SetErrorForTest( + ash::NetworkHandler::Get()->network_state_handler()->SetErrorForTest( kWifi1ServicePath, "TestErrorState"); EXPECT_TRUE(RunNetworkingSubtest("getErrorState")) << message_; } @@ -1007,7 +1007,7 @@ OnCertificateListsChangedEvent) { ExtensionTestMessageListener listener("eventListenerReady"); listener.SetOnSatisfied(base::BindOnce([](const std::string& message) { - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_certificate_handler() ->AddAuthorityCertificateForTest("authority_cert"); })); @@ -1117,7 +1117,7 @@ ::onc::global_network_config::kAllowOnlyPolicyWiFiToConnect, base::Value(false)); global_config.SetKey("SomeNewGlobalPolicy", base::Value(false)); - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->managed_network_configuration_handler() ->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY, std::string() /* no username hash */, base::ListValue(), @@ -1153,7 +1153,7 @@ } IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetCertificateLists) { - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_certificate_handler() ->AddAuthorityCertificateForTest("authority_cert"); EXPECT_TRUE(RunNetworkingSubtest("getCertificateLists")) << message_;
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc index fd805ae..c2cd6118 100644 --- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc +++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -578,8 +578,8 @@ "borderedkey", base::FeatureList::IsEnabled( chromeos::features::kVirtualKeyboardBorderedKey))); features.Append(GenerateFeatureFlag( - "multitouch", - base::FeatureList::IsEnabled(features::kVirtualKeyboardMultitouch))); + "multitouch", base::FeatureList::IsEnabled( + chromeos::features::kVirtualKeyboardMultitouch))); features.Append(GenerateFeatureFlag( "roundCorners", base::FeatureList::IsEnabled( chromeos::features::kVirtualKeyboardRoundCorners)));
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index fc516d8c..00c1b61 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1744,11 +1744,6 @@ "Enable an entry point to Google Lens to allow users to search what they " "see using their mobile camera."; -const char kLocationBarModelOptimizationsName[] = - "LocationBarModel optimizations"; -const char kLocationBarModelOptimizationsDescription[] = - "Cache commonly used data in LocationBarModel to improve performance"; - const char kLogJsConsoleMessagesName[] = "Log JS console messages in system logs"; const char kLogJsConsoleMessagesDescription[] =
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index a27fa642..2e81877f 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -249,7 +249,6 @@ &kKitKatSupported, &kLensCameraAssistedSearch, &kLensOnQuickActionSearchWidget, - &kLocationBarModelOptimizations, &kMostRecentTabOnBackgroundCloseTab, &kNewInstanceFromDraggedLink, &kNewTabPageTilesTitleWrapAround, @@ -547,7 +546,7 @@ "CCTResizable90MaximumHeight", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kCCTResizableAllowResizeByUserGesture{ - "CCTResizableAllowResizeByUserGesture", base::FEATURE_DISABLED_BY_DEFAULT}; + "CCTResizableAllowResizeByUserGesture", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kCCTResizableForFirstParties{ "CCTResizableForFirstParties", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -700,9 +699,6 @@ const base::Feature kKitKatSupported{"KitKatSupported", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kLocationBarModelOptimizations{ - "LocationBarModelOptimizations", base::FEATURE_DISABLED_BY_DEFAULT}; - const base::Feature kSearchEnginePromoExistingDevice{ "SearchEnginePromo.ExistingDevice", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index b725687..cc937bd 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -393,7 +393,6 @@ public static final String LEAK_DETECTION_UNAUTHENTICATED = "LeakDetectionUnauthenticated"; public static final String LENS_ON_QUICK_ACTION_SEARCH_WIDGET = "LensOnQuickActionSearchWidget"; public static final String LIGHTWEIGHT_REACTIONS = "LightweightReactions"; - public static final String LOCATION_BAR_MODEL_OPTIMIZATIONS = "LocationBarModelOptimizations"; public static final String LOOKALIKE_NAVIGATION_URL_SUGGESTIONS_UI = "LookalikeUrlNavigationSuggestionsUI"; public static final String MARK_HTTP_AS = "MarkHttpAs";
diff --git a/chrome/browser/lens/OWNERS b/chrome/browser/lens/OWNERS index be4c83e..7c3e4cc 100644 --- a/chrome/browser/lens/OWNERS +++ b/chrome/browser/lens/OWNERS
@@ -1,4 +1,5 @@ benwgold@google.com juanmojica@google.com sinansahin@google.com +stanfield@google.com twellington@chromium.org
diff --git a/chrome/browser/media/router/BUILD.gn b/chrome/browser/media/router/BUILD.gn index 37d6cc9..20395dc2 100644 --- a/chrome/browser/media/router/BUILD.gn +++ b/chrome/browser/media/router/BUILD.gn
@@ -39,7 +39,6 @@ "//content/public/common", "//crypto", "//media", - "//ui/base:buildflags", ] } @@ -69,7 +68,6 @@ "//components/media_router/browser", "//components/media_router/common", "//components/media_router/common/mojom:media_router", - "//components/sessions:sessions", ] sources = [ "chrome_media_router_factory.cc", @@ -80,27 +78,22 @@ if (!is_android) { deps += [ + # We can't depend on //chrome/browser/ui due to introducing a cyclic + # dependency. Remove this target from the `allow_circular_includes_from` + # list in chrome/browser/ui/BUILD.gn once the issues is resolved. + # TODO(crbug.com/1030821): Resolve circular dependencies. + "discovery:discovery", - "//build:chromeos_buildflags", "//chrome/browser:browser_process", "//chrome/browser/profiles:profile", "//components/embedder_support:browser_util", "//components/mirroring/mojom:host", "//components/mirroring/mojom:service", - - # We can't depend on //chrome/browser/ui due to introducing a cyclic - # dependency, so we have to depend on this directly to fix include - # resolution for browser.h, which is used in media_router_mojo_impl.cc. - # TODO(crbug.com/1030821): Resolve circular dependencies - "//components/paint_preview/buildflags", - "//components/signin/public/base:signin_buildflags", - "//components/translate/content/common", "//components/ukm/content:content", "//components/version_info:version_info", "//mojo/public/cpp/bindings", "//services/metrics/public/cpp:ukm_builders", "//third_party/openscreen/src/cast/common/channel/proto:channel_proto", - "//ui/base:buildflags", ] public_deps += [ "//components/media_router/common/mojom:logger" ]
diff --git a/chrome/browser/media/router/discovery/access_code/BUILD.gn b/chrome/browser/media/router/discovery/access_code/BUILD.gn index 6364bc52..fc29662 100644 --- a/chrome/browser/media/router/discovery/access_code/BUILD.gn +++ b/chrome/browser/media/router/discovery/access_code/BUILD.gn
@@ -67,6 +67,7 @@ "//components/signin/public/base:base", "//components/signin/public/identity_manager:identity_manager", "//components/user_manager:user_manager", + "//content/public/browser", "//services/preferences/public/cpp:cpp", ] }
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc index 67ff2c0d6..c59641d1 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc
@@ -250,13 +250,10 @@ // the sink if a new route wasn't established during the pause. auto route = GetActiveRoute(sink->id()); - // If a sink is pending expiration that means we can - // remove it from the media router. - if (!route.has_value() && pending_expirations_.count(sink->id())) { - RemoveSinkIdFromAllEntries(sink->id()); - RemoveAndDisconnectMediaSinkFromRouter(sink); - pending_expirations_.erase(sink->id()); - } + // If there is no active route, check manually if the device should be + // instantly expired. + if (!route.has_value()) + CheckMediaSinkForExpiration(sink->id()); } void AccessCodeCastSinkService::DiscoverSink(const std::string& access_code, @@ -666,7 +663,6 @@ "route has " "ended.", sink.id()); - pending_expirations_.insert(sink.id()); return; } RemoveSinkIdFromAllEntries(sink.id()); @@ -814,7 +810,6 @@ if (!GetAccessCodeCastEnabledPref(prefs_)) { RemoveAndDisconnectExistingSinksOnNetwork(); ResetExpirationTimers(); - pending_expirations_.clear(); pref_updater_->ClearDevicesDict(); pref_updater_->ClearDeviceAddedTimeDict(); }
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h index 73444ec..2da0c1d 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h
@@ -309,21 +309,11 @@ net::BackoffEntry::Policy backoff_policy_; - // Map of callbacks that we are currently waiting to alert callers about the - // completion of discovery. This cannot be done until all routes on any given - // sink are terminated. - std::map<MediaSink::Id, AddSinkResultCallback> pending_callbacks_; - // Map of sink_ids keyed to a value of expiration timers for the current // session (this is updated when the profile session or network is changed). std::map<MediaSink::Id, std::unique_ptr<base::OneShotTimer>> current_session_expiration_timers_; - // Set of devices that have expired but still have an open route. These - // devices are removed from the media router AND removed from the pref - // service. - std::set<MediaSink::Id> pending_expirations_; - scoped_refptr<base::SequencedTaskRunner> task_runner_; // Raw pointer to DiscoveryNetworkMonitor, which is a global leaky singleton
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc index 41e68a2..cb64d99 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc
@@ -219,6 +219,7 @@ // Test to see that an AccessCode cast sink will be removed after the session // is ended. mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + SetDeviceDurationPrefForTest(base::Seconds(10)); // Add a non-access code cast sink to media router and route list. MediaSinkInternal cast_sink1 = CreateCastSink(1); @@ -240,6 +241,11 @@ route_list.push_back(media_route_access); + mock_cast_media_sink_service_impl()->AddSinkForTest(access_code_sink2); + access_code_cast_sink_service_->SetExpirationTimer(&access_code_sink2); + access_code_cast_sink_service_->StoreSinkInPrefs(&access_code_sink2); + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + // Expect that the removed_route_id_ member variable has not changes since no // route was removed. access_code_cast_sink_service_->media_routes_observer_->OnRoutesUpdated( @@ -278,14 +284,15 @@ media_route_access.media_route_id()); mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + // Expire the access code cast sink while the route is still active. + task_environment_.AdvanceClock(base::Seconds(100)); + access_code_cast_sink_service_->HandleMediaRouteRemovedByAccessCode( &access_code_sink2); - // Expect that there is a pending attempt to examine the sink to see if it - // should be expired. + EXPECT_CALL(*mock_cast_media_sink_service_impl(), DisconnectAndRemoveSink(access_code_sink2)); - access_code_cast_sink_service_->pending_expirations_.insert( - access_code_sink2.id()); + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); } @@ -856,7 +863,7 @@ EXPECT_TRUE(access_code_cast_sink_service_ ->current_session_expiration_timers_[cast_sink3.id()] ->IsRunning()); - EXPECT_TRUE(access_code_cast_sink_service_->pending_expirations_.empty()); + FastForwardUiAndIoTasks(); content::RunAllTasksUntilIdle(); }
diff --git a/chrome/browser/media/router/discovery/dial/dial_service_impl.cc b/chrome/browser/media/router/discovery/dial/dial_service_impl.cc index 841e6cc..0819bed2 100644 --- a/chrome/browser/media/router/discovery/dial/dial_service_impl.cc +++ b/chrome/browser/media/router/discovery/dial/dial_service_impl.cc
@@ -139,7 +139,7 @@ // ChromeOS version can prioritize wifi and ethernet interfaces. void InsertBestBindAddressChromeOS(const ash::NetworkTypePattern& type, net::IPAddressList* bind_address_list) { - const ash::NetworkState* state = chromeos::NetworkHandler::Get() + const ash::NetworkState* state = ash::NetworkHandler::Get() ->network_state_handler() ->ConnectedNetworkByType(type); if (!state) @@ -156,7 +156,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); net::IPAddressList bind_address_list; - if (chromeos::NetworkHandler::IsInitialized()) { + if (ash::NetworkHandler::IsInitialized()) { InsertBestBindAddressChromeOS(ash::NetworkTypePattern::Ethernet(), &bind_address_list); InsertBestBindAddressChromeOS(ash::NetworkTypePattern::WiFi(),
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc index 0b89d4b..53639fd 100644 --- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc +++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -9,24 +9,14 @@ #include <utility> #include "base/bind.h" -#include "base/check_op.h" -#include "base/containers/contains.h" -#include "base/containers/cxx20_erase.h" -#include "base/guid.h" #include "base/metrics/histogram_functions.h" -#include "base/notreached.h" #include "base/observer_list.h" #include "base/strings/stringprintf.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/media/cast_mirroring_service_host.h" #include "chrome/browser/media/cast_remoting_connector.h" -#include "chrome/browser/media/router/media_router_feature.h" #include "chrome/browser/media/router/mojo/media_router_mojo_metrics.h" #include "chrome/browser/media/router/mojo/media_sink_service_status.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_list.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/grit/chromium_strings.h" #include "components/media_router/browser/issues_observer.h" #include "components/media_router/browser/media_router_metrics.h" @@ -35,7 +25,6 @@ #include "components/media_router/browser/route_message_observer.h" #include "components/media_router/common/media_source.h" #include "components/media_router/common/providers/cast/cast_media_source.h" -#include "components/sessions/content/session_tab_helper.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/desktop_streams_registry.h" @@ -54,37 +43,7 @@ namespace media_router { namespace { -// Get the WebContents associated with the given tab id. Returns nullptr if the -// tab id is invalid, or if the searching fails. -// TODO(xjz): Move this to SessionTabHelper to allow it being used by -// extensions::ExtensionTabUtil::GetTabById() as well. -content::WebContents* GetWebContentsFromId( - int32_t tab_id, - content::BrowserContext* browser_context, - bool include_incognito) { - if (tab_id < 0) - return nullptr; - Profile* profile = Profile::FromBrowserContext(browser_context); - Profile* incognito_profile = - include_incognito && profile->HasPrimaryOTRProfile() - ? profile->GetPrimaryOTRProfile(/*create_if_needed=*/true) - : nullptr; - for (auto* target_browser : *BrowserList::GetInstance()) { - if (target_browser->profile() == profile || - target_browser->profile() == incognito_profile) { - TabStripModel* target_tab_strip = target_browser->tab_strip_model(); - for (int i = 0; i < target_tab_strip->count(); ++i) { - content::WebContents* target_contents = - target_tab_strip->GetWebContentsAt(i); - if (sessions::SessionTabHelper::IdForTab(target_contents).id() == - tab_id) { - return target_contents; - } - } - } - } - return nullptr; -} +const int kDefaultFrameTreeNodeId = -1; DesktopMediaPickerController::Params MakeDesktopPickerParams( content::WebContents* web_contents) { @@ -298,12 +257,12 @@ presentation_id, origin, web_contents, timeout, off_the_record, std::move(mr_callback))); } else { - // Previously the tab ID was set to -1 for non-mirroring sessions, which - // mostly works, but it breaks auto-joining. - const int tab_id = sessions::SessionTabHelper::IdForTab(web_contents).id(); + const int frame_tree_node_id = + web_contents ? web_contents->GetPrimaryMainFrame()->GetFrameTreeNodeId() + : kDefaultFrameTreeNodeId; media_route_providers_[provider_id]->CreateRoute( - source_id, sink_id, presentation_id, origin, tab_id, timeout, - off_the_record, std::move(mr_callback)); + source_id, sink_id, presentation_id, origin, frame_tree_node_id, + timeout, off_the_record, std::move(mr_callback)); } } @@ -327,13 +286,15 @@ return; } - int tab_id = sessions::SessionTabHelper::IdForTab(web_contents).id(); + const int frame_tree_node_id = + web_contents ? web_contents->GetPrimaryMainFrame()->GetFrameTreeNodeId() + : kDefaultFrameTreeNodeId; auto mr_callback = base::BindOnce( &MediaRouterMojoImpl::RouteResponseReceived, weak_factory_.GetWeakPtr(), presentation_id, *provider_id, off_the_record, std::move(callback), true); media_route_providers_[*provider_id]->JoinRoute( - source_id, presentation_id, origin, tab_id, timeout, off_the_record, - std::move(mr_callback)); + source_id, presentation_id, origin, frame_tree_node_id, timeout, + off_the_record, std::move(mr_callback)); } void MediaRouterMojoImpl::TerminateRoute(const MediaRoute::Id& route_id) { @@ -784,11 +745,10 @@ } void MediaRouterMojoImpl::GetMirroringServiceHostForTab( - int32_t target_tab_id, + int32_t frame_tree_node_id, mojo::PendingReceiver<mirroring::mojom::MirroringServiceHost> receiver) { mirroring::CastMirroringServiceHost::GetForTab( - GetWebContentsFromId(target_tab_id, context_, - true /* include_incognito */), + content::WebContents::FromFrameTreeNodeId(frame_tree_node_id), std::move(receiver)); } @@ -796,7 +756,6 @@ // but eventually it won't be. When that happens, change the sigature so it can // report errors. Also remove the |initiator_tab_id| parameter. void MediaRouterMojoImpl::GetMirroringServiceHostForDesktop( - int32_t initiator_tab_id, const std::string& desktop_stream_id, mojo::PendingReceiver<mirroring::mojom::MirroringServiceHost> receiver) { if (!pending_stream_request_ || @@ -1000,7 +959,8 @@ media_route_providers_[provider_id]->CreateRoute( MediaSource::ForDesktop(request.stream_id, media_id.audio_share).id(), - sink_id, presentation_id, origin, -1, timeout, off_the_record, + sink_id, presentation_id, origin, kDefaultFrameTreeNodeId, timeout, + off_the_record, base::BindOnce( [](mojom::MediaRouteProvider::CreateRouteCallback inner_callback, base::WeakPtr<MediaRouterMojoImpl> self,
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.h b/chrome/browser/media/router/mojo/media_router_mojo_impl.h index b05f0e17..af09b14 100644 --- a/chrome/browser/media/router/mojo/media_router_mojo_impl.h +++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
@@ -327,11 +327,10 @@ void GetMediaSinkServiceStatus( mojom::MediaRouter::GetMediaSinkServiceStatusCallback callback) override; void GetMirroringServiceHostForTab( - int32_t target_tab_id, + int32_t frame_tree_node_id, mojo::PendingReceiver<mirroring::mojom::MirroringServiceHost> receiver) override; void GetMirroringServiceHostForDesktop( - int32_t initiator_tab_id, const std::string& desktop_stream_id, mojo::PendingReceiver<mirroring::mojom::MirroringServiceHost> receiver) override;
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc index e9f3b50..f55392a 100644 --- a/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc +++ b/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc
@@ -83,7 +83,7 @@ const char kSinkName[] = "sinkName"; const char kPresentationId[] = "presentationId"; const char kOrigin[] = "http://origin/"; -const int kInvalidTabId = -1; +const int kInvalidFrameNodeId = -1; const int kTimeoutMillis = 5 * 1000; IssueInfo CreateIssueInfo(const std::string& title) { @@ -265,16 +265,13 @@ EXPECT_CALL(mock_cast_provider_, CreateRouteInternal(kSource, kSinkId, _, url::Origin::Create(GURL(kOrigin)), - kInvalidTabId, _, _, _)) - .WillOnce(Invoke([&expected_route]( - const std::string& source, const std::string& sink, - const std::string& presentation_id, - const url::Origin& origin, int tab_id, - base::TimeDelta timeout, bool off_the_record, - mojom::MediaRouteProvider::CreateRouteCallback& cb) { - std::move(cb).Run(expected_route, nullptr, std::string(), - mojom::RouteRequestResultCode::OK); - })); + kInvalidFrameNodeId, _, _, _)) + .WillOnce(WithArg<7>( + Invoke([&expected_route]( + mojom::MediaRouteProvider::CreateRouteCallback& cb) { + std::move(cb).Run(expected_route, nullptr, std::string(), + mojom::RouteRequestResultCode::OK); + }))); base::RunLoop run_loop; RouteResponseCallbackHandler handler; @@ -294,17 +291,14 @@ TEST_F(MediaRouterMojoImplTest, CreateRouteFails) { ProvideTestSink(mojom::MediaRouteProviderId::CAST, kSinkId); EXPECT_CALL(mock_cast_provider_, - CreateRouteInternal( - kSource, kSinkId, _, url::Origin::Create(GURL(kOrigin)), - kInvalidTabId, base::Milliseconds(kTimeoutMillis), _, _)) - .WillOnce(Invoke([](const std::string& source, const std::string& sink, - const std::string& presentation_id, - const url::Origin& origin, int tab_id, - base::TimeDelta timeout, bool off_the_record, - mojom::MediaRouteProvider::CreateRouteCallback& cb) { - std::move(cb).Run(absl::nullopt, nullptr, std::string(kError), - mojom::RouteRequestResultCode::TIMED_OUT); - })); + CreateRouteInternal(kSource, kSinkId, _, + url::Origin::Create(GURL(kOrigin)), + kInvalidFrameNodeId, _, _, _)) + .WillOnce(WithArg<7>( + Invoke([](mojom::MediaRouteProvider::CreateRouteCallback& cb) { + std::move(cb).Run(absl::nullopt, nullptr, std::string(kError), + mojom::RouteRequestResultCode::TIMED_OUT); + }))); RouteResponseCallbackHandler handler; base::RunLoop run_loop; @@ -324,17 +318,14 @@ TEST_F(MediaRouterMojoImplTest, CreateRouteIncognitoMismatchFails) { ProvideTestSink(mojom::MediaRouteProviderId::CAST, kSinkId); EXPECT_CALL(mock_cast_provider_, - CreateRouteInternal( - kSource, kSinkId, _, url::Origin::Create(GURL(kOrigin)), - kInvalidTabId, base::Milliseconds(kTimeoutMillis), true, _)) - .WillOnce(Invoke([](const std::string& source, const std::string& sink, - const std::string& presentation_id, - const url::Origin& origin, int tab_id, - base::TimeDelta timeout, bool off_the_record, - mojom::MediaRouteProvider::CreateRouteCallback& cb) { - std::move(cb).Run(CreateMediaRoute(), nullptr, std::string(), - mojom::RouteRequestResultCode::OK); - })); + CreateRouteInternal(kSource, kSinkId, _, + url::Origin::Create(GURL(kOrigin)), + kInvalidFrameNodeId, _, _, _)) + .WillOnce(WithArg<7>( + Invoke([](mojom::MediaRouteProvider::CreateRouteCallback& cb) { + std::move(cb).Run(CreateMediaRoute(), nullptr, std::string(), + mojom::RouteRequestResultCode::OK); + }))); RouteResponseCallbackHandler handler; base::RunLoop run_loop; @@ -384,18 +375,16 @@ UpdateRoutes(mojom::MediaRouteProviderId::CAST, routes); EXPECT_TRUE(router()->HasJoinableRoute()); - EXPECT_CALL(mock_cast_provider_, - JoinRouteInternal( - kSource, kPresentationId, url::Origin::Create(GURL(kOrigin)), - kInvalidTabId, base::Milliseconds(kTimeoutMillis), _, _)) - .WillOnce(Invoke([](const std::string& source, - const std::string& presentation_id, - const url::Origin& origin, int tab_id, - base::TimeDelta timeout, bool off_the_record, - mojom::MediaRouteProvider::JoinRouteCallback& cb) { - std::move(cb).Run(absl::nullopt, nullptr, std::string(kError), - mojom::RouteRequestResultCode::TIMED_OUT); - })); + EXPECT_CALL( + mock_cast_provider_, + JoinRouteInternal(kSource, kPresentationId, + url::Origin::Create(GURL(kOrigin)), kInvalidFrameNodeId, + base::Milliseconds(kTimeoutMillis), _, _)) + .WillOnce(WithArg<6>( + Invoke([](mojom::MediaRouteProvider::JoinRouteCallback& cb) { + std::move(cb).Run(absl::nullopt, nullptr, std::string(kError), + mojom::RouteRequestResultCode::TIMED_OUT); + }))); RouteResponseCallbackHandler handler; base::RunLoop run_loop; @@ -424,19 +413,16 @@ // Use a lambda function as an invocation target here to work around // a limitation with GMock::Invoke that prevents it from using move-only types // in runnable parameter lists. - EXPECT_CALL(mock_cast_provider_, - JoinRouteInternal( - kSource, kPresentationId, url::Origin::Create(GURL(kOrigin)), - kInvalidTabId, base::Milliseconds(kTimeoutMillis), true, _)) - .WillOnce( - Invoke([&route](const std::string& source, - const std::string& presentation_id, - const url::Origin& origin, int tab_id, - base::TimeDelta timeout, bool off_the_record, - mojom::MediaRouteProvider::JoinRouteCallback& cb) { + EXPECT_CALL( + mock_cast_provider_, + JoinRouteInternal(kSource, kPresentationId, + url::Origin::Create(GURL(kOrigin)), kInvalidFrameNodeId, + base::Milliseconds(kTimeoutMillis), _, _)) + .WillOnce(WithArg<6>( + Invoke([&route](mojom::MediaRouteProvider::JoinRouteCallback& cb) { std::move(cb).Run(route, nullptr, std::string(), mojom::RouteRequestResultCode::OK); - })); + }))); RouteResponseCallbackHandler handler; base::RunLoop run_loop;
diff --git a/chrome/browser/media/router/providers/cast/app_activity.cc b/chrome/browser/media/router/providers/cast/app_activity.cc index 492450b..fdc1457 100644 --- a/chrome/browser/media/router/providers/cast/app_activity.cc +++ b/chrome/browser/media/router/providers/cast/app_activity.cc
@@ -160,12 +160,13 @@ bool AppActivity::HasJoinableClient(AutoJoinPolicy policy, const url::Origin& origin, - int tab_id) const { + int frame_tree_node_id) const { return std::any_of(connected_clients_.begin(), connected_clients_.end(), - [policy, &origin, tab_id](const auto& client) { - return IsAutoJoinAllowed(policy, origin, tab_id, - client.second->origin(), - client.second->tab_id()); + [policy, &origin, frame_tree_node_id](const auto& client) { + return IsAutoJoinAllowed( + policy, origin, frame_tree_node_id, + client.second->origin(), + client.second->frame_tree_node_id()); }); }
diff --git a/chrome/browser/media/router/providers/cast/cast_activity.cc b/chrome/browser/media/router/providers/cast/cast_activity.cc index 3665226..c4c47cd 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity.cc +++ b/chrome/browser/media/router/providers/cast/cast_activity.cc
@@ -30,15 +30,16 @@ mojom::RoutePresentationConnectionPtr CastActivity::AddClient( const CastMediaSource& source, const url::Origin& origin, - int tab_id) { + int frame_tree_node_id) { const std::string& client_id = source.client_id(); DCHECK(!base::Contains(connected_clients_, client_id)); std::unique_ptr<CastSessionClient> client = client_factory_for_test_ - ? client_factory_for_test_->MakeClientForTest(client_id, origin, - tab_id) + ? client_factory_for_test_->MakeClientForTest( // IN-TEST + client_id, origin, frame_tree_node_id) : std::make_unique<CastSessionClientImpl>( - client_id, origin, tab_id, source.auto_join_policy(), this); + client_id, origin, frame_tree_node_id, + source.auto_join_policy(), this); auto presentation_connection = client->Init(); connected_clients_.emplace(client_id, std::move(client)); @@ -167,7 +168,8 @@ auto& client = *client_it->second; std::vector<std::string> leaving_client_ids; for (const auto& pair : connected_clients_) { - if (pair.second->MatchesAutoJoinPolicy(client.origin(), client.tab_id())) + if (pair.second->MatchesAutoJoinPolicy(client.origin(), + client.frame_tree_node_id())) leaving_client_ids.push_back(pair.first); }
diff --git a/chrome/browser/media/router/providers/cast/cast_activity.h b/chrome/browser/media/router/providers/cast/cast_activity.h index 604261c..ec308a04 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity.h +++ b/chrome/browser/media/router/providers/cast/cast_activity.h
@@ -55,7 +55,6 @@ const MediaRoute& route() const { return route_; } const std::string& app_id() const { return app_id_; } const absl::optional<std::string>& session_id() const { return session_id_; } - absl::optional<int> mirroring_tab_id() const { return mirroring_tab_id_; } const MediaSinkInternal sink() const { return sink_; } void SetRouteIsConnecting(bool is_connecting); @@ -66,7 +65,7 @@ virtual mojom::RoutePresentationConnectionPtr AddClient( const CastMediaSource& source, const url::Origin& origin, - int tab_id); + int frame_tree_node_id); virtual void RemoveClient(const std::string& client_id); @@ -174,7 +173,6 @@ MediaRoute route_; std::string app_id_; - absl::optional<int> mirroring_tab_id_; // TODO(https://crbug.com/809249): Consider wrapping CastMessageHandler with // known parameters (sink, client ID, session transport ID) and passing them
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc index c7a10818..02a61d6 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc +++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
@@ -87,21 +87,21 @@ const MediaSinkInternal& sink, const std::string& presentation_id, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, bool off_the_record, mojom::MediaRouteProvider::CreateRouteCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (cast_source.app_params().empty()) { - LaunchSessionParsed(cast_source, sink, presentation_id, origin, tab_id, - off_the_record, std::move(callback), + LaunchSessionParsed(cast_source, sink, presentation_id, origin, + frame_tree_node_id, off_the_record, std::move(callback), data_decoder::DataDecoder::ValueOrError()); } else { GetDataDecoder().ParseJson( cast_source.app_params(), base::BindOnce(&CastActivityManager::LaunchSessionParsed, weak_ptr_factory_.GetWeakPtr(), cast_source, sink, - presentation_id, origin, tab_id, off_the_record, - std::move(callback))); + presentation_id, origin, frame_tree_node_id, + off_the_record, std::move(callback))); } } @@ -110,7 +110,7 @@ const MediaSinkInternal& sink, const std::string& presentation_id, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, bool off_the_record, mojom::MediaRouteProvider::CreateRouteCallback callback, data_decoder::DataDecoder::ValueOrError result) { @@ -151,8 +151,9 @@ if (result.has_value() && !result->is_none()) opt_result = std::move(*result); - DoLaunchSessionParams params(route, cast_source, sink, origin, tab_id, - std::move(opt_result), std::move(callback)); + DoLaunchSessionParams params(route, cast_source, sink, origin, + frame_tree_node_id, std::move(opt_result), + std::move(callback)); // If there is currently a session on the sink, it must be terminated before // the new session can be launched. @@ -182,7 +183,7 @@ const MediaRoute::Id& route_id = route.media_route_id(); const CastMediaSource& cast_source = params.cast_source; const MediaSinkInternal& sink = params.sink; - const int tab_id = params.tab_id; + const int frame_tree_node_id = params.frame_tree_node_id; std::string app_id = ChooseAppId(cast_source, params.sink); auto app_params = std::move(params.app_params); @@ -194,17 +195,18 @@ cast_source.supported_app_types()); cast_source.ContainsStreamingApp() - ? AddMirroringActivity(route, app_id, tab_id, sink.cast_data()) + ? AddMirroringActivity(route, app_id, frame_tree_node_id, + sink.cast_data()) : AddAppActivity(route, app_id); - if (tab_id != -1) { - // If there is a route from this tab already, stop it. - auto route_it = routes_by_tab_.find(tab_id); - if (route_it != routes_by_tab_.end()) { + if (frame_tree_node_id != -1) { + // If there is a route from this frame already, stop it. + auto route_it = routes_by_frame_.find(frame_tree_node_id); + if (route_it != routes_by_frame_.end()) { TerminateSession(route_it->second, base::DoNothing()); } - routes_by_tab_[tab_id] = route_id; + routes_by_frame_[frame_tree_node_id] = route_id; } NotifyAllOnRoutesUpdated(); @@ -261,7 +263,7 @@ AppActivity* CastActivityManager::FindActivityForAutoJoin( const CastMediaSource& cast_source, const url::Origin& origin, - int tab_id) { + int frame_tree_node_id) { switch (cast_source.auto_join_policy()) { case AutoJoinPolicy::kTabAndOriginScoped: case AutoJoinPolicy::kOriginScoped: @@ -270,17 +272,17 @@ return nullptr; } - auto it = - std::find_if(app_activities_.begin(), app_activities_.end(), - [&cast_source, &origin, tab_id](const auto& pair) { - AutoJoinPolicy policy = cast_source.auto_join_policy(); - const AppActivity* activity = pair.second; - if (!activity->route().is_local()) - return false; - if (!cast_source.ContainsApp(activity->app_id())) - return false; - return activity->HasJoinableClient(policy, origin, tab_id); - }); + auto it = std::find_if( + app_activities_.begin(), app_activities_.end(), + [&cast_source, &origin, frame_tree_node_id](const auto& pair) { + AutoJoinPolicy policy = cast_source.auto_join_policy(); + const AppActivity* activity = pair.second; + if (!activity->route().is_local()) + return false; + if (!cast_source.ContainsApp(activity->app_id())) + return false; + return activity->HasJoinableClient(policy, origin, frame_tree_node_id); + }); return it == app_activities_.end() ? nullptr : it->second; } @@ -288,18 +290,18 @@ const CastMediaSource& cast_source, const std::string& presentation_id, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, bool off_the_record, mojom::MediaRouteProvider::JoinRouteCallback callback) { AppActivity* activity = nullptr; if (presentation_id == kAutoJoinPresentationId) { - activity = FindActivityForAutoJoin(cast_source, origin, tab_id); + activity = FindActivityForAutoJoin(cast_source, origin, frame_tree_node_id); if (!activity && cast_source.default_action_policy() != DefaultActionPolicy::kCastThisTab) { - auto sink = ConvertMirrorToCast(tab_id); + auto sink = ConvertMirrorToCast(frame_tree_node_id); if (sink) { - LaunchSession(cast_source, *sink, presentation_id, origin, tab_id, - off_the_record, std::move(callback)); + LaunchSession(cast_source, *sink, presentation_id, origin, + frame_tree_node_id, off_the_record, std::move(callback)); return; } } @@ -328,7 +330,7 @@ } mojom::RoutePresentationConnectionPtr presentation_connection = - activity->AddClient(cast_source, origin, tab_id); + activity->AddClient(cast_source, origin, frame_tree_node_id); if (!activity->session_id()) { // This should never happen, but it looks like maybe it does. See @@ -405,7 +407,7 @@ DLOG(ERROR) << "Invalid state: " << state; } - base::EraseIf(routes_by_tab_, [activity_it](const auto& pair) { + base::EraseIf(routes_by_frame_, [activity_it](const auto& pair) { return pair.second == activity_it->first; }); app_activities_.erase(activity_it->first); @@ -439,8 +441,8 @@ // There is no session associated with the route, e.g. the launch request is // still pending. if (!session_id) { - // |route_id| might be a reference to the item in |routes_by_tab_|. - // RemoveActivity() deletes this item in |routes_by_tab_| and invalidates + // |route_id| might be a reference to the item in |routes_by_frame_|. + // RemoveActivity() deletes this item in |routes_by_frame_| and invalidates // |route_id|. RemoveActivity(activity_it, PresentationConnectionState::TERMINATED, PresentationConnectionCloseReason::CLOSED); @@ -511,7 +513,7 @@ CastActivity* CastActivityManager::AddMirroringActivity( const MediaRoute& route, const std::string& app_id, - const int tab_id, + const int frame_tree_node_id, const CastSinkExtraData& cast_data) { // We could theoretically use base::Unretained() below instead of // GetWeakPtr(), but that seems like an unnecessary optimization here. @@ -523,7 +525,7 @@ route, app_id, std::move(on_stop)) : std::make_unique<MirroringActivity>( route, app_id, message_handler_, session_tracker_, - tab_id, cast_data, std::move(on_stop)); + frame_tree_node_id, cast_data, std::move(on_stop)); activity->CreateMojoBindings(media_router_); auto* const activity_ptr = activity.get(); activities_.emplace(route.media_route_id(), std::move(activity)); @@ -638,19 +640,6 @@ std::move(callback)); } -const MediaRoute* CastActivityManager::FindMirroringRouteForTab( - int32_t tab_id) { - for (const auto& entry : activities_) { - const std::string& route_id = entry.first; - const CastActivity& activity = *entry.second; - if (activity.mirroring_tab_id() == tab_id && - !base::Contains(app_activities_, route_id)) { - return &activity.route(); - } - } - return nullptr; -} - void CastActivityManager::SendRouteMessage(const std::string& media_route_id, const std::string& message) { GetDataDecoder().ParseJson( @@ -812,7 +801,7 @@ if (MediaSource(cast_source.source_id()).IsCastPresentationUrl()) { presentation_connection = activity_it->second->AddClient( - cast_source, params.origin, params.tab_id); + cast_source, params.origin, params.frame_tree_node_id); if (!client_id.empty()) { activity_it->second->SendMessageToClient( client_id, @@ -880,8 +869,8 @@ MediaRoute::GetPresentationIdFromMediaRouteId(route_id); if (result == cast_channel::Result::kOk) { - // |route_id| might be a reference to the item in |routes_by_tab_|. - // RemoveActivity() deletes this item in |routes_by_tab_| and invalidates + // |route_id| might be a reference to the item in |routes_by_frame_|. + // RemoveActivity() deletes this item in |routes_by_frame_| and invalidates // |route_id|. RemoveActivity(activity_it, PresentationConnectionState::TERMINATED, PresentationConnectionCloseReason::CLOSED); @@ -947,13 +936,17 @@ } absl::optional<MediaSinkInternal> CastActivityManager::ConvertMirrorToCast( - int tab_id) { - for (const auto& pair : activities_) { - if (pair.second->mirroring_tab_id() == tab_id) { - return pair.second->sink(); - } + int frame_tree_node_id) { + auto route_it = routes_by_frame_.find(frame_tree_node_id); + if (route_it == routes_by_frame_.end()) { + return absl::nullopt; } + const MediaRoute::Id& route_id = route_it->second; + if (activities_.find(route_id) != activities_.end() && + app_activities_.find(route_id) == app_activities_.end()) { + return activities_.find(route_id)->second->sink(); + } return absl::nullopt; } @@ -994,14 +987,14 @@ const CastMediaSource& cast_source, const MediaSinkInternal& sink, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, const absl::optional<base::Value> app_params, mojom::MediaRouteProvider::CreateRouteCallback callback) : route(route), cast_source(cast_source), sink(sink), origin(origin), - tab_id(tab_id), + frame_tree_node_id(frame_tree_node_id), callback(std::move(callback)) { if (app_params) this->app_params = app_params->Clone();
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.h b/chrome/browser/media/router/providers/cast/cast_activity_manager.h index cd18c2127..3a38cf9 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity_manager.h +++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.h
@@ -80,14 +80,14 @@ const MediaSinkInternal& sink, const std::string& presentation_id, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, bool incognito, mojom::MediaRouteProvider::CreateRouteCallback callback); void JoinSession(const CastMediaSource& cast_source, const std::string& presentation_id, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, bool incognito, mojom::MediaRouteProvider::JoinRouteCallback callback); @@ -128,8 +128,6 @@ const std::string& route_id, mojom::MediaRouteProvider::TerminateRouteCallback callback) override; - const MediaRoute* FindMirroringRouteForTab(int32_t tab_id); - void SendRouteMessage(const std::string& media_route_id, const std::string& message); @@ -156,7 +154,7 @@ const MediaSinkInternal& sink, const std::string& presentation_id, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, bool incognito, mojom::MediaRouteProvider::CreateRouteCallback callback, data_decoder::DataDecoder::ValueOrError result); @@ -171,7 +169,7 @@ const CastMediaSource& cast_source, const MediaSinkInternal& sink, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, const absl::optional<base::Value> app_params, mojom::MediaRouteProvider::CreateRouteCallback callback); DoLaunchSessionParams(const DoLaunchSessionParams& other) = delete; @@ -192,8 +190,9 @@ // The origin of the Cast SDK client. Used for auto-join. url::Origin origin; - // The tab ID of the Cast SDK client. Used for auto-join. - int tab_id; + // The FrameTreeNodeId of the WebContents of the Cast SDK client. Used for + // Mirroring and auto-join. + int frame_tree_node_id; // The JSON object sent from the Cast SDK. absl::optional<base::Value> app_params; @@ -241,7 +240,7 @@ AppActivity* FindActivityForAutoJoin(const CastMediaSource& cast_source, const url::Origin& origin, - int tab_id); + int frame_tree_node_id); bool CanJoinSession(const AppActivity& activity, const CastMediaSource& cast_source, bool incognito) const; @@ -264,12 +263,12 @@ const std::string& app_id); CastActivity* AddMirroringActivity(const MediaRoute& route, const std::string& app_id, - int tab_id, + const int frame_tree_node_id, const CastSinkExtraData& cast_data); // Returns a sink used to convert a mirroring activity to a cast activity. // If no conversion should occur, returns absl::nullopt. - absl::optional<MediaSinkInternal> ConvertMirrorToCast(int tab_id); + absl::optional<MediaSinkInternal> ConvertMirrorToCast(int frame_tree_node_id); std::string ChooseAppId(const CastMediaSource& source, const MediaSinkInternal& sink) const; @@ -286,12 +285,13 @@ // there is a AppActivity. AppActivityMap app_activities_; - // Mapping from tab IDs to the active route for that tab. This map is used to - // ensure that there is at most one active route for each tab. Removing this - // map and the code that uses it will allow a tab to be cast to multiple - // receivers, but there may be unintended consequences, such as confusing - // users or causing performance problems on low-end devices. - base::flat_map<int, MediaRoute::Id> routes_by_tab_; + // Mapping from FrameTreeNode IDs to the active routes for that main frame. + // This map is used to ensure that there is at most one active route for each + // main frame. Removing this map and the code that uses it will allow a + // main frame to be cast to multiple receivers, but there may be unintended + // consequences, such as confusing users or causing performance problems on + // low-end devices. + base::flat_map<int, MediaRoute::Id> routes_by_frame_; // Information for a session that will be launched once |this| is notified // that the existing session on the receiver has been removed. We only store
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc index 5053dc1..cefd8f0 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc +++ b/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc
@@ -63,8 +63,8 @@ constexpr int kChannelId2 = 43; constexpr char kClientId[] = "theClientId"; constexpr char kOrigin[] = "https://google.com"; -constexpr int kTabId = 1; -constexpr int kTabId2 = 2; +constexpr int kFrameTreeNodeId = 1; +constexpr int kFrameTreeNodeId2 = 2; constexpr char kAppId1[] = "ABCDEFGH"; constexpr char kAppId2[] = "BBBBBBBB"; constexpr char kAppParams[] = R"( @@ -263,7 +263,8 @@ ASSERT_TRUE(source); // Callback needs to be invoked by running |launch_session_callback_|. - manager_->LaunchSession(*source, sink_, kPresentationId, origin_, kTabId, + manager_->LaunchSession(*source, sink_, kPresentationId, origin_, + kFrameTreeNodeId, /*incognito*/ false, std::move(callback)); RunUntilIdle(); @@ -585,7 +586,7 @@ // Callback will be invoked synchronously. manager_->LaunchSession( - *source, sink_, kPresentationId, origin_, kTabId, + *source, sink_, kPresentationId, origin_, kFrameTreeNodeId, /*incognito*/ false, base::BindOnce(&CastActivityManagerTest::ExpectLaunchSessionFailure, base::Unretained(this))); @@ -615,7 +616,8 @@ // LaunchSessionParsed() is called asynchronously and will fail the test. manager_->LaunchSessionParsed( // TODO(crbug.com/1291744): Verify that presentation ID is used correctly. - *source, sink_, kPresentationId2, origin_, kTabId2, /*incognito*/ + *source, sink_, kPresentationId2, origin_, + kFrameTreeNodeId2, /*incognito*/ false, base::BindOnce(&CastActivityManagerTest::ExpectLaunchSessionSuccess, base::Unretained(this)), @@ -644,7 +646,8 @@ // Use LaunchSessionParsed() instead of LaunchSession() here because // LaunchSessionParsed() is called asynchronously and will fail the test. manager_->LaunchSessionParsed( - *source, sink2_, kPresentationId2, origin_, kTabId, /*incognito*/ + *source, sink2_, kPresentationId2, origin_, + kFrameTreeNodeId, /*incognito*/ false, base::BindOnce(&CastActivityManagerTest::ExpectLaunchSessionSuccess, base::Unretained(this)), @@ -661,7 +664,8 @@ // Use LaunchSessionParsed() instead of LaunchSession() here because // LaunchSessionParsed() is called asynchronously and will fail the test. manager_->LaunchSessionParsed( - *source, sink2_, kPresentationId2, origin_, kTabId, /*incognito*/ + *source, sink2_, kPresentationId2, origin_, + kFrameTreeNodeId, /*incognito*/ false, base::BindOnce(&CastActivityManagerTest::ExpectLaunchSessionSuccess, base::Unretained(this)), @@ -803,7 +807,8 @@ EXPECT_EQ(mojom::RouteRequestResultCode::CANCELLED, code); })); for (int i = 0; i < 2; i++) { - manager_->LaunchSession(*source, sink_, kPresentationId, origin_, kTabId, + manager_->LaunchSession(*source, sink_, kPresentationId, origin_, + kFrameTreeNodeId, /*incognito*/ false, base::BindOnce(&MockLaunchSessionCallback::Run, base::Unretained(&callback)));
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc b/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc index fd1afef5..97ed863 100644 --- a/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc +++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
@@ -106,7 +106,7 @@ const std::string& sink_id, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, CreateRouteCallback callback) { @@ -136,15 +136,15 @@ mojom::RouteRequestResultCode::NO_SUPPORTED_PROVIDER); return; } - activity_manager_->LaunchSession(*cast_source, *sink, presentation_id, origin, - tab_id, incognito, std::move(callback)); + frame_tree_node_id, incognito, + std::move(callback)); } void CastMediaRouteProvider::JoinRoute(const std::string& media_source, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, JoinRouteCallback callback) { @@ -175,9 +175,9 @@ mojom::RouteRequestResultCode::UNKNOWN_ERROR); return; } - - activity_manager_->JoinSession(*cast_source, presentation_id, origin, tab_id, - incognito, std::move(callback)); + activity_manager_->JoinSession(*cast_source, presentation_id, origin, + frame_tree_node_id, incognito, + std::move(callback)); } void CastMediaRouteProvider::TerminateRoute(const std::string& route_id,
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider.h b/chrome/browser/media/router/providers/cast/cast_media_route_provider.h index 76d6953..8411d2c 100644 --- a/chrome/browser/media/router/providers/cast/cast_media_route_provider.h +++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider.h
@@ -57,14 +57,14 @@ const std::string& sink_id, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, CreateRouteCallback callback) override; void JoinRoute(const std::string& media_source, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, JoinRouteCallback callback) override;
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc b/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc index 520c64f..1fa7724e 100644 --- a/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc +++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc
@@ -39,7 +39,7 @@ "\"mobile\"}"; static constexpr char kPresentationId[] = "presentationId"; static constexpr char kOrigin[] = "https://www.youtube.com"; -static constexpr int kTabId = 1; +static constexpr int kFrameTreeNodeId = 1; static constexpr base::TimeDelta kRouteTimeout = base::Seconds(30); base::Value MakeReceiverStatus() { @@ -194,7 +194,8 @@ TEST_F(CastMediaRouteProviderTest, CreateRouteFailsInvalidSink) { // Sink does not exist. provider_->CreateRoute( - kCastSource, "sinkId", kPresentationId, origin_, kTabId, kRouteTimeout, + kCastSource, "sinkId", kPresentationId, origin_, kFrameTreeNodeId, + kRouteTimeout, /* incognito */ false, base::BindOnce(&CastMediaRouteProviderTest::ExpectCreateRouteFailure, base::Unretained(this), @@ -206,8 +207,8 @@ media_sink_service_.AddOrUpdateSink(sink); provider_->CreateRoute( - "invalidSource", sink.sink().id(), kPresentationId, origin_, kTabId, - kRouteTimeout, /* incognito */ false, + "invalidSource", sink.sink().id(), kPresentationId, origin_, + kFrameTreeNodeId, kRouteTimeout, /* incognito */ false, base::BindOnce(&CastMediaRouteProviderTest::ExpectCreateRouteFailure, base::Unretained(this), mojom::RouteRequestResultCode::NO_SUPPORTED_PROVIDER)); @@ -226,7 +227,7 @@ launch_session_callback_ = std::move(callback); })); provider_->CreateRoute( - kCastSource, sink.sink().id(), kPresentationId, origin_, kTabId, + kCastSource, sink.sink().id(), kPresentationId, origin_, kFrameTreeNodeId, kRouteTimeout, /* incognito */ false, base::BindOnce( &CastMediaRouteProviderTest::ExpectCreateRouteSuccessAndSetRoute, @@ -245,7 +246,7 @@ launch_session_callback_ = std::move(callback); })); provider_->CreateRoute( - kCastSource, sink.sink().id(), kPresentationId, origin_, kTabId, + kCastSource, sink.sink().id(), kPresentationId, origin_, kFrameTreeNodeId, kRouteTimeout, /* incognito */ false, base::BindOnce( &CastMediaRouteProviderTest::ExpectCreateRouteSuccessAndSetRoute,
diff --git a/chrome/browser/media/router/providers/cast/cast_session_client.cc b/chrome/browser/media/router/providers/cast/cast_session_client.cc index c3f10545..4fcb8a09 100644 --- a/chrome/browser/media/router/providers/cast/cast_session_client.cc +++ b/chrome/browser/media/router/providers/cast/cast_session_client.cc
@@ -8,8 +8,10 @@ CastSessionClient::CastSessionClient(const std::string& client_id, const url::Origin& origin, - int tab_id) - : client_id_(client_id), origin_(origin), tab_id_(tab_id) {} + int frame_tree_node_id) + : client_id_(client_id), + origin_(origin), + frame_tree_node_id_(frame_tree_node_id) {} CastSessionClient::~CastSessionClient() = default;
diff --git a/chrome/browser/media/router/providers/cast/cast_session_client.h b/chrome/browser/media/router/providers/cast/cast_session_client.h index 22ae7869..4eb3037 100644 --- a/chrome/browser/media/router/providers/cast/cast_session_client.h +++ b/chrome/browser/media/router/providers/cast/cast_session_client.h
@@ -27,7 +27,7 @@ public: CastSessionClient(const std::string& client_id, const url::Origin& origin, - int tab_id); + int frame_tree_node_id); CastSessionClient(const CastSessionClient&) = delete; CastSessionClient& operator=(const CastSessionClient&) = delete; virtual ~CastSessionClient(); @@ -35,7 +35,7 @@ const std::string& client_id() const { return client_id_; } const absl::optional<std::string>& session_id() const { return session_id_; } const url::Origin& origin() const { return origin_; } - int tab_id() const { return tab_id_; } + int frame_tree_node_id() const { return frame_tree_node_id_; } // Initializes the PresentationConnection Mojo message pipes and returns the // handles of the two pipes to be held by Blink. Also transitions the @@ -59,17 +59,18 @@ blink::mojom::PresentationConnectionCloseReason close_reason) = 0; virtual void TerminateConnection() = 0; - // Tests whether the specified origin and tab ID match this session's origin - // and tab ID to the extent required by this sesssion's auto-join policy. - // Depending on the value of |auto_join_policy_|, |origin|, |tab_id|, or both - // may be ignored. + // Tests whether the specified origin and FrameTreeNode ID match this + // session's origin and FrameTreeNode ID to the extent required by this + // sesssion's auto-join policy. Depending on the value of |auto_join_policy_|, + // |origin|, |frame_tree_node_id_|, or both may be ignored. // // TODO(crbug.com/1291742): It appears the purpose of this method is to detect // whether this session was created by an auto-join request. It might make // more sense to record at session creation time whether a particular session // was created by an auto-join request, in which case this method would no // longer be needed. - virtual bool MatchesAutoJoinPolicy(url::Origin origin, int tab_id) const = 0; + virtual bool MatchesAutoJoinPolicy(url::Origin origin, + int frame_tree_node_id) const = 0; virtual void SendErrorCodeToClient( int sequence_number, @@ -85,10 +86,10 @@ std::string client_id_; absl::optional<std::string> session_id_; - // The origin and tab ID parameters originally passed to the CreateRoute - // method of the MediaRouteProvider Mojo interface. + // The origin and FrameTreeNode ID parameters originally passed to the + // CreateRoute method of the MediaRouteProvider Mojo interface. url::Origin origin_; - int tab_id_; + int frame_tree_node_id_; }; class CastSessionClientFactoryForTest { @@ -96,7 +97,7 @@ virtual std::unique_ptr<CastSessionClient> MakeClientForTest( const std::string& client_id, const url::Origin& origin, - int tab_id) = 0; + int frame_tree_node_id) = 0; }; } // namespace media_router
diff --git a/chrome/browser/media/router/providers/cast/cast_session_client_impl.cc b/chrome/browser/media/router/providers/cast/cast_session_client_impl.cc index 71ca9b1..00552639 100644 --- a/chrome/browser/media/router/providers/cast/cast_session_client_impl.cc +++ b/chrome/browser/media/router/providers/cast/cast_session_client_impl.cc
@@ -51,10 +51,10 @@ CastSessionClientImpl::CastSessionClientImpl(const std::string& client_id, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, AutoJoinPolicy auto_join_policy, CastActivity* activity) - : CastSessionClient(client_id, origin, tab_id), + : CastSessionClient(client_id, origin, frame_tree_node_id), auto_join_policy_(auto_join_policy), activity_(activity) {} @@ -98,13 +98,15 @@ CreateV2Message(client_id(), media_status, sequence_number)); } -bool CastSessionClientImpl::MatchesAutoJoinPolicy(url::Origin other_origin, - int other_tab_id) const { +bool CastSessionClientImpl::MatchesAutoJoinPolicy( + url::Origin other_origin, + int other_frame_tree_node_id) const { switch (auto_join_policy_) { case AutoJoinPolicy::kPageScoped: return false; case AutoJoinPolicy::kTabAndOriginScoped: - return other_origin == origin() && other_tab_id == tab_id(); + return other_origin == origin() && + other_frame_tree_node_id == frame_tree_node_id(); case AutoJoinPolicy::kOriginScoped: return other_origin == origin(); }
diff --git a/chrome/browser/media/router/providers/cast/cast_session_client_impl.h b/chrome/browser/media/router/providers/cast/cast_session_client_impl.h index 150fa79..27a46225 100644 --- a/chrome/browser/media/router/providers/cast/cast_session_client_impl.h +++ b/chrome/browser/media/router/providers/cast/cast_session_client_impl.h
@@ -20,7 +20,7 @@ public: CastSessionClientImpl(const std::string& client_id, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, AutoJoinPolicy auto_join_policy, CastActivity* activity); ~CastSessionClientImpl() override; @@ -36,7 +36,8 @@ void CloseConnection( blink::mojom::PresentationConnectionCloseReason close_reason) override; void TerminateConnection() override; - bool MatchesAutoJoinPolicy(url::Origin origin, int tab_id) const override; + bool MatchesAutoJoinPolicy(url::Origin origin, + int frame_tree_node_id) const override; void SendErrorCodeToClient(int sequence_number, CastInternalMessage::ErrorCode error_code, absl::optional<std::string> description) override;
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity.cc b/chrome/browser/media/router/providers/cast/mirroring_activity.cc index edd0a7a..f08cecc 100644 --- a/chrome/browser/media/router/providers/cast/mirroring_activity.cc +++ b/chrome/browser/media/router/providers/cast/mirroring_activity.cc
@@ -93,13 +93,8 @@ } } -// Get the mirroring type for a media route. Note that |target_tab_id| is -// usually ignored here, because mirroring typically only happens with a special -// URL that includes the tab ID it needs, which should be the same as the tab ID -// selected by the media router. absl::optional<MirroringActivity::MirroringType> GetMirroringType( - const MediaRoute& route, - int target_tab_id) { + const MediaRoute& route) { if (!route.is_local()) return absl::nullopt; @@ -109,28 +104,23 @@ if (source.IsDesktopMirroringSource()) return MirroringActivity::MirroringType::kDesktop; - if (source.url().is_valid()) { - if (source.IsCastPresentationUrl()) { - const auto cast_source = CastMediaSource::FromMediaSource(source); - if (cast_source && cast_source->ContainsStreamingApp()) { - // This is a weird case. Normally if the source is a presentation URL, - // we use 2-UA mode rather than mirroring, but if the app ID it - // specifies is one of the special streaming app IDs, we activate - // mirroring instead. This only happens when a Cast SDK client requests - // a mirroring app ID, which causes its own tab to be mirrored. This is - // a strange thing to do and it's not officially supported, but some - // apps, like, Google Slides rely on it. Unlike a proper tab-based - // MediaSource, this kind of MediaSource doesn't specify a tab in the - // URL, so we choose the tab that was active when the request was made. - DCHECK_GE(target_tab_id, 0); - return MirroringActivity::MirroringType::kTab; - } else { - NOTREACHED() << "Non-mirroring Cast app: " << source; - return absl::nullopt; - } - } else if (source.url().SchemeIsHTTPOrHTTPS()) { - return MirroringActivity::MirroringType::kOffscreenTab; + if (!source.url().is_valid()) { + NOTREACHED() << "Invalid source: " << source; + return absl::nullopt; + } + + if (source.IsCastPresentationUrl()) { + const auto cast_source = CastMediaSource::FromMediaSource(source); + if (cast_source && cast_source->ContainsStreamingApp()) { + // Site-initiated Mirroring has a Cast Presentatino URL and contains + // StreamingApp. We should return Tab Mirroring here. + return MirroringActivity::MirroringType::kTab; + } else { + NOTREACHED() << "Non-mirroring Cast app: " << source; + return absl::nullopt; } + } else if (source.url().SchemeIsHTTPOrHTTPS()) { + return MirroringActivity::MirroringType::kOffscreenTab; } NOTREACHED() << "Invalid source: " << source; @@ -144,16 +134,14 @@ const std::string& app_id, cast_channel::CastMessageHandler* message_handler, CastSessionTracker* session_tracker, - int target_tab_id, + int frame_tree_node_id, const CastSinkExtraData& cast_data, OnStopCallback callback) : CastActivity(route, app_id, message_handler, session_tracker), - mirroring_type_(GetMirroringType(route, target_tab_id)), + mirroring_type_(GetMirroringType(route)), + frame_tree_node_id_(frame_tree_node_id), cast_data_(cast_data), - on_stop_(std::move(callback)) { - if (target_tab_id != -1) - mirroring_tab_id_ = target_tab_id; -} + on_stop_(std::move(callback)) {} MirroringActivity::~MirroringActivity() { if (!did_start_mirroring_timestamp_) { @@ -198,13 +186,12 @@ auto stream_id = route_.media_source().DesktopStreamId(); DCHECK(stream_id); media_router->GetMirroringServiceHostForDesktop( - /* tab_id */ -1, *stream_id, host_.BindNewPipeAndPassReceiver()); + *stream_id, host_.BindNewPipeAndPassReceiver()); break; } case MirroringType::kTab: - DCHECK(mirroring_tab_id_.has_value()); media_router->GetMirroringServiceHostForTab( - *mirroring_tab_id_, host_.BindNewPipeAndPassReceiver()); + frame_tree_node_id_, host_.BindNewPipeAndPassReceiver()); break; case MirroringType::kOffscreenTab: media_router->GetMirroringServiceHostForOffscreenTab(
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity.h b/chrome/browser/media/router/providers/cast/mirroring_activity.h index 46ca250..152c3f37 100644 --- a/chrome/browser/media/router/providers/cast/mirroring_activity.h +++ b/chrome/browser/media/router/providers/cast/mirroring_activity.h
@@ -48,7 +48,7 @@ const std::string& app_id, cast_channel::CastMessageHandler* message_handler, CastSessionTracker* session_tracker, - int target_tab_id, + int frame_tree_node_id, const CastSinkExtraData& cast_data, OnStopCallback callback); ~MirroringActivity() override; @@ -114,6 +114,9 @@ absl::optional<base::Time> did_start_mirroring_timestamp_; const absl::optional<MirroringType> mirroring_type_; + + // The FrameTreeNode ID to retrieve the WebContents of the tab to mirror. + const int frame_tree_node_id_; const CastSinkExtraData cast_data_; OnStopCallback on_stop_; base::WeakPtrFactory<MirroringActivity> weak_ptr_factory_{this};
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity_unittest.cc b/chrome/browser/media/router/providers/cast/mirroring_activity_unittest.cc index bd19fb2..684606e 100644 --- a/chrome/browser/media/router/providers/cast/mirroring_activity_unittest.cc +++ b/chrome/browser/media/router/providers/cast/mirroring_activity_unittest.cc
@@ -31,7 +31,8 @@ namespace media_router { namespace { -constexpr int kTabId = 123; +constexpr int kFrameTreeNodeId = 123; +constexpr int kTabId = 234; constexpr char kDescription[] = ""; constexpr char kDesktopMediaId[] = "theDesktopMediaId"; constexpr char kPresentationId[] = "thePresentationId"; @@ -84,16 +85,18 @@ std::move(receiver)); }; ON_CALL(media_router_, GetMirroringServiceHostForDesktop) - .WillByDefault(WithArg<2>(make_mirroring_service)); + .WillByDefault(WithArg<1>(make_mirroring_service)); ON_CALL(media_router_, GetMirroringServiceHostForTab) .WillByDefault(WithArg<1>(make_mirroring_service)); ON_CALL(media_router_, GetMirroringServiceHostForOffscreenTab) .WillByDefault(WithArg<2>(make_mirroring_service)); } - void MakeActivity() { MakeActivity(MediaSource::ForTab(kTabId), kTabId); } + void MakeActivity() { MakeActivity(MediaSource::ForTab(kTabId)); } - void MakeActivity(const MediaSource& source, int tab_id = -1, + void MakeActivity( + const MediaSource& source, + int frame_tree_node_id = kFrameTreeNodeId, CastDiscoveryType discovery_type = CastDiscoveryType::kMdns) { CastSinkExtraData cast_data; cast_data.cast_channel_id = kChannelId; @@ -102,8 +105,8 @@ MediaRoute route(kRouteId, source, kSinkId, kDescription, route_is_local_); route.set_presentation_id(kPresentationId); activity_ = std::make_unique<MirroringActivity>( - route, kAppId, &message_handler_, &session_tracker_, kTabId, cast_data, - on_stop_.Get()); + route, kAppId, &message_handler_, &session_tracker_, frame_tree_node_id, + cast_data, on_stop_.Get()); activity_->CreateMojoBindings(&media_router_); @@ -140,7 +143,7 @@ TEST_F(MirroringActivityTest, MirrorDesktop) { base::HistogramTester uma_recorder; EXPECT_CALL(media_router_, - GetMirroringServiceHostForDesktop(_, kDesktopMediaId, _)); + GetMirroringServiceHostForDesktop(kDesktopMediaId, _)); MediaSource source = MediaSource::ForDesktop(kDesktopMediaId, true); ASSERT_TRUE(source.IsDesktopMirroringSource()); MakeActivity(source); @@ -157,10 +160,11 @@ TEST_F(MirroringActivityTest, MirrorTab) { base::HistogramTester uma_recorder; - EXPECT_CALL(media_router_, GetMirroringServiceHostForTab(kTabId, _)); + EXPECT_CALL(media_router_, + GetMirroringServiceHostForTab(kFrameTreeNodeId, _)); MediaSource source = MediaSource::ForTab(kTabId); ASSERT_TRUE(source.IsTabMirroringSource()); - MakeActivity(source, kTabId); + MakeActivity(source); activity_->DidStart(); activity_.reset(); @@ -174,12 +178,13 @@ TEST_F(MirroringActivityTest, CreateMojoBindingsForTabWithCastAppUrl) { base::HistogramTester uma_recorder; - EXPECT_CALL(media_router_, GetMirroringServiceHostForTab(kTabId, _)); + EXPECT_CALL(media_router_, + GetMirroringServiceHostForTab(kFrameTreeNodeId, _)); auto site_initiated_mirroring_source = CastMediaSource::ForSiteInitiatedMirroring(); MediaSource source(site_initiated_mirroring_source->source_id()); ASSERT_TRUE(source.IsCastPresentationUrl()); - MakeActivity(source, kTabId); + MakeActivity(source); activity_->DidStart(); activity_.reset(); @@ -213,10 +218,12 @@ TEST_F(MirroringActivityTest, MirrorAccessCode) { base::HistogramTester uma_recorder; - EXPECT_CALL(media_router_, GetMirroringServiceHostForTab(kTabId, _)); + EXPECT_CALL(media_router_, + GetMirroringServiceHostForTab(kFrameTreeNodeId, _)); MediaSource source = MediaSource::ForTab(kTabId); ASSERT_TRUE(source.IsTabMirroringSource()); - MakeActivity(source, kTabId, CastDiscoveryType::kAccessCodeManualEntry); + MakeActivity(source, kFrameTreeNodeId, + CastDiscoveryType::kAccessCodeManualEntry); activity_->DidStart(); activity_.reset();
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc index 0c9ab5c..8a3f6973 100644 --- a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc +++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
@@ -83,7 +83,8 @@ const std::string& sink_id, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, + base::TimeDelta timeout, bool incognito, CreateRouteCallback callback) { @@ -152,7 +153,7 @@ void DialMediaRouteProvider::JoinRoute(const std::string& media_source, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, JoinRouteCallback callback) {
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider.h b/chrome/browser/media/router/providers/dial/dial_media_route_provider.h index 1ead2ac..8f048a1 100644 --- a/chrome/browser/media/router/providers/dial/dial_media_route_provider.h +++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider.h
@@ -72,14 +72,14 @@ const std::string& sink_id, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, CreateRouteCallback callback) override; void JoinRoute(const std::string& media_source, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, JoinRouteCallback callback) override;
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc b/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc index 7a63369..83bf78e 100644 --- a/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc +++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc
@@ -36,6 +36,10 @@ namespace media_router { +namespace { +static constexpr int kFrameTreeNodeId = 1; +} + class TestDialMediaSinkServiceImpl : public DialMediaSinkServiceImpl { public: TestDialMediaSinkServiceImpl() @@ -150,7 +154,8 @@ // CreateRoute, but MR will add the route returned in the response. EXPECT_CALL(mock_router_, OnRoutesUpdated(_, _)).Times(0); provider_->CreateRoute( - source_id, sink_id, presentation_id, origin_, 1, base::TimeDelta(), + source_id, sink_id, presentation_id, origin_, kFrameTreeNodeId, + base::TimeDelta(), /* off_the_record */ false, base::BindOnce(&DialMediaRouteProviderTest::ExpectRouteResult, base::Unretained(this), @@ -203,7 +208,7 @@ client_incognito ? *client_incognito : route_->is_off_the_record(); provider_->JoinRoute( - source, presentation, origin, /*tab_id*/ 5, base::TimeDelta(), + source, presentation, origin, kFrameTreeNodeId, base::TimeDelta(), incognito, base::BindOnce(&DialMediaRouteProviderTest::ExpectRouteResult, base::Unretained(this), expected_result));
diff --git a/chrome/browser/media/router/providers/test/test_media_route_provider.cc b/chrome/browser/media/router/providers/test/test_media_route_provider.cc index 9148be1..7857918 100644 --- a/chrome/browser/media/router/providers/test/test_media_route_provider.cc +++ b/chrome/browser/media/router/providers/test/test_media_route_provider.cc
@@ -71,7 +71,7 @@ const std::string& sink_id, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, CreateRouteCallback callback) { @@ -85,8 +85,8 @@ GetWeakPtr(), std::move(callback)), delay_); } else { - DVLOG(2) << "CreateRoute with origin: " << origin << " and tab ID " - << tab_id; + DVLOG(2) << "CreateRoute with origin: " << origin + << " and FrameTreeNode ID " << frame_tree_node_id; MediaRoute route(presentation_id, MediaSource(media_source), sink_id, std::string("Test Route"), true); route.set_presentation_id(presentation_id); @@ -115,7 +115,7 @@ void TestMediaRouteProvider::JoinRoute(const std::string& media_source, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, JoinRouteCallback callback) {
diff --git a/chrome/browser/media/router/providers/test/test_media_route_provider.h b/chrome/browser/media/router/providers/test/test_media_route_provider.h index c1731ec..3bb32637 100644 --- a/chrome/browser/media/router/providers/test/test_media_route_provider.h +++ b/chrome/browser/media/router/providers/test/test_media_route_provider.h
@@ -36,14 +36,14 @@ const std::string& sink_id, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, CreateRouteCallback callback) override; void JoinRoute(const std::string& media_source, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool incognito, JoinRouteCallback callback) override;
diff --git a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc index 8416b20..8b32777 100644 --- a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc +++ b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc
@@ -95,7 +95,7 @@ const std::string& sink_id, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool off_the_record, CreateRouteCallback callback) { @@ -132,7 +132,7 @@ const std::string& media_source, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool off_the_record, JoinRouteCallback callback) {
diff --git a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h index 3e05bf49..0bdbcead 100644 --- a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h +++ b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h
@@ -61,14 +61,14 @@ const std::string& sink_id, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool off_the_record, CreateRouteCallback callback) override; void JoinRoute(const std::string& media_source, const std::string& presentation_id, const url::Origin& origin, - int32_t tab_id, + int32_t frame_tree_node_id, base::TimeDelta timeout, bool off_the_record, JoinRouteCallback callback) override;
diff --git a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider_unittest.cc b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider_unittest.cc index 2347c146..54de256 100644 --- a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider_unittest.cc +++ b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider_unittest.cc
@@ -34,6 +34,8 @@ namespace { +static constexpr int kFrameTreeNodeId = 1; + class MockCallback { public: MOCK_METHOD4(CreateRoute, @@ -331,8 +333,8 @@ Start(presentation_id, GURL(kPresentationSource))); provider_remote_->CreateRoute( kPresentationSource, GetSinkId(secondary_display1_), presentation_id, - url::Origin::Create(GURL(kPresentationSource)), 0, base::Seconds(100), - false, + url::Origin::Create(GURL(kPresentationSource)), kFrameTreeNodeId, + base::Seconds(100), false, base::BindOnce(&MockCallback::CreateRoute, base::Unretained(&callback))); base::RunLoop().RunUntilIdle(); @@ -367,8 +369,8 @@ // Create a route for |presentation_id|. provider_remote_->CreateRoute( kPresentationSource, GetSinkId(secondary_display1_), presentation_id, - url::Origin::Create(GURL(kPresentationSource)), 0, base::Seconds(100), - false, + url::Origin::Create(GURL(kPresentationSource)), kFrameTreeNodeId, + base::Seconds(100), false, base::BindOnce(&MockCallback::CreateRoute, base::Unretained(&callback))); base::RunLoop().RunUntilIdle(); @@ -396,8 +398,8 @@ provider_remote_->CreateRoute( kPresentationSource, GetSinkId(secondary_display1_), "presentationId", - url::Origin::Create(GURL(kPresentationSource)), 0, base::Seconds(100), - false, + url::Origin::Create(GURL(kPresentationSource)), kFrameTreeNodeId, + base::Seconds(100), false, base::BindOnce(&MockCallback::CreateRoute, base::Unretained(&callback))); base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/media/router/test/media_router_mojo_test.cc b/chrome/browser/media/router/test/media_router_mojo_test.cc index d20ebe7..c87d4bb 100644 --- a/chrome/browser/media/router/test/media_router_mojo_test.cc +++ b/chrome/browser/media/router/test/media_router_mojo_test.cc
@@ -15,6 +15,7 @@ using testing::NiceMock; using testing::Not; using testing::Pointee; +using testing::WithArg; namespace media_router { @@ -27,7 +28,7 @@ const char kRouteId[] = "routeId"; const char kSource[] = "source1"; const char kSinkId[] = "sink"; -const int kInvalidTabId = -1; +const int kInvalidFrameTreeNodeId = -1; const int kTimeoutMillis = 5 * 1000; const uint8_t kBinaryMessage[] = {0x01, 0x02, 0x03, 0x04}; @@ -177,15 +178,12 @@ EXPECT_CALL(mock_cast_provider_, CreateRouteInternal(kSource, kSinkId, _, url::Origin::Create(GURL(kOrigin)), - kInvalidTabId, _, _, _)) - .WillOnce(Invoke([](const std::string& source, const std::string& sink, - const std::string& presentation_id, - const url::Origin& origin, int tab_id, - base::TimeDelta timeout, bool incognito, - mojom::MediaRouteProvider::CreateRouteCallback& cb) { - std::move(cb).Run(CreateMediaRoute(), nullptr, std::string(), - mojom::RouteRequestResultCode::OK); - })); + kInvalidFrameTreeNodeId, _, _, _)) + .WillOnce(WithArg<7>( + Invoke([](mojom::MediaRouteProvider::CreateRouteCallback& cb) { + std::move(cb).Run(CreateMediaRoute(), nullptr, std::string(), + mojom::RouteRequestResultCode::OK); + }))); RouteResponseCallbackHandler handler; EXPECT_CALL(handler, DoInvoke(Pointee(expected_route), Not(""), "", @@ -217,18 +215,15 @@ // a limitation with GMock::Invoke that prevents it from using move-only types // in runnable parameter lists. EXPECT_CALL(mock_cast_provider_, - JoinRouteInternal( - kSource, presentation_id, url::Origin::Create(GURL(kOrigin)), - kInvalidTabId, base::Milliseconds(kTimeoutMillis), _, _)) - .WillOnce( - Invoke([&route](const std::string& source, - const std::string& presentation_id, - const url::Origin& origin, int tab_id, - base::TimeDelta timeout, bool incognito, - mojom::MediaRouteProvider::JoinRouteCallback& cb) { + JoinRouteInternal(kSource, presentation_id, + url::Origin::Create(GURL(kOrigin)), + kInvalidFrameTreeNodeId, + base::Milliseconds(kTimeoutMillis), _, _)) + .WillOnce(WithArg<6>( + Invoke([&route](mojom::MediaRouteProvider::JoinRouteCallback& cb) { std::move(cb).Run(route, nullptr, std::string(), mojom::RouteRequestResultCode::OK); - })); + }))); RouteResponseCallbackHandler handler; EXPECT_CALL(handler, DoInvoke(Pointee(expected_route), Not(""), "",
diff --git a/chrome/browser/media/router/test/media_router_mojo_test.h b/chrome/browser/media/router/test/media_router_mojo_test.h index eef6b08d..542da93 100644 --- a/chrome/browser/media/router/test/media_router_mojo_test.h +++ b/chrome/browser/media/router/test/media_router_mojo_test.h
@@ -47,41 +47,43 @@ const std::string& sink_id, const std::string& presentation_id, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, base::TimeDelta timeout, bool incognito, CreateRouteCallback callback) override { - CreateRouteInternal(source_urn, sink_id, presentation_id, origin, tab_id, - timeout, incognito, callback); + CreateRouteInternal(source_urn, sink_id, presentation_id, origin, + frame_tree_node_id, timeout, incognito, callback); } - MOCK_METHOD8(CreateRouteInternal, - void(const std::string& source_urn, - const std::string& sink_id, - const std::string& presentation_id, - const url::Origin& origin, - int tab_id, - base::TimeDelta timeout, - bool incognito, - CreateRouteCallback& callback)); + MOCK_METHOD(void, + CreateRouteInternal, + (const std::string& source_urn, + const std::string& sink_id, + const std::string& presentation_id, + const url::Origin& origin, + int frame_tree_node_id, + base::TimeDelta timeout, + bool incognito, + CreateRouteCallback& callback)); void JoinRoute(const std::string& source_urn, const std::string& presentation_id, const url::Origin& origin, - int tab_id, + int frame_tree_node_id, base::TimeDelta timeout, bool incognito, JoinRouteCallback callback) override { - JoinRouteInternal(source_urn, presentation_id, origin, tab_id, timeout, - incognito, callback); + JoinRouteInternal(source_urn, presentation_id, origin, frame_tree_node_id, + timeout, incognito, callback); } - MOCK_METHOD7(JoinRouteInternal, - void(const std::string& source_urn, - const std::string& presentation_id, - const url::Origin& origin, - int tab_id, - base::TimeDelta timeout, - bool incognito, - JoinRouteCallback& callback)); - MOCK_METHOD1(DetachRoute, void(const std::string& route_id)); + MOCK_METHOD(void, + JoinRouteInternal, + (const std::string& source_urn, + const std::string& presentation_id, + const url::Origin& origin, + int frame_tree_node_id, + base::TimeDelta timeout, + bool incognito, + JoinRouteCallback& callback)); + MOCK_METHOD(void, DetachRoute, (const std::string& route_id)); void TerminateRoute(const std::string& route_id, TerminateRouteCallback callback) override { TerminateRouteInternal(route_id, callback);
diff --git a/chrome/browser/media/router/test/mock_mojo_media_router.h b/chrome/browser/media/router/test/mock_mojo_media_router.h index dc08246..0b48b6a 100644 --- a/chrome/browser/media/router/test/mock_mojo_media_router.h +++ b/chrome/browser/media/router/test/mock_mojo_media_router.h
@@ -62,13 +62,12 @@ MOCK_METHOD0(GetMediaSinkServiceStatus, std::string()); MOCK_METHOD2( GetMirroringServiceHostForTab, - void(int32_t target_tab_id, + void(int32_t frame_tree_node_id, mojo::PendingReceiver<mirroring::mojom::MirroringServiceHost> receiver)); - MOCK_METHOD3( + MOCK_METHOD2( GetMirroringServiceHostForDesktop, - void(int32_t initiator_tab_id, - const std::string& desktop_stream_id, + void(const std::string& desktop_stream_id, mojo::PendingReceiver<mirroring::mojom::MirroringServiceHost> receiver)); MOCK_METHOD3(
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 537bf3c..30a326e 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -188,6 +188,10 @@ #include "components/spellcheck/browser/pref_names.h" #endif // BUILDFLAG(ENABLE_SPELLCHECK) +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) +#include "components/device_signals/core/browser/pref_names.h" +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) + #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_FUCHSIA) #include "chrome/browser/web_applications/policy/web_app_settings_policy_handler.h" @@ -1400,6 +1404,11 @@ prefs::kBackgroundModeEnabled, base::Value::Type::BOOLEAN }, #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) + { key::kUnmanagedDeviceSignalsConsentFlowEnabled, + device_signals::prefs::kUnmanagedDeviceSignalsConsentFlowEnabled, + base::Value::Type::BOOLEAN }, +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) \ || BUILDFLAG(IS_FUCHSIA) { key::kDefaultBrowserSettingEnabled,
diff --git a/chrome/browser/policy/networking/user_network_configuration_updater_factory.cc b/chrome/browser/policy/networking/user_network_configuration_updater_factory.cc index 6de7d79..014e52c 100644 --- a/chrome/browser/policy/networking/user_network_configuration_updater_factory.cc +++ b/chrome/browser/policy/networking/user_network_configuration_updater_factory.cc
@@ -89,7 +89,7 @@ return UserNetworkConfigurationUpdaterAsh::CreateForUserPolicy( profile, *user, profile->GetProfilePolicyConnector()->policy_service(), - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->managed_network_configuration_handler()) .release(); }
diff --git a/chrome/browser/power_bookmarks/DEPS b/chrome/browser/power_bookmarks/DEPS new file mode 100644 index 0000000..9bcdd2e --- /dev/null +++ b/chrome/browser/power_bookmarks/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+components/power_bookmarks", +] \ No newline at end of file
diff --git a/chrome/browser/power_bookmarks/OWNERS b/chrome/browser/power_bookmarks/OWNERS new file mode 100644 index 0000000..9c8001ff --- /dev/null +++ b/chrome/browser/power_bookmarks/OWNERS
@@ -0,0 +1 @@ +file://components/power_bookmarks/OWNERS
diff --git a/chrome/browser/power_bookmarks/power_bookmark_service_factory.cc b/chrome/browser/power_bookmarks/power_bookmark_service_factory.cc new file mode 100644 index 0000000..77a0ad6 --- /dev/null +++ b/chrome/browser/power_bookmarks/power_bookmark_service_factory.cc
@@ -0,0 +1,33 @@ +// Copyright 2022 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/power_bookmarks/power_bookmark_service_factory.h" + +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/power_bookmarks/core/power_bookmark_service.h" + +// static +power_bookmarks::PowerBookmarkService* +PowerBookmarkServiceFactory::GetForBrowserContext( + content::BrowserContext* context) { + return static_cast<power_bookmarks::PowerBookmarkService*>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +PowerBookmarkServiceFactory* PowerBookmarkServiceFactory::GetInstance() { + return base::Singleton<PowerBookmarkServiceFactory>::get(); +} + +PowerBookmarkServiceFactory::PowerBookmarkServiceFactory() + : BrowserContextKeyedServiceFactory( + "PowerBookmarkService", + BrowserContextDependencyManager::GetInstance()) {} + +PowerBookmarkServiceFactory::~PowerBookmarkServiceFactory() = default; + +KeyedService* PowerBookmarkServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new power_bookmarks::PowerBookmarkService(); +}
diff --git a/chrome/browser/power_bookmarks/power_bookmark_service_factory.h b/chrome/browser/power_bookmarks/power_bookmark_service_factory.h new file mode 100644 index 0000000..096bf3b --- /dev/null +++ b/chrome/browser/power_bookmarks/power_bookmark_service_factory.h
@@ -0,0 +1,37 @@ +// Copyright 2022 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_POWER_BOOKMARKS_POWER_BOOKMARK_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_POWER_BOOKMARKS_POWER_BOOKMARK_SERVICE_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +namespace power_bookmarks { +class PowerBookmarkService; +} + +// Factory to create one PowerBookmarkService per browser context. +class PowerBookmarkServiceFactory : public BrowserContextKeyedServiceFactory { + public: + static power_bookmarks::PowerBookmarkService* GetForBrowserContext( + content::BrowserContext* browser_context); + static PowerBookmarkServiceFactory* GetInstance(); + + PowerBookmarkServiceFactory(const PowerBookmarkServiceFactory&) = delete; + PowerBookmarkServiceFactory& operator=(const PowerBookmarkServiceFactory&) = + delete; + + private: + friend struct base::DefaultSingletonTraits<PowerBookmarkServiceFactory>; + + PowerBookmarkServiceFactory(); + ~PowerBookmarkServiceFactory() override; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; +}; + +#endif // CHROME_BROWSER_POWER_BOOKMARKS_POWER_BOOKMARK_SERVICE_FACTORY_H_
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 14a0582..08a3d7d 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -393,7 +393,6 @@ #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" #include "chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h" #include "chrome/browser/upgrade_detector/upgrade_detector_chromeos.h" -#include "chrome/browser/web_applications/externally_installed_web_app_prefs.h" #include "chromeos/ash/components/local_search_service/search_metrics_reporter.h" #include "chromeos/ash/components/network/cellular_esim_profile_handler_impl.h" #include "chromeos/ash/components/network/cellular_metrics_logger.h" @@ -439,9 +438,9 @@ #include "components/os_crypt/os_crypt.h" #endif -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \ - (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) #include "chrome/browser/web_applications/url_handler_prefs.h" +#include "components/device_signals/core/browser/pref_names.h" #endif // TODO(crbug.com/1052397): Revisit the macro expression once build flag switch @@ -747,6 +746,12 @@ const char kSettingsShowOSBanner[] = "settings.cros.show_os_banner"; #endif +#if BUILDFLAG(IS_CHROMEOS_ASH) +// Deprecated 08/2022. +constexpr char kSecurityTokenSessionNotificationDisplayed[] = + "security_token_session_notification_displayed"; +#endif + // Register local state used only for migration (clearing or moving to a new // key). void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) { @@ -971,6 +976,12 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) registry->RegisterBooleanPref(kSettingsShowOSBanner, false); #endif // BUILDFLAG(IS_CHROMEOS_ASH) + +#if BUILDFLAG(IS_CHROMEOS_ASH) + // Deprecated 08/2022 + registry->RegisterBooleanPref(kSecurityTokenSessionNotificationDisplayed, + false); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } } // namespace @@ -1191,10 +1202,9 @@ #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) #endif // BUILDFLAG(IS_WIN) -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \ - (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) web_app::url_handler_prefs::RegisterLocalStatePrefs(registry); -#endif +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) RegisterDefaultBrowserPromptPrefs(registry); @@ -1444,7 +1454,6 @@ ash::file_system_provider::RegisterProfilePrefs(registry); ash::full_restore::RegisterProfilePrefs(registry); ash::KerberosCredentialsManager::RegisterProfilePrefs(registry); - ash::login::SecurityTokenSessionController::RegisterProfilePrefs(registry); ash::multidevice_setup::MultiDeviceSetupService::RegisterProfilePrefs( registry); ash::MultiProfileUserController::RegisterProfilePrefs(registry); @@ -1507,6 +1516,10 @@ safe_browsing::PostCleanupSettingsResetter::RegisterProfilePrefs(registry); #endif +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) + device_signals::RegisterProfilePrefs(registry); +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) + // TODO(crbug.com/1052397): Revisit the macro expression once build flag switch // of lacros-chrome is complete. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \ @@ -1715,12 +1728,6 @@ profile_prefs->ClearPref(kCanShowFolderSelectionNudge); #endif // BUILDFLAG(IS_CHROMEOS_ASH) -#if BUILDFLAG(IS_CHROMEOS_ASH) - // Added 2021/08. - web_app::ExternallyInstalledWebAppPrefs::RemoveTerminalPWA(profile_prefs); - -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - #if !BUILDFLAG(IS_ANDROID) // Added 09/2021. profile_prefs->ClearPref(kNtpSearchSuggestionsBlocklist); @@ -1917,6 +1924,11 @@ profile_prefs->ClearPref(kSettingsShowOSBanner); #endif +#if BUILDFLAG(IS_CHROMEOS_ASH) + // Added 08/2022. + profile_prefs->ClearPref(kSecurityTokenSessionNotificationDisplayed); +#endif + // Please don't delete the following line. It is used by PRESUBMIT.py. // END_MIGRATE_OBSOLETE_PROFILE_PREFS
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation.js index 66bfdbc..e9b0860 100644 --- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation.js +++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation.js
@@ -151,7 +151,6 @@ // utterances added to the queue later. chrome.accessibilityPrivate.silenceSpokenFeedback(); } - this.startTone_.play(); this.setStopTimeout_( Dictation.Timeouts.NO_FOCUSED_IME_MS, 'Dictation stopped automatically: No focused IME'); @@ -310,6 +309,7 @@ return; } + this.startTone_.play(); this.clearInterimText_(); // Record metrics.
diff --git a/chrome/browser/resources/chromeos/arc_support/main.js b/chrome/browser/resources/chromeos/arc_support/main.js index c9809d1..53dcb0c7 100644 --- a/chrome/browser/resources/chromeos/arc_support/main.js +++ b/chrome/browser/resources/chromeos/arc_support/main.js
@@ -3,7 +3,6 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/hidden_style_css.m.js'; - import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/chromeos/crostini_upgrader/app.js b/chrome/browser/resources/chromeos/crostini_upgrader/app.js index 3ee924b..d510302 100644 --- a/chrome/browser/resources/chromeos/crostini_upgrader/app.js +++ b/chrome/browser/resources/chromeos/crostini_upgrader/app.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; import 'chrome://resources/polymer/v3_0/paper-progress/paper-progress.js'; import './strings.m.js';
diff --git a/chrome/browser/resources/chromeos/emulator/audio_settings.js b/chrome/browser/resources/chromeos/emulator/audio_settings.js index c904e4c..58ec2f7 100644 --- a/chrome/browser/resources/chromeos/emulator/audio_settings.js +++ b/chrome/browser/resources/chromeos/emulator/audio_settings.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
diff --git a/chrome/browser/resources/chromeos/emulator/battery_settings.js b/chrome/browser/resources/chromeos/emulator/battery_settings.js index 399df8c..f2c37f0 100644 --- a/chrome/browser/resources/chromeos/emulator/battery_settings.js +++ b/chrome/browser/resources/chromeos/emulator/battery_settings.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.m.js';
diff --git a/chrome/browser/resources/chromeos/emulator/bluetooth_settings.js b/chrome/browser/resources/chromeos/emulator/bluetooth_settings.js index 1af478a8..cdaf2b5 100644 --- a/chrome/browser/resources/chromeos/emulator/bluetooth_settings.js +++ b/chrome/browser/resources/chromeos/emulator/bluetooth_settings.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
diff --git a/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni b/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni index 243e576..d348bc38 100644 --- a/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni +++ b/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
@@ -92,9 +92,10 @@ ] oobe_migrated_imports = [ - "ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.html", + "ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html", "ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html", - "ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.html", "ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_icon.html", + "ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.html", "ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html", + "ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.html", ]
diff --git a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn index d511f71..7064d52 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn +++ b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn
@@ -440,7 +440,7 @@ "../../components/dialogs:oobe_adaptive_dialog.m", "../../components/dialogs:oobe_modal_dialog.m", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox.m", + "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox", "//ui/webui/resources/js:util.m", ] extra_deps = [ ":oobe_reset_module" ] @@ -667,6 +667,7 @@ html_file = "app_downloading.html" html_type = "dom-module" auto_imports = oobe_auto_imports + migrated_imports = oobe_migrated_imports namespace_rewrites = oobe_namespace_rewrites } @@ -683,6 +684,7 @@ html_file = "arc_terms_of_service.html" html_type = "dom-module" auto_imports = oobe_auto_imports + migrated_imports = oobe_migrated_imports namespace_rewrites = oobe_namespace_rewrites } @@ -773,6 +775,7 @@ html_type = "dom-module" auto_imports = oobe_auto_imports namespace_rewrites = oobe_namespace_rewrites + migrated_imports = oobe_migrated_imports } polymer_modulizer("managed_terms_of_service") { @@ -813,6 +816,7 @@ html_type = "dom-module" auto_imports = oobe_auto_imports namespace_rewrites = oobe_namespace_rewrites + migrated_imports = oobe_migrated_imports } polymer_modulizer("oobe_reset") { @@ -821,6 +825,7 @@ html_type = "dom-module" auto_imports = oobe_auto_imports namespace_rewrites = oobe_namespace_rewrites + migrated_imports = oobe_migrated_imports } polymer_modulizer("os_install") { @@ -861,6 +866,7 @@ html_type = "dom-module" auto_imports = oobe_auto_imports namespace_rewrites = oobe_namespace_rewrites + migrated_imports = oobe_migrated_imports } polymer_modulizer("user_creation") { @@ -901,6 +907,7 @@ html_type = "dom-module" auto_imports = oobe_auto_imports namespace_rewrites = oobe_namespace_rewrites + migrated_imports = oobe_migrated_imports } polymer_modulizer("theme_selection") {
diff --git a/chrome/browser/resources/chromeos/network_ui/network_logs_ui.js b/chrome/browser/resources/chromeos/network_ui/network_logs_ui.js index ee3afb6..10d74855 100644 --- a/chrome/browser/resources/chromeos/network_ui/network_logs_ui.js +++ b/chrome/browser/resources/chromeos/network_ui/network_logs_ui.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.m.js'; import 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.m.js'; import 'chrome://resources/cr_elements/shared_style_css.m.js';
diff --git a/chrome/browser/resources/chromeos/notification_tester/notification_tester.js b/chrome/browser/resources/chromeos/notification_tester/notification_tester.js index 53e02f5..790fbbc 100644 --- a/chrome/browser/resources/chromeos/notification_tester/notification_tester.js +++ b/chrome/browser/resources/chromeos/notification_tester/notification_tester.js
@@ -6,7 +6,7 @@ import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.m.js'; import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -296,4 +296,4 @@ } } -customElements.define(NotificationTester.is, NotificationTester); \ No newline at end of file +customElements.define(NotificationTester.is, NotificationTester);
diff --git a/chrome/browser/resources/extensions/extensions.ts b/chrome/browser/resources/extensions/extensions.ts index 5a20e92..4d1af5f 100644 --- a/chrome/browser/resources/extensions/extensions.ts +++ b/chrome/browser/resources/extensions/extensions.ts
@@ -4,7 +4,7 @@ import './manager.js'; -export {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +export {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; export {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.js'; export {IronIconElement} from 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; export {ActivityLogExtensionPlaceholder, ExtensionsActivityLogElement} from './activity_log/activity_log.js';
diff --git a/chrome/browser/resources/extensions/kiosk_dialog.ts b/chrome/browser/resources/extensions/kiosk_dialog.ts index cfa27051..0e39489 100644 --- a/chrome/browser/resources/extensions/kiosk_dialog.ts +++ b/chrome/browser/resources/extensions/kiosk_dialog.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/cr_icons_css.m.js'; @@ -11,7 +11,7 @@ import 'chrome://resources/cr_elements/shared_style_css.m.js'; import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import {assert} from 'chrome://resources/js/assert_ts.js';
diff --git a/chrome/browser/resources/history/history_item.ts b/chrome/browser/resources/history/history_item.ts index 8688389..e69fd49 100644 --- a/chrome/browser/resources/history/history_item.ts +++ b/chrome/browser/resources/history/history_item.ts
@@ -10,7 +10,7 @@ import 'chrome://resources/js/icon.js'; import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import {FocusRowBehavior} from 'chrome://resources/js/cr/ui/focus_row_behavior.m.js'; import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
diff --git a/chrome/browser/resources/history/lazy_load.ts b/chrome/browser/resources/history/lazy_load.ts index a6adfbee..5475200a 100644 --- a/chrome/browser/resources/history/lazy_load.ts +++ b/chrome/browser/resources/history/lazy_load.ts
@@ -5,7 +5,7 @@ import './synced_device_manager.js'; import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_drawer/cr_drawer.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
diff --git a/chrome/browser/resources/inline_login/welcome_page_app.js b/chrome/browser/resources/inline_login/welcome_page_app.js index 0486995c..eae22a9c 100644 --- a/chrome/browser/resources/inline_login/welcome_page_app.js +++ b/chrome/browser/resources/inline_login/welcome_page_app.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js'; import './account_manager_shared_css.js';
diff --git a/chrome/browser/resources/media_router/cast_feedback/cast_feedback_ui.ts b/chrome/browser/resources/media_router/cast_feedback/cast_feedback_ui.ts index 98bc4343..bc13a27 100644 --- a/chrome/browser/resources/media_router/cast_feedback/cast_feedback_ui.ts +++ b/chrome/browser/resources/media_router/cast_feedback/cast_feedback_ui.ts
@@ -4,7 +4,7 @@ import './strings.m.js'; import '//resources/cr_elements/cr_button/cr_button.m.js'; -import '//resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import '//resources/cr_elements/cr_checkbox/cr_checkbox.js'; import '//resources/cr_elements/cr_dialog/cr_dialog.m.js'; import '//resources/cr_elements/cr_input/cr_input.m.js'; import '//resources/cr_elements/cr_radio_button/cr_radio_button.m.js';
diff --git a/chrome/browser/resources/nearby_share/BUILD.gn b/chrome/browser/resources/nearby_share/BUILD.gn index acfc4e3..66db547 100644 --- a/chrome/browser/resources/nearby_share/BUILD.gn +++ b/chrome/browser/resources/nearby_share/BUILD.gn
@@ -181,7 +181,7 @@ "//chrome/browser/ui/webui/nearby_share:share_type_js_library_for_compile", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/cr_elements/cr_button:cr_button.m", - "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox.m", + "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox", "//ui/webui/resources/js:i18n_behavior.m", ] }
diff --git a/chrome/browser/resources/nearby_share/nearby_confirmation_page.js b/chrome/browser/resources/nearby_share/nearby_confirmation_page.js index a49d5c8..01ff5dc14 100644 --- a/chrome/browser/resources/nearby_share/nearby_confirmation_page.js +++ b/chrome/browser/resources/nearby_share/nearby_confirmation_page.js
@@ -9,7 +9,7 @@ */ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_lottie/cr_lottie.m.js'; import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js';
diff --git a/chrome/browser/resources/print_preview/print_preview.ts b/chrome/browser/resources/print_preview/print_preview.ts index ba0e02ba..7725442d 100644 --- a/chrome/browser/resources/print_preview/print_preview.ts +++ b/chrome/browser/resources/print_preview/print_preview.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. export {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -export {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +export {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; export {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; export {PluralStringProxyImpl as PrintPreviewPluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js'; export {IronMeta} from 'chrome://resources/polymer/v3_0/iron-meta/iron-meta.js';
diff --git a/chrome/browser/resources/print_preview/ui/advanced_settings_item.ts b/chrome/browser/resources/print_preview/ui/advanced_settings_item.ts index 8596e68d..71568abc 100644 --- a/chrome/browser/resources/print_preview/ui/advanced_settings_item.ts +++ b/chrome/browser/resources/print_preview/ui/advanced_settings_item.ts
@@ -3,14 +3,14 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/hidden_style_css.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import 'chrome://resources/cr_elements/search_highlight_style.css.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; import 'chrome://resources/cr_elements/md_select_css.m.js'; import './print_preview_shared.css.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/print_preview/ui/copies_settings.ts b/chrome/browser/resources/print_preview/ui/copies_settings.ts index 19cdc1b..3eb2e63 100644 --- a/chrome/browser/resources/print_preview/ui/copies_settings.ts +++ b/chrome/browser/resources/print_preview/ui/copies_settings.ts
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import './number_settings_section.js'; import './print_preview_shared.css.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/print_preview/ui/duplex_settings.ts b/chrome/browser/resources/print_preview/ui/duplex_settings.ts index e4aee956..d14470e 100644 --- a/chrome/browser/resources/print_preview/ui/duplex_settings.ts +++ b/chrome/browser/resources/print_preview/ui/duplex_settings.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/hidden_style_css.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/md_select_css.m.js'; import 'chrome://resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js'; import 'chrome://resources/polymer/v3_0/iron-meta/iron-meta.js'; @@ -11,7 +11,7 @@ import './print_preview_shared.css.js'; import './settings_section.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {IronMeta} from 'chrome://resources/polymer/v3_0/iron-meta/iron-meta.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/print_preview/ui/other_options_settings.ts b/chrome/browser/resources/print_preview/ui/other_options_settings.ts index 0024de0..1206452 100644 --- a/chrome/browser/resources/print_preview/ui/other_options_settings.ts +++ b/chrome/browser/resources/print_preview/ui/other_options_settings.ts
@@ -3,12 +3,12 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/hidden_style_css.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import './print_preview_shared.css.js'; import './settings_section.js'; import '../strings.m.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {I18nMixin} from 'chrome://resources/js/i18n_mixin.js'; import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/print_preview/ui/pin_settings.ts b/chrome/browser/resources/print_preview/ui/pin_settings.ts index 40ac96f..2643c4ea 100644 --- a/chrome/browser/resources/print_preview/ui/pin_settings.ts +++ b/chrome/browser/resources/print_preview/ui/pin_settings.ts
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js'; import './print_preview_shared.css.js'; import './settings_section.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import {I18nMixin} from 'chrome://resources/js/i18n_mixin.js'; import {WebUIListenerMixin} from 'chrome://resources/js/web_ui_listener_mixin.js';
diff --git a/chrome/browser/resources/settings/autofill_page/password_move_multiple_passwords_to_account_dialog.ts b/chrome/browser/resources/settings/autofill_page/password_move_multiple_passwords_to_account_dialog.ts index 5f42dcc..2e832a6 100644 --- a/chrome/browser/resources/settings/autofill_page/password_move_multiple_passwords_to_account_dialog.ts +++ b/chrome/browser/resources/settings/autofill_page/password_move_multiple_passwords_to_account_dialog.ts
@@ -11,7 +11,7 @@ import './avatar_icon.js'; import './password_list_item.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
diff --git a/chrome/browser/resources/settings/autofill_page/password_remove_dialog.ts b/chrome/browser/resources/settings/autofill_page/password_remove_dialog.ts index 69834ed..e5b2ef7b 100644 --- a/chrome/browser/resources/settings/autofill_page/password_remove_dialog.ts +++ b/chrome/browser/resources/settings/autofill_page/password_remove_dialog.ts
@@ -11,12 +11,12 @@ */ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/shared_style_css.m.js'; import './avatar_icon.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {assert} from 'chrome://resources/js/assert_ts.js'; import {I18nMixin} from 'chrome://resources/js/i18n_mixin.js';
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index 7acc984..bedd765 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -400,9 +400,7 @@ "controls/pref_control_mixin.js", "controls/settings_boolean_control_mixin.js", "extension_control_browser_proxy.js", - "i18n_setup.js", "icons.html.js", - "lifetime_browser_proxy.js", "open_window_proxy.js", "people_page/profile_info_browser_proxy.js", "people_page/sync_browser_proxy.js", @@ -494,7 +492,6 @@ "keyboard_shortcut_banner:closure_compile_module", "multidevice_page:closure_compile_module", "os_a11y_page:closure_compile_module", - "os_about_page:closure_compile_module", "os_apps_page:closure_compile_module", "os_apps_page/app_management_page:closure_compile_module", "os_apps_page/app_management_page/borealis_page:closure_compile_module",
diff --git a/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.js b/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.js index 4a70d8f..3313c23f 100644 --- a/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.js +++ b/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.js
@@ -8,7 +8,7 @@ */ import './album_list.js'; import './art_album_dialog.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_components/localized_link/localized_link.js'; import '../../settings_shared.css.js';
diff --git a/chrome/browser/resources/settings/chromeos/device_page/display.js b/chrome/browser/resources/settings/chromeos/device_page/display.js index ed1c7c1..b19cd37 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/display.js +++ b/chrome/browser/resources/settings/chromeos/device_page/display.js
@@ -7,7 +7,7 @@ * 'settings-display' is the settings subpage for display settings. */ -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js'; import 'chrome://resources/cr_elements/cr_tabs/cr_tabs.js'; import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js';
diff --git a/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_add_account_dialog.js b/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_add_account_dialog.js index 96393adc4..e40ac96 100644 --- a/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_add_account_dialog.js +++ b/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_add_account_dialog.js
@@ -8,7 +8,7 @@ */ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import 'chrome://resources/cr_elements/icons.m.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_about_page/BUILD.gn deleted file mode 100644 index c9536ab..0000000 --- a/chrome/browser/resources/settings/chromeos/os_about_page/BUILD.gn +++ /dev/null
@@ -1,106 +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. - -import("//third_party/closure_compiler/compile_js.gni") -import("../os_settings.gni") - -js_type_check("closure_compile_module") { - closure_flags = os_settings_closure_flags - is_polymer3 = true - deps = [ - ":about_page_browser_proxy", - ":channel_switcher_dialog", - ":consumer_auto_update_toggle_dialog", - ":detailed_build_info", - ":device_name_browser_proxy", - ":device_name_util", - ":edit_hostname_dialog", - ":os_about_page", - ":update_warning_dialog", - ] -} - -js_library("about_page_browser_proxy") { - deps = [ "//ui/webui/resources/js:cr.m" ] -} - -js_library("channel_switcher_dialog") { - deps = [ - ":about_page_browser_proxy", - "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/js:assert.m", - "//ui/webui/resources/js:load_time_data.m", - ] -} - -js_library("consumer_auto_update_toggle_dialog") { - deps = [ - "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - ] -} - -js_library("detailed_build_info") { - deps = [ - ":about_page_browser_proxy", - ":channel_switcher_dialog", - ":consumer_auto_update_toggle_dialog", - ":device_name_util", - ":edit_hostname_dialog", - "..:deep_linking_behavior", - "..:os_route", - "..:prefs_behavior", - "..:route_observer_behavior", - "../..:router", - "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/cr_elements/policy:cr_policy_indicator_behavior.m", - "//ui/webui/resources/cr_elements/policy:cr_tooltip_icon.m", - "//ui/webui/resources/js:i18n_behavior.m", - "//ui/webui/resources/js:web_ui_listener_behavior.m", - ] -} - -js_library("device_name_browser_proxy") { - deps = [ "//ui/webui/resources/js:cr.m" ] - externs_list = [ "$externs_path/chrome_send.js" ] -} - -js_library("device_name_util") { - deps = [] -} - -js_library("edit_hostname_dialog") { - deps = [ - ":about_page_browser_proxy", - "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/js:assert.m", - "//ui/webui/resources/js:load_time_data.m", - ] -} - -js_library("os_about_page") { - deps = [ - ":about_page_browser_proxy", - ":device_name_browser_proxy", - "..:deep_linking_behavior", - "..:os_route", - "..:route_observer_behavior", - "../..:router", - "../os_settings_page:main_page_behavior", - "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/js:i18n_behavior.m", - "//ui/webui/resources/js:load_time_data.m", - "//ui/webui/resources/js:parse_html_subset.m", - "//ui/webui/resources/js:web_ui_listener_behavior.m", - ] - - externs_list = [ "../settings_controls_types.js" ] -} - -js_library("update_warning_dialog") { - deps = [ - ":about_page_browser_proxy", - "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/js:i18n_behavior.m", - ] -}
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/about_page_browser_proxy.js b/chrome/browser/resources/settings/chromeos/os_about_page/about_page_browser_proxy.js deleted file mode 100644 index ab0498ed..0000000 --- a/chrome/browser/resources/settings/chromeos/os_about_page/about_page_browser_proxy.js +++ /dev/null
@@ -1,390 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview A helper object used from the "About" section to interact with - * the browser. - */ - -import {assertNotReached} from 'chrome://resources/js/assert.m.js'; -import {sendWithPromise} from 'chrome://resources/js/cr.m.js'; - -/** - * @typedef {{ - * text: string, - * url: string, - * }} - */ -export let RegulatoryInfo; - -/** - * @typedef {{ - * currentChannel: BrowserChannel, - * targetChannel: BrowserChannel, - * isLts: boolean, - * }} - */ -export let ChannelInfo; - -/** - * @typedef {{ - * arcVersion: string, - * osFirmware: string, - * osVersion: string, - * }} - */ -export let VersionInfo; - -/** - * @typedef {{ - * version: (string|undefined), - * size: (string|undefined), - * }} - */ -export let AboutPageUpdateInfo; - -/** - * @typedef {{ - * hasEndOfLife: (boolean|undefined), - * eolMessageWithMonthAndYear: (string|undefined), - * }} - */ -let EndOfLifeInfo; - -/** - * Enumeration of all possible browser channels. - * @enum {string} - */ -export const BrowserChannel = { - BETA: 'beta-channel', - CANARY: 'canary-channel', - DEV: 'dev-channel', - STABLE: 'stable-channel', -}; - -/** - * @typedef {{ - * updateAvailable: boolean, - * }} - */ -export let TPMFirmwareUpdateStatusChangedEvent; - -/** - * Enumeration of all possible update statuses. The string literals must match - * the ones defined at |AboutHandler::UpdateStatusToString|. - * @enum {string} - */ -export const UpdateStatus = { - CHECKING: 'checking', - UPDATING: 'updating', - NEARLY_UPDATED: 'nearly_updated', - UPDATED: 'updated', - FAILED: 'failed', - FAILED_HTTP: 'failed_http', - FAILED_DOWNLOAD: 'failed_download', - DISABLED: 'disabled', - DISABLED_BY_ADMIN: 'disabled_by_admin', - NEED_PERMISSION_TO_UPDATE: 'need_permission_to_update', - DEFERRED: 'deferred', -}; - -/** - * @typedef {{ - * status: !UpdateStatus, - * progress: (number|undefined), - * message: (string|undefined), - * connectionTypes: (string|undefined), - * version: (string|undefined), - * size: (string|undefined), - * }} - */ -export let UpdateStatusChangedEvent; - -/** - * @param {!BrowserChannel} channel - * @param {boolean} isLts - * @return {string} - */ -export function browserChannelToI18nId(channel, isLts) { - if (isLts) { - return 'aboutChannelLongTermSupport'; - } - - switch (channel) { - case BrowserChannel.BETA: - return 'aboutChannelBeta'; - case BrowserChannel.CANARY: - return 'aboutChannelCanary'; - case BrowserChannel.DEV: - return 'aboutChannelDev'; - case BrowserChannel.STABLE: - return 'aboutChannelStable'; - } - - assertNotReached(); -} - -/** - * @param {!BrowserChannel} currentChannel - * @param {!BrowserChannel} targetChannel - * @return {boolean} Whether the target channel is more stable than the - * current channel. - */ -export function isTargetChannelMoreStable(currentChannel, targetChannel) { - // List of channels in increasing stability order. - const channelList = [ - BrowserChannel.CANARY, - BrowserChannel.DEV, - BrowserChannel.BETA, - BrowserChannel.STABLE, - ]; - const currentIndex = channelList.indexOf(currentChannel); - const targetIndex = channelList.indexOf(targetChannel); - return currentIndex < targetIndex; -} - -/** @interface */ -export class AboutPageBrowserProxy { - /** - * Applies deferred update if it exists. - */ - applyDeferredUpdate() {} - - /** - * Indicates to the browser that the page is ready. - */ - pageReady() {} - - /** - * Request update status from the browser. It results in one or more - * 'update-status-changed' WebUI events. - */ - refreshUpdateStatus() {} - - /** Opens the release notes app. */ - launchReleaseNotes() {} - - // <if expr="_google_chrome"> - /** - * Opens the feedback dialog. - */ - openFeedbackDialog() {} - - // </if> - - /** Opens the diagnostics page. */ - openDiagnostics() {} - - /** Opens the OS help page. */ - openOsHelpPage() {} - - /** Opens the firmware updates page. */ - openFirmwareUpdatesPage() {} - - /** - * Requests the number of firmware updates. - * @return {!Promise<number>} - */ - getFirmwareUpdateCount() {} - - /** - * Checks for available update and applies if it exists. - */ - requestUpdate() {} - - /** - * Checks for the update with specified version and size and applies over - * cellular. The target version and size are the same as were received from - * 'update-status-changed' WebUI event. We send this back all the way to - * update engine for it to double check with update server in case there's a - * new update available. This prevents downloading the new update that user - * didn't agree to. - * @param {string} target_version - * @param {string} target_size - */ - requestUpdateOverCellular(target_version, target_size) {} - - /** - * @param {!BrowserChannel} channel - * @param {boolean} isPowerwashAllowed - */ - setChannel(channel, isPowerwashAllowed) {} - - /** - * Requests channel info from the version updater. This may have latency if - * the version updater is busy, for example with downloading updates. - * @return {!Promise<!ChannelInfo>} - */ - getChannelInfo() {} - - /** @return {!Promise<!boolean>} */ - canChangeChannel() {} - - /** @return {!Promise<!VersionInfo>} */ - getVersionInfo() {} - - /** @return {!Promise<?RegulatoryInfo>} */ - getRegulatoryInfo() {} - - /** - * Checks if the device has reached end-of-life status and will no longer - * receive updates. - * @return {!Promise<!EndOfLifeInfo>} - */ - getEndOfLifeInfo() {} - - /** - * Request TPM firmware update status from the browser. It results in one or - * more 'tpm-firmware-update-status-changed' WebUI events. - */ - refreshTPMFirmwareUpdateStatus() {} - - /** - * Checks if the device is connected to the internet. - * @return {!Promise<boolean>} - */ - checkInternetConnection() {} - - /** @return {!Promise<boolean>} */ - isManagedAutoUpdateEnabled() {} - - /** @return {!Promise<boolean>} */ - isConsumerAutoUpdateEnabled() {} - - /** - * @param {boolean} enable - */ - setConsumerAutoUpdate(enable) {} -} - -/** @type {?AboutPageBrowserProxy} */ -let instance = null; - -/** - * @implements {AboutPageBrowserProxy} - */ -export class AboutPageBrowserProxyImpl { - /** @return {!AboutPageBrowserProxy} */ - static getInstance() { - return instance || (instance = new AboutPageBrowserProxyImpl()); - } - - /** @param {!AboutPageBrowserProxy} obj */ - static setInstanceForTesting(obj) { - instance = obj; - } - - /** @override */ - applyDeferredUpdate() { - chrome.send('applyDeferredUpdate'); - } - - /** @override */ - pageReady() { - chrome.send('aboutPageReady'); - } - - /** @override */ - refreshUpdateStatus() { - chrome.send('refreshUpdateStatus'); - } - - /** @override */ - launchReleaseNotes() { - chrome.send('launchReleaseNotes'); - } - - // <if expr="_google_chrome"> - /** @override */ - openFeedbackDialog() { - chrome.send('openFeedbackDialog'); - } - - // </if> - - /** @override */ - openDiagnostics() { - chrome.send('openDiagnostics'); - } - - /** @override */ - openOsHelpPage() { - chrome.send('openOsHelpPage'); - } - - /** @override */ - openFirmwareUpdatesPage() { - chrome.send('openFirmwareUpdatesPage'); - } - - /** @override */ - getFirmwareUpdateCount() { - return sendWithPromise('getFirmwareUpdateCount'); - } - - /** @override */ - requestUpdate() { - chrome.send('requestUpdate'); - } - - /** @override */ - requestUpdateOverCellular(target_version, target_size) { - chrome.send('requestUpdateOverCellular', [target_version, target_size]); - } - - /** @override */ - setChannel(channel, isPowerwashAllowed) { - chrome.send('setChannel', [channel, isPowerwashAllowed]); - } - - /** @override */ - getChannelInfo() { - return sendWithPromise('getChannelInfo'); - } - - /** @override */ - canChangeChannel() { - return sendWithPromise('canChangeChannel'); - } - - /** @override */ - getVersionInfo() { - return sendWithPromise('getVersionInfo'); - } - - /** @override */ - getRegulatoryInfo() { - return sendWithPromise('getRegulatoryInfo'); - } - - /** @override */ - getEndOfLifeInfo() { - return sendWithPromise('getEndOfLifeInfo'); - } - - /** @override */ - checkInternetConnection() { - return sendWithPromise('checkInternetConnection'); - } - - /** @override */ - refreshTPMFirmwareUpdateStatus() { - chrome.send('refreshTPMFirmwareUpdateStatus'); - } - - /** @override */ - isManagedAutoUpdateEnabled() { - return sendWithPromise('isManagedAutoUpdateEnabled'); - } - - /** @override */ - isConsumerAutoUpdateEnabled() { - return sendWithPromise('isConsumerAutoUpdateEnabled'); - } - - /** @override */ - setConsumerAutoUpdate(enable) { - chrome.send('setConsumerAutoUpdate', [enable]); - } -}
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/about_page_browser_proxy.ts b/chrome/browser/resources/settings/chromeos/os_about_page/about_page_browser_proxy.ts new file mode 100644 index 0000000..967d4c5de --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_about_page/about_page_browser_proxy.ts
@@ -0,0 +1,311 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview A helper object used from the "About" section to interact with + * the browser. + */ + +import {sendWithPromise} from 'chrome://resources/js/cr.m.js'; + +export interface RegulatoryInfo { + text: string; + url: string; +} + +/** + * Enumeration of all possible browser channels. + */ +export enum BrowserChannel { + BETA = 'beta-channel', + CANARY = 'canary-channel', + DEV = 'dev-channel', + STABLE = 'stable-channel', +} + +export interface ChannelInfo { + currentChannel: BrowserChannel; + targetChannel: BrowserChannel; + isLts: boolean; +} + +export interface VersionInfo { + arcVersion: string; + osFirmware: string; + osVersion: string; +} + +export interface AboutPageUpdateInfo { + version?: string; + size?: string; +} + +interface EndOfLifeInfo { + hasEndOfLife?: boolean; + aboutPageEndOfLifeMessage?: string; +} + +export interface TPMFirmwareUpdateStatusChangedEvent { + updateAvailable: boolean; +} + +/** + * Enumeration of all possible update statuses. The string literals must match + * the ones defined at |AboutHandler::UpdateStatusToString|. + */ +export enum UpdateStatus { + CHECKING = 'checking', + UPDATING = 'updating', + NEARLY_UPDATED = 'nearly_updated', + UPDATED = 'updated', + FAILED = 'failed', + FAILED_HTTP = 'failed_http', + FAILED_DOWNLOAD = 'failed_download', + DISABLED = 'disabled', + DISABLED_BY_ADMIN = 'disabled_by_admin', + NEED_PERMISSION_TO_UPDATE = 'need_permission_to_update', + DEFERRED = 'deferred', +} + +export interface UpdateStatusChangedEvent { + status: UpdateStatus; + progress?: number; + message?: string; + connectionTypes?: string; + version?: string; + size?: string; + rollback?: boolean; + powerwash?: boolean; +} + +export function browserChannelToI18nId( + channel: BrowserChannel, isLts: boolean): string { + if (isLts) { + return 'aboutChannelLongTermSupport'; + } + + switch (channel) { + case BrowserChannel.BETA: + return 'aboutChannelBeta'; + case BrowserChannel.CANARY: + return 'aboutChannelCanary'; + case BrowserChannel.DEV: + return 'aboutChannelDev'; + case BrowserChannel.STABLE: + return 'aboutChannelStable'; + } +} + +/** + * Returns whether the target channel is more stable than the current channel. + */ +export function isTargetChannelMoreStable( + currentChannel: BrowserChannel, targetChannel: BrowserChannel): boolean { + // List of channels in increasing stability order. + const channelList = [ + BrowserChannel.CANARY, + BrowserChannel.DEV, + BrowserChannel.BETA, + BrowserChannel.STABLE, + ]; + const currentIndex = channelList.indexOf(currentChannel); + const targetIndex = channelList.indexOf(targetChannel); + return currentIndex < targetIndex; +} + +export interface AboutPageBrowserProxy { + /** + * Applies deferred update if it exists. + */ + applyDeferredUpdate(): void; + + /** + * Indicates to the browser that the page is ready. + */ + pageReady(): void; + + /** + * Request update status from the browser. It results in one or more + * 'update-status-changed' WebUI events. + */ + refreshUpdateStatus(): void; + + /** Opens the release notes app. */ + launchReleaseNotes(): void; + + // <if expr="_google_chrome"> + /** + * Opens the feedback dialog. + */ + openFeedbackDialog(): void; + // </if> + + /** Opens the diagnostics page. */ + openDiagnostics(): void; + + /** Opens the OS help page. */ + openOsHelpPage(): void; + + /** Opens the firmware updates page. */ + openFirmwareUpdatesPage(): void; + + /** + * Requests the number of firmware updates. + */ + getFirmwareUpdateCount(): Promise<number>; + + /** + * Checks for available update and applies if it exists. + */ + requestUpdate(): void; + + /** + * Checks for the update with specified version and size and applies over + * cellular. The target version and size are the same as were received from + * 'update-status-changed' WebUI event. We send this back all the way to + * update engine for it to double check with update server in case there's a + * new update available. This prevents downloading the new update that user + * didn't agree to. + */ + requestUpdateOverCellular(targetVersion: string, targetSize: string): void; + + setChannel(channel: BrowserChannel, isPowerwashAllowed: boolean): void; + + /** + * Requests channel info from the version updater. This may have latency if + * the version updater is busy, for example with downloading updates. + */ + getChannelInfo(): Promise<ChannelInfo>; + + canChangeChannel(): Promise<boolean>; + + getVersionInfo(): Promise<VersionInfo>; + + getRegulatoryInfo(): Promise<RegulatoryInfo|null>; + + /** + * Checks if the device has reached end-of-life status and will no longer + * receive updates. + */ + getEndOfLifeInfo(): Promise<EndOfLifeInfo>; + + /** + * Request TPM firmware update status from the browser. It results in one or + * more 'tpm-firmware-update-status-changed' WebUI events. + */ + refreshTPMFirmwareUpdateStatus(): void; + + /** + * Checks if the device is connected to the internet. + */ + checkInternetConnection(): Promise<boolean>; + + isManagedAutoUpdateEnabled(): Promise<boolean>; + + isConsumerAutoUpdateEnabled(): Promise<boolean>; + + setConsumerAutoUpdate(enable: boolean): void; +} + +let instance: AboutPageBrowserProxy|null = null; + +export class AboutPageBrowserProxyImpl implements AboutPageBrowserProxy { + static getInstance(): AboutPageBrowserProxy { + return instance || (instance = new AboutPageBrowserProxyImpl()); + } + + static setInstanceForTesting(obj: AboutPageBrowserProxy) { + instance = obj; + } + + applyDeferredUpdate() { + chrome.send('applyDeferredUpdate'); + } + + pageReady() { + chrome.send('aboutPageReady'); + } + + refreshUpdateStatus() { + chrome.send('refreshUpdateStatus'); + } + + launchReleaseNotes() { + chrome.send('launchReleaseNotes'); + } + + // <if expr="_google_chrome"> + openFeedbackDialog() { + chrome.send('openFeedbackDialog'); + } + // </if> + + openDiagnostics() { + chrome.send('openDiagnostics'); + } + + openOsHelpPage() { + chrome.send('openOsHelpPage'); + } + + openFirmwareUpdatesPage() { + chrome.send('openFirmwareUpdatesPage'); + } + + getFirmwareUpdateCount() { + return sendWithPromise('getFirmwareUpdateCount'); + } + + requestUpdate() { + chrome.send('requestUpdate'); + } + + requestUpdateOverCellular(targetVersion: string, targetSize: string) { + chrome.send('requestUpdateOverCellular', [targetVersion, targetSize]); + } + + setChannel(channel: BrowserChannel, isPowerwashAllowed: boolean) { + chrome.send('setChannel', [channel, isPowerwashAllowed]); + } + + getChannelInfo(): Promise<ChannelInfo> { + return sendWithPromise('getChannelInfo'); + } + + canChangeChannel(): Promise<boolean> { + return sendWithPromise('canChangeChannel'); + } + + getVersionInfo(): Promise<VersionInfo> { + return sendWithPromise('getVersionInfo'); + } + + getRegulatoryInfo(): Promise<RegulatoryInfo|null> { + return sendWithPromise('getRegulatoryInfo'); + } + + getEndOfLifeInfo(): Promise<EndOfLifeInfo> { + return sendWithPromise('getEndOfLifeInfo'); + } + + checkInternetConnection(): Promise<boolean> { + return sendWithPromise('checkInternetConnection'); + } + + refreshTPMFirmwareUpdateStatus(): void { + chrome.send('refreshTPMFirmwareUpdateStatus'); + } + + isManagedAutoUpdateEnabled(): Promise<boolean> { + return sendWithPromise('isManagedAutoUpdateEnabled'); + } + + isConsumerAutoUpdateEnabled(): Promise<boolean> { + return sendWithPromise('isConsumerAutoUpdateEnabled'); + } + + setConsumerAutoUpdate(enable: boolean): void { + chrome.send('setConsumerAutoUpdate', [enable]); + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/channel_switcher_dialog.js b/chrome/browser/resources/settings/chromeos/os_about_page/channel_switcher_dialog.ts similarity index 72% rename from chrome/browser/resources/settings/chromeos/os_about_page/channel_switcher_dialog.js rename to chrome/browser/resources/settings/chromeos/os_about_page/channel_switcher_dialog.ts index 0442202..f0f56093 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/channel_switcher_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_about_page/channel_switcher_dialog.ts
@@ -9,20 +9,27 @@ * release channel to notify parents of this dialog. */ -import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.m.js'; import 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.m.js'; -import 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js'; import '../../settings_shared.css.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {assert} from 'chrome://resources/js/assert.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; +import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {AboutPageBrowserProxy, AboutPageBrowserProxyImpl, BrowserChannel, isTargetChannelMoreStable} from './about_page_browser_proxy.js'; import {getTemplate} from './channel_switcher_dialog.html.js'; +interface SettingsChannelSwitcherDialogElement { + $: { + dialog: CrDialogElement, + warningSelector: IronSelectorElement, + }; +} + const WarningMessage = { NONE: -1, ENTERPRISE_MANAGED: 0, @@ -30,7 +37,6 @@ UNSTABLE: 2, }; -/** @polymer */ class SettingsChannelSwitcherDialogElement extends PolymerElement { static get is() { return 'settings-channel-switcher-dialog'; @@ -42,22 +48,17 @@ static get properties() { return { - /** @private */ browserChannelEnum_: { type: Object, value: BrowserChannel, }, - /** @private {!BrowserChannel} */ currentChannel_: String, - /** @private {!BrowserChannel} */ targetChannel_: String, /** * Controls which of the two action buttons is visible. - * @private {?{changeChannel: boolean, changeChannelAndPowerwash: - * boolean}} */ shouldShowButtons_: { type: Object, @@ -66,72 +67,76 @@ }; } + private browserChannelEnum_: typeof BrowserChannel; + private currentChannel_: BrowserChannel; + private targetChannel_: BrowserChannel; + private shouldShowButtons_: { + changeChannel: boolean, + changeChannelAndPowerwash: boolean, + }|null; + + private browserProxy_: AboutPageBrowserProxy; + constructor() { super(); - /** @private {AboutPageBrowserProxy} */ this.browserProxy_ = AboutPageBrowserProxyImpl.getInstance(); } - /** @override */ - ready() { + override ready() { super.ready(); this.browserProxy_.getChannelInfo().then(info => { this.currentChannel_ = info.currentChannel; this.targetChannel_ = info.targetChannel; // Pre-populate radio group with target channel. - const radioGroup = this.shadowRoot.querySelector('cr-radio-group'); + const radioGroup = this.shadowRoot!.querySelector('cr-radio-group')!; radioGroup.selected = this.targetChannel_; radioGroup.focus(); }); } - /** @override */ - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.$.dialog.showModal(); } - /** @private */ - onCancelTap_() { + private onCancelTap_() { this.$.dialog.close(); } - /** @private */ - onChangeChannelTap_() { + private onChangeChannelTap_() { const selectedChannel = - this.shadowRoot.querySelector('cr-radio-group').selected; + this.shadowRoot!.querySelector('cr-radio-group')!.selected as + BrowserChannel; this.browserProxy_.setChannel(selectedChannel, false); this.$.dialog.close(); this.fireTargetChannelChangedEvent_(selectedChannel); } - /** @private */ - onChangeChannelAndPowerwashTap_() { + private onChangeChannelAndPowerwashTap_() { const selectedChannel = - this.shadowRoot.querySelector('cr-radio-group').selected; + this.shadowRoot!.querySelector('cr-radio-group')!.selected as + BrowserChannel; this.browserProxy_.setChannel(selectedChannel, true); this.$.dialog.close(); this.fireTargetChannelChangedEvent_(selectedChannel); } - /** @private */ - fireTargetChannelChangedEvent_(detail = {}) { + private fireTargetChannelChangedEvent_(detail = {}) { const event = new CustomEvent( 'target-channel-changed', {bubbles: true, composed: true, detail}); this.dispatchEvent(event); } /** - * @param {boolean} changeChannel Whether the changeChannel button should be - * visible. - * @param {boolean} changeChannelAndPowerwash Whether the - * changeChannelAndPowerwash button should be visible. - * @private + * @param changeChannel Whether the changeChannel button should be visible. + * @param changeChannelAndPowerwash Whether the changeChannelAndPowerwash + * button should be visible. */ - updateButtons_(changeChannel, changeChannelAndPowerwash) { + private updateButtons_( + changeChannel: boolean, changeChannelAndPowerwash: boolean) { if (changeChannel || changeChannelAndPowerwash) { // Ensure that at most one button is visible at any given time. assert(changeChannel !== changeChannelAndPowerwash); @@ -143,10 +148,10 @@ }; } - /** @private */ - onChannelSelectionChanged_() { + private onChannelSelectionChanged_() { const selectedChannel = - this.shadowRoot.querySelector('cr-radio-group').selected; + this.shadowRoot!.querySelector('cr-radio-group')!.selected as + BrowserChannel; // Selected channel is the same as the target channel so only show 'cancel'. if (selectedChannel === this.targetChannel_) { @@ -184,17 +189,17 @@ } } - /** - * @param {string} format - * @param {string} replacement - * @return {string} - * @private - */ - substituteString_(format, replacement) { + private substituteString_(format: string, replacement: string): string { return loadTimeData.substituteString(format, replacement); } } +declare global { + interface HTMLElementTagNameMap { + 'settings-channel-switcher-dialog': SettingsChannelSwitcherDialogElement; + } +} + customElements.define( SettingsChannelSwitcherDialogElement.is, SettingsChannelSwitcherDialogElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/consumer_auto_update_toggle_dialog.js b/chrome/browser/resources/settings/chromeos/os_about_page/consumer_auto_update_toggle_dialog.ts similarity index 71% rename from chrome/browser/resources/settings/chromeos/os_about_page/consumer_auto_update_toggle_dialog.js rename to chrome/browser/resources/settings/chromeos/os_about_page/consumer_auto_update_toggle_dialog.ts index 7d63ed2aa..8c5d441 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/consumer_auto_update_toggle_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_about_page/consumer_auto_update_toggle_dialog.ts
@@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; - +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './consumer_auto_update_toggle_dialog.html.js'; -/** @polymer */ +interface SettingsConsumerAutoUpdateToggleDialogElement { + $: { + dialog: CrDialogElement, + }; +} + class SettingsConsumerAutoUpdateToggleDialogElement extends PolymerElement { static get is() { return 'settings-consumer-auto-update-toggle-dialog'; @@ -18,15 +22,13 @@ return getTemplate(); } - /** @override */ - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.$.dialog.showModal(); } - /** @private */ - onTurnOffTap_() { + private onTurnOffTap_() { this.dispatchEvent(new CustomEvent('set-consumer-auto-update', { bubbles: true, composed: true, @@ -37,8 +39,7 @@ this.$.dialog.close(); } - /** @private */ - onKeepUpdatesTap_() { + private onKeepUpdatesTap_() { this.dispatchEvent(new CustomEvent('set-consumer-auto-update', { bubbles: true, composed: true, @@ -50,6 +51,13 @@ } } +declare global { + interface HTMLElementTagNameMap { + 'settings-consumer-auto-update-toggle-dialog': + SettingsConsumerAutoUpdateToggleDialogElement; + } +} + customElements.define( SettingsConsumerAutoUpdateToggleDialogElement.is, SettingsConsumerAutoUpdateToggleDialogElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.js b/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts similarity index 72% rename from chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.js rename to chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts index fdd3da0..8e2b9de 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.js +++ b/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts
@@ -20,8 +20,8 @@ import {CrPolicyIndicatorType} from 'chrome://resources/cr_elements/policy/cr_policy_indicator_behavior.m.js'; import {assert} from 'chrome://resources/js/assert.m.js'; import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; -import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/js/web_ui_listener_behavior.m.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/js/i18n_mixin.js'; +import {WebUIListenerMixin, WebUIListenerMixinInterface} from 'chrome://resources/js/web_ui_listener_mixin.js'; import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {loadTimeData} from '../../i18n_setup.js'; @@ -30,32 +30,32 @@ import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js'; import {routes} from '../os_route.js'; import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js'; -import {RouteObserverBehavior} from '../route_observer_behavior.js'; +import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js'; import {AboutPageBrowserProxy, AboutPageBrowserProxyImpl, browserChannelToI18nId, ChannelInfo, VersionInfo} from './about_page_browser_proxy.js'; import {getTemplate} from './detailed_build_info.html.js'; import {DeviceNameBrowserProxy, DeviceNameBrowserProxyImpl, DeviceNameMetadata} from './device_name_browser_proxy.js'; import {DeviceNameState} from './device_name_util.js'; -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - * @implements {WebUIListenerBehaviorInterface} - * @implements {DeepLinkingBehaviorInterface} - * @implements {PrefsBehaviorInterface} - */ -const SettingsDetailedBuildInfoBase = mixinBehaviors( - [ - DeepLinkingBehavior, - WebUIListenerBehavior, - I18nBehavior, - PrefsBehavior, - RouteObserverBehavior, - ], - PolymerElement); +declare global { + interface HTMLElementEventMap { + 'set-consumer-auto-update': CustomEvent<{item: boolean}>; + } +} -/** @polymer */ +const SettingsDetailedBuildInfoBase = + mixinBehaviors( + [ + DeepLinkingBehavior, + PrefsBehavior, + RouteObserverBehavior, + ], + I18nMixin(WebUIListenerMixin(PolymerElement))) as { + new (): PolymerElement & DeepLinkingBehaviorInterface & + WebUIListenerMixinInterface & I18nMixinInterface & + PrefsBehaviorInterface & RouteObserverBehaviorInterface, + }; + class SettingsDetailedBuildInfoElement extends SettingsDetailedBuildInfoBase { static get is() { return 'settings-detailed-build-info'; @@ -73,31 +73,22 @@ notify: true, }, - /** @private {!VersionInfo} */ versionInfo_: Object, - /** @private {!ChannelInfo} */ channelInfo_: Object, - /** @private {!DeviceNameMetadata} */ deviceNameMetadata_: Object, - /** @private */ currentlyOnChannelText_: String, - /** @private */ showChannelSwitcherDialog_: Boolean, - /** @private */ showEditHostnameDialog_: Boolean, - /** @private */ canChangeChannel_: Boolean, - /** @private */ isManagedAutoUpdateEnabled_: Boolean, - /** @private */ showConsumerAutoUpdateToggleDialog_: Boolean, eolMessageWithMonthAndYear: { @@ -107,7 +98,6 @@ /** * Used by DeepLinkingBehavior to focus this page's deep links. - * @type {!Set<!Setting>} */ supportedSettingIds: { type: Object, @@ -118,13 +108,11 @@ ]), }, - /** @private */ shouldHideEolInfo_: { type: Boolean, computed: 'computeShouldHideEolInfo_(eolMessageWithMonthAndYear)', }, - /** @private */ isHostnameSettingEnabled_: { type: Boolean, value() { @@ -136,7 +124,6 @@ /** * Whether the browser/ChromeOS is managed by their organization * through enterprise policies. - * @private */ isManaged_: { type: Boolean, @@ -148,7 +135,6 @@ /** * Whether or not the consumer auto update toggling is allowed. - * @private */ isConsumerAutoUpdateTogglingAllowed_: { type: Boolean, @@ -160,7 +146,6 @@ /** * Whether or not to show the consumer auto update toggle. - * @private */ showConsumerAutoUpdateToggle_: { type: Boolean, @@ -173,24 +158,41 @@ }; } + private versionInfo_: VersionInfo; + private channelInfo_: ChannelInfo; + private deviceNameMetadata_: DeviceNameMetadata; + private currentlyOnChannelText_: string; + private showChannelSwitcherDialog_: boolean; + private showEditHostnameDialog_: boolean; + private canChangeChannel_: boolean; + private isManagedAutoUpdateEnabled_: boolean; + private showConsumerAutoUpdateToggleDialog_: boolean; + private eolMessageWithMonthAndYear: string; + override supportedSettingIds: Set<Setting>; + private shouldHideEolInfo_: boolean; + private isHostnameSettingEnabled_: boolean; + private isManaged_: boolean; + private isConsumerAutoUpdateTogglingAllowed_: boolean; + private showConsumerAutoUpdateToggle_: boolean; + + private aboutPageBrowserProxy_: AboutPageBrowserProxy; + private deviceNameBrowserProxy_: DeviceNameBrowserProxy; + constructor() { super(); - /** @private {!AboutPageBrowserProxy} */ this.aboutPageBrowserProxy_ = AboutPageBrowserProxyImpl.getInstance(); - - /** @private {!DeviceNameBrowserProxy} */ this.deviceNameBrowserProxy_ = DeviceNameBrowserProxyImpl.getInstance(); } - /** @override */ - ready() { + override ready() { super.ready(); this.aboutPageBrowserProxy_.pageReady(); - this.addEventListener('set-consumer-auto-update', e => { - this.aboutPageBrowserProxy_.setConsumerAutoUpdate(e.detail.item); - }); + this.addEventListener( + 'set-consumer-auto-update', (event: CustomEvent<{item: boolean}>) => { + this.aboutPageBrowserProxy_.setConsumerAutoUpdate(event.detail.item); + }); if (this.isManaged_) { this.syncManagedAutoUpdateToggle_(); @@ -211,16 +213,12 @@ if (this.isHostnameSettingEnabled_) { this.addWebUIListener( 'settings.updateDeviceNameMetadata', - (data) => this.updateDeviceNameMetadata_(data)); + (data: DeviceNameMetadata) => this.updateDeviceNameMetadata_(data)); this.deviceNameBrowserProxy_.notifyReadyForDeviceName(); } } - /** - * @param {!Route} route - * @param {!Route} oldRoute - */ - currentRouteChanged(route, oldRoute) { + override currentRouteChanged(route: Route, _oldRoute?: Route) { // Does not apply to this page. if (route !== routes.DETAILED_BUILD_INFO) { return; @@ -229,16 +227,11 @@ this.attemptDeepLink(); } - /** - * @return {boolean} - * @private - */ - computeShouldHideEolInfo_() { + private computeShouldHideEolInfo_(): boolean { return this.isManaged_ || !this.eolMessageWithMonthAndYear; } - /** @private */ - updateChannelInfo_() { + private updateChannelInfo_() { // canChangeChannel() call is expected to be low-latency, so fetch this // value by itself to ensure UI consistency (see https://crbug.com/848750). this.aboutPageBrowserProxy_.canChangeChannel().then(canChangeChannel => { @@ -256,34 +249,24 @@ }); } - /** @private */ - syncManagedAutoUpdateToggle_() { + private syncManagedAutoUpdateToggle_() { this.aboutPageBrowserProxy_.isManagedAutoUpdateEnabled().then( isManagedAutoUpdateEnabled => { this.isManagedAutoUpdateEnabled_ = isManagedAutoUpdateEnabled; }); } - /** @private */ - syncConsumerAutoUpdateToggle_() { + private syncConsumerAutoUpdateToggle_() { this.aboutPageBrowserProxy_.isConsumerAutoUpdateEnabled().then(enabled => { this.aboutPageBrowserProxy_.setConsumerAutoUpdate(enabled); }); } - /** - * @param {!DeviceNameMetadata} data - * @private - */ - updateDeviceNameMetadata_(data) { + private updateDeviceNameMetadata_(data: DeviceNameMetadata) { this.deviceNameMetadata_ = data; } - /** - * @return {string} - * @private - */ - getDeviceNameText_() { + private getDeviceNameText_(): string { if (!this.deviceNameMetadata_) { return ''; } @@ -291,11 +274,7 @@ return this.deviceNameMetadata_.deviceName; } - /** - * @return {string} - * @private - */ - getDeviceNameEditButtonA11yDescription_() { + private getDeviceNameEditButtonA11yDescription_(): string { if (!this.deviceNameMetadata_) { return ''; } @@ -304,11 +283,7 @@ 'aboutDeviceNameEditBtnA11yDescription', this.getDeviceNameText_()); } - /** - * @return {boolean} - * @private - */ - canEditDeviceName_() { + private canEditDeviceName_(): boolean { if (!this.deviceNameMetadata_) { return false; } @@ -317,27 +292,15 @@ DeviceNameState.CAN_BE_MODIFIED; } - /** - * @return {boolean} - * @private - */ - shouldShowPolicyIndicator_() { + private shouldShowPolicyIndicator_(): boolean { return this.getDeviceNameIndicatorType_() !== CrPolicyIndicatorType.NONE; } - /** - * @return {boolean} - * @private - */ - shouldShowConsumerAutoUpdateToggle_() { + private shouldShowConsumerAutoUpdateToggle_(): boolean { return !this.isManaged_; } - /** - * @return {string} - * @private - */ - getDeviceNameIndicatorType_() { + private getDeviceNameIndicatorType_(): string { if (!this.deviceNameMetadata_) { return CrPolicyIndicatorType.NONE; } @@ -355,12 +318,8 @@ return CrPolicyIndicatorType.NONE; } - /** - * @param {boolean} canChangeChannel - * @return {string} - * @private - */ - getChangeChannelIndicatorSourceName_(canChangeChannel) { + private getChangeChannelIndicatorSourceName_(canChangeChannel: boolean): + string { if (canChangeChannel) { // the indicator should be invisible. return ''; @@ -370,12 +329,8 @@ loadTimeData.getString('ownerEmail'); } - /** - * @param {boolean} canChangeChannel - * @return {CrPolicyIndicatorType} - * @private - */ - getChangeChannelIndicatorType_(canChangeChannel) { + private getChangeChannelIndicatorType_(canChangeChannel: boolean): + CrPolicyIndicatorType { if (canChangeChannel) { return CrPolicyIndicatorType.NONE; } @@ -384,35 +339,22 @@ CrPolicyIndicatorType.OWNER; } - /** - * @param {!Event} e - * @private - */ - onChangeChannelTap_(e) { + private onChangeChannelTap_(e: Event) { e.preventDefault(); this.showChannelSwitcherDialog_ = true; } - /** - * @param {!Event} e - * @private - */ - onEditHostnameTap_(e) { + private onEditHostnameTap_(e: Event) { e.preventDefault(); this.showEditHostnameDialog_ = true; } - /** - * @return {boolean} - * @private - */ - copyToClipBoardEnabled_() { + private copyToClipBoardEnabled_(): boolean { return !!this.versionInfo_ && !!this.channelInfo_; } - /** @private */ - onCopyBuildDetailsToClipBoardTap_() { - const buildInfo = { + private onCopyBuildDetailsToClipBoardTap_() { + const buildInfo: {[key: string]: string|boolean} = { 'application_label': loadTimeData.getString('aboutBrowserVersion'), 'platform': this.versionInfo_.osVersion, 'aboutChannelLabel': this.channelInfo_.targetChannel, @@ -425,27 +367,22 @@ loadTimeData.getBoolean('aboutIsDeveloperMode'), }; - const entries = []; + const entries: string[] = []; for (const key in buildInfo) { - entries.push(this.i18n(key) + ': ' + buildInfo[key]); + entries.push(this.i18n(key) + ': ' + String(buildInfo[key])); } navigator.clipboard.writeText(entries.join('\n')); } - /** - * @param {!Event} e - * @private - */ - onConsumerAutoUpdateToggled_(e) { + private onConsumerAutoUpdateToggled_(_event: Event) { if (!this.isConsumerAutoUpdateTogglingAllowed_) { return; } this.showDialogOrFlushConsumerAutoUpdateToggle(); } - /** @private */ - onConsumerAutoUpdateToggledSettingsBox_() { + private onConsumerAutoUpdateToggledSettingsBox_() { if (!this.isConsumerAutoUpdateTogglingAllowed_) { return; } @@ -456,8 +393,7 @@ this.showDialogOrFlushConsumerAutoUpdateToggle(); } - /** @private */ - showDialogOrFlushConsumerAutoUpdateToggle() { + private showDialogOrFlushConsumerAutoUpdateToggle() { if (!this.getPref('settings.consumer_auto_update_toggle').value) { // Only show dialog when turning the toggle off. this.showConsumerAutoUpdateToggleDialog_ = true; @@ -467,31 +403,30 @@ this.aboutPageBrowserProxy_.setConsumerAutoUpdate(true); } - /** @private */ - onConsumerAutoUpdateToggleDialogClosed_() { + private onConsumerAutoUpdateToggleDialogClosed_() { this.showConsumerAutoUpdateToggleDialog_ = false; } - /** - * @param {!Event} e - * @private - */ - onVisitBuildDetailsPageTap_(e) { + private onVisitBuildDetailsPageTap_(e: Event) { e.preventDefault(); window.open('chrome://version'); } - /** @private */ - onChannelSwitcherDialogClosed_() { + private onChannelSwitcherDialogClosed_() { this.showChannelSwitcherDialog_ = false; - focusWithoutInk(assert(this.shadowRoot.querySelector('cr-button'))); + focusWithoutInk(assert(this.shadowRoot!.querySelector('cr-button'))!); this.updateChannelInfo_(); } - /** @private */ - onEditHostnameDialogClosed_() { + private onEditHostnameDialogClosed_() { this.showEditHostnameDialog_ = false; - focusWithoutInk(assert(this.shadowRoot.querySelector('cr-button'))); + focusWithoutInk(assert(this.shadowRoot!.querySelector('cr-button'))!); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'settings-detailed-build-info': SettingsDetailedBuildInfoElement; } }
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/device_name_browser_proxy.js b/chrome/browser/resources/settings/chromeos/os_about_page/device_name_browser_proxy.js deleted file mode 100644 index eefe6eb..0000000 --- a/chrome/browser/resources/settings/chromeos/os_about_page/device_name_browser_proxy.js +++ /dev/null
@@ -1,58 +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. - -import {sendWithPromise} from 'chrome://resources/js/cr.m.js'; -import {DeviceNameState, SetDeviceNameResult} from './device_name_util.js'; - -/** - * @typedef {{ - * deviceName: string, - * deviceNameState: !DeviceNameState, - * }} - */ -export let DeviceNameMetadata; - -/** @interface */ -export class DeviceNameBrowserProxy { - /** - * Notifies the system that the page is ready for the device name. - * @return {!Promise<!DeviceNameMetadata>} - */ - notifyReadyForDeviceName() {} - - /** - * Attempts to set the device name to the new name entered by the user. - * @param {string} name - * @return {!Promise<!SetDeviceNameResult>} - */ - attemptSetDeviceName(name) {} -} - -/** @type {?DeviceNameBrowserProxy} */ -let instance = null; - -/** - * @implements {DeviceNameBrowserProxy} - */ -export class DeviceNameBrowserProxyImpl { - /** @return {!DeviceNameBrowserProxy} */ - static getInstance() { - return instance || (instance = new DeviceNameBrowserProxyImpl()); - } - - /** @param {!DeviceNameBrowserProxy} obj */ - static setInstanceForTesting(obj) { - instance = obj; - } - - /** @override */ - notifyReadyForDeviceName() { - return chrome.send('notifyReadyForDeviceName'); - } - - /** @override */ - attemptSetDeviceName(name) { - return sendWithPromise('attemptSetDeviceName', name); - } -}
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/device_name_browser_proxy.ts b/chrome/browser/resources/settings/chromeos/os_about_page/device_name_browser_proxy.ts new file mode 100644 index 0000000..173acc4 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_about_page/device_name_browser_proxy.ts
@@ -0,0 +1,44 @@ +// 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. + +import {sendWithPromise} from 'chrome://resources/js/cr.m.js'; + +import {DeviceNameState, SetDeviceNameResult} from './device_name_util.js'; + +export interface DeviceNameMetadata { + deviceName: string; + deviceNameState: DeviceNameState; +} + +export interface DeviceNameBrowserProxy { + /** + * Notifies the system that the page is ready for the device name. + */ + notifyReadyForDeviceName(): Promise<DeviceNameMetadata>; + + /** + * Attempts to set the device name to the new name entered by the user. + */ + attemptSetDeviceName(name: string): Promise<SetDeviceNameResult>; +} + +let instance: DeviceNameBrowserProxy|null = null; + +export class DeviceNameBrowserProxyImpl implements DeviceNameBrowserProxy { + static getInstance(): DeviceNameBrowserProxy { + return instance || (instance = new DeviceNameBrowserProxyImpl()); + } + + static setInstanceForTesting(obj: DeviceNameBrowserProxy): void { + instance = obj; + } + + notifyReadyForDeviceName(): Promise<DeviceNameMetadata> { + return sendWithPromise('notifyReadyForDeviceName'); + } + + attemptSetDeviceName(name: string): Promise<SetDeviceNameResult> { + return sendWithPromise('attemptSetDeviceName', name); + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/device_name_util.js b/chrome/browser/resources/settings/chromeos/os_about_page/device_name_util.ts similarity index 74% rename from chrome/browser/resources/settings/chromeos/os_about_page/device_name_util.js rename to chrome/browser/resources/settings/chromeos/os_about_page/device_name_util.ts index fd34c24f..fd19daa 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/device_name_util.js +++ b/chrome/browser/resources/settings/chromeos/os_about_page/device_name_util.ts
@@ -10,36 +10,34 @@ * DeviceNameState stores information about the states of the device name. * Numerical values from this enum must stay in sync with the C++ enum in * device_name_store.h. - * @enum {number} */ -export const DeviceNameState = { +export enum DeviceNameState { // We can modify the device name. - CAN_BE_MODIFIED: 0, + CAN_BE_MODIFIED = 0, // We cannot modify the device name because of active policies. - CANNOT_BE_MODIFIED_BECAUSE_OF_POLICIES: 1, + CANNOT_BE_MODIFIED_BECAUSE_OF_POLICIES = 1, // We cannot modify the device name because user is not device // owner. - CANNOT_BE_MODIFIED_BECAUSE_NOT_DEVICE_OWNER: 2, -}; + CANNOT_BE_MODIFIED_BECAUSE_NOT_DEVICE_OWNER = 2, +} /** * NameUpdateResult stores information about the result of the name update * attempt. Numerical values from this enum must stay in sync with the C++ enum * in device_name_store.h. - * @enum {number} */ -export const SetDeviceNameResult = { +export enum SetDeviceNameResult { // Update was successful. - UPDATE_SUCCESSFUL: 0, + UPDATE_SUCCESSFUL = 0, // Update was unsuccessful because it is prohibited by policy. - ERROR_DUE_TO_POLICY: 1, + ERROR_DUE_TO_POLICY = 1, // Update was unsuccessful because user is not the device owner. - ERROR_DUE_TO_NOT_DEVICE_OWNER: 2, + ERROR_DUE_TO_NOT_DEVICE_OWNER = 2, // Update was unsuccessful because user input an invalid name. - ERROR_DUE_TO_INVALID_INPUT: 3, -}; \ No newline at end of file + ERROR_DUE_TO_INVALID_INPUT = 3, +}
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/edit_hostname_dialog.js b/chrome/browser/resources/settings/chromeos/os_about_page/edit_hostname_dialog.ts similarity index 77% rename from chrome/browser/resources/settings/chromeos/os_about_page/edit_hostname_dialog.js rename to chrome/browser/resources/settings/chromeos/os_about_page/edit_hostname_dialog.ts index fa86822..7312520 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/edit_hostname_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_about_page/edit_hostname_dialog.ts
@@ -7,41 +7,39 @@ * user to edit the device hostname. */ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.m.js'; import 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.m.js'; import 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js'; import '../../settings_shared.css.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/js/i18n_mixin.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {DeviceNameBrowserProxy, DeviceNameBrowserProxyImpl} from './device_name_browser_proxy.js'; import {SetDeviceNameResult} from './device_name_util.js'; import {getTemplate} from './edit_hostname_dialog.html.js'; -/** @type {number} */ const MAX_INPUT_LENGTH = 15; -/** @type {number} */ const MIN_INPUT_LENGTH = 1; const UNALLOWED_CHARACTERS = '[^0-9A-Za-z-]+'; -/** @type {RegExp} */ const EMOJI_REGEX_EXP = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/gi; -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const EditHostnameDialogElementBase = - mixinBehaviors([I18nBehavior], PolymerElement); +interface EditHostnameDialogElement { + $: { + dialog: CrDialogElement, + }; +} -/** @polymer */ +const EditHostnameDialogElementBase = I18nMixin(PolymerElement) as { + new (): PolymerElement & I18nMixinInterface, +}; + class EditHostnameDialogElement extends EditHostnameDialogElementBase { static get is() { return 'edit-hostname-dialog'; @@ -53,51 +51,49 @@ static get properties() { return { - /** @private {string} */ deviceName_: { type: String, value: '', observer: 'onDeviceNameChanged_', }, - /** @private {boolean} */ isInputInvalid_: { type: Boolean, value: false, reflectToAttribute: true, }, - /** @private {string} */ inputCountString_: { type: String, computed: 'computeInputCountString_(deviceName_)', }, - }; } + private deviceName_: string; + private isInputInvalid_: boolean; + private inputCountString_: string; + + private deviceNameBrowserProxy_: DeviceNameBrowserProxy; + constructor() { super(); - /** @private {DeviceNameBrowserProxy} */ this.deviceNameBrowserProxy_ = DeviceNameBrowserProxyImpl.getInstance(); } /** * Returns a formatted string containing the current number of characters * entered in the input compared to the maximum number of characters allowed. - * @return {string} - * @private */ - computeInputCountString_() { + private computeInputCountString_(): string { return this.i18n( 'aboutDeviceNameInputCharacterCount', this.deviceName_.length.toLocaleString(), MAX_INPUT_LENGTH.toLocaleString()); } - /** @private */ - onCancelTap_() { + private onCancelTap_() { this.$.dialog.close(); } @@ -105,11 +101,8 @@ * Observer for deviceName_ that sanitizes its value by removing any * Emojis and truncating it to MAX_INPUT_LENGTH. This method will be * recursively called until deviceName_ is fully sanitized. - * @param {string} newValue - * @param {string} oldValue - * @private */ - onDeviceNameChanged_(newValue, oldValue) { + private onDeviceNameChanged_(_newValue: string, oldValue: string) { if (oldValue) { const sanitizedOldValue = oldValue.replace(EMOJI_REGEX_EXP, ''); // If sanitizedOldValue.length > MAX_INPUT_LENGTH, the user attempted to @@ -132,8 +125,7 @@ } } - /** @private */ - onDoneTap_() { + private onDoneTap_() { this.deviceNameBrowserProxy_.attemptSetDeviceName(this.deviceName_) .then(result => { this.handleSetDeviceNameResponse_(result); @@ -141,15 +133,17 @@ this.$.dialog.close(); } - /** - * @param {SetDeviceNameResult} result - * @private - */ - handleSetDeviceNameResponse_(result) { + private handleSetDeviceNameResponse_(result: SetDeviceNameResult) { if (result !== SetDeviceNameResult.UPDATE_SUCCESSFUL) { console.error('ERROR IN UPDATE', result); } } } +declare global { + interface HTMLElementTagNameMap { + 'edit-hostname-dialog': EditHostnameDialogElement; + } +} + customElements.define(EditHostnameDialogElement.is, EditHostnameDialogElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.ts similarity index 79% rename from chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js rename to chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.ts index 6fb524d2..ded44ffd 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js +++ b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.ts
@@ -27,9 +27,9 @@ import 'chrome://resources/polymer/v3_0/iron-media-query/iron-media-query.js'; import {assert} from 'chrome://resources/js/assert.m.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/js/i18n_mixin.js'; import {parseHtmlSubset} from 'chrome://resources/js/parse_html_subset.m.js'; -import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/js/web_ui_listener_behavior.m.js'; +import {WebUIListenerMixin, WebUIListenerMixinInterface} from 'chrome://resources/js/web_ui_listener_mixin.js'; import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {loadTimeData} from '../../i18n_setup.js'; @@ -45,27 +45,33 @@ import {AboutPageBrowserProxy, AboutPageBrowserProxyImpl, AboutPageUpdateInfo, BrowserChannel, browserChannelToI18nId, RegulatoryInfo, TPMFirmwareUpdateStatusChangedEvent, UpdateStatus, UpdateStatusChangedEvent} from './about_page_browser_proxy.js'; import {getTemplate} from './os_about_page.html.js'; -/** - * @constructor - * @extends {PolymerElement} - * @implements {DeepLinkingBehaviorInterface} - * @implements {WebUIListenerBehaviorInterface} - * @implements {MainPageBehaviorInterface} - * @implements {RouteObserverBehaviorInterface} - * @implements {I18nBehaviorInterface} - */ -const OsSettingsAboutPageBase = mixinBehaviors( - [ - DeepLinkingBehavior, - WebUIListenerBehavior, - MainPageBehavior, - RouteObserverBehavior, - I18nBehavior, - ], - PolymerElement); +declare global { + interface HTMLElementEventMap { + 'target-channel-changed': CustomEvent<BrowserChannel>; + } +} -/** @polymer */ -class OsSettingsAboutPageElement extends OsSettingsAboutPageBase { +interface OsSettingsAboutPageElement { + $: { + updateStatusMessageInner: HTMLDivElement, + 'product-logo': HTMLImageElement, + }; +} + +const OsSettingsAboutPageBaseElement = + mixinBehaviors( + [ + DeepLinkingBehavior, + MainPageBehavior, + RouteObserverBehavior, + ], + I18nMixin(WebUIListenerMixin(PolymerElement))) as { + new (): PolymerElement & DeepLinkingBehaviorInterface & + WebUIListenerMixinInterface & MainPageBehaviorInterface & + RouteObserverBehaviorInterface & I18nMixinInterface, + }; + +class OsSettingsAboutPageElement extends OsSettingsAboutPageBaseElement { static get is() { return 'os-settings-about-page'; } @@ -78,14 +84,12 @@ return { /** * Whether the about page is being rendered in dark mode. - * @private */ isDarkModeActive_: { type: Boolean, value: false, }, - /** @private {?UpdateStatusChangedEvent} */ currentUpdateStatusEvent_: { type: Object, value: { @@ -100,7 +104,6 @@ /** * Whether the browser/ChromeOS is managed by their organization * through enterprise policies. - * @private */ isManaged_: { type: Boolean, @@ -111,7 +114,6 @@ /** * The domain of the organization managing the device. - * @private */ deviceManager_: { type: String, @@ -120,96 +122,78 @@ }, }, - /** @private */ hasCheckedForUpdates_: { type: Boolean, value: false, }, - /** @private {!BrowserChannel} */ currentChannel_: String, - /** @private {!BrowserChannel} */ targetChannel_: String, - /** @private */ isLts_: { type: Boolean, value: false, }, - /** @private {?RegulatoryInfo} */ regulatoryInfo_: Object, - /** @private */ hasEndOfLife_: { type: Boolean, value: false, }, - /** @private */ hasDeferredUpdate_: { type: Boolean, value: false, }, - /** @private */ eolMessageWithMonthAndYear_: { type: String, value: '', }, - /** @private */ hasInternetConnection_: { type: Boolean, value: false, }, - /** @private */ firmwareUpdateCount_: { type: Number, value: 0, }, - /** @private */ showCrostini: Boolean, - /** @private */ showCrostiniLicense_: { type: Boolean, value: false, }, - /** @private */ showUpdateStatus_: { type: Boolean, value: false, }, - /** @private */ showButtonContainer_: Boolean, - /** @private */ showRelaunch_: { type: Boolean, value: false, computed: 'computeShowRelaunch_(currentUpdateStatusEvent_)', }, - /** @private */ showCheckUpdates_: { type: Boolean, computed: 'computeShowCheckUpdates_(' + 'currentUpdateStatusEvent_, hasCheckedForUpdates_, hasEndOfLife_)', }, - /** @protected */ showFirmwareUpdatesApp_: { type: Boolean, value: () => loadTimeData.getBoolean('isFirmwareUpdaterAppEnabled'), }, - /** @private {!Map<string, string>} */ focusConfig_: { type: Object, value() { @@ -223,28 +207,23 @@ }, }, - /** @private */ showUpdateWarningDialog_: { type: Boolean, value: false, }, - /** @private */ showTPMFirmwareUpdateLineItem_: { type: Boolean, value: false, }, - /** @private */ showTPMFirmwareUpdateDialog_: Boolean, - /** @private {!AboutPageUpdateInfo|undefined} */ updateInfo_: Object, /** * Whether the deep link to the check for OS update setting was unable * to be shown. - * @private */ isPendingOsUpdateDeepLink_: { type: Boolean, @@ -253,7 +232,6 @@ /** * Used by DeepLinkingBehavior to focus this page's deep links. - * @type {!Set<!Setting>} */ supportedSettingIds: { type: Object, @@ -279,22 +257,52 @@ ]; } + private isDarkModeActive_: boolean; + private currentUpdateStatusEvent_: UpdateStatusChangedEvent; + private isManaged_: boolean; + private deviceManager_: string; + private hasCheckedForUpdates_: boolean; + private currentChannel_: BrowserChannel; + private targetChannel_: BrowserChannel; + private isLts_: boolean; + private regulatoryInfo_: RegulatoryInfo|null; + private hasEndOfLife_: boolean; + private hasDeferredUpdate_: boolean; + private eolMessageWithMonthAndYear_: string; + private hasInternetConnection_: boolean; + private firmwareUpdateCount_: number; + private showCrostini: boolean; + private showCrostiniLicense_: boolean; + private showUpdateStatus_: boolean; + private showButtonContainer_: boolean; + private showRelaunch_: boolean; + private showCheckUpdates_: boolean; + protected showFirmwareUpdatesApp_: boolean; + private focusConfig_: Map<string, string>; + private showUpdateWarningDialog_: boolean; + private showTPMFirmwareUpdateLineItem_: boolean; + private showTPMFirmwareUpdateDialog_: boolean; + private updateInfo_?: AboutPageUpdateInfo; + private isPendingOsUpdateDeepLink_: boolean; + override supportedSettingIds: Set<Setting>; + + private aboutBrowserProxy_: AboutPageBrowserProxy; + constructor() { super(); - /** @private {!AboutPageBrowserProxy} */ this.aboutBrowserProxy_ = AboutPageBrowserProxyImpl.getInstance(); } - /** @override */ - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.aboutBrowserProxy_.pageReady(); - this.addEventListener('target-channel-changed', e => { - this.targetChannel_ = e.detail; - }); + this.addEventListener( + 'target-channel-changed', (e: CustomEvent<BrowserChannel>) => { + this.targetChannel_ = e.detail; + }); this.aboutBrowserProxy_.getChannelInfo().then(info => { this.currentChannel_ = info.currentChannel; @@ -328,12 +336,7 @@ } } - /** - * @override - * @param {!Route} newRoute - * @param {!Route=} oldRoute - */ - currentRouteChanged(newRoute, oldRoute) { + override currentRouteChanged(newRoute: Route, oldRoute?: Route) { // super.currentRouteChanged() does not produce desired results since // RouteObserverBehavior has higher precedence than MainPageBehavior given // this element's behavior list order. In order to trigger the @@ -356,13 +359,11 @@ }); } - /** @override */ - containsRoute(route) { + override containsRoute(route: Route) { return !route || routes.ABOUT.contains(route); } - /** @private */ - startListening_() { + private startListening_() { this.addWebUIListener( 'update-status-changed', this.onUpdateStatusChanged_.bind(this)); this.aboutBrowserProxy_.refreshUpdateStatus(); @@ -372,11 +373,7 @@ this.aboutBrowserProxy_.refreshTPMFirmwareUpdateStatus(); } - /** - * @param {!UpdateStatusChangedEvent} event - * @private - */ - onUpdateStatusChanged_(event) { + private onUpdateStatusChanged_(event: UpdateStatusChangedEvent) { if (event.status === UpdateStatus.CHECKING) { this.hasCheckedForUpdates_ = true; } else if (event.status === UpdateStatus.NEED_PERMISSION_TO_UPDATE) { @@ -387,47 +384,37 @@ this.currentUpdateStatusEvent_ = event; } - /** - * @param {!Event} event - * @private - */ - onLearnMoreClick_(event) { + private onLearnMoreClick_(event: Event) { // Stop the propagation of events, so that clicking on links inside // actionable items won't trigger action. event.stopPropagation(); } - /** @private */ - onReleaseNotesTap_() { + private onReleaseNotesTap_() { this.aboutBrowserProxy_.launchReleaseNotes(); } - /** @private */ - onHelpClick_() { + private onHelpClick_() { this.aboutBrowserProxy_.openOsHelpPage(); } - /** @private */ - onDiagnosticsClick_() { + private onDiagnosticsClick_() { this.aboutBrowserProxy_.openDiagnostics(); recordSettingChange(Setting.kDiagnostics); } - /** @private */ - onFirmwareUpdatesClick_() { + private onFirmwareUpdatesClick_() { assert(this.showFirmwareUpdatesApp_); this.aboutBrowserProxy_.openFirmwareUpdatesPage(); recordSettingChange(Setting.kFirmwareUpdates); } - /** @private */ - onRelaunchClick_() { + private onRelaunchClick_() { recordSettingChange(); LifetimeBrowserProxyImpl.getInstance().relaunch(); } - /** @private */ - updateShowUpdateStatus_() { + private updateShowUpdateStatus_() { // Do not show the "updated" status or error states from a previous update // attempt if we haven't checked yet or the update warning dialog is shown // to user. @@ -455,9 +442,8 @@ /** * Hide the button container if all buttons are hidden, otherwise the * container displays an unwanted border (see separator class). - * @private */ - updateShowButtonContainer_() { + private updateShowButtonContainer_() { this.showButtonContainer_ = this.showRelaunch_ || this.showCheckUpdates_; // Check if we have yet to focus the check for update button. @@ -472,32 +458,19 @@ }); } - /** @private */ - computeShowRelaunch_() { + private computeShowRelaunch_() { return this.checkStatus_(UpdateStatus.NEARLY_UPDATED); } - /** - * @return {boolean} - * @private - */ - shouldShowLearnMoreLink_() { + private shouldShowLearnMoreLink_(): boolean { return this.currentUpdateStatusEvent_.status === UpdateStatus.FAILED; } - /** - * @return {boolean} - * @private - */ - shouldShowFirmwareUpdatesBadge_() { + private shouldShowFirmwareUpdatesBadge_(): boolean { return this.showFirmwareUpdatesApp_ && this.firmwareUpdateCount_ > 0; } - /** - * @return {string} - * @private - */ - getUpdateStatusMessage_() { + private getUpdateStatusMessage_(): string { switch (this.currentUpdateStatusEvent_.status) { case UpdateStatus.CHECKING: case UpdateStatus.NEED_PERMISSION_TO_UPDATE: @@ -516,7 +489,7 @@ return this.i18nAdvanced('aboutUpgradeUpToDate'); case UpdateStatus.UPDATING: assert(typeof this.currentUpdateStatusEvent_.progress === 'number'); - const progressPercent = this.currentUpdateStatusEvent_.progress + '%'; + const progressPercent = this.currentUpdateStatusEvent_.progress! + '%'; if (this.currentChannel_ !== this.targetChannel_) { return this.i18nAdvanced('aboutUpgradeUpdatingChannelSwitch', { @@ -532,7 +505,7 @@ substitutions: [this.deviceManager_, progressPercent], }); } - if (this.currentUpdateStatusEvent_.progress > 0) { + if (this.currentUpdateStatusEvent_.progress! > 0) { // NOTE(dbeam): some platforms (i.e. Mac) always send 0% while // updating (they don't support incremental upgrade progress). Though // it's certainly quite possible to validly end up here with 0% on @@ -552,9 +525,10 @@ case UpdateStatus.DEFERRED: return this.i18nAdvanced('aboutUpgradeNotUpToDate'); default: - function formatMessage(msg) { - return parseHtmlSubset('<b>' + msg + '</b>', ['br', 'pre']) - .firstChild.innerHTML; + function formatMessage(msg: string) { + return (parseHtmlSubset('<b>' + msg + '</b>', ['br', 'pre']) + .firstChild as HTMLElement) + .innerHTML; } let result = ''; const message = this.currentUpdateStatusEvent_.message; @@ -569,11 +543,7 @@ } } - /** - * @return {?string} - * @private - */ - getUpdateStatusIcon_() { + private getUpdateStatusIcon_(): string|null { // If Chrome OS has reached end of life, display a special icon and // ignore UpdateStatus. if (this.hasEndOfLife_) { @@ -598,11 +568,7 @@ } } - /** - * @return {string} - * @private - */ - getFirmwareUpdatesIcon_() { + private getFirmwareUpdatesIcon_(): string { if (this.firmwareUpdateCount_ === 0) { return ''; } @@ -614,11 +580,7 @@ return `os-settings:counter-${updateBadgeId}`; } - /** - * @return {?string} - * @private - */ - getThrobberSrcIfUpdating_() { + private getThrobberSrcIfUpdating_(): string|null { if (this.hasEndOfLife_) { return null; } @@ -634,38 +596,23 @@ } } - /** - * @param {!UpdateStatus} status - * @return {boolean} - * @private - */ - checkStatus_(status) { + private checkStatus_(status: UpdateStatus): boolean { return this.currentUpdateStatusEvent_.status === status; } - /** @private */ - onManagementPageClick_() { + private onManagementPageClick_() { window.open('chrome://management'); } - /** - * @return {boolean} - * @private - */ - isPowerwash_() { - return this.currentUpdateStatusEvent_.powerwash; + private isPowerwash_(): boolean { + return !!this.currentUpdateStatusEvent_.powerwash; } - /** @private */ - onDetailedBuildInfoClick_() { + private onDetailedBuildInfoClick_() { Router.getInstance().navigateTo(routes.DETAILED_BUILD_INFO); } - /** - * @return {string} - * @private - */ - getRelaunchButtonText_() { + private getRelaunchButtonText_(): string { if (this.checkStatus_(UpdateStatus.NEARLY_UPDATED)) { if (this.isPowerwash_()) { return this.i18nAdvanced('aboutRelaunchAndPowerwash'); @@ -676,30 +623,23 @@ return ''; } - /** @private */ - onCheckUpdatesClick_() { + private onCheckUpdatesClick_() { this.onUpdateStatusChanged_({status: UpdateStatus.CHECKING}); this.aboutBrowserProxy_.requestUpdate(); this.$.updateStatusMessageInner.focus(); } - /** @private */ - onApplyDeferredUpdateClick_() { + private onApplyDeferredUpdateClick_() { this.aboutBrowserProxy_.applyDeferredUpdate(); this.$.updateStatusMessageInner.focus(); } - /** @private */ - onApplyAndSetAutoUpdateClick_() { + private onApplyAndSetAutoUpdateClick_() { this.aboutBrowserProxy_.setConsumerAutoUpdate(true); this.onApplyDeferredUpdateClick_(); } - /** - * @return {boolean} - * @private - */ - computeShowCheckUpdates_() { + private computeShowCheckUpdates_(): boolean { // Disable update button if the device is end of life. if (this.hasEndOfLife_) { return false; @@ -716,77 +656,55 @@ } /** - * @param {boolean} showCrostiniLicense True if Crostini is enabled and + * @param showCrostiniLicense True if Crostini is enabled and * Crostini UI is allowed. - * @return {string} - * @private */ - getAboutProductOsLicense_(showCrostiniLicense) { + private getAboutProductOsLicense_(showCrostiniLicense: boolean): string { return showCrostiniLicense ? this.i18nAdvanced('aboutProductOsWithLinuxLicense') : this.i18nAdvanced('aboutProductOsLicense'); } /** - * @param {boolean} enabled True if Crostini is enabled. - * @private + * @param enabled True if Crostini is enabled. */ - handleCrostiniEnabledChanged_(enabled) { + private handleCrostiniEnabledChanged_(enabled: boolean) { this.showCrostiniLicense_ = enabled && this.showCrostini; } - /** - * @return {boolean} - * @private - */ - shouldShowSafetyInfo_() { + private shouldShowSafetyInfo_(): boolean { return loadTimeData.getBoolean('shouldShowSafetyInfo'); } - /** - * @return {boolean} - * @private - */ - shouldShowRegulatoryInfo_() { + private shouldShowRegulatoryInfo_(): boolean { return this.regulatoryInfo_ !== null; } - /** - * @return {boolean} - * @private - */ - shouldShowRegulatoryOrSafetyInfo_() { + private shouldShowRegulatoryOrSafetyInfo_(): boolean { return this.shouldShowSafetyInfo_() || this.shouldShowRegulatoryInfo_(); } - /** @private */ - onUpdateWarningDialogClose_() { + private onUpdateWarningDialogClose_() { this.showUpdateWarningDialog_ = false; // Shows 'check for updates' button in case that the user cancels the // dialog and then intends to check for update again. this.hasCheckedForUpdates_ = false; } - /** - * @param {!TPMFirmwareUpdateStatusChangedEvent} event - * @private - */ - onTPMFirmwareUpdateStatusChanged_(event) { + private onTPMFirmwareUpdateStatusChanged_( + event: TPMFirmwareUpdateStatusChangedEvent) { this.showTPMFirmwareUpdateLineItem_ = event.updateAvailable; } - /** @private */ - onTPMFirmwareUpdateClick_() { + private onTPMFirmwareUpdateClick_() { this.showTPMFirmwareUpdateDialog_ = true; } - /** @private */ - onPowerwashDialogClose_() { + private onPowerwashDialogClose_() { this.showTPMFirmwareUpdateDialog_ = false; } - /** @private */ - onProductLogoClick_() { + private onProductLogoClick_() { this.$['product-logo'].animate( { transform: ['none', 'rotate(-10turn)'], @@ -798,27 +716,18 @@ } // <if expr="_google_chrome"> - /** @private */ - onReportIssueClick_() { + private onReportIssueClick_() { this.aboutBrowserProxy_.openFeedbackDialog(); } - /** - * @return {string} - * @private - */ - getReportIssueLabel_() { + private getReportIssueLabel_(): string { return loadTimeData.getBoolean('isOsFeedbackEnabled') ? this.i18nAdvanced('aboutSendFeedback') : this.i18nAdvanced('aboutReportAnIssue'); } // </if> - /** - * @return {boolean} - * @private - */ - shouldShowIcons_() { + private shouldShowIcons_(): boolean { if (this.hasEndOfLife_) { return true; } @@ -826,5 +735,11 @@ } } +declare global { + interface HTMLElementTagNameMap { + 'os-settings-about-page': OsSettingsAboutPageElement; + } +} + customElements.define( OsSettingsAboutPageElement.is, OsSettingsAboutPageElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/update_warning_dialog.js b/chrome/browser/resources/settings/chromeos/os_about_page/update_warning_dialog.ts similarity index 60% rename from chrome/browser/resources/settings/chromeos/os_about_page/update_warning_dialog.js rename to chrome/browser/resources/settings/chromeos/os_about_page/update_warning_dialog.ts index 471f12a..d3b44f3 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/update_warning_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_about_page/update_warning_dialog.ts
@@ -8,24 +8,25 @@ * agrees to download update using mobile data. */ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import '../../settings_shared.css.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/js/i18n_mixin.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {AboutPageBrowserProxy, AboutPageBrowserProxyImpl, AboutPageUpdateInfo} from './about_page_browser_proxy.js'; import {getTemplate} from './update_warning_dialog.html.js'; -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const SettingsUpdateWarningDialogElementBase = - mixinBehaviors([I18nBehavior], PolymerElement); +interface SettingsUpdateWarningDialogElement { + $: { + dialog: CrDialogElement, + }; +} -/** @polymer */ +const SettingsUpdateWarningDialogElementBase = I18nMixin(PolymerElement) as { + new (): PolymerElement & I18nMixinInterface, +}; + class SettingsUpdateWarningDialogElement extends SettingsUpdateWarningDialogElementBase { static get is() { @@ -38,7 +39,6 @@ static get properties() { return { - /** @type {!AboutPageUpdateInfo|undefined} */ updateInfo: { type: Object, observer: 'updateInfoChanged_', @@ -46,40 +46,43 @@ }; } + updateInfo?: AboutPageUpdateInfo; + + private browserProxy_: AboutPageBrowserProxy; + constructor() { super(); - /** @private {AboutPageBrowserProxy} */ this.browserProxy_ = AboutPageBrowserProxyImpl.getInstance(); } - /** @override */ - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.$.dialog.showModal(); } - /** @private */ - onCancelTap_() { + private onCancelTap_() { this.$.dialog.close(); } - /** @private */ - onContinueTap_() { - if (!this.updateInfo || !this.updateInfo.version || !this.updateInfo.size){ + private onContinueTap_() { + if (!this.updateInfo || !this.updateInfo.version || !this.updateInfo.size) { console.warn('ERROR: requestUpdateOverCellular arguments are undefined'); return; } this.browserProxy_.requestUpdateOverCellular( - /** @type {!string} */ (this.updateInfo.version), - /** @type {!string} */ (this.updateInfo.size)); + this.updateInfo.version, this.updateInfo.size); this.$.dialog.close(); } - /** @private */ - updateInfoChanged_() { - this.shadowRoot.querySelector('#update-warning-message').innerHTML = + private updateInfoChanged_() { + if (!this.updateInfo || this.updateInfo.size === undefined) { + console.warn('ERROR: Update size is undefined'); + return; + } + + this.shadowRoot!.querySelector('#update-warning-message')!.innerHTML = this.i18n( 'aboutUpdateWarningMessage', // Convert bytes to megabytes @@ -87,5 +90,11 @@ } } +declare global { + interface HTMLElementTagNameMap { + 'settings-update-warning-dialog': SettingsUpdateWarningDialogElement; + } +} + customElements.define( SettingsUpdateWarningDialogElement.is, SettingsUpdateWarningDialogElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn index eda15f44..8b7d7fa 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn
@@ -89,7 +89,7 @@ "//ui/webui/resources/cr_elements:cr_scrollable_behavior.m", "//ui/webui/resources/cr_elements:find_shortcut_behavior", "//ui/webui/resources/cr_elements/cr_button:cr_button.m", - "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox.m", + "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox", "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m", ] externs_list = [ "//ui/webui/resources/cr_elements/cr_search_field/cr_search_field_externs.js" ] @@ -122,7 +122,7 @@ "//third_party/polymer/v3_0/components-chromium/iron-icon:iron-icon", "//third_party/polymer/v3_0/components-chromium/paper-tooltip:paper-tooltip", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox.m", + "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox", ] }
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/cr_checkbox_with_policy.js b/chrome/browser/resources/settings/chromeos/os_languages_page/cr_checkbox_with_policy.js index 131b803..3181a4c 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/cr_checkbox_with_policy.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/cr_checkbox_with_policy.js
@@ -21,7 +21,7 @@ * element to focus. This does not work when the element to focus is in a shadow * root. */ -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; import 'chrome://resources/polymer/v3_0/paper-tooltip/paper-tooltip.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.js b/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.js index cab7f7b..12fa7c8 100644 --- a/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.js
@@ -8,7 +8,7 @@ * from the user for a device reset (aka powerwash). */ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; import 'chrome://resources/cr_components/localized_link/localized_link.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni index e60811b..3d215d8 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.gni +++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -83,12 +83,12 @@ # TODO(crbug/1292025) Files that have their HTML wrapper file generated # by html_to_wrapper() go here. web_component_files = [ - "chromeos/os_about_page/channel_switcher_dialog.js", - "chromeos/os_about_page/consumer_auto_update_toggle_dialog.js", - "chromeos/os_about_page/detailed_build_info.js", - "chromeos/os_about_page/edit_hostname_dialog.js", - "chromeos/os_about_page/os_about_page.js", - "chromeos/os_about_page/update_warning_dialog.js", + "chromeos/os_about_page/channel_switcher_dialog.ts", + "chromeos/os_about_page/consumer_auto_update_toggle_dialog.ts", + "chromeos/os_about_page/detailed_build_info.ts", + "chromeos/os_about_page/edit_hostname_dialog.ts", + "chromeos/os_about_page/os_about_page.ts", + "chromeos/os_about_page/update_warning_dialog.ts", ] # Files that are passed as input to html_to_wrapper(). @@ -147,9 +147,9 @@ "chromeos/os_a11y_page/switch_access_subpage_browser_proxy.js", "chromeos/os_a11y_page/text_to_speech_page_browser_proxy.js", "chromeos/os_a11y_page/tts_subpage_browser_proxy.js", - "chromeos/os_about_page/about_page_browser_proxy.js", - "chromeos/os_about_page/device_name_browser_proxy.js", - "chromeos/os_about_page/device_name_util.js", + "chromeos/os_about_page/about_page_browser_proxy.ts", + "chromeos/os_about_page/device_name_browser_proxy.ts", + "chromeos/os_about_page/device_name_util.ts", "chromeos/os_apps_page/android_apps_browser_proxy.js", "chromeos/os_apps_page/app_management_page/actions.js", "chromeos/os_apps_page/app_management_page/api_listener.js", @@ -183,6 +183,10 @@ "chromeos/personalization_page/change_picture_browser_proxy.js", "chromeos/personalization_page/personalization_hub_browser_proxy.js", "chromeos/personalization_page/wallpaper_browser_proxy.js", + + # Files below are from Browser Settings and shared with ChromeOS Settings + "i18n_setup.ts", + "lifetime_browser_proxy.ts", "router.js", ]
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.js b/chrome/browser/resources/settings/chromeos/os_settings.js index b90cd15..6b1edc7 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.js +++ b/chrome/browser/resources/settings/chromeos/os_settings.js
@@ -150,7 +150,7 @@ export {TextToSpeechPageBrowserProxy, TextToSpeechPageBrowserProxyImpl} from './os_a11y_page/text_to_speech_page_browser_proxy.js'; export {TtsSubpageBrowserProxy, TtsSubpageBrowserProxyImpl} from './os_a11y_page/tts_subpage_browser_proxy.js'; export {AboutPageBrowserProxyImpl, BrowserChannel, UpdateStatus} from './os_about_page/about_page_browser_proxy.js'; -export {DeviceNameBrowserProxy, DeviceNameBrowserProxyImpl} from './os_about_page/device_name_browser_proxy.js'; +export {DeviceNameBrowserProxyImpl} from './os_about_page/device_name_browser_proxy.js'; export {DeviceNameState, SetDeviceNameResult} from './os_about_page/device_name_util.js'; export {AndroidAppsBrowserProxyImpl} from './os_apps_page/android_apps_browser_proxy.js'; export {addApp, changeApp, removeApp, updateSelectedAppId} from './os_apps_page/app_management_page/actions.js';
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.ts b/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.ts index 3fd4b17..fbf1c0b 100644 --- a/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.ts +++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.ts
@@ -7,7 +7,7 @@ * An installed app could be a domain with data that the user might want * to protect from being deleted. */ -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/policy/cr_policy_pref_indicator.m.js'; import '../settings_shared.css.js'; import '../site_favicon.js';
diff --git a/chrome/browser/resources/settings/controls/settings_checkbox.ts b/chrome/browser/resources/settings/controls/settings_checkbox.ts index abcabe6..ac2ccfe 100644 --- a/chrome/browser/resources/settings/controls/settings_checkbox.ts +++ b/chrome/browser/resources/settings/controls/settings_checkbox.ts
@@ -6,11 +6,11 @@ * @fileoverview * `settings-checkbox` is a checkbox that controls a supplied preference. */ -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/policy/cr_policy_pref_indicator.m.js'; import '../settings_shared.css.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {SettingsBooleanControlMixin} from './settings_boolean_control_mixin.js';
diff --git a/chrome/browser/resources/settings/languages_page/add_languages_dialog.ts b/chrome/browser/resources/settings/languages_page/add_languages_dialog.ts index bc41dc3e..3684324 100644 --- a/chrome/browser/resources/settings/languages_page/add_languages_dialog.ts +++ b/chrome/browser/resources/settings/languages_page/add_languages_dialog.ts
@@ -7,14 +7,14 @@ * languages. */ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_search_field/cr_search_field.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; import '../settings_shared.css.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {CrScrollableBehavior} from 'chrome://resources/cr_elements/cr_scrollable_behavior.m.js'; import {CrSearchFieldElement} from 'chrome://resources/cr_elements/cr_search_field/cr_search_field.js';
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.ts b/chrome/browser/resources/settings/languages_page/languages_page.ts index 1a669b4..dd21975 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.ts +++ b/chrome/browser/resources/settings/languages_page/languages_page.ts
@@ -11,7 +11,7 @@ import 'chrome://resources/cr_components/managed_dialog/managed_dialog.js'; import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; import 'chrome://resources/cr_elements/icons.m.js'; @@ -29,7 +29,7 @@ import '../settings_vars.css.js'; import {CrActionMenuElement} from '//resources/cr_elements/cr_action_menu/cr_action_menu.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; import {assert} from 'chrome://resources/js/assert_ts.js'; import {isWindows} from 'chrome://resources/js/cr.m.js';
diff --git a/chrome/browser/resources/settings/languages_page/spell_check_page.ts b/chrome/browser/resources/settings/languages_page/spell_check_page.ts index 91c72817..c23d92f 100644 --- a/chrome/browser/resources/settings/languages_page/spell_check_page.ts +++ b/chrome/browser/resources/settings/languages_page/spell_check_page.ts
@@ -139,7 +139,7 @@ private onSelectedSpellingServiceChange_() { this.languageSettingsMetricsProxy_.recordSettingsMetric( - this.prefs.spellcheck.use_spelling_service ? + this.prefs.spellcheck.use_spelling_service.value ? LanguageSettingsActionType.SELECT_ENHANCED_SPELL_CHECK : LanguageSettingsActionType.SELECT_BASIC_SPELL_CHECK); }
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts index 27eec361..aa0f0b8 100644 --- a/chrome/browser/resources/settings/lazy_load.ts +++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -69,7 +69,7 @@ // </if> -export {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +export {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; export {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; export {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; export {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
diff --git a/chrome/browser/resources/settings/people_page/signout_dialog.ts b/chrome/browser/resources/settings/people_page/signout_dialog.ts index aaf8ea6..b327b16 100644 --- a/chrome/browser/resources/settings/people_page/signout_dialog.ts +++ b/chrome/browser/resources/settings/people_page/signout_dialog.ts
@@ -7,7 +7,7 @@ * user to turn off sync and sign out of Chromium. */ import '//resources/cr_elements/cr_button/cr_button.m.js'; -import '//resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import '//resources/cr_elements/cr_checkbox/cr_checkbox.js'; import '//resources/cr_elements/cr_dialog/cr_dialog.m.js'; import '//resources/cr_elements/cr_expand_button/cr_expand_button.js'; import '//resources/cr_elements/shared_style_css.m.js';
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.ts b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.ts index fa110714..8357b05 100644 --- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.ts +++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.ts
@@ -11,7 +11,7 @@ * variant will be used. */ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/js/action_link.js'; import 'chrome://resources/cr_elements/action_link_css.m.js'; @@ -19,7 +19,7 @@ import '../settings_shared.css.js'; import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {I18nMixin} from 'chrome://resources/js/i18n_mixin.js'; import {PaperSpinnerLiteElement} from 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
diff --git a/chrome/browser/resources/settings/site_settings/add_site_dialog.ts b/chrome/browser/resources/settings/site_settings/add_site_dialog.ts index c7a3f30d..93114f8 100644 --- a/chrome/browser/resources/settings/site_settings/add_site_dialog.ts +++ b/chrome/browser/resources/settings/site_settings/add_site_dialog.ts
@@ -8,13 +8,13 @@ * Settings category. */ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import '../settings_shared.css.js'; import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import {assert} from 'chrome://resources/js/assert_ts.js';
diff --git a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.ts b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.ts index 9616b03b..40c54c3 100644 --- a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.ts +++ b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; import 'chrome://resources/cr_elements/icons.m.js';
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.ts b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.ts index e5c11618..ed3a417 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.ts +++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.ts b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.ts index 5af0677..11e0702cc2 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.ts +++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.ts
@@ -6,14 +6,14 @@ import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; import 'chrome://resources/cr_elements/shared_style_css.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; import './icons.js'; import './profile_card.js'; import './profile_picker_shared.css.js'; import './strings.m.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {WebUIListenerMixin} from 'chrome://resources/js/web_ui_listener_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/support_tool/data_collectors.ts b/chrome/browser/resources/support_tool/data_collectors.ts index cba80de..3481fdc 100644 --- a/chrome/browser/resources/support_tool/data_collectors.ts +++ b/chrome/browser/resources/support_tool/data_collectors.ts
@@ -4,7 +4,7 @@ import './support_tool_shared.css.js'; import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/support_tool/pii_selection.ts b/chrome/browser/resources/support_tool/pii_selection.ts index b51de97..26fb2de 100644 --- a/chrome/browser/resources/support_tool/pii_selection.ts +++ b/chrome/browser/resources/support_tool/pii_selection.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js'; import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.m.js'; import 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.m.js';
diff --git a/chrome/browser/resources/support_tool/url_generator.ts b/chrome/browser/resources/support_tool/url_generator.ts index e396554..d8bd180 100644 --- a/chrome/browser/resources/support_tool/url_generator.ts +++ b/chrome/browser/resources/support_tool/url_generator.ts
@@ -6,7 +6,7 @@ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo_component.ts index e7c94c7..0c4b313 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo_component.ts +++ b/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo_component.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo_component.ts index 83dd173..6c54fbc4 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo_component.ts +++ b/chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo_component.ts
@@ -5,7 +5,7 @@ import 'chrome://resources/cr_elements/cr_icons_css.m.js'; import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import 'chrome://resources/cr_elements/icons.m.js';
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_checkbox_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_checkbox_demo.html index 132f1892..96c3cde 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_checkbox_demo.html +++ b/chrome/browser/resources/webui_gallery/demos/cr_checkbox_demo.html
@@ -20,7 +20,7 @@ </template> </dom-bind> - <script src="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js" + <script src="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js" type="module"></script> </body> </html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo_component.ts index 2812b14..f4161d4 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo_component.ts +++ b/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo_component.ts
@@ -4,7 +4,7 @@ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; @@ -86,4 +86,4 @@ } } -customElements.define(CrDialogDemoComponent.is, CrDialogDemoComponent); \ No newline at end of file +customElements.define(CrDialogDemoComponent.is, CrDialogDemoComponent);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo_component.ts index 18a08a9..05384020 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo_component.ts +++ b/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo_component.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_slider/cr_slider.js'; import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc index f982ee32..5b037d51 100644 --- a/chrome/browser/signin/chrome_signin_client.cc +++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -256,10 +256,10 @@ void ChromeSigninClient::DelayNetworkCall(base::OnceClosure callback) { #if BUILDFLAG(IS_CHROMEOS_ASH) - // Do not make network requests in unit tests. chromeos::NetworkHandler should + // Do not make network requests in unit tests. ash::NetworkHandler should // not be used and is not expected to have been initialized in unit tests. if (url_loader_factory_for_testing_ && - !chromeos::NetworkHandler::IsInitialized()) { + !ash::NetworkHandler::IsInitialized()) { std::move(callback).Run(); return; }
diff --git a/chrome/browser/speech/speech_recognition_client_browser_interface.h b/chrome/browser/speech/speech_recognition_client_browser_interface.h index 04a3dbaa..da12d57 100644 --- a/chrome/browser/speech/speech_recognition_client_browser_interface.h +++ b/chrome/browser/speech/speech_recognition_client_browser_interface.h
@@ -48,7 +48,9 @@ void OnSodaInstalled(speech::LanguageCode language_code) override; void OnSodaProgress(speech::LanguageCode language_code, int progress) override {} - void OnSodaError(speech::LanguageCode language_code) override {} + void OnSodaInstallError( + speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) override {} private: void OnSpeechRecognitionAvailabilityChanged();
diff --git a/chrome/browser/sync/sync_service_factory_unittest.cc b/chrome/browser/sync/sync_service_factory_unittest.cc index 3369657..24e7b1b 100644 --- a/chrome/browser/sync/sync_service_factory_unittest.cc +++ b/chrome/browser/sync/sync_service_factory_unittest.cc
@@ -74,9 +74,9 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) SyncServiceFactoryTest() { // Fake network stack is required for WIFI_CONFIGURATIONS datatype. - chromeos::NetworkHandler::Initialize(); + ash::NetworkHandler::Initialize(); } - ~SyncServiceFactoryTest() override { chromeos::NetworkHandler::Shutdown(); } + ~SyncServiceFactoryTest() override { ash::NetworkHandler::Shutdown(); } #else SyncServiceFactoryTest() = default; ~SyncServiceFactoryTest() override = default;
diff --git a/chrome/browser/sync/test/integration/secondary_account_helper.cc b/chrome/browser/sync/test/integration/secondary_account_helper.cc index 1d2984d..4f42d37 100644 --- a/chrome/browser/sync/test/integration/secondary_account_helper.cc +++ b/chrome/browser/sync/test/integration/secondary_account_helper.cc
@@ -47,9 +47,8 @@ void InitNetwork() { auto* portal_detector = new ash::NetworkPortalDetectorTestImpl(); - const ash::NetworkState* default_network = chromeos::NetworkHandler::Get() - ->network_state_handler() - ->DefaultNetwork(); + const ash::NetworkState* default_network = + ash::NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); portal_detector->SetDefaultNetworkForTesting(default_network->guid());
diff --git a/chrome/browser/sync/wifi_configuration_sync_service_factory.cc b/chrome/browser/sync/wifi_configuration_sync_service_factory.cc index f1f1b76..96a85edd 100644 --- a/chrome/browser/sync/wifi_configuration_sync_service_factory.cc +++ b/chrome/browser/sync/wifi_configuration_sync_service_factory.cc
@@ -41,8 +41,7 @@ // Run when signed in to a real account. Skip during tests when network stack // has not been initialized. return profile && ash::ProfileHelper::IsRegularProfile(profile) && - !profile->IsOffTheRecord() && - chromeos::NetworkHandler::IsInitialized(); + !profile->IsOffTheRecord() && ash::NetworkHandler::IsInitialized(); } WifiConfigurationSyncServiceFactory::WifiConfigurationSyncServiceFactory()
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 3ff96cce..379c2ee1 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1844,6 +1844,7 @@ "//ui/base/dragdrop/mojom:mojom_headers", ] + # TODO(crbug.com/1030821): Resolve circular dependencies. allow_circular_includes_from += [ "//chrome/browser/media/router" ] if (use_ozone && !is_chromeos_ash) { @@ -5468,8 +5469,8 @@ "views/extensions/media_galleries_dialog_views.h", "views/extensions/media_gallery_checkbox_view.cc", "views/extensions/media_gallery_checkbox_view.h", - "views/extensions/settings_overridden_dialog_view.cc", - "views/extensions/settings_overridden_dialog_view.h", + "views/extensions/settings_overridden_dialog.cc", + "views/extensions/settings_overridden_dialog.h", "views/javascript_app_modal_event_blocker.h", "web_applications/app_browser_controller.cc", "web_applications/app_browser_controller.h",
diff --git a/chrome/browser/ui/android/fast_checkout/internal/BUILD.gn b/chrome/browser/ui/android/fast_checkout/internal/BUILD.gn index d48371a..5d29064 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/BUILD.gn +++ b/chrome/browser/ui/android/fast_checkout/internal/BUILD.gn
@@ -3,6 +3,9 @@ # found in the LICENSE file. import("//build/config/android/rules.gni") +import("//build/config/locales.gni") +import("//chrome/common/features.gni") +import("//tools/grit/grit_rule.gni") android_library("java") { sources = [ @@ -10,18 +13,39 @@ "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutCoordinator.java", "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediator.java", "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutModel.java", - "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutView.java", - "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutViewBinder.java", + "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java", ] deps = [ + ":java_resources", "//base:base_java", "//base:jni_java", "//build/android:build_java", "//chrome/browser/ui/android/fast_checkout:java", + "//chrome/browser/ui/android/strings:ui_strings_grd", "//components/autofill_assistant/android:public_java", "//components/browser_ui/bottomsheet/android:java", + "//components/browser_ui/strings/android:browser_ui_strings_grd", "//third_party/androidx:androidx_annotation_annotation_java", "//ui/android:ui_no_recycler_view_java", ] annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] + resources_package = "org.chromium.chrome.browser.ui.fast_checkout" +} + +android_resources("java_resources") { + deps = [ + ":java_strings_grd", + "//ui/android:ui_java_resources", + ] + custom_package = "org.chromium.chrome.browser.ui.fast_checkout" +} + +java_strings_grd("java_strings_grd") { + defines = chrome_grit_defines + grd_file = "java/strings/android_fast_checkout_strings.grd" + outputs = + [ "values/android_fast_checkout_strings.xml" ] + + process_file_template( + android_bundle_locales_as_resources, + [ "values-{{source_name_part}}/android_fast_checkout_strings.xml" ]) }
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutCoordinator.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutCoordinator.java index 74109af..fb9c96e 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutCoordinator.java +++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutCoordinator.java
@@ -12,25 +12,37 @@ import org.chromium.chrome.browser.ui.fast_checkout.data.FastCheckoutCreditCard; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.ui.modelutil.PropertyModel; -import org.chromium.ui.modelutil.PropertyModelChangeProcessor; class FastCheckoutCoordinator implements FastCheckoutComponent { private FastCheckoutMediator mMediator = new FastCheckoutMediator(); + private PropertyModel mModel = FastCheckoutModel.createDefaultModel(); + private FastCheckoutSheetContent mContent; @Override public void initialize(Context context, BottomSheetController sheetController, FastCheckoutComponent.Delegate delegate) { - PropertyModel model = FastCheckoutModel.createDefaultModel(mMediator::onDismissed); - mMediator.initialize(delegate, model, sheetController); + mMediator.initialize(delegate, mModel, sheetController); LinearLayout rootView = new LinearLayout(context); rootView.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); rootView.setOrientation(LinearLayout.VERTICAL); - // TODO(crbug.com/1334642): Create views for all 3 screens. + mContent = new FastCheckoutSheetContent(rootView); - setUpModelChangeProcessors(model, new FastCheckoutView(rootView, sheetController)); + // TODO(crbug.com/1334642): Create views for all 3 screens. + mModel.addObserver((source, propertyKey) -> { + if (FastCheckoutModel.CURRENT_SCREEN == propertyKey) { + mContent.updateCurrentScreen(mModel.get(FastCheckoutModel.CURRENT_SCREEN)); + } else if (FastCheckoutModel.VISIBLE == propertyKey) { + // Dismiss the sheet if it can't be immediately shown. + boolean visibilityChangeSuccessful = + mMediator.setVisible(mModel.get(FastCheckoutModel.VISIBLE), mContent); + if (!visibilityChangeSuccessful && mModel.get(FastCheckoutModel.VISIBLE)) { + mMediator.dismiss(BottomSheetController.StateChangeReason.NONE); + } + } + }); } @Override @@ -38,9 +50,4 @@ FastCheckoutAutofillProfile[] profiles, FastCheckoutCreditCard[] creditCards) { mMediator.showOptions(profiles, creditCards); } - - static void setUpModelChangeProcessors(PropertyModel model, FastCheckoutView view) { - PropertyModelChangeProcessor.create( - model, view, FastCheckoutViewBinder::bindFastCheckoutView); - } }
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediator.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediator.java index 43ed1628..93929e4 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediator.java +++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediator.java
@@ -6,6 +6,7 @@ import android.view.View; +import androidx.annotation.MainThread; import androidx.annotation.Nullable; import org.chromium.chrome.browser.ui.fast_checkout.data.FastCheckoutAutofillProfile; @@ -27,6 +28,7 @@ private FastCheckoutComponent.Delegate mDelegate; private BottomSheetController mBottomSheetController; private BottomSheetObserver mBottomSheetClosedObserver; + private BottomSheetObserver mBottomSheetDismissedObserver; void initialize(FastCheckoutComponent.Delegate delegate, PropertyModel model, BottomSheetController bottomSheetController) { @@ -43,6 +45,15 @@ } } }; + + mBottomSheetDismissedObserver = new EmptyBottomSheetObserver() { + @Override + public void onSheetClosed(@BottomSheetController.StateChangeReason int reason) { + super.onSheetClosed(reason); + dismiss(reason); + mBottomSheetController.removeObserver(mBottomSheetDismissedObserver); + } + }; } public void showOptions( @@ -61,7 +72,29 @@ } } - public void onDismissed(@StateChangeReason int reason) { + /** + * If set to true, requests to show the bottom sheet. Otherwise, requests to hide the sheet. + * @param isVisible A boolean describing whether to show or hide the sheet. + * @param content The bottom sheet content to show/hide. + * @return True if the request was successful, false otherwise. + */ + public boolean setVisible(boolean isVisible, BottomSheetContent content) { + if (isVisible) { + mBottomSheetController.addObserver(mBottomSheetDismissedObserver); + if (!mBottomSheetController.requestShowContent(content, true)) { + mBottomSheetController.removeObserver(mBottomSheetDismissedObserver); + return false; + } + } else { + mBottomSheetController.hideContent(content, true); + } + return true; + } + + /** + * Dismisses the current bottom sheet. + */ + public void dismiss(@StateChangeReason int reason) { if (!mModel.get(FastCheckoutModel.VISIBLE)) return; // Dismiss only if not dismissed yet. // TODO(crbug.com/1334642): Record dismissal metrics. mModel.set(FastCheckoutModel.VISIBLE, false); @@ -79,4 +112,12 @@ && view.getTag().equals( AutofillAssistantPublicTags.AUTOFILL_ASSISTANT_BOTTOM_SHEET_CONTENT_TAG); } + + /** + * Releases the resources used by FastCheckoutMediator. + */ + @MainThread + private void destroy() { + mBottomSheetController.removeObserver(mBottomSheetDismissedObserver); + } }
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutModel.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutModel.java index 6c456a4d..b1aca1bc3 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutModel.java +++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutModel.java
@@ -6,7 +6,6 @@ import androidx.annotation.IntDef; -import org.chromium.base.Callback; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; @@ -29,10 +28,6 @@ int CREDIT_CARDS_SCREEN = 2; } - /** The handler for dismissing the bottom sheet. */ - public static final PropertyModel.WritableObjectPropertyKey<Callback<Integer>> DISMISS_HANDLER = - new PropertyModel.WritableObjectPropertyKey<>(); - /** Property that indicates the bottom sheet visibility. */ public static final PropertyModel.WritableBooleanPropertyKey VISIBLE = new PropertyModel.WritableBooleanPropertyKey(); @@ -44,15 +39,13 @@ public static final PropertyModel.WritableIntPropertyKey CURRENT_SCREEN = new PropertyModel.WritableIntPropertyKey(); - static PropertyModel createDefaultModel(Callback<Integer> dismissHandler) { + static PropertyModel createDefaultModel() { return new PropertyModel.Builder(ALL_KEYS) .with(VISIBLE, false) - .with(DISMISS_HANDLER, dismissHandler) .with(CURRENT_SCREEN, ScreenType.HOME_SCREEN) .build(); } /** All keys used for the fast checkout bottom sheet. */ - static final PropertyKey[] ALL_KEYS = - new PropertyKey[] {CURRENT_SCREEN, DISMISS_HANDLER, VISIBLE}; + static final PropertyKey[] ALL_KEYS = new PropertyKey[] {CURRENT_SCREEN, VISIBLE}; }
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java new file mode 100644 index 0000000..eb59092 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java
@@ -0,0 +1,106 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.ui.fast_checkout; + +import android.view.View; + +import androidx.annotation.Nullable; + +import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; + +/** + * The {@link BottomSheetContent} for Fast Checkout. + */ +public class FastCheckoutSheetContent implements BottomSheetContent { + private final View mContentView; + + /** + * Constructs a FastCheckoutSheetContent which creates, modifies, and shows the bottom sheet. + */ + FastCheckoutSheetContent(View contentView) { + mContentView = contentView; + } + + /** + * Sets the screen to show on the bottom sheet. + * @param screenType A {@link ScreenType} specifying the screen to show. + */ + void updateCurrentScreen(int screenType) { + // TODO(crbug.com/1334642): Implement. + } + + @Override + public View getContentView() { + return mContentView; + } + + @Nullable + @Override + public View getToolbarView() { + // TODO(crbug.com/1334642): Implement. + return null; + } + + @Override + public int getVerticalScrollOffset() { + // TODO(crbug.com/1334642): Implement. + return 0; + } + + @Override + public void destroy() {} + + @Override + public int getPriority() { + return BottomSheetContent.ContentPriority.HIGH; + } + + @Override + public boolean swipeToDismissEnabled() { + return false; + } + + @Override + public boolean skipHalfStateOnScrollingDown() { + return false; + } + + @Override + public int getPeekHeight() { + return BottomSheetContent.HeightMode.DISABLED; + } + + @Override + public float getFullHeightRatio() { + // TODO(crbug.com/1334642): Implement. + return HeightMode.DEFAULT; + } + + @Override + public float getHalfHeightRatio() { + // TODO(crbug.com/1334642): Implement. + return BottomSheetContent.HeightMode.DEFAULT; + } + + @Override + public int getSheetContentDescriptionStringId() { + return R.string.fast_checkout_content_description; + } + + @Override + public int getSheetClosedAccessibilityStringId() { + return R.string.fast_checkout_sheet_closed; + } + + @Override + public int getSheetHalfHeightAccessibilityStringId() { + return R.string.fast_checkout_sheet_half_height; + } + + @Override + public int getSheetFullHeightAccessibilityStringId() { + return R.string.fast_checkout_sheet_full_height; + } +}
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutView.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutView.java deleted file mode 100644 index 022868b..0000000 --- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutView.java +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.ui.fast_checkout; - -import android.view.View; - -import org.chromium.base.Callback; -import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; - -/** - * The {@link BottomSheetContent} for Fast Checkout. TODO(crbug.com/1334642): The view - * should implement BottomSheetContent. - */ -public class FastCheckoutView { - private final BottomSheetController mBottomSheetController; - private final View mContentView; - - /** - * Constructs a FastCheckoutView which creates, modifies, and shows the bottom sheet. - */ - FastCheckoutView(View contentView, BottomSheetController bottomSheetController) { - mBottomSheetController = bottomSheetController; - mContentView = contentView; - } - - /** - * Sets a new listener that reacts to events like item selection or dismissal. - * @param dismissHandler A {@link Callback<Integer>}. - */ - void setDismissHandler(Callback<Integer> dismissHandler) { - // TODO(crbug.com/1334642): Implement. - } - - /** - * If set to true, requests to show the bottom sheet. Otherwise, requests to hide the sheet. - * @param isVisible A boolean describing whether to show or hide the sheet. - * @return True if the request was successful, false otherwise. - */ - boolean setVisible(boolean isVisible) { - // TODO(crbug.com/1334642): Implement. - return false; - } - - /** - * Sets the screen to show on the bottom sheet. - * @param screenType A {@link ScreenType} specifying the screen to show. - */ - void updateCurrentScreen(int screenType) { - // TODO(crbug.com/1334642): Implement. - } -}
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutViewBinder.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutViewBinder.java deleted file mode 100644 index e00f9ede..0000000 --- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutViewBinder.java +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.ui.fast_checkout; - -import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutModel.DISMISS_HANDLER; -import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutModel.VISIBLE; - -import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel; - -/** - * Provides functions that map {@link FastCheckoutModel} changes to the suitable - * method in {@link FastCheckoutView}. - */ -public class FastCheckoutViewBinder { - static void bindFastCheckoutView( - PropertyModel model, FastCheckoutView view, PropertyKey propertyKey) { - if (FastCheckoutModel.CURRENT_SCREEN == propertyKey) { - view.updateCurrentScreen(model.get(FastCheckoutModel.CURRENT_SCREEN)); - } else if (FastCheckoutModel.DISMISS_HANDLER == propertyKey) { - view.setDismissHandler(model.get(DISMISS_HANDLER)); - } else if (FastCheckoutModel.VISIBLE == propertyKey) { - // Dismiss the sheet if it can't be immediately shown. - boolean visibilityChangeSuccessful = view.setVisible(model.get(VISIBLE)); - if (!visibilityChangeSuccessful && model.get(VISIBLE)) { - assert (model.get(DISMISS_HANDLER) != null); - model.get(DISMISS_HANDLER).onResult(BottomSheetController.StateChangeReason.NONE); - } - } - } -}
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings.grd b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings.grd new file mode 100644 index 0000000..a3e83af --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings.grd
@@ -0,0 +1,193 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright 2022 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. --> + +<grit current_release="1" latest_public_release="0" output_all_resource_defines="false"> + <outputs> + <output filename="values-af/android_fast_checkout_strings.xml" lang="af" type="android" /> + <output filename="values-am/android_fast_checkout_strings.xml" lang="am" type="android" /> + <output filename="values-ar/android_fast_checkout_strings.xml" lang="ar" type="android" /> + <output filename="values-as/android_fast_checkout_strings.xml" lang="as" type="android" /> + <output filename="values-az/android_fast_checkout_strings.xml" lang="az" type="android" /> + <output filename="values-be/android_fast_checkout_strings.xml" lang="be" type="android" /> + <output filename="values-bg/android_fast_checkout_strings.xml" lang="bg" type="android" /> + <output filename="values-bn/android_fast_checkout_strings.xml" lang="bn" type="android" /> + <output filename="values-bs/android_fast_checkout_strings.xml" lang="bs" type="android" /> + <output filename="values-ca/android_fast_checkout_strings.xml" lang="ca" type="android" /> + <output filename="values-cs/android_fast_checkout_strings.xml" lang="cs" type="android" /> + <output filename="values-da/android_fast_checkout_strings.xml" lang="da" type="android" /> + <output filename="values-de/android_fast_checkout_strings.xml" lang="de" type="android" /> + <output filename="values-el/android_fast_checkout_strings.xml" lang="el" type="android" /> + <output filename="values/android_fast_checkout_strings.xml" lang="en" type="android" /> + <output filename="values-en-rGB/android_fast_checkout_strings.xml" lang="en-GB" type="android" /> + <output filename="values-es/android_fast_checkout_strings.xml" lang="es" type="android" /> + <output filename="values-es-rUS/android_fast_checkout_strings.xml" lang="es-419" type="android" /> + <output filename="values-et/android_fast_checkout_strings.xml" lang="et" type="android" /> + <output filename="values-eu/android_fast_checkout_strings.xml" lang="eu" type="android" /> + <output filename="values-fa/android_fast_checkout_strings.xml" lang="fa" type="android" /> + <output filename="values-fi/android_fast_checkout_strings.xml" lang="fi" type="android" /> + <output filename="values-tl/android_fast_checkout_strings.xml" lang="fil" type="android" /> + <output filename="values-fr/android_fast_checkout_strings.xml" lang="fr" type="android" /> + <output filename="values-fr-rCA/android_fast_checkout_strings.xml" lang="fr-CA" type="android" /> + <output filename="values-gl/android_fast_checkout_strings.xml" lang="gl" type="android" /> + <output filename="values-gu/android_fast_checkout_strings.xml" lang="gu" type="android" /> + <output filename="values-hi/android_fast_checkout_strings.xml" lang="hi" type="android" /> + <output filename="values-hr/android_fast_checkout_strings.xml" lang="hr" type="android" /> + <output filename="values-hu/android_fast_checkout_strings.xml" lang="hu" type="android" /> + <output filename="values-hy/android_fast_checkout_strings.xml" lang="hy" type="android" /> + <output filename="values-in/android_fast_checkout_strings.xml" lang="id" type="android" /> + <output filename="values-is/android_fast_checkout_strings.xml" lang="is" type="android" /> + <output filename="values-it/android_fast_checkout_strings.xml" lang="it" type="android" /> + <output filename="values-iw/android_fast_checkout_strings.xml" lang="iw" type="android" /> + <output filename="values-ja/android_fast_checkout_strings.xml" lang="ja" type="android" /> + <output filename="values-ka/android_fast_checkout_strings.xml" lang="ka" type="android" /> + <output filename="values-kk/android_fast_checkout_strings.xml" lang="kk" type="android" /> + <output filename="values-km/android_fast_checkout_strings.xml" lang="km" type="android" /> + <output filename="values-kn/android_fast_checkout_strings.xml" lang="kn" type="android" /> + <output filename="values-ko/android_fast_checkout_strings.xml" lang="ko" type="android" /> + <output filename="values-ky/android_fast_checkout_strings.xml" lang="ky" type="android" /> + <output filename="values-lo/android_fast_checkout_strings.xml" lang="lo" type="android" /> + <output filename="values-lt/android_fast_checkout_strings.xml" lang="lt" type="android" /> + <output filename="values-lv/android_fast_checkout_strings.xml" lang="lv" type="android" /> + <output filename="values-mk/android_fast_checkout_strings.xml" lang="mk" type="android" /> + <output filename="values-ml/android_fast_checkout_strings.xml" lang="ml" type="android" /> + <output filename="values-mn/android_fast_checkout_strings.xml" lang="mn" type="android" /> + <output filename="values-mr/android_fast_checkout_strings.xml" lang="mr" type="android" /> + <output filename="values-ms/android_fast_checkout_strings.xml" lang="ms" type="android" /> + <output filename="values-my/android_fast_checkout_strings.xml" lang="my" type="android" /> + <output filename="values-ne/android_fast_checkout_strings.xml" lang="ne" type="android" /> + <output filename="values-nl/android_fast_checkout_strings.xml" lang="nl" type="android" /> + <output filename="values-nb/android_fast_checkout_strings.xml" lang="no" type="android" /> + <output filename="values-or/android_fast_checkout_strings.xml" lang="or" type="android" /> + <output filename="values-pa/android_fast_checkout_strings.xml" lang="pa" type="android" /> + <output filename="values-pl/android_fast_checkout_strings.xml" lang="pl" type="android" /> + <output filename="values-pt-rBR/android_fast_checkout_strings.xml" lang="pt-BR" type="android" /> + <output filename="values-pt-rPT/android_fast_checkout_strings.xml" lang="pt-PT" type="android" /> + <output filename="values-ro/android_fast_checkout_strings.xml" lang="ro" type="android" /> + <output filename="values-ru/android_fast_checkout_strings.xml" lang="ru" type="android" /> + <output filename="values-si/android_fast_checkout_strings.xml" lang="si" type="android" /> + <output filename="values-sk/android_fast_checkout_strings.xml" lang="sk" type="android" /> + <output filename="values-sl/android_fast_checkout_strings.xml" lang="sl" type="android" /> + <output filename="values-sq/android_fast_checkout_strings.xml" lang="sq" type="android" /> + <output filename="values-sr/android_fast_checkout_strings.xml" lang="sr" type="android" /> + <output filename="values-b+sr+Latn/android_fast_checkout_strings.xml" lang="sr-Latn" type="android" /> + <output filename="values-sv/android_fast_checkout_strings.xml" lang="sv" type="android" /> + <output filename="values-sw/android_fast_checkout_strings.xml" lang="sw" type="android" /> + <output filename="values-ta/android_fast_checkout_strings.xml" lang="ta" type="android" /> + <output filename="values-te/android_fast_checkout_strings.xml" lang="te" type="android" /> + <output filename="values-th/android_fast_checkout_strings.xml" lang="th" type="android" /> + <output filename="values-tr/android_fast_checkout_strings.xml" lang="tr" type="android" /> + <output filename="values-uk/android_fast_checkout_strings.xml" lang="uk" type="android" /> + <output filename="values-ur/android_fast_checkout_strings.xml" lang="ur" type="android" /> + <output filename="values-uz/android_fast_checkout_strings.xml" lang="uz" type="android" /> + <output filename="values-vi/android_fast_checkout_strings.xml" lang="vi" type="android" /> + <output filename="values-zh-rCN/android_fast_checkout_strings.xml" lang="zh-CN" type="android" /> + <output filename="values-zh-rHK/android_fast_checkout_strings.xml" lang="zh-HK" type="android" /> + <output filename="values-zh-rTW/android_fast_checkout_strings.xml" lang="zh-TW" type="android" /> + <output filename="values-zu/android_fast_checkout_strings.xml" lang="zu" type="android" /> + <!-- Pseudolocales --> + <output filename="values-ar-rXB/android_fast_checkout_strings.xml" lang="ar-XB" type="android" /> + <output filename="values-en-rXA/android_fast_checkout_strings.xml" lang="en-XA" type="android" /> + </outputs> + <translations> + <file path="translations/android_fast_checkout_strings_af.xtb" lang="af"/> + <file path="translations/android_fast_checkout_strings_am.xtb" lang="am"/> + <file path="translations/android_fast_checkout_strings_ar.xtb" lang="ar"/> + <file path="translations/android_fast_checkout_strings_as.xtb" lang="as"/> + <file path="translations/android_fast_checkout_strings_az.xtb" lang="az"/> + <file path="translations/android_fast_checkout_strings_be.xtb" lang="be"/> + <file path="translations/android_fast_checkout_strings_bg.xtb" lang="bg"/> + <file path="translations/android_fast_checkout_strings_bn.xtb" lang="bn"/> + <file path="translations/android_fast_checkout_strings_bs.xtb" lang="bs"/> + <file path="translations/android_fast_checkout_strings_ca.xtb" lang="ca"/> + <file path="translations/android_fast_checkout_strings_cs.xtb" lang="cs"/> + <file path="translations/android_fast_checkout_strings_cy.xtb" lang="cy"/> + <file path="translations/android_fast_checkout_strings_da.xtb" lang="da"/> + <file path="translations/android_fast_checkout_strings_de.xtb" lang="de"/> + <file path="translations/android_fast_checkout_strings_el.xtb" lang="el"/> + <file path="translations/android_fast_checkout_strings_en-GB.xtb" lang="en-GB"/> + <file path="translations/android_fast_checkout_strings_es.xtb" lang="es"/> + <file path="translations/android_fast_checkout_strings_es-419.xtb" lang="es-419"/> + <file path="translations/android_fast_checkout_strings_et.xtb" lang="et"/> + <file path="translations/android_fast_checkout_strings_eu.xtb" lang="eu"/> + <file path="translations/android_fast_checkout_strings_fa.xtb" lang="fa"/> + <file path="translations/android_fast_checkout_strings_fi.xtb" lang="fi"/> + <file path="translations/android_fast_checkout_strings_fil.xtb" lang="fil"/> + <file path="translations/android_fast_checkout_strings_fr.xtb" lang="fr"/> + <file path="translations/android_fast_checkout_strings_fr-CA.xtb" lang="fr-CA"/> + <file path="translations/android_fast_checkout_strings_gl.xtb" lang="gl"/> + <file path="translations/android_fast_checkout_strings_gu.xtb" lang="gu"/> + <file path="translations/android_fast_checkout_strings_hi.xtb" lang="hi"/> + <file path="translations/android_fast_checkout_strings_hr.xtb" lang="hr"/> + <file path="translations/android_fast_checkout_strings_hu.xtb" lang="hu"/> + <file path="translations/android_fast_checkout_strings_hy.xtb" lang="hy"/> + <file path="translations/android_fast_checkout_strings_id.xtb" lang="id"/> + <file path="translations/android_fast_checkout_strings_is.xtb" lang="is"/> + <file path="translations/android_fast_checkout_strings_it.xtb" lang="it"/> + <file path="translations/android_fast_checkout_strings_iw.xtb" lang="iw"/> + <file path="translations/android_fast_checkout_strings_ja.xtb" lang="ja"/> + <file path="translations/android_fast_checkout_strings_ka.xtb" lang="ka"/> + <file path="translations/android_fast_checkout_strings_kk.xtb" lang="kk"/> + <file path="translations/android_fast_checkout_strings_km.xtb" lang="km"/> + <file path="translations/android_fast_checkout_strings_kn.xtb" lang="kn"/> + <file path="translations/android_fast_checkout_strings_ko.xtb" lang="ko"/> + <file path="translations/android_fast_checkout_strings_ky.xtb" lang="ky"/> + <file path="translations/android_fast_checkout_strings_lo.xtb" lang="lo"/> + <file path="translations/android_fast_checkout_strings_lt.xtb" lang="lt"/> + <file path="translations/android_fast_checkout_strings_lv.xtb" lang="lv"/> + <file path="translations/android_fast_checkout_strings_mk.xtb" lang="mk"/> + <file path="translations/android_fast_checkout_strings_ml.xtb" lang="ml"/> + <file path="translations/android_fast_checkout_strings_mn.xtb" lang="mn"/> + <file path="translations/android_fast_checkout_strings_mr.xtb" lang="mr"/> + <file path="translations/android_fast_checkout_strings_ms.xtb" lang="ms"/> + <file path="translations/android_fast_checkout_strings_my.xtb" lang="my"/> + <file path="translations/android_fast_checkout_strings_ne.xtb" lang="ne"/> + <file path="translations/android_fast_checkout_strings_nl.xtb" lang="nl"/> + <file path="translations/android_fast_checkout_strings_no.xtb" lang="no"/> + <file path="translations/android_fast_checkout_strings_or.xtb" lang="or"/> + <file path="translations/android_fast_checkout_strings_pa.xtb" lang="pa"/> + <file path="translations/android_fast_checkout_strings_pl.xtb" lang="pl"/> + <file path="translations/android_fast_checkout_strings_pt-BR.xtb" lang="pt-BR"/> + <file path="translations/android_fast_checkout_strings_pt-PT.xtb" lang="pt-PT"/> + <file path="translations/android_fast_checkout_strings_ro.xtb" lang="ro"/> + <file path="translations/android_fast_checkout_strings_ru.xtb" lang="ru"/> + <file path="translations/android_fast_checkout_strings_si.xtb" lang="si"/> + <file path="translations/android_fast_checkout_strings_sk.xtb" lang="sk"/> + <file path="translations/android_fast_checkout_strings_sl.xtb" lang="sl"/> + <file path="translations/android_fast_checkout_strings_sq.xtb" lang="sq"/> + <file path="translations/android_fast_checkout_strings_sr.xtb" lang="sr"/> + <file path="translations/android_fast_checkout_strings_sr-Latn.xtb" lang="sr-Latn"/> + <file path="translations/android_fast_checkout_strings_sv.xtb" lang="sv"/> + <file path="translations/android_fast_checkout_strings_sw.xtb" lang="sw"/> + <file path="translations/android_fast_checkout_strings_ta.xtb" lang="ta"/> + <file path="translations/android_fast_checkout_strings_te.xtb" lang="te"/> + <file path="translations/android_fast_checkout_strings_th.xtb" lang="th"/> + <file path="translations/android_fast_checkout_strings_tr.xtb" lang="tr"/> + <file path="translations/android_fast_checkout_strings_uk.xtb" lang="uk"/> + <file path="translations/android_fast_checkout_strings_ur.xtb" lang="ur"/> + <file path="translations/android_fast_checkout_strings_uz.xtb" lang="uz"/> + <file path="translations/android_fast_checkout_strings_vi.xtb" lang="vi"/> + <file path="translations/android_fast_checkout_strings_zh-CN.xtb" lang="zh-CN"/> + <file path="translations/android_fast_checkout_strings_zh-HK.xtb" lang="zh-HK"/> + <file path="translations/android_fast_checkout_strings_zh-TW.xtb" lang="zh-TW"/> + <file path="translations/android_fast_checkout_strings_zu.xtb" lang="zu"/> + </translations> + <release allow_pseudo="false" seq="1"> + <messages fallback_to_english="true"> + <!-- Fast Checkout --> + <message name="IDS_FAST_CHECKOUT_CONTENT_DESCRIPTION" desc="Accessibility string read when the Fast Checkout bottom sheet is opened. It describes the bottom sheet where a user can pick an address and payment option to fill during checkout flows"> + List of addresses and payment options to be filled during checkout flows. + </message> + <message name="IDS_FAST_CHECKOUT_SHEET_HALF_HEIGHT" desc="Accessibility string read when the Fast Checkout bottom sheet showing a list of the user stored addresses and payment options is opened at half height. The sheet will occupy the bottom half the screen."> + List of addresses and payment options to be filled during checkout flows opened at half height. + </message> + <message name="IDS_FAST_CHECKOUT_SHEET_FULL_HEIGHT" desc="Accessibility string read when the Fast Checkout bottom sheet showing a list of the user stored addresses and payment options is opened at full height. The sheet will occupy the entire screen."> + List of addresses and payment options to be filled during checkout flows opened at full height. + </message> + <message name="IDS_FAST_CHECKOUT_SHEET_CLOSED" desc="Accessibility string read when the Fast Checkout bottom sheet showing a list of the user stored addresses and payment options is closed."> + List of addresses and payment options to be filled during checkout flows is closed. + </message> + </messages> + </release> +</grit>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_CONTENT_DESCRIPTION.png.sha1 b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_CONTENT_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..4b78845 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_CONTENT_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +7536bf3c61acf2dbc814ac68882a5ec5d4f783f4 \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_CLOSED.png.sha1 b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_CLOSED.png.sha1 new file mode 100644 index 0000000..4b78845 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_CLOSED.png.sha1
@@ -0,0 +1 @@ +7536bf3c61acf2dbc814ac68882a5ec5d4f783f4 \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_FULL_HEIGHT.png.sha1 b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_FULL_HEIGHT.png.sha1 new file mode 100644 index 0000000..4b78845 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_FULL_HEIGHT.png.sha1
@@ -0,0 +1 @@ +7536bf3c61acf2dbc814ac68882a5ec5d4f783f4 \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_HALF_HEIGHT.png.sha1 b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_HALF_HEIGHT.png.sha1 new file mode 100644 index 0000000..4b78845 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_HALF_HEIGHT.png.sha1
@@ -0,0 +1 @@ +7536bf3c61acf2dbc814ac68882a5ec5d4f783f4 \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_SUBTITLE.png.sha1 b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_SUBTITLE.png.sha1 new file mode 100644 index 0000000..4b78845 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_SUBTITLE.png.sha1
@@ -0,0 +1 @@ +7536bf3c61acf2dbc814ac68882a5ec5d4f783f4 \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_TITLE.png.sha1 b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_TITLE.png.sha1 new file mode 100644 index 0000000..4b78845 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings_grd/IDS_FAST_CHECKOUT_SHEET_TITLE.png.sha1
@@ -0,0 +1 @@ +7536bf3c61acf2dbc814ac68882a5ec5d4f783f4 \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_af.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_af.xtb new file mode 100644 index 0000000..b369e833 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_af.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="af"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_am.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_am.xtb new file mode 100644 index 0000000..92406ec2 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_am.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="am"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ar.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ar.xtb new file mode 100644 index 0000000..198ea62 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ar.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ar"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_as.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_as.xtb new file mode 100644 index 0000000..9aebd78 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_as.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="as"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_az.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_az.xtb new file mode 100644 index 0000000..db47f35 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_az.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="az"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_be.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_be.xtb new file mode 100644 index 0000000..ccab734 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_be.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="be"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_bg.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_bg.xtb new file mode 100644 index 0000000..6681995 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_bg.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="bg"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_bn.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_bn.xtb new file mode 100644 index 0000000..eca68d46 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_bn.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="bn"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_bs.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_bs.xtb new file mode 100644 index 0000000..07aea3c6 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_bs.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="bs"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ca.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ca.xtb new file mode 100644 index 0000000..71cdd772 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ca.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ca"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_cs.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_cs.xtb new file mode 100644 index 0000000..dc153a85 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_cs.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="cs"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_cy.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_cy.xtb new file mode 100644 index 0000000..eae5ddc --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_cy.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="cy"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_da.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_da.xtb new file mode 100644 index 0000000..1256832 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_da.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="da"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_de.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_de.xtb new file mode 100644 index 0000000..91de7f51 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_de.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="de"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_el.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_el.xtb new file mode 100644 index 0000000..6e5e7d8 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_el.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="el"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_en-GB.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_en-GB.xtb new file mode 100644 index 0000000..12c3fa00 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_en-GB.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="en-GB"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_es-419.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_es-419.xtb new file mode 100644 index 0000000..b652ed0 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_es-419.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="es-419"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_es.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_es.xtb new file mode 100644 index 0000000..4d4f400 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_es.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="es"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_et.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_et.xtb new file mode 100644 index 0000000..ab777bc5 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_et.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="et"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_eu.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_eu.xtb new file mode 100644 index 0000000..6910975 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_eu.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="eu"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fa.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fa.xtb new file mode 100644 index 0000000..4cff15d --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fa.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="fa"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fi.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fi.xtb new file mode 100644 index 0000000..60ba9aa --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fi.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="fi"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fil.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fil.xtb new file mode 100644 index 0000000..8f6a880 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fil.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="fil"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fr-CA.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fr-CA.xtb new file mode 100644 index 0000000..e2557d0 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fr-CA.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="fr-CA"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fr.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fr.xtb new file mode 100644 index 0000000..bf48975a --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_fr.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="fr"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_gl.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_gl.xtb new file mode 100644 index 0000000..e04c577 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_gl.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="gl"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_gu.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_gu.xtb new file mode 100644 index 0000000..7969d06 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_gu.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="gu"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hi.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hi.xtb new file mode 100644 index 0000000..a6ddd5d --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hi.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="hi"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hr.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hr.xtb new file mode 100644 index 0000000..26f99d0 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hr.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="hr"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hu.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hu.xtb new file mode 100644 index 0000000..bdc02ee --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hu.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="hu"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hy.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hy.xtb new file mode 100644 index 0000000..c9b28dd --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_hy.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="hy"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_id.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_id.xtb new file mode 100644 index 0000000..5f2882d --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_id.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="id"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_is.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_is.xtb new file mode 100644 index 0000000..6d0302a --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_is.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="is"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_it.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_it.xtb new file mode 100644 index 0000000..e7df702 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_it.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="it"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_iw.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_iw.xtb new file mode 100644 index 0000000..a29d4ad --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_iw.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="iw"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ja.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ja.xtb new file mode 100644 index 0000000..d8a3543 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ja.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ja"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ka.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ka.xtb new file mode 100644 index 0000000..b5877bc --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ka.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ka"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_kk.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_kk.xtb new file mode 100644 index 0000000..94816de --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_kk.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="kk"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_km.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_km.xtb new file mode 100644 index 0000000..6a62979 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_km.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="km"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_kn.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_kn.xtb new file mode 100644 index 0000000..4ecb12b --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_kn.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="kn"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ko.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ko.xtb new file mode 100644 index 0000000..558b05b --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ko.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ko"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ky.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ky.xtb new file mode 100644 index 0000000..71a0883 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ky.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ky"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_lo.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_lo.xtb new file mode 100644 index 0000000..eb6216c --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_lo.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="lo"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_lt.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_lt.xtb new file mode 100644 index 0000000..f20c0fa2 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_lt.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="lt"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_lv.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_lv.xtb new file mode 100644 index 0000000..6f3afbc --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_lv.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="lv"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_mk.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_mk.xtb new file mode 100644 index 0000000..02ed730 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_mk.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="mk"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ml.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ml.xtb new file mode 100644 index 0000000..e01197e --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ml.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ml"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_mn.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_mn.xtb new file mode 100644 index 0000000..0713767 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_mn.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="mn"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_mr.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_mr.xtb new file mode 100644 index 0000000..b137924e --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_mr.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="mr"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ms.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ms.xtb new file mode 100644 index 0000000..518685dd --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ms.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ms"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_my.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_my.xtb new file mode 100644 index 0000000..60d303e4 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_my.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="my"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ne.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ne.xtb new file mode 100644 index 0000000..66f9f15 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ne.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ne"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_nl.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_nl.xtb new file mode 100644 index 0000000..05ab957 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_nl.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="nl"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_no.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_no.xtb new file mode 100644 index 0000000..ede4de30 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_no.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="no"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_or.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_or.xtb new file mode 100644 index 0000000..27b3d81c --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_or.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="or"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pa.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pa.xtb new file mode 100644 index 0000000..5c7ac50 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pa.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="pa"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pl.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pl.xtb new file mode 100644 index 0000000..4519e3d --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pl.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="pl"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pt-BR.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pt-BR.xtb new file mode 100644 index 0000000..de39dfa --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pt-BR.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="pt-BR"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pt-PT.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pt-PT.xtb new file mode 100644 index 0000000..0b98ee77 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_pt-PT.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="pt-PT"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ro.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ro.xtb new file mode 100644 index 0000000..7129eb4 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ro.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ro"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ru.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ru.xtb new file mode 100644 index 0000000..6dfaa442 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ru.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ru"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_si.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_si.xtb new file mode 100644 index 0000000..cc50fd5 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_si.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="si"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sk.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sk.xtb new file mode 100644 index 0000000..202e515a --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sk.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="sk"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sl.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sl.xtb new file mode 100644 index 0000000..31b5a1a --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sl.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="sl"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sq.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sq.xtb new file mode 100644 index 0000000..a954869 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sq.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="sq"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sr-Latn.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sr-Latn.xtb new file mode 100644 index 0000000..c205597 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sr-Latn.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="sr-Latn"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sr.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sr.xtb new file mode 100644 index 0000000..984d7192 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sr.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="sr"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sv.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sv.xtb new file mode 100644 index 0000000..9a787b8 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sv.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="sv"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sw.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sw.xtb new file mode 100644 index 0000000..9aa61cb --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_sw.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="sw"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ta.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ta.xtb new file mode 100644 index 0000000..ef90687 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ta.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ta"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_te.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_te.xtb new file mode 100644 index 0000000..48c714b --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_te.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="te"> +</translationbundle>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_th.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_th.xtb new file mode 100644 index 0000000..dbe6a601 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_th.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="th"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_tr.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_tr.xtb new file mode 100644 index 0000000..d99480c --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_tr.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="tr"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_uk.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_uk.xtb new file mode 100644 index 0000000..6e80099d --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_uk.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="uk"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ur.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ur.xtb new file mode 100644 index 0000000..624b043 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_ur.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="ur"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_uz.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_uz.xtb new file mode 100644 index 0000000..63653888 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_uz.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="uz"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_vi.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_vi.xtb new file mode 100644 index 0000000..8a42ab1 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_vi.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="vi"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zh-CN.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zh-CN.xtb new file mode 100644 index 0000000..c7d76e8 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zh-CN.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="zh-CN"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zh-HK.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zh-HK.xtb new file mode 100644 index 0000000..b78b9774 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zh-HK.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="zh-HK"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zh-TW.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zh-TW.xtb new file mode 100644 index 0000000..3e0c306 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zh-TW.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="zh-TW"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zu.xtb b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zu.xtb new file mode 100644 index 0000000..be432e9a --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/strings/translations/android_fast_checkout_strings_zu.xtb
@@ -0,0 +1,4 @@ +<?xml version="1.0" ?> +<!DOCTYPE translationbundle> +<translationbundle lang="zu"> +</translationbundle> \ No newline at end of file
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java index c495201..f0572a05 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
@@ -40,7 +40,6 @@ import org.chromium.components.browser_ui.site_settings.SiteSettingsUtil; import org.chromium.components.content_settings.ContentSettingValues; import org.chromium.components.content_settings.ContentSettingsType; -import org.chromium.components.embedder_support.util.UrlUtilities; import org.chromium.components.page_info.PageInfoController; import org.chromium.components.page_info.PageInfoDiscoverabilityMetrics; import org.chromium.components.page_info.PageInfoDiscoverabilityMetrics.DiscoverabilityAction; @@ -328,15 +327,14 @@ // This logic doesn't apply to tablets. if (mIsTablet) return; - boolean shouldShowLogo = mSearchEngineLogoUtils.shouldShowSearchEngineLogo( - mLocationBarDataProvider.isIncognito()); + boolean shouldShowLogo = !mLocationBarDataProvider.isIncognito(); setShowIconsWhenUrlFocused(shouldShowLogo); if (!shouldShowLogo) return; if (mLocationBarDataProvider.isInOverviewAndShowingOmnibox()) { setStatusIconShown(true); } else if (mProfileSupplier.get() != null - && UrlUtilities.isCanonicalizedNTPUrl(mLocationBarDataProvider.getCurrentUrl())) { + && mLocationBarDataProvider.getNewTabPageDelegate().isCurrentlyVisible()) { setStatusIconShown(shouldShowLogo && (mUrlHasFocus || mUrlFocusPercent > 0)); } else { setStatusIconShown(true); @@ -356,7 +354,7 @@ // Only fade the animation on the new tab page. if (mProfileSupplier.get() != null - && UrlUtilities.isCanonicalizedNTPUrl(mLocationBarDataProvider.getCurrentUrl())) { + && mLocationBarDataProvider.getNewTabPageDelegate().isCurrentlyVisible()) { float focusAnimationProgress = percent; if (!mUrlHasFocus) { focusAnimationProgress = MathUtils.clamp( @@ -519,14 +517,13 @@ boolean maybeUpdateStatusIconForSearchEngineIcon() { // Show the logo unfocused if we're on the NTP. if (shouldDisplaySearchEngineIcon()) { - getStatusIconResourceForSearchEngineIcon( - mLocationBarDataProvider.isIncognito(), (statusIconRes) -> { - // Check again in case the conditions have changed since this callback was - // created. - if (shouldDisplaySearchEngineIcon()) { - mModel.set(StatusProperties.STATUS_ICON_RESOURCE, statusIconRes); - } - }); + getStatusIconResourceForSearchEngineIcon((statusIconRes) -> { + // Check again in case the conditions have changed since this callback was + // created. + if (shouldDisplaySearchEngineIcon()) { + mModel.set(StatusProperties.STATUS_ICON_RESOURCE, statusIconRes); + } + }); return true; } else { mShouldCancelCustomFavicon = true; @@ -539,28 +536,29 @@ * independent from alpha/visibility. */ boolean shouldDisplaySearchEngineIcon() { - boolean showIconWhenFocused = mUrlHasFocus && mShowStatusIconWhenUrlFocused; - boolean showIconOnNTP = mProfileSupplier.get() != null - && UrlUtilities.isCanonicalizedNTPUrl(mLocationBarDataProvider.getCurrentUrl()) - && !mLocationBarDataProvider.isLoading() && !mIsTablet - && (mUrlHasFocus || mUrlFocusPercent > 0); + if (mLocationBarDataProvider.isIncognito()) { + return false; + } - return mSearchEngineLogoUtils.shouldShowSearchEngineLogo( - mLocationBarDataProvider.isIncognito()) - && (showIconWhenFocused || showIconOnNTP); + if (mUrlHasFocus && mShowStatusIconWhenUrlFocused) { + return true; + } + + return (mUrlHasFocus || mUrlFocusPercent > 0) + && mLocationBarDataProvider.getNewTabPageDelegate().isCurrentlyVisible() + && mProfileSupplier.get() != null; } /** * Set the security icon resource for the search engine icon and invoke the callback to inform * the caller which resource has been set. * - * @param isIncognito True if the user is incognito. * @param resourceCallback Called when the final value is set for the security icon resource. * Meant to give the caller a chance to set the tint for the given * resource. */ private void getStatusIconResourceForSearchEngineIcon( - boolean isIncognito, Callback<StatusIconResource> resourceCallback) { + Callback<StatusIconResource> resourceCallback) { mShouldCancelCustomFavicon = false; // If the current url text is a valid url, then swap the dse icon for a globe. if (!mUrlBarTextIsSearch) { @@ -574,9 +572,7 @@ /** Return the resource id for the accessibility description or 0 if none apply. */ private int getAccessibilityDescriptionRes() { - if (mUrlHasFocus - && mSearchEngineLogoUtils.shouldShowSearchEngineLogo( - mLocationBarDataProvider.isIncognito())) { + if (mUrlHasFocus && !mLocationBarDataProvider.isIncognito()) { return 0; } return (mSecurityIconRes != 0) ? mSecurityIconDescriptionRes : 0;
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java index 12ed55b5..a2c3fe6 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java
@@ -52,7 +52,6 @@ import org.chromium.chrome.browser.ui.theme.BrandedColorScheme; import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; -import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.components.permissions.PermissionDialogController; import org.chromium.components.search_engines.TemplateUrlService; import org.chromium.components.security_state.ConnectionSecurityLevel; @@ -108,6 +107,7 @@ }; doReturn(false).when(mLocationBarDataProvider).isInOverviewAndShowingOmnibox(); doReturn(false).when(mLocationBarDataProvider).isIncognito(); + doReturn(mNewTabPageDelegate).when(mLocationBarDataProvider).getNewTabPageDelegate(); doAnswer(logoAnswer) .when(mSearchEngineLogoUtils) .getSearchEngineLogo( @@ -139,9 +139,6 @@ @Test @SmallTest public void searchEngineLogo_isGoogleLogo() { - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); - mMediator.setUrlHasFocus(true); mMediator.setShowIconsWhenUrlFocused(true); Assert.assertEquals(R.drawable.ic_logo_googleg_20dp, @@ -151,9 +148,7 @@ @Test @SmallTest public void searchEngineLogo_isGoogleLogo_hideAfterUnfocusFinished() { - doReturn(UrlConstants.NTP_URL).when(mLocationBarDataProvider).getCurrentUrl(); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); + doReturn(true).when(mNewTabPageDelegate).isCurrentlyVisible(); mMediator.setUrlHasFocus(true); mMediator.setUrlHasFocus(false); @@ -163,9 +158,6 @@ @Test @SmallTest public void searchEngineLogo_isGoogleLogo_noHideIconAfterUnfocusedWhenScrolled() { - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); - mMediator.setUrlHasFocus(false); mMediator.setShowIconsWhenUrlFocused(true); mMediator.setUrlFocusChangePercent(1f); @@ -177,9 +169,7 @@ @Test @SmallTest public void searchEngineLogo_isGoogleLogoOnNtp() { - doReturn(UrlConstants.NTP_URL).when(mLocationBarDataProvider).getCurrentUrl(); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ false, /* loupeEverywhere= */ false); + doReturn(true).when(mNewTabPageDelegate).isCurrentlyVisible(); mMediator.setUrlHasFocus(false); mMediator.setShowIconsWhenUrlFocused(true); @@ -191,9 +181,7 @@ @SmallTest public void searchEngineLogo_isGoogleLogoOnNtpTablet() { setupStatusMediator(/* isTablet= */ true); - doReturn(UrlConstants.NTP_URL).when(mLocationBarDataProvider).getCurrentUrl(); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ false, /* loupeEverywhere= */ false); + doReturn(true).when(mNewTabPageDelegate).isCurrentlyVisible(); mMediator.setUrlHasFocus(false); mMediator.setShowIconsWhenUrlFocused(true); @@ -205,12 +193,7 @@ @SmallTest public void searchEngineLogo_isGoogleLogo_whenScrolled() { doReturn(false).when(mLocationBarDataProvider).isLoading(); - doReturn(UrlConstants.NTP_URL).when(mLocationBarDataProvider).getCurrentUrl(); - doReturn(mNewTabPageDelegate).when(mLocationBarDataProvider).getNewTabPageDelegate(); doReturn(true).when(mNewTabPageDelegate).isCurrentlyVisible(); - doReturn(UrlConstants.NTP_URL).when(mLocationBarDataProvider).getCurrentUrl(); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); mMediator.setUrlHasFocus(false); mMediator.setShowIconsWhenUrlFocused(true); @@ -221,13 +204,10 @@ @Test @SmallTest - public void searchEngineLogo_onTextChanged_globeReplacesIconWhenTextIsSite() { mMediator.setUrlHasFocus(true); mMediator.setShowIconsWhenUrlFocused(true); doReturn(TEST_SEARCH_URL).when(mUrlBarEditingTextStateProvider).getTextWithAutocomplete(); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); mMediator.updateLocationBarIconForDefaultMatchCategory(false); Assert.assertEquals(R.drawable.ic_globe_24dp, @@ -236,13 +216,10 @@ @Test @SmallTest - public void searchEngineLogo_onTextChanged_globeReplacesIconWhenAutocompleteSiteContainsText() { mMediator.setUrlHasFocus(true); mMediator.setShowIconsWhenUrlFocused(true); doReturn(TEST_SEARCH_URL).when(mUrlBarEditingTextStateProvider).getTextWithAutocomplete(); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); mMediator.updateLocationBarIconForDefaultMatchCategory(false); Assert.assertEquals(R.drawable.ic_globe_24dp, @@ -255,8 +232,6 @@ mMediator.setUrlHasFocus(true); mMediator.setShowIconsWhenUrlFocused(true); doReturn(TEST_SEARCH_URL).when(mUrlBarEditingTextStateProvider).getTextWithAutocomplete(); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); mMediator.updateLocationBarIconForDefaultMatchCategory(true); Assert.assertNotEquals(R.drawable.ic_globe_24dp, @@ -265,14 +240,11 @@ @Test @SmallTest - public void searchEngineLogo_onTextChanged_noGlobeReplacementWhenUrlBarTextIsEmpty() { mMediator.setUrlHasFocus(true); mMediator.setShowIconsWhenUrlFocused(true); // Setup a valid url to prevent the default "" from matching the url. doReturn(TEST_SEARCH_URL).when(mUrlBarEditingTextStateProvider).getTextWithAutocomplete(); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); mMediator.updateLocationBarIconForDefaultMatchCategory(false); mMediator.updateLocationBarIconForDefaultMatchCategory(true); @@ -293,8 +265,6 @@ @SmallTest public void searchEngineLogo_incognitoNoIcon() { doReturn(true).when(mLocationBarDataProvider).isIncognito(); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); mMediator.setUrlHasFocus(false); mMediator.setShowIconsWhenUrlFocused(true); @@ -309,8 +279,6 @@ mMediator.setUrlHasFocus(true); mMediator.setShowIconsWhenUrlFocused(true); mMediator.updateSecurityIcon(0, 0, 0); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); Assert.assertTrue(mMediator.maybeUpdateStatusIconForSearchEngineIcon()); Assert.assertEquals(R.drawable.ic_logo_googleg_20dp, @@ -319,13 +287,10 @@ @Test @SmallTest - public void searchEngineLogo_maybeUpdateStatusIconForSearchEngineIconNoChanges() { mMediator.setUrlHasFocus(true); mMediator.setShowIconsWhenUrlFocused(false); mMediator.updateSecurityIcon(0, 0, 0); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); Assert.assertFalse(mMediator.maybeUpdateStatusIconForSearchEngineIcon()); } @@ -353,8 +318,6 @@ public void testIncognitoStateChange_goingToIncognito() { mMediator.setShowIconsWhenUrlFocused(true); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); doReturn(true).when(mLocationBarDataProvider).isIncognito(); mMediator.onIncognitoStateChanged(); Assert.assertEquals(null, mModel.get(StatusProperties.STATUS_ICON_RESOURCE)); @@ -366,8 +329,6 @@ public void testIncognitoStateChange_backFromIncognito() { mMediator.setShowIconsWhenUrlFocused(true); - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); doReturn(true).when(mLocationBarDataProvider).isIncognito(); mMediator.onIncognitoStateChanged(); doReturn(false).when(mLocationBarDataProvider).isIncognito(); @@ -412,9 +373,6 @@ @Test @SmallTest public void testTemplateUrlServiceChanged() { - setupSearchEngineLogoForTesting( - /* showLogo= */ true, /* isGoogle= */ true, /* loupeEverywhere= */ false); - mMediator.setShowIconsWhenUrlFocused(true); mMediator.setUrlHasFocus(true); @@ -513,17 +471,6 @@ } /** - * @param showLogo Whether the search engine logo should be shown. - * @param isGoogle Whether the search engine is Google. - * @param loupeEverywhere Whether to show the loupe everywhere. - */ - private void setupSearchEngineLogoForTesting( - boolean showLogo, boolean isGoogle, boolean loupeEverywhere) { - doReturn(showLogo).when(mSearchEngineLogoUtils).shouldShowSearchEngineLogo(false); - doReturn(false).when(mSearchEngineLogoUtils).shouldShowSearchEngineLogo(true); - } - - /** * @param currentUrl Url of current page. * @param isIncognito Whether the current page is in an incognito mode. */
diff --git a/chrome/browser/ui/android/overlay/overlay_window_android.cc b/chrome/browser/ui/android/overlay/overlay_window_android.cc index 8d580cb..534059d73a 100644 --- a/chrome/browser/ui/android/overlay/overlay_window_android.cc +++ b/chrome/browser/ui/android/overlay/overlay_window_android.cc
@@ -36,6 +36,7 @@ compositor_view_(nullptr), surface_layer_(cc::SurfaceLayer::Create()), bounds_(gfx::Rect(0, 0)), + update_action_timer_(std::make_unique<base::OneShotTimer>()), controller_(controller) { surface_layer_->SetIsDrawable(true); surface_layer_->SetStretchContentToFillBounds(true); @@ -93,7 +94,13 @@ Java_PictureInPictureActivity_setPlaybackState(env, java_ref_.get(env), playback_state_); - MaybeNotifyVisibleActionsChanged(); + Java_PictureInPictureActivity_setMicrophoneMuted(env, java_ref_.get(env), + microphone_muted_); + Java_PictureInPictureActivity_setCameraState(env, java_ref_.get(env), + camera_on_); + + if (!update_action_timer_->IsRunning()) + MaybeNotifyVisibleActionsChanged(); if (video_size_.IsEmpty()) return; @@ -124,7 +131,11 @@ window_android_ = nullptr; } - controller_->OnWindowDestroyed(/*should_pause_video=*/true); + // Only pause the video when play/pause button is visible. + controller_->OnWindowDestroyed( + /*should_pause_video=*/visible_actions_.find( + static_cast<int>(media_session::mojom::MediaSessionAction::kPlay)) != + visible_actions_.end()); } void OverlayWindowAndroid::TogglePlayPause(JNIEnv* env) { @@ -140,6 +151,18 @@ controller_->PreviousTrack(); } +void OverlayWindowAndroid::ToggleMicrophone(JNIEnv* env) { + controller_->ToggleMicrophone(); +} + +void OverlayWindowAndroid::ToggleCamera(JNIEnv* env) { + controller_->ToggleCamera(); +} + +void OverlayWindowAndroid::HangUp(JNIEnv* env) { + controller_->HangUp(); +} + void OverlayWindowAndroid::CompositorViewCreated( JNIEnv* env, const base::android::JavaParamRef<jobject>& compositor_view) { @@ -229,30 +252,61 @@ playback_state); } -void OverlayWindowAndroid::SetPlayPauseButtonVisibility(bool is_visible) { - if (!MaybeUpdateVisibleAction(media_session::mojom::MediaSessionAction::kPlay, - is_visible)) { +void OverlayWindowAndroid::SetMicrophoneMuted(bool muted) { + if (microphone_muted_ == muted) return; - } - MaybeUpdateVisibleAction(media_session::mojom::MediaSessionAction::kPause, + microphone_muted_ = muted; + if (java_ref_.is_uninitialized()) + return; + + JNIEnv* env = base::android::AttachCurrentThread(); + Java_PictureInPictureActivity_setMicrophoneMuted(env, java_ref_.get(env), + microphone_muted_); +} + +void OverlayWindowAndroid::SetCameraState(bool turned_on) { + if (camera_on_ == turned_on) + return; + + camera_on_ = turned_on; + if (java_ref_.is_uninitialized()) + return; + + JNIEnv* env = base::android::AttachCurrentThread(); + Java_PictureInPictureActivity_setCameraState(env, java_ref_.get(env), + camera_on_); +} + +void OverlayWindowAndroid::SetPlayPauseButtonVisibility(bool is_visible) { + MaybeUpdateVisibleAction(media_session::mojom::MediaSessionAction::kPlay, is_visible); - MaybeNotifyVisibleActionsChanged(); } void OverlayWindowAndroid::SetNextTrackButtonVisibility(bool is_visible) { - if (MaybeUpdateVisibleAction( - media_session::mojom::MediaSessionAction::kNextTrack, is_visible)) { - MaybeNotifyVisibleActionsChanged(); - } + MaybeUpdateVisibleAction(media_session::mojom::MediaSessionAction::kNextTrack, + is_visible); } void OverlayWindowAndroid::SetPreviousTrackButtonVisibility(bool is_visible) { - if (MaybeUpdateVisibleAction( - media_session::mojom::MediaSessionAction::kPreviousTrack, - is_visible)) { - MaybeNotifyVisibleActionsChanged(); - } + MaybeUpdateVisibleAction( + media_session::mojom::MediaSessionAction::kPreviousTrack, is_visible); +} + +void OverlayWindowAndroid::SetToggleMicrophoneButtonVisibility( + bool is_visible) { + MaybeUpdateVisibleAction( + media_session::mojom::MediaSessionAction::kToggleMicrophone, is_visible); +} + +void OverlayWindowAndroid::SetToggleCameraButtonVisibility(bool is_visible) { + MaybeUpdateVisibleAction( + media_session::mojom::MediaSessionAction::kToggleCamera, is_visible); +} + +void OverlayWindowAndroid::SetHangUpButtonVisibility(bool is_visible) { + MaybeUpdateVisibleAction(media_session::mojom::MediaSessionAction::kHangUp, + is_visible); } void OverlayWindowAndroid::SetSurfaceId(const viz::SurfaceId& surface_id) { @@ -289,13 +343,13 @@ std::vector<int>(visible_actions_.begin(), visible_actions_.end()))); } -bool OverlayWindowAndroid::MaybeUpdateVisibleAction( +void OverlayWindowAndroid::MaybeUpdateVisibleAction( const media_session::mojom::MediaSessionAction& action, bool is_visible) { int action_code = static_cast<int>(action); if ((visible_actions_.find(action_code) != visible_actions_.end()) == is_visible) { - return false; + return; } if (is_visible) @@ -303,5 +357,10 @@ else visible_actions_.erase(action_code); - return true; + if (!update_action_timer_->IsRunning()) { + update_action_timer_->Start( + FROM_HERE, base::Seconds(1), + base::BindOnce(&OverlayWindowAndroid::MaybeNotifyVisibleActionsChanged, + base::Unretained(this))); + } }
diff --git a/chrome/browser/ui/android/overlay/overlay_window_android.h b/chrome/browser/ui/android/overlay/overlay_window_android.h index b655bad..b1daeb1 100644 --- a/chrome/browser/ui/android/overlay/overlay_window_android.h +++ b/chrome/browser/ui/android/overlay/overlay_window_android.h
@@ -8,6 +8,7 @@ #include "base/android/jni_weak_ref.h" #include "base/android/scoped_java_ref.h" #include "base/memory/raw_ptr.h" +#include "base/timer/timer.h" #include "content/public/browser/overlay_window.h" #include "third_party/blink/public/mojom/mediasession/media_session.mojom.h" #include "ui/android/window_android.h" @@ -39,6 +40,9 @@ void TogglePlayPause(JNIEnv* env); void NextTrack(JNIEnv* env); void PreviousTrack(JNIEnv* env); + void ToggleMicrophone(JNIEnv* env); + void ToggleCamera(JNIEnv* env); + void HangUp(JNIEnv* env); void CompositorViewCreated( JNIEnv* env, const base::android::JavaParamRef<jobject>& compositor_view); @@ -70,12 +74,11 @@ void SetSkipAdButtonVisibility(bool is_visible) override {} void SetNextTrackButtonVisibility(bool is_visible) override; void SetPreviousTrackButtonVisibility(bool is_visible) override; - // TODO(crbug.com/1331269): Implement video conferencing actions. - void SetMicrophoneMuted(bool muted) override {} - void SetCameraState(bool turned_on) override {} - void SetToggleMicrophoneButtonVisibility(bool is_visible) override {} - void SetToggleCameraButtonVisibility(bool is_visible) override {} - void SetHangUpButtonVisibility(bool is_visible) override {} + void SetMicrophoneMuted(bool muted) override; + void SetCameraState(bool turned_on) override; + void SetToggleMicrophoneButtonVisibility(bool is_visible) override; + void SetToggleCameraButtonVisibility(bool is_visible) override; + void SetHangUpButtonVisibility(bool is_visible) override; void SetSurfaceId(const viz::SurfaceId& surface_id) override; cc::Layer* GetLayerForTesting() override; @@ -84,7 +87,7 @@ void MaybeNotifyVisibleActionsChanged(); // Maybe update visible actions. Returns true if update happened. - bool MaybeUpdateVisibleAction( + void MaybeUpdateVisibleAction( const media_session::mojom::MediaSessionAction& action, bool is_visible); void CloseInternal(); @@ -100,6 +103,11 @@ PlaybackState playback_state_ = PlaybackState::kEndOfVideo; std::unordered_set<int> visible_actions_; + bool microphone_muted_ = false; + bool camera_on_ = false; + + std::unique_ptr<base::OneShotTimer> update_action_timer_; + raw_ptr<content::VideoPictureInPictureWindowController> controller_; };
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java index 334ed75..60ba4b6 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -204,7 +204,7 @@ */ public void initializeWithNative() { mOptimizationsEnabled = - ChromeFeatureList.isEnabled(ChromeFeatureList.LOCATION_BAR_MODEL_OPTIMIZATIONS); + ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS); mLastUsedNonOTRProfile = Profile.getLastUsedRegularProfile(); if (mOptimizationsEnabled) { mSpannableDisplayTextCache = new LruCache<>(LRU_CACHE_SIZE);
diff --git a/chrome/browser/ui/ash/assistant/device_actions.cc b/chrome/browser/ui/ash/assistant/device_actions.cc index 582e785..963a8a3 100644 --- a/chrome/browser/ui/ash/assistant/device_actions.cc +++ b/chrome/browser/ui/ash/assistant/device_actions.cc
@@ -31,9 +31,9 @@ #include "components/user_manager/user_manager.h" #include "ui/display/types/display_constants.h" +using ::ash::NetworkHandler; +using ::ash::NetworkStateHandler; using ::ash::NetworkTypePattern; -using chromeos::NetworkHandler; -using chromeos::NetworkStateHandler; using chromeos::assistant::AndroidAppInfo; using chromeos::assistant::AppStatus;
diff --git a/chrome/browser/ui/ash/network/enrollment_dialog_view.cc b/chrome/browser/ui/ash/network/enrollment_dialog_view.cc index 76bb5c3..5759048 100644 --- a/chrome/browser/ui/ash/network/enrollment_dialog_view.cc +++ b/chrome/browser/ui/ash/network/enrollment_dialog_view.cc
@@ -260,7 +260,7 @@ if (!policy) return false; - client_cert::ClientCertConfig cert_config; + ash::client_cert::ClientCertConfig cert_config; OncToClientCertConfig(onc_source, policy->GetDict(), &cert_config); if (cert_config.client_cert_type != onc::client_cert::kPattern)
diff --git a/chrome/browser/ui/ash/network/mobile_data_notifications.cc b/chrome/browser/ui/ash/network/mobile_data_notifications.cc index f8709fb..7702e145 100644 --- a/chrome/browser/ui/ash/network/mobile_data_notifications.cc +++ b/chrome/browser/ui/ash/network/mobile_data_notifications.cc
@@ -26,9 +26,9 @@ #include "third_party/cros_system_api/dbus/service_constants.h" #include "ui/base/l10n/l10n_util.h" +using ::ash::NetworkHandler; using ::ash::NetworkState; -using chromeos::NetworkHandler; -using chromeos::NetworkStateHandler; +using ::ash::NetworkStateHandler; using session_manager::SessionManager; using user_manager::UserManager;
diff --git a/chrome/browser/ui/ash/network/mobile_data_notifications.h b/chrome/browser/ui/ash/network/mobile_data_notifications.h index 2fe7744..84a4d65 100644 --- a/chrome/browser/ui/ash/network/mobile_data_notifications.h +++ b/chrome/browser/ui/ash/network/mobile_data_notifications.h
@@ -82,7 +82,7 @@ base::OneShotTimer one_shot_notification_check_delay_; - base::ScopedObservation<chromeos::NetworkStateHandler, + base::ScopedObservation<ash::NetworkStateHandler, ash::NetworkStateHandlerObserver> network_state_handler_observer_{this};
diff --git a/chrome/browser/ui/ash/network/network_state_notifier.cc b/chrome/browser/ui/ash/network/network_state_notifier.cc index 262256ba..04ff974 100644 --- a/chrome/browser/ui/ash/network/network_state_notifier.cc +++ b/chrome/browser/ui/ash/network/network_state_notifier.cc
@@ -556,7 +556,7 @@ network_name = *esim_name; } if (network_name.empty() && shill_properties) { - network_name = shill_property_util::GetNameFromProperties( + network_name = ash::shill_property_util::GetNameFromProperties( service_path, shill_properties.value()); }
diff --git a/chrome/browser/ui/ash/network/network_state_notifier.h b/chrome/browser/ui/ash/network/network_state_notifier.h index 2ecc160..49e9575 100644 --- a/chrome/browser/ui/ash/network/network_state_notifier.h +++ b/chrome/browser/ui/ash/network/network_state_notifier.h
@@ -140,7 +140,7 @@ // Tracks GUIDs of activating cellular networks for activation notification. std::set<std::string> cellular_activating_guids_; - base::ScopedObservation<chromeos::NetworkStateHandler, + base::ScopedObservation<ash::NetworkStateHandler, ash::NetworkStateHandlerObserver> network_state_handler_observer_{this};
diff --git a/chrome/browser/ui/ash/projector/projector_soda_installation_controller.cc b/chrome/browser/ui/ash/projector/projector_soda_installation_controller.cc index 530195d..efa9434 100644 --- a/chrome/browser/ui/ash/projector/projector_soda_installation_controller.cc +++ b/chrome/browser/ui/ash/projector/projector_soda_installation_controller.cc
@@ -91,8 +91,9 @@ app_client_->OnSodaInstalled(); } -void ProjectorSodaInstallationController::OnSodaError( - speech::LanguageCode language_code) { +void ProjectorSodaInstallationController::OnSodaInstallError( + speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) { // Check that language code matches the selected language for projector or is // LanguageCode::kNone (signifying the SODA binary failed). if (language_code != speech::GetLanguageCode(GetLocale()) &&
diff --git a/chrome/browser/ui/ash/projector/projector_soda_installation_controller.h b/chrome/browser/ui/ash/projector/projector_soda_installation_controller.h index 0056eb0..49772f2 100644 --- a/chrome/browser/ui/ash/projector/projector_soda_installation_controller.h +++ b/chrome/browser/ui/ash/projector/projector_soda_installation_controller.h
@@ -50,7 +50,8 @@ protected: // speech::SodaInstaller::Observer: void OnSodaInstalled(speech::LanguageCode language_code) override; - void OnSodaError(speech::LanguageCode language_code) override; + void OnSodaInstallError(speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) override; void OnSodaProgress(speech::LanguageCode language_code, int progress) override;
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc index 9311b7c..e534f77 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -68,6 +68,7 @@ #include "chrome/browser/ash/system_web_apps/test_support/test_system_web_app_manager.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/test_extension_system.h" +#include "chrome/browser/media/router/media_router_feature.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/sync_service_factory.h" @@ -1198,12 +1199,17 @@ public ::testing::WithParamInterface<bool> { public: ChromeShelfControllerTest() { + // `media_router::kMediaRouter` is disabled because it has unmet + // dependencies and is unrelated to this unit test. if (ShouldEnableSyncSettingsCategorization()) { - feature_list_.InitAndEnableFeature( - chromeos::features::kSyncSettingsCategorization); + feature_list_.InitWithFeatures( + /*enabled=*/{chromeos::features::kSyncSettingsCategorization}, + /*disabled=*/{media_router::kMediaRouter}); } else { - feature_list_.InitAndDisableFeature( - chromeos::features::kSyncSettingsCategorization); + feature_list_.InitWithFeatures( + /*enabled=*/{}, + /*disabled=*/{chromeos::features::kSyncSettingsCategorization, + media_router::kMediaRouter}); } } ~ChromeShelfControllerTest() override = default; @@ -1387,9 +1393,13 @@ : public ChromeShelfControllerTestBase { protected: MultiProfileMultiBrowserShelfLayoutChromeShelfControllerTest() { - // Lacros does not support the ChromeOS Legacy multi profile feature. - scoped_feature_list_.InitAndDisableFeature( - chromeos::features::kLacrosSupport); + // `kLacrosSupport` is disabled since Lacros does not support the ChromeOS + // Legacy multi profile feature. + // `kMediaRouter` is disabled because it has unmet dependencies and is + // unrelated to this unit test. + scoped_feature_list_.InitWithFeatures( + /*enabled=*/{}, /*disabled=*/{chromeos::features::kLacrosSupport, + media_router::kMediaRouter}); } MultiProfileMultiBrowserShelfLayoutChromeShelfControllerTest( const MultiProfileMultiBrowserShelfLayoutChromeShelfControllerTest&) =
diff --git a/chrome/browser/ui/ash/system_tray_client_impl.cc b/chrome/browser/ui/ash/system_tray_client_impl.cc index 3692578..ea2ae6a 100644 --- a/chrome/browser/ui/ash/system_tray_client_impl.cc +++ b/chrome/browser/ui/ash/system_tray_client_impl.cc
@@ -123,7 +123,7 @@ const ash::NetworkState* GetNetworkState(const std::string& network_id) { if (network_id.empty()) return nullptr; - return chromeos::NetworkHandler::Get() + return ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(network_id); } @@ -564,7 +564,7 @@ if (SessionManager::Get()->IsScreenLocked()) return; - DCHECK(chromeos::NetworkHandler::IsInitialized()); + DCHECK(ash::NetworkHandler::IsInitialized()); const ash::NetworkState* network_state = GetNetworkState(network_id); if (!network_state) { LOG(ERROR) << "Network not found: " << network_id;
diff --git a/chrome/browser/ui/cocoa/screentime/screentime_tab_helper_unittest.mm b/chrome/browser/ui/cocoa/screentime/screentime_tab_helper_unittest.mm index 209b8c6d1..1e9dd96 100644 --- a/chrome/browser/ui/cocoa/screentime/screentime_tab_helper_unittest.mm +++ b/chrome/browser/ui/cocoa/screentime/screentime_tab_helper_unittest.mm
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/cocoa/screentime/tab_helper.h" #include "base/test/scoped_feature_list.h" +#include "chrome/browser/media/router/media_router_feature.h" #include "chrome/browser/ui/cocoa/screentime/fake_webpage_controller.h" #include "chrome/browser/ui/cocoa/screentime/screentime_features.h" #include "chrome/browser/ui/cocoa/screentime/tab_helper.h" @@ -27,7 +28,10 @@ ::testing::Test::SetUp(); TabHelper::UseFakeWebpageControllerForTesting(); - features_.InitAndEnableFeature(kScreenTime); + // `kMediaRouter` is disabled because it has unmet dependencies and is + // unrelated to this unit test. + features_.InitWithFeatures(/*enabled=*/{kScreenTime}, + /*disabled=*/{media_router::kMediaRouter}); profile_ = std::make_unique<TestingProfile>(); }
diff --git a/chrome/browser/ui/extensions/extensions_dialogs.h b/chrome/browser/ui/extensions/extensions_dialogs.h index d000e88..0a2e532 100644 --- a/chrome/browser/ui/extensions/extensions_dialogs.h +++ b/chrome/browser/ui/extensions/extensions_dialogs.h
@@ -54,11 +54,6 @@ content::WebContents* contents, base::OnceCallback<void(bool)> callback); -// Shows a dialog indicating that an extension has overridden a setting. -void ShowExtensionSettingsOverriddenDialog( - std::unique_ptr<SettingsOverriddenDialogController> controller, - Browser* browser); - // Shows a dialog when extensions require a refresh for their action // to be run or blocked. The dialog content is based on whether caller // `is_updating_permissions`. When the dialog is accepted, `callback` is @@ -69,6 +64,12 @@ bool is_updating_permissions, base::OnceClosure callback); +// Shows a dialog with a warning to the user that their settings have been +// overridden by an extension. +void ShowSettingsOverriddenDialog( + std::unique_ptr<SettingsOverriddenDialogController> controller, + Browser* browser); + #if BUILDFLAG(ENABLE_SUPERVISED_USERS) // The type of action that the ExtensionInstalledBlockedByParentDialog
diff --git a/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc b/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc index 23d38aa..2ec03e1 100644 --- a/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc +++ b/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc
@@ -153,7 +153,7 @@ if (!dialog->ShouldShow()) return; - ShowExtensionSettingsOverriddenDialog(std::move(dialog), browser); + ShowSettingsOverriddenDialog(std::move(dialog), browser); #endif } @@ -201,7 +201,7 @@ if (!dialog->ShouldShow()) return; - ShowExtensionSettingsOverriddenDialog(std::move(dialog), browser); + ShowSettingsOverriddenDialog(std::move(dialog), browser); } } // namespace extensions
diff --git a/chrome/browser/ui/global_media_controls/media_notification_service.cc b/chrome/browser/ui/global_media_controls/media_notification_service.cc index c1c8a5d..e80f153 100644 --- a/chrome/browser/ui/global_media_controls/media_notification_service.cc +++ b/chrome/browser/ui/global_media_controls/media_notification_service.cc
@@ -45,15 +45,6 @@ message)); } -base::WeakPtr<media_router::WebContentsPresentationManager> -GetPresentationManager(content::WebContents* web_contents) { - if (!web_contents || - !media_router::MediaRouterEnabled(web_contents->GetBrowserContext())) { - return nullptr; - } - return media_router::WebContentsPresentationManager::Get(web_contents); -} - // Here we check to see if the WebContents is focused. Note that we can't just // use |WebContentsObserver::OnWebContentsFocused()| and // |WebContentsObserver::OnWebContentsLostFocus()| because focusing the @@ -76,47 +67,6 @@ } // namespace -MediaNotificationService::PresentationManagerObservation:: - PresentationManagerObservation(base::RepeatingClosure cast_started_callback, - content::WebContents* web_contents) - : cast_started_callback_(cast_started_callback), - presentation_manager_(GetPresentationManager(web_contents)) { - if (presentation_manager_) - presentation_manager_->AddObserver(this); - - bool has_presentation_request = - presentation_manager_ && - presentation_manager_->HasDefaultPresentationRequest(); - base::UmaHistogramBoolean( - "Media.GlobalMediaControls.HasDefaultPresentationRequest", - has_presentation_request); -} - -MediaNotificationService::PresentationManagerObservation:: - ~PresentationManagerObservation() { - if (presentation_manager_) - presentation_manager_->RemoveObserver(this); -} - -void MediaNotificationService::PresentationManagerObservation:: - OnPresentationsChanged(bool has_presentation) { - // If there is no presentation, then casting hasn't started. - if (!has_presentation) - return; - - // This will dismiss the backing item and therefore delete |this|. Do not use - // |this| after this call. - cast_started_callback_.Run(); -} - -void MediaNotificationService::PresentationManagerObservation:: - SetPresentationManagerForTesting( - base::WeakPtr<media_router::WebContentsPresentationManager> - presentation_manager) { - presentation_manager_ = presentation_manager; - presentation_manager_->AddObserver(this); -} - MediaNotificationService::MediaNotificationService( Profile* profile, bool show_from_all_profiles) { @@ -167,7 +117,6 @@ MediaNotificationService::~MediaNotificationService() { media_session_item_producer_->RemoveObserver(this); - presentation_manager_observations_.clear(); item_manager_->RemoveItemProducer(media_session_item_producer_.get()); } @@ -211,25 +160,6 @@ id, std::move(callback)); } -void MediaNotificationService::OnMediaSessionItemCreated( - const std::string& id) { - auto* web_contents = content::MediaSession::GetWebContentsFromRequestId(id); - - // base::Unretained is safe here since we own the object that owns this - // callback. - presentation_manager_observations_.emplace( - std::piecewise_construct, std::forward_as_tuple(id), - std::forward_as_tuple( - base::BindRepeating(&MediaNotificationService::OnCastStarted, - base::Unretained(this), web_contents), - web_contents)); -} - -void MediaNotificationService::OnMediaSessionItemDestroyed( - const std::string& id) { - presentation_manager_observations_.erase(id); -} - void MediaNotificationService::OnMediaSessionActionButtonPressed( const std::string& id, media_session::mojom::MediaSessionAction action) { @@ -367,27 +297,6 @@ device_provider_ = std::move(device_provider); } -void MediaNotificationService::OnCastStarted( - content::WebContents* web_contents) { - // Hide the dialog. - item_manager_->HideDialog(); - - if (!web_contents) - return; - - // If there is a media item associated with this WebContents, dismiss it. - auto request_id = - content::MediaSession::GetRequestIdFromWebContents(web_contents); - if (!request_id) - return; - - auto item = media_session_item_producer_->GetMediaItem(request_id.ToString()); - if (!item) - return; - - item->Dismiss(); -} - bool MediaNotificationService::HasCastNotificationsForWebContents( content::WebContents* web_contents) const { return !media_router::WebContentsPresentationManager::Get(web_contents)
diff --git a/chrome/browser/ui/global_media_controls/media_notification_service.h b/chrome/browser/ui/global_media_controls/media_notification_service.h index 38c9ba2d..b2cf8a1 100644 --- a/chrome/browser/ui/global_media_controls/media_notification_service.h +++ b/chrome/browser/ui/global_media_controls/media_notification_service.h
@@ -65,8 +65,8 @@ base::RepeatingCallback<void(bool)> callback) override; // global_media_controls::MediaSessionItemProducerObserver: - void OnMediaSessionItemCreated(const std::string& id) override; - void OnMediaSessionItemDestroyed(const std::string& id) override; + void OnMediaSessionItemCreated(const std::string& id) override {} + void OnMediaSessionItemDestroyed(const std::string& id) override {} void OnMediaSessionActionButtonPressed( const std::string& id, media_session::mojom::MediaSessionAction action) override; @@ -119,33 +119,6 @@ FRIEND_TEST_ALL_PREFIXES(MediaNotificationServiceCastTest, ShowSupplementalNotifications); - class PresentationManagerObservation : public content::PresentationObserver { - public: - PresentationManagerObservation(base::RepeatingClosure cast_started_callback, - content::WebContents* web_contents); - PresentationManagerObservation(const PresentationManagerObservation&) = - delete; - PresentationManagerObservation& operator=( - const PresentationManagerObservation&) = delete; - ~PresentationManagerObservation() override; - - // content::PresentationObserver: - void OnPresentationsChanged(bool has_presentation) override; - - void SetPresentationManagerForTesting( - base::WeakPtr<media_router::WebContentsPresentationManager> - presentation_manager); - - private: - base::RepeatingClosure cast_started_callback_; - base::WeakPtr<media_router::WebContentsPresentationManager> - presentation_manager_; - }; - - // Called by PresentationManagerObservation when casting starts for its - // WebContents. - void OnCastStarted(content::WebContents* web_contents); - // True if there are cast notifications associated with |web_contents|. bool HasCastNotificationsForWebContents( content::WebContents* web_contents) const; @@ -164,11 +137,6 @@ std::unique_ptr<PresentationRequestNotificationProducer> presentation_request_notification_producer_; - // Observes media_router::WebContentsPresentationManagers so we can dismiss - // the dialog when casting starts. - std::map<std::string, PresentationManagerObservation> - presentation_manager_observations_; - // Used to initialize a MediaRouterUI. std::unique_ptr<media_router::StartPresentationContext> context_;
diff --git a/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc b/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc index 6027cf0..4ab32b7 100644 --- a/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc +++ b/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc
@@ -161,14 +161,6 @@ service_->cast_notification_producer_->OnRoutesUpdated(routes); } - MediaNotificationService::PresentationManagerObservation* - GetPresentationObservation(const base::UnguessableToken& id) { - auto it = service_->presentation_manager_observations_.find(id.ToString()); - return (it == service_->presentation_manager_observations_.end()) - ? nullptr - : &it->second; - } - MediaNotificationService* service() { return service_.get(); } private: @@ -265,28 +257,6 @@ }; TEST_F(MediaNotificationServiceCastTest, - HideNotification_NewCastSessionStarted) { - // If a new cast session starts, hide the media dialog. - base::UnguessableToken id = SimulatePlayingControllableMedia(); - NiceMock<global_media_controls::test::MockMediaDialogDelegate> - dialog_delegate; - SimulateDialogOpened(&dialog_delegate); - EXPECT_TRUE(HasOpenDialog()); - - auto presentation_manager = - std::make_unique<MockWebContentsPresentationManager>(); - auto media_route = CreateMediaRoute("id"); - auto* observation = GetPresentationObservation(id); - observation->SetPresentationManagerForTesting( - presentation_manager.get()->GetWeakPtr()); - - EXPECT_CALL(dialog_delegate, HideMediaDialog()); - presentation_manager->NotifyMediaRoutesChanged({media_route}); - - task_environment()->RunUntilIdle(); -} - -TEST_F(MediaNotificationServiceCastTest, ShowCastSessionsForPresentationRequest) { NiceMock<global_media_controls::test::MockMediaDialogDelegate> dialog_delegate;
diff --git a/chrome/browser/ui/global_media_controls/presentation_request_notification_item.cc b/chrome/browser/ui/global_media_controls/presentation_request_notification_item.cc index 3c6b55c..0a9a2acd 100644 --- a/chrome/browser/ui/global_media_controls/presentation_request_notification_item.cc +++ b/chrome/browser/ui/global_media_controls/presentation_request_notification_item.cc
@@ -20,6 +20,8 @@ namespace { +content::MediaSession* g_media_session_for_test = nullptr; + content::WebContents* GetWebContentsFromPresentationRequest( const content::PresentationRequest& request) { auto* rfh = content::RenderFrameHost::FromID(request.render_frame_host_id); @@ -45,6 +47,13 @@ return gfx::ImageSkia::CreateFrom1xBitmap(color_type_copy); } +content::MediaSession* GetMediaSession(content::WebContents* web_contents) { + if (g_media_session_for_test) { + return g_media_session_for_test; + } + return content::MediaSession::Get(web_contents); +} + } // namespace PresentationRequestNotificationItem::PresentationRequestNotificationItem( @@ -67,7 +76,7 @@ // the page has no media players. auto* web_contents = GetWebContentsFromPresentationRequest(request_); DCHECK(web_contents); - auto* media_session = content::MediaSession::Get(web_contents); + auto* media_session = GetMediaSession(web_contents); DCHECK(media_session); media_session->AddObserver(observer_receiver_.BindNewPipeAndPassRemote()); } @@ -104,7 +113,7 @@ std::vector<media_session::MediaImage>>& images) { auto* web_contents = GetWebContentsFromPresentationRequest(request_); DCHECK(web_contents); - auto* media_session = content::MediaSession::Get(web_contents); + auto* media_session = GetMediaSession(web_contents); DCHECK(media_session); media_session::MediaImageManager manager( global_media_controls::kMediaItemArtworkMinSize, @@ -152,6 +161,12 @@ UpdateViewWithImages(); } +// static +void PresentationRequestNotificationItem::SetMediaSessionForTest( + content::MediaSession* media_session) { + g_media_session_for_test = media_session; +} + media_message_center::SourceType PresentationRequestNotificationItem::SourceType() { return media_message_center::SourceType::kPresentationRequest;
diff --git a/chrome/browser/ui/global_media_controls/presentation_request_notification_item.h b/chrome/browser/ui/global_media_controls/presentation_request_notification_item.h index f5f9df06..a3e3e28 100644 --- a/chrome/browser/ui/global_media_controls/presentation_request_notification_item.h +++ b/chrome/browser/ui/global_media_controls/presentation_request_notification_item.h
@@ -15,6 +15,10 @@ #include "services/media_session/public/mojom/media_session.mojom.h" #include "ui/gfx/image/image_skia.h" +namespace content { +class MediaSession; +} // namespace content + namespace global_media_controls { class MediaItemManager; } // namespace global_media_controls @@ -63,6 +67,8 @@ return weak_ptr_factory_.GetWeakPtr(); } + static void SetMediaSessionForTest(content::MediaSession* media_session); + const std::string& id() const { return id_; } media_router::StartPresentationContext* context() const { return context_.get();
diff --git a/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc b/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc index 654744e4..7f6e479 100644 --- a/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc +++ b/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
@@ -9,10 +9,66 @@ #include "components/media_message_center/mock_media_notification_view.h" #include "components/media_router/common/mojom/media_router.mojom.h" #include "content/public/browser/global_routing_id.h" +#include "content/public/browser/media_session.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/web_contents.h" #include "testing/gtest/include/gtest/gtest.h" +class MockMediaSession : public content::MediaSession { + public: + MOCK_METHOD(void, + DidReceiveAction, + (media_session::mojom::MediaSessionAction action), + (override)); + MOCK_METHOD(void, + SetDuckingVolumeMultiplier, + (double multiplier), + (override)); + MOCK_METHOD(void, + SetAudioFocusGroupId, + (const base::UnguessableToken& group_id), + (override)); + MOCK_METHOD(void, Suspend, (SuspendType suspend_type), (override)); + MOCK_METHOD(void, Resume, (SuspendType suspend_type), (override)); + MOCK_METHOD(void, StartDucking, (), (override)); + MOCK_METHOD(void, StopDucking, (), (override)); + MOCK_METHOD(void, + GetMediaSessionInfo, + (GetMediaSessionInfoCallback callback), + (override)); + MOCK_METHOD(void, GetDebugInfo, (GetDebugInfoCallback callback), (override)); + MOCK_METHOD(void, + AddObserver, + (mojo::PendingRemote<media_session::mojom::MediaSessionObserver> + observer), + (override)); + MOCK_METHOD(void, PreviousTrack, (), (override)); + MOCK_METHOD(void, NextTrack, (), (override)); + MOCK_METHOD(void, SkipAd, (), (override)); + MOCK_METHOD(void, Seek, (base::TimeDelta seek_time), (override)); + MOCK_METHOD(void, Stop, (SuspendType suspend_type), (override)); + MOCK_METHOD(void, + GetMediaImageBitmap, + (const media_session::MediaImage& image, + int minimum_size_px, + int desired_size_px, + GetMediaImageBitmapCallback callback), + (override)); + MOCK_METHOD(void, SeekTo, (base::TimeDelta seek_time), (override)); + MOCK_METHOD(void, ScrubTo, (base::TimeDelta seek_time), (override)); + MOCK_METHOD(void, EnterPictureInPicture, (), (override)); + MOCK_METHOD(void, ExitPictureInPicture, (), (override)); + MOCK_METHOD(void, + SetAudioSinkId, + (const absl::optional<std::string>& id), + (override)); + MOCK_METHOD(void, ToggleMicrophone, (), (override)); + MOCK_METHOD(void, ToggleCamera, (), (override)); + MOCK_METHOD(void, HangUp, (), (override)); + MOCK_METHOD(void, Raise, (), (override)); + MOCK_METHOD(void, SetMute, (bool mute), (override)); +}; + class PresentationRequestNotificationItemTest : public ChromeRenderViewHostTestHarness { public: @@ -23,11 +79,25 @@ const PresentationRequestNotificationItemTest&) = delete; ~PresentationRequestNotificationItemTest() override = default; + void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + PresentationRequestNotificationItem::SetMediaSessionForTest( + &media_session_); + } + + void TearDown() override { + PresentationRequestNotificationItem::SetMediaSessionForTest(nullptr); + ChromeRenderViewHostTestHarness::TearDown(); + } + content::PresentationRequest CreatePresentationRequest() { return content::PresentationRequest( main_rfh()->GetGlobalId(), {GURL("http://presentation.com")}, url::Origin::Create(GURL("http://google2.com"))); } + + private: + MockMediaSession media_session_; }; TEST_F(PresentationRequestNotificationItemTest, NotificationHeader) {
diff --git a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc index 62ebbfc7..bc05769 100644 --- a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc +++ b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc
@@ -81,6 +81,16 @@ return; } + bool is_disabled = GetVisualState() == Button::STATE_DISABLED; + SkColor background_color = + is_disabled ? GetForegroundColor(ButtonState::STATE_DISABLED) + : GetColorProvider()->GetColor( + kColorDownloadToolbarButtonRingBackground); + SkColor progress_color = + is_disabled + ? GetForegroundColor(ButtonState::STATE_DISABLED) + : GetColorProvider()->GetColor(kColorDownloadToolbarButtonActive); + int x = width() / 2 - kProgressRingRadius; int y = height() / 2 - kProgressRingRadius; int diameter = 2 * kProgressRingRadius; @@ -92,20 +102,16 @@ scanning_animation_.Reset(); scanning_animation_.Show(); } - views::DrawSpinningRing( - canvas, gfx::RectFToSkRect(ring_bounds), - GetColorProvider()->GetColor(kColorDownloadToolbarButtonRingBackground), - GetColorProvider()->GetColor(kColorDownloadToolbarButtonActive), - kProgressRingStrokeWidth, /*start_angle=*/ - gfx::Tween::IntValueBetween(scanning_animation_.GetCurrentValue(), 0, - 360)); + views::DrawSpinningRing(canvas, gfx::RectFToSkRect(ring_bounds), + background_color, progress_color, + kProgressRingStrokeWidth, /*start_angle=*/ + gfx::Tween::IntValueBetween( + scanning_animation_.GetCurrentValue(), 0, 360)); return; } views::DrawProgressRing( - canvas, gfx::RectFToSkRect(ring_bounds), - GetColorProvider()->GetColor(kColorDownloadToolbarButtonRingBackground), - GetColorProvider()->GetColor(kColorDownloadToolbarButtonActive), + canvas, gfx::RectFToSkRect(ring_bounds), background_color, progress_color, kProgressRingStrokeWidth, /*start_angle=*/-90, /*sweep_angle=*/360 * progress_info.progress_percentage / 100.0); } @@ -175,12 +181,16 @@ new_icon = &kDownloadToolbarButtonIcon; } - if (icon_color != gfx::kPlaceholderColor) { - for (auto state : kButtonStates) { - SetImageModel(state, - ui::ImageModel::FromVectorIcon(*new_icon, icon_color)); - } - } + SetImageModel(ButtonState::STATE_NORMAL, + ui::ImageModel::FromVectorIcon(*new_icon, icon_color)); + SetImageModel(ButtonState::STATE_HOVERED, + ui::ImageModel::FromVectorIcon(*new_icon, icon_color)); + SetImageModel(ButtonState::STATE_PRESSED, + ui::ImageModel::FromVectorIcon(*new_icon, icon_color)); + SetImageModel( + Button::STATE_DISABLED, + ui::ImageModel::FromVectorIcon( + *new_icon, GetForegroundColor(ButtonState::STATE_DISABLED))); } std::unique_ptr<views::View> DownloadToolbarButtonView::GetPrimaryView() {
diff --git a/chrome/browser/ui/views/extensions/settings_overridden_dialog.cc b/chrome/browser/ui/views/extensions/settings_overridden_dialog.cc new file mode 100644 index 0000000..c78246e --- /dev/null +++ b/chrome/browser/ui/views/extensions/settings_overridden_dialog.cc
@@ -0,0 +1,115 @@ +// Copyright 2022 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/extensions/settings_overridden_dialog.h" + +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/settings_overridden_dialog_controller.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/grit/generated_resources.h" +#include "components/constrained_window/constrained_window_views.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/dialog_model.h" +#include "ui/base/models/image_model.h" +#include "ui/color/color_id.h" +#include "ui/gfx/paint_vector_icon.h" + +using DialogResult = SettingsOverriddenDialogController::DialogResult; + +namespace { + +// Model delegate that notifies the `controller_` when a click event occurs in +// the settings overriden dialog. +class SettingsOverriddenDialogDelegate : public ui::DialogModelDelegate { + public: + explicit SettingsOverriddenDialogDelegate( + std::unique_ptr<SettingsOverriddenDialogController> controller) + : controller_(std::move(controller)) {} + + void OnDialogAccepted() { + HandleDialogResult(DialogResult::kChangeSettingsBack); + } + void OnDialogCancelled() { + HandleDialogResult(DialogResult::kKeepNewSettings); + } + void OnDialogClosed() { HandleDialogResult(DialogResult::kDialogDismissed); } + void OnDialogDestroyed() { + if (!result_) { + // The dialog may close without firing any of the [accept | cancel | + // close] callbacks if e.g. the parent window closes. In this case, notify + // the controller that the dialog closed without user action. + HandleDialogResult(DialogResult::kDialogClosedWithoutUserAction); + } + } + + SettingsOverriddenDialogController* controller() { return controller_.get(); } + + private: + void HandleDialogResult(DialogResult result) { + DCHECK(!result_) + << "Trying to re-notify controller of result. Previous result: " + << static_cast<int>(*result_) + << ", new result: " << static_cast<int>(result); + result_ = result; + controller_->HandleDialogResult(result); + } + std::unique_ptr<SettingsOverriddenDialogController> controller_; + absl::optional<DialogResult> result_; +}; + +} // namespace + +namespace extensions { + +void ShowSettingsOverriddenDialog( + std::unique_ptr<SettingsOverriddenDialogController> controller, + Browser* browser) { + SettingsOverriddenDialogController::ShowParams show_params = + controller->GetShowParams(); + + auto dialog_delegate_unique = + std::make_unique<SettingsOverriddenDialogDelegate>(std::move(controller)); + SettingsOverriddenDialogDelegate* dialog_delegate = + dialog_delegate_unique.get(); + + ui::DialogModel::Builder dialog_builder = + ui::DialogModel::Builder(std::move(dialog_delegate_unique)); + dialog_builder.SetInternalName(kExtensionSettingsOverridenDialogName) + .SetTitle(show_params.dialog_title) + .AddBodyText(ui::DialogModelLabel(show_params.message)) + .AddOkButton( + base::BindOnce(&SettingsOverriddenDialogDelegate::OnDialogAccepted, + base::Unretained(dialog_delegate)), + l10n_util::GetStringUTF16( + IDS_EXTENSION_SETTINGS_OVERRIDDEN_DIALOG_CHANGE_IT_BACK)) + .AddCancelButton( + base::BindOnce(&SettingsOverriddenDialogDelegate::OnDialogCancelled, + base::Unretained(dialog_delegate)), + l10n_util::GetStringUTF16( + IDS_EXTENSION_SETTINGS_OVERRIDDEN_DIALOG_KEEP_IT)) + .SetCloseActionCallback( + base::BindOnce(&SettingsOverriddenDialogDelegate::OnDialogClosed, + base::Unretained(dialog_delegate))) + .SetDialogDestroyingCallback( + base::BindOnce(&SettingsOverriddenDialogDelegate::OnDialogDestroyed, + base::Unretained(dialog_delegate))) + .OverrideShowCloseButton(false); + + if (show_params.icon) { + gfx::ImageSkia icon = + gfx::CreateVectorIcon(*show_params.icon, + ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_BUBBLE_HEADER_VECTOR_ICON_SIZE), + ui::kColorIcon); + + dialog_builder.SetIcon(ui::ImageModel::FromImageSkia(icon)); + } + + constrained_window::ShowBrowserModal(dialog_builder.Build(), + browser->window()->GetNativeWindow()); + dialog_delegate->controller()->OnDialogShown(); +} + +} // namespace extensions
diff --git a/chrome/browser/ui/views/extensions/settings_overridden_dialog.h b/chrome/browser/ui/views/extensions/settings_overridden_dialog.h new file mode 100644 index 0000000..589ea2b --- /dev/null +++ b/chrome/browser/ui/views/extensions/settings_overridden_dialog.h
@@ -0,0 +1,11 @@ +// Copyright 2022 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_EXTENSIONS_SETTINGS_OVERRIDDEN_DIALOG_H_ +#define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_SETTINGS_OVERRIDDEN_DIALOG_H_ + +static constexpr char kExtensionSettingsOverridenDialogName[] = + "ExtensionSettingsOverridenDialog"; + +#endif // CHROME_BROWSER_UI_VIEWS_EXTENSIONS_SETTINGS_OVERRIDDEN_DIALOG_H_
diff --git a/chrome/browser/ui/views/extensions/settings_overridden_dialog_view_browsertest.cc b/chrome/browser/ui/views/extensions/settings_overridden_dialog_browsertest.cc similarity index 90% rename from chrome/browser/ui/views/extensions/settings_overridden_dialog_view_browsertest.cc rename to chrome/browser/ui/views/extensions/settings_overridden_dialog_browsertest.cc index 2537224..e239f8cb 100644 --- a/chrome/browser/ui/views/extensions/settings_overridden_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/extensions/settings_overridden_dialog_browsertest.cc
@@ -2,19 +2,17 @@ // 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/extensions/settings_overridden_dialog_view.h" +#include "chrome/browser/ui/views/extensions/settings_overridden_dialog.h" #include "base/memory/raw_ptr.h" #include "base/path_service.h" -#include "base/strings/utf_string_conversions.h" #include "base/time/time.h" -#include "build/build_config.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/extensions/chrome_test_extension_loader.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/extensions_dialogs.h" #include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h" #include "chrome/browser/ui/extensions/settings_overridden_dialog_controller.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -29,6 +27,10 @@ #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "ui/views/test/widget_test.h" +#include "ui/views/widget/any_widget_observer.h" +#include "ui/views/widget/widget.h" + +using DialogResult = SettingsOverriddenDialogController::DialogResult; namespace { @@ -100,22 +102,23 @@ } } - // Creates, shows, and returns a dialog anchored to the given |browser|. The + // Creates, shows, and returns a dialog anchored to the given `browser`. The // dialog is owned by the views framework. - SettingsOverriddenDialogView* ShowSimpleDialog(bool show_icon, - Browser* browser) { + views::Widget* ShowSimpleDialog(bool show_icon, Browser* browser) { SettingsOverriddenDialogController::ShowParams params{ u"Settings overridden dialog title", u"Settings overriden dialog body, which is quite a bit " u"longer than the title alone"}; if (show_icon) params.icon = &kProductIcon; - auto* dialog = - new SettingsOverriddenDialogView(std::make_unique<TestDialogController>( - std::move(params), &dialog_result_)); - dialog->Show(browser->window()->GetNativeWindow()); - return dialog; + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + kExtensionSettingsOverridenDialogName); + extensions::ShowSettingsOverriddenDialog( + std::make_unique<TestDialogController>(std::move(params), + &dialog_result_), + browser); + return waiter.WaitIfNeededAndGet(); } void ShowNtpOverriddenDefaultDialog() { @@ -156,10 +159,7 @@ return true; } - absl::optional<SettingsOverriddenDialogController::DialogResult> - dialog_result() const { - return dialog_result_; - } + absl::optional<DialogResult> dialog_result() const { return dialog_result_; } private: void LoadExtensionOverridingNewTab() { @@ -231,9 +231,7 @@ } std::string test_name_; - - absl::optional<SettingsOverriddenDialogController::DialogResult> - dialog_result_; + absl::optional<DialogResult> dialog_result_; }; //////////////////////////////////////////////////////////////////////////////// @@ -296,15 +294,11 @@ Browser* second_browser = CreateBrowser(browser()->profile()); ASSERT_TRUE(second_browser); - SettingsOverriddenDialogView* dialog = - ShowSimpleDialog(false, second_browser); - - views::test::WidgetDestroyedWaiter widget_destroyed_waiter( - dialog->GetWidget()); + views::Widget* dialog = ShowSimpleDialog(false, second_browser); + views::test::WidgetDestroyedWaiter widget_destroyed_waiter(dialog); CloseBrowserSynchronously(second_browser); widget_destroyed_waiter.Wait(); + ASSERT_TRUE(dialog_result()); - EXPECT_EQ(SettingsOverriddenDialogController::DialogResult:: - kDialogClosedWithoutUserAction, - *dialog_result()); + EXPECT_EQ(DialogResult::kDialogClosedWithoutUserAction, *dialog_result()); }
diff --git a/chrome/browser/ui/views/extensions/settings_overridden_dialog_unittest.cc b/chrome/browser/ui/views/extensions/settings_overridden_dialog_unittest.cc new file mode 100644 index 0000000..23bcd8f5 --- /dev/null +++ b/chrome/browser/ui/views/extensions/settings_overridden_dialog_unittest.cc
@@ -0,0 +1,124 @@ +// 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 "chrome/browser/ui/views/extensions/settings_overridden_dialog.h" + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/ui/extensions/extensions_dialogs.h" +#include "chrome/browser/ui/extensions/settings_overridden_dialog_controller.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/frame/test_with_browser_view.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/views/test/widget_test.h" +#include "ui/views/widget/any_widget_observer.h" +#include "ui/views/widget/widget.h" +#include "ui/views/window/dialog_delegate.h" + +using DialogResult = SettingsOverriddenDialogController::DialogResult; + +namespace { + +struct DialogState { + bool shown = false; + absl::optional<DialogResult> result; +}; + +// A dialog controller that updates the provided DialogState when the dialog +// is interacted with. +class TestDialogController : public SettingsOverriddenDialogController { + public: + explicit TestDialogController(DialogState* state) + : state_(state), show_params_{u"Dialog Title", u"Dialog Body"} {} + TestDialogController(const TestDialogController&) = delete; + TestDialogController& operator=(const TestDialogController&) = delete; + ~TestDialogController() override = default; + + private: + bool ShouldShow() override { return true; } + ShowParams GetShowParams() override { return show_params_; } + void OnDialogShown() override { + EXPECT_FALSE(state_->shown) << "OnDialogShown() called more than once!"; + state_->shown = true; + } + void HandleDialogResult(DialogResult result) override { + state_->result = result; + } + + const raw_ptr<DialogState> state_; + const ShowParams show_params_; +}; + +} // namespace + +class SettingsOverriddenDialogViewUnitTest : public TestWithBrowserView { + public: + SettingsOverriddenDialogViewUnitTest() = default; + SettingsOverriddenDialogViewUnitTest( + const SettingsOverriddenDialogViewUnitTest&) = delete; + const SettingsOverriddenDialogViewUnitTest& operator=( + const SettingsOverriddenDialogViewUnitTest&) = delete; + ~SettingsOverriddenDialogViewUnitTest() override = default; + + views::Widget* ShowDialog(DialogState* state) { + auto controller = std::make_unique<TestDialogController>(state); + EXPECT_FALSE(state->shown); + + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + kExtensionSettingsOverridenDialogName); + extensions::ShowSettingsOverriddenDialog(std::move(controller), + browser_view()->browser()); + views::Widget* dialog = waiter.WaitIfNeededAndGet(); + EXPECT_TRUE(state->shown); + + return dialog; + } +}; + +TEST_F(SettingsOverriddenDialogViewUnitTest, DialogResult_ChangeSettingsBack) { + DialogState state; + views::Widget* dialog = ShowDialog(&state); + + views::test::WidgetDestroyedWaiter dialog_waiter(dialog); + dialog->widget_delegate()->AsDialogDelegate()->AcceptDialog(); + dialog_waiter.Wait(); + + ASSERT_TRUE(state.result); + EXPECT_EQ(DialogResult::kChangeSettingsBack, state.result); +} + +TEST_F(SettingsOverriddenDialogViewUnitTest, DialogResult_KeepNewSettings) { + DialogState state; + views::Widget* dialog = ShowDialog(&state); + + views::test::WidgetDestroyedWaiter dialog_waiter(dialog); + dialog->widget_delegate()->AsDialogDelegate()->CancelDialog(); + dialog_waiter.Wait(); + + ASSERT_TRUE(state.result); + EXPECT_EQ(DialogResult::kKeepNewSettings, state.result); +} + +TEST_F(SettingsOverriddenDialogViewUnitTest, DialogResult_DismissDialog) { + DialogState state; + views::Widget* dialog = ShowDialog(&state); + + views::test::WidgetDestroyedWaiter dialog_waiter(dialog); + dialog->Close(); + dialog_waiter.Wait(); + + ASSERT_TRUE(state.result); + EXPECT_EQ(DialogResult::kDialogDismissed, state.result); +} + +TEST_F(SettingsOverriddenDialogViewUnitTest, DialogResult_CloseParentWidget) { + DialogState state; + views::Widget* dialog = ShowDialog(&state); + + views::test::WidgetDestroyedWaiter dialog_waiter(dialog); + dialog->CloseNow(); + dialog_waiter.Wait(); + + ASSERT_TRUE(state.result); + EXPECT_EQ(DialogResult::kDialogClosedWithoutUserAction, state.result); +}
diff --git a/chrome/browser/ui/views/extensions/settings_overridden_dialog_view.cc b/chrome/browser/ui/views/extensions/settings_overridden_dialog_view.cc deleted file mode 100644 index 354c39d..0000000 --- a/chrome/browser/ui/views/extensions/settings_overridden_dialog_view.cc +++ /dev/null
@@ -1,118 +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 "chrome/browser/ui/views/extensions/settings_overridden_dialog_view.h" - -#include "base/bind.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/views/chrome_layout_provider.h" -#include "chrome/browser/ui/views/chrome_typography.h" -#include "chrome/grit/generated_resources.h" -#include "components/constrained_window/constrained_window_views.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/metadata/metadata_impl_macros.h" -#include "ui/color/color_id.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" - -namespace extensions { - -void ShowExtensionSettingsOverriddenDialog( - std::unique_ptr<SettingsOverriddenDialogController> controller, - Browser* browser) { - // Note: ownership is taken by the view hierarchy. - auto* dialog_view = new SettingsOverriddenDialogView(std::move(controller)); - dialog_view->Show(browser->window()->GetNativeWindow()); -} - -} // namespace extensions - -SettingsOverriddenDialogView::SettingsOverriddenDialogView( - std::unique_ptr<SettingsOverriddenDialogController> controller) - : controller_(std::move(controller)) { - SetButtonLabel(ui::DIALOG_BUTTON_OK, - l10n_util::GetStringUTF16( - IDS_EXTENSION_SETTINGS_OVERRIDDEN_DIALOG_CHANGE_IT_BACK)); - SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, - l10n_util::GetStringUTF16( - IDS_EXTENSION_SETTINGS_OVERRIDDEN_DIALOG_KEEP_IT)); - SetLayoutManager(std::make_unique<views::FillLayout>()); - set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType( - views::DialogContentType::kText, views::DialogContentType::kText)); - - using DialogResult = SettingsOverriddenDialogController::DialogResult; - auto make_result_callback = [this](DialogResult result) { - // NOTE: The following Bind's are safe because the callback is - // owned by this object (indirectly, as a DialogDelegate). - return base::BindOnce( - &SettingsOverriddenDialogView::NotifyControllerOfResult, - base::Unretained(this), result); - }; - SetAcceptCallback(make_result_callback(DialogResult::kChangeSettingsBack)); - SetCancelCallback(make_result_callback(DialogResult::kKeepNewSettings)); - SetCloseCallback(make_result_callback(DialogResult::kDialogDismissed)); - - SetModalType(ui::MODAL_TYPE_WINDOW); - SetShowCloseButton(false); - set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric( - views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH)); - - SettingsOverriddenDialogController::ShowParams show_params = - controller_->GetShowParams(); - SetTitle(show_params.dialog_title); - if (show_params.icon) - SetShowIcon(true); - - auto message_label = std::make_unique<views::Label>( - show_params.message, views::style::CONTEXT_DIALOG_BODY_TEXT, - views::style::STYLE_SECONDARY); - message_label->SetMultiLine(true); - message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - AddChildView(std::move(message_label)); -} - -SettingsOverriddenDialogView::~SettingsOverriddenDialogView() { - if (!result_) { - // The dialog may close without firing any of the [accept | cancel | close] - // callbacks if e.g. the parent window closes. In this case, notify the - // controller that the dialog closed without user action. - controller_->HandleDialogResult( - SettingsOverriddenDialogController::DialogResult:: - kDialogClosedWithoutUserAction); - } -} - -void SettingsOverriddenDialogView::OnThemeChanged() { - views::DialogDelegateView::OnThemeChanged(); - - const gfx::VectorIcon* icon = controller_->GetShowParams().icon; - if (icon) { - SetIcon( - gfx::CreateVectorIcon(*icon, - ChromeLayoutProvider::Get()->GetDistanceMetric( - DISTANCE_BUBBLE_HEADER_VECTOR_ICON_SIZE), - GetColorProvider()->GetColor(ui::kColorIcon))); - } -} - -void SettingsOverriddenDialogView::Show(gfx::NativeWindow parent) { - constrained_window::CreateBrowserModalDialogViews(this, parent)->Show(); - controller_->OnDialogShown(); -} - -void SettingsOverriddenDialogView::NotifyControllerOfResult( - SettingsOverriddenDialogController::DialogResult result) { - DCHECK(!result_) - << "Trying to re-notify controller of result. Previous result: " - << static_cast<int>(*result_) - << ", new result: " << static_cast<int>(result); - result_ = result; - controller_->HandleDialogResult(result); -} - -BEGIN_METADATA(SettingsOverriddenDialogView, views::DialogDelegateView) -END_METADATA
diff --git a/chrome/browser/ui/views/extensions/settings_overridden_dialog_view.h b/chrome/browser/ui/views/extensions/settings_overridden_dialog_view.h deleted file mode 100644 index 2c8ae93..0000000 --- a/chrome/browser/ui/views/extensions/settings_overridden_dialog_view.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_SETTINGS_OVERRIDDEN_DIALOG_VIEW_H_ -#define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_SETTINGS_OVERRIDDEN_DIALOG_VIEW_H_ - -#include <memory> - -#include "chrome/browser/ui/extensions/settings_overridden_dialog_controller.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "ui/base/metadata/metadata_header_macros.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/views/window/dialog_delegate.h" - -// A dialog that displays a warning to the user that their settings have been -// overridden by an extension. -class SettingsOverriddenDialogView : public views::DialogDelegateView { - public: - METADATA_HEADER(SettingsOverriddenDialogView); - explicit SettingsOverriddenDialogView( - std::unique_ptr<SettingsOverriddenDialogController> controller); - SettingsOverriddenDialogView(const SettingsOverriddenDialogView&) = delete; - SettingsOverriddenDialogView& operator=(const SettingsOverriddenDialogView&) = - delete; - ~SettingsOverriddenDialogView() override; - - void OnThemeChanged() override; - - // Displays the dialog with the given |parent|. - void Show(gfx::NativeWindow parent); - - private: - // Notifies the |controller_| of the |result|. - void NotifyControllerOfResult( - SettingsOverriddenDialogController::DialogResult result); - - // The result of the dialog; set when notifying the controller. - absl::optional<SettingsOverriddenDialogController::DialogResult> result_; - - std::unique_ptr<SettingsOverriddenDialogController> controller_; -}; - -#endif // CHROME_BROWSER_UI_VIEWS_EXTENSIONS_SETTINGS_OVERRIDDEN_DIALOG_VIEW_H_
diff --git a/chrome/browser/ui/views/extensions/settings_overridden_dialog_view_unittest.cc b/chrome/browser/ui/views/extensions/settings_overridden_dialog_view_unittest.cc deleted file mode 100644 index 821d987..0000000 --- a/chrome/browser/ui/views/extensions/settings_overridden_dialog_view_unittest.cc +++ /dev/null
@@ -1,150 +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 "chrome/browser/ui/views/extensions/settings_overridden_dialog_view.h" - -#include "base/memory/raw_ptr.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/ui/extensions/settings_overridden_dialog_controller.h" -#include "chrome/browser/ui/views/chrome_constrained_window_views_client.h" -#include "chrome/test/views/chrome_views_test_base.h" -#include "components/constrained_window/constrained_window_views.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "ui/views/test/widget_test.h" - -namespace { - -struct DialogState { - bool shown = false; - absl::optional<SettingsOverriddenDialogController::DialogResult> result; -}; - -// A dialog controller that updates the provided DialogState when the dialog -// is interacted with. -class TestDialogController : public SettingsOverriddenDialogController { - public: - explicit TestDialogController(DialogState* state) - : state_(state), show_params_{u"Dialog Title", u"Dialog Body"} {} - TestDialogController(const TestDialogController&) = delete; - TestDialogController& operator=(const TestDialogController&) = delete; - ~TestDialogController() override = default; - - private: - bool ShouldShow() override { return true; } - ShowParams GetShowParams() override { return show_params_; } - void OnDialogShown() override { - EXPECT_FALSE(state_->shown) << "OnDialogShown() called more than once!"; - state_->shown = true; - } - void HandleDialogResult(DialogResult result) override { - state_->result = result; - } - - const raw_ptr<DialogState> state_; - const ShowParams show_params_; -}; - -} // namespace - -class SettingsOverriddenDialogViewUnitTest : public ChromeViewsTestBase { - public: - SettingsOverriddenDialogViewUnitTest() = default; - - void SetUp() override { - ChromeViewsTestBase::SetUp(); - SetConstrainedWindowViewsClient(CreateChromeConstrainedWindowViewsClient()); - - // Create a widget to host the anchor view. - anchor_widget_ = CreateTestWidget(); - anchor_widget_->Show(); - } - - void TearDown() override { - anchor_widget_ = nullptr; - ChromeViewsTestBase::TearDown(); - } - - SettingsOverriddenDialogView* CreateAndShowDialog( - std::unique_ptr<TestDialogController> controller) { - auto* dialog = new SettingsOverriddenDialogView(std::move(controller)); - dialog->Show(GetNativeAnchorWindow()); - return dialog; - } - - gfx::NativeWindow GetNativeAnchorWindow() { - return anchor_widget_->GetNativeWindow(); - } - - void CloseAnchorWindow() { - // Move out the anchor widget since we'll be closing it. - auto anchor_widget = std::move(anchor_widget_); - views::test::WidgetDestroyedWaiter destroyed_waiter(anchor_widget.get()); - anchor_widget->Close(); - destroyed_waiter.Wait(); - } - - private: - std::unique_ptr<views::Widget> anchor_widget_; -}; - -TEST_F(SettingsOverriddenDialogViewUnitTest, - DialogControllerIsNotifiedWhenShown) { - DialogState state; - auto controller = std::make_unique<TestDialogController>(&state); - auto* dialog = new SettingsOverriddenDialogView(std::move(controller)); - - EXPECT_FALSE(state.shown); - dialog->Show(GetNativeAnchorWindow()); - EXPECT_TRUE(state.shown); - - dialog->GetWidget()->CloseNow(); -} - -TEST_F(SettingsOverriddenDialogViewUnitTest, DialogResult_ChangeSettingsBack) { - DialogState state; - auto controller = std::make_unique<TestDialogController>(&state); - auto* dialog = CreateAndShowDialog(std::move(controller)); - - dialog->AcceptDialog(); - ASSERT_TRUE(state.result); - EXPECT_EQ( - SettingsOverriddenDialogController::DialogResult::kChangeSettingsBack, - *state.result); -} - -TEST_F(SettingsOverriddenDialogViewUnitTest, DialogResult_KeepNewSettings) { - DialogState state; - auto controller = std::make_unique<TestDialogController>(&state); - auto* dialog = CreateAndShowDialog(std::move(controller)); - - dialog->CancelDialog(); - ASSERT_TRUE(state.result); - EXPECT_EQ(SettingsOverriddenDialogController::DialogResult::kKeepNewSettings, - *state.result); -} - -TEST_F(SettingsOverriddenDialogViewUnitTest, DialogResult_DismissDialog) { - DialogState state; - auto controller = std::make_unique<TestDialogController>(&state); - auto* dialog = CreateAndShowDialog(std::move(controller)); - - views::test::WidgetDestroyedWaiter destroyed_waiter(dialog->GetWidget()); - dialog->GetWidget()->Close(); - destroyed_waiter.Wait(); - ASSERT_TRUE(state.result); - EXPECT_EQ(SettingsOverriddenDialogController::DialogResult::kDialogDismissed, - *state.result); -} - -TEST_F(SettingsOverriddenDialogViewUnitTest, DialogResult_CloseParentWidget) { - DialogState state; - auto controller = std::make_unique<TestDialogController>(&state); - CreateAndShowDialog(std::move(controller)); - - CloseAnchorWindow(); - ASSERT_TRUE(state.result); - EXPECT_EQ(SettingsOverriddenDialogController::DialogResult:: - kDialogClosedWithoutUserAction, - *state.result); -}
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_chromeos.cc index 171a590..336f7b6 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_chromeos.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_chromeos.cc
@@ -3,12 +3,19 @@ // found in the LICENSE file. #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h" namespace chrome { std::unique_ptr<BrowserNonClientFrameView> CreateBrowserNonClientFrameView( BrowserFrame* frame, BrowserView* browser_view) { + if (browser_view->browser()->is_type_picture_in_picture()) { + return std::make_unique<PictureInPictureBrowserFrameView>(frame, + browser_view); + } + auto frame_view = std::make_unique<BrowserNonClientFrameViewChromeOS>(frame, browser_view); frame_view->Init();
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 0f310d1f..a17261ba 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -3575,7 +3575,13 @@ panes->push_back(infobar_container_); if (download_shelf_) panes->push_back(download_shelf_->GetView()); -// TODO(crbug.com/1055150): Implement for mac. + if (right_aligned_side_panel_) + panes->push_back(right_aligned_side_panel_); + if (lens_side_panel_) + panes->push_back(lens_side_panel_); + if (side_search_side_panel_) + panes->push_back(side_search_side_panel_); + // TODO(crbug.com/1055150): Implement for mac. panes->push_back(contents_web_view_); if (devtools_web_view_->GetVisible()) panes->push_back(devtools_web_view_);
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc index f30f5c0..cf669ce 100644 --- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
@@ -33,7 +33,9 @@ constexpr int kWindowBorderThickness = 5; constexpr int kResizeAreaCornerSize = 10; -constexpr int kMinWindowWidth = 500; +// The window has a standard Chrome minimum size and does not have a maximum +// size. +constexpr gfx::Size kMinWindowSize(500, 500); class BackToTabButton : public OverlayWindowImageButton { public: @@ -146,10 +148,6 @@ return 0; } -void PictureInPictureBrowserFrameView::UpdateMinimumSize() { - GetWidget()->OnSizeConstraintsChanged(); -} - gfx::Rect PictureInPictureBrowserFrameView::GetBoundsForClientView() const { return bounds(); } @@ -196,13 +194,7 @@ } gfx::Size PictureInPictureBrowserFrameView::GetMinimumSize() const { - // TODO(https://crbug.com/1346734): Calculate the size as OverlayWindowViews. - return gfx::Size(kMinWindowWidth, kMinWindowWidth); -} - -gfx::Size PictureInPictureBrowserFrameView::GetMaximumSize() const { - // TODO(https://crbug.com/1346734): Calculate the size as OverlayWindowViews. - return browser_view()->GetMaximumSize(); + return kMinWindowSize; } void PictureInPictureBrowserFrameView::OnThemeChanged() {
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h index 90bfd0e..f8bc64a 100644 --- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h +++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h
@@ -33,7 +33,6 @@ const gfx::Size& tabstrip_minimum_size) const override; int GetTopInset(bool restored) const override; int GetThemeBackgroundXInset() const override; - void UpdateMinimumSize() override; void UpdateThrobber(bool running) override {} gfx::Rect GetBoundsForClientView() const override; gfx::Rect GetWindowBoundsForClientBounds( @@ -45,7 +44,6 @@ void UpdateWindowTitle() override; void SizeConstraintsChanged() override {} gfx::Size GetMinimumSize() const override; - gfx::Size GetMaximumSize() const override; void OnThemeChanged() override; // Gets the bounds of the controls.
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc index 2124afd..04ba278 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
@@ -381,7 +381,9 @@ live_caption_title_->SetText(GetLiveCaptionTitle(profile_->GetPrefs())); } -void MediaDialogView::OnSodaError(speech::LanguageCode language_code) { +void MediaDialogView::OnSodaInstallError( + speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) { // Check that language code matches the selected language for Live Caption or // is LanguageCode::kNone (signifying the SODA binary failed). if (!prefs::IsLanguageCodeForLiveCaption(language_code,
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h index a50139a..c2d93a41 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
@@ -128,7 +128,8 @@ // SodaInstaller::Observer overrides: void OnSodaInstalled(speech::LanguageCode language_code) override; - void OnSodaError(speech::LanguageCode language_code) override; + void OnSodaInstallError(speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) override; void OnSodaProgress(speech::LanguageCode language_code, int progress) override;
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.cc b/chrome/browser/ui/views/intent_picker_bubble_view.cc index 3b5bb55..ec58b98b 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view.cc +++ b/chrome/browser/ui/views/intent_picker_bubble_view.cc
@@ -525,7 +525,7 @@ } DCHECK(intent_picker_bubble_->HasCandidates()); - widget->Show(); + intent_picker_bubble_->ShowForReason(DisplayReason::USER_GESTURE); intent_picker_bubble_->SelectDefaultItem(); return widget;
diff --git a/chrome/browser/ui/views/lens/OWNERS b/chrome/browser/ui/views/lens/OWNERS index cc13b6e6..93aa6fa 100644 --- a/chrome/browser/ui/views/lens/OWNERS +++ b/chrome/browser/ui/views/lens/OWNERS
@@ -1,3 +1,4 @@ benwgold@google.com juanmojica@google.com +stanfield@google.com yusuyoutube@google.com
diff --git a/chrome/browser/ui/views/side_panel/history_clusters/history_clusters_side_panel_coordinator.cc b/chrome/browser/ui/views/side_panel/history_clusters/history_clusters_side_panel_coordinator.cc index 5f5f2e5..16c000a 100644 --- a/chrome/browser/ui/views/side_panel/history_clusters/history_clusters_side_panel_coordinator.cc +++ b/chrome/browser/ui/views/side_panel/history_clusters/history_clusters_side_panel_coordinator.cc
@@ -30,7 +30,8 @@ global_registry->Register(std::make_unique<SidePanelEntry>( SidePanelEntry::Id::kHistoryClusters, l10n_util::GetStringUTF16(IDS_HISTORY_CLUSTERS_JOURNEYS_TAB_LABEL), - ui::ImageModel::FromVectorIcon(kJourneysIcon, ui::kColorIcon), + ui::ImageModel::FromVectorIcon(kJourneysIcon, ui::kColorIcon, + /*icon_size=*/16), base::BindRepeating( &HistoryClustersSidePanelCoordinator::CreateHistoryClustersWebView, base::Unretained(this))));
diff --git a/chrome/browser/ui/views/side_panel/side_panel.h b/chrome/browser/ui/views/side_panel/side_panel.h index ee4a525..c078616 100644 --- a/chrome/browser/ui/views/side_panel/side_panel.h +++ b/chrome/browser/ui/views/side_panel/side_panel.h
@@ -8,13 +8,13 @@ #include "base/memory/raw_ptr.h" #include "components/prefs/pref_change_registrar.h" #include "ui/base/metadata/metadata_header_macros.h" +#include "ui/views/accessible_pane_view.h" #include "ui/views/controls/resize_area_delegate.h" -#include "ui/views/view.h" #include "ui/views/view_observer.h" class BrowserView; -class SidePanel : public views::View, +class SidePanel : public views::AccessiblePaneView, public views::ViewObserver, public views::ResizeAreaDelegate { public:
diff --git a/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.cc b/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.cc index 4431bf9..cd9ca53 100644 --- a/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.cc +++ b/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.cc
@@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/memory/ref_counted.h" -#include "base/strings/string_piece.h" #include "base/values.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_key.h" @@ -37,38 +36,38 @@ // consisting of a title and a list of fields. Returns a pointer to the new // section's contents, for use with |AddSectionEntry| below. Note that // |parent_list|, not the caller, owns the newly added section. -base::Value::List* AddSection(base::Value::List* parent_list, - base::StringPiece title) { - base::Value::Dict section; - base::Value::List section_contents; - section.Set("title", title); +base::ListValue* AddSection(base::ListValue* parent_list, + const std::string& title) { + std::unique_ptr<base::DictionaryValue> section(new base::DictionaryValue); + std::unique_ptr<base::ListValue> section_contents(new base::ListValue); + section->SetStringKey("title", title); // Grab a raw pointer to the result before |Pass()|ing it on. - base::Value::List* result = - section.Set("data", std::move(section_contents))->GetIfList(); - parent_list->Append(std::move(section)); + base::ListValue* result = + section->SetList("data", std::move(section_contents)); + parent_list->Append(base::Value::FromUniquePtrValue(std::move(section))); return result; } // Adds a bool entry to a section (created with |AddSection| above). -void AddSectionEntry(base::Value::List* section_list, - base::StringPiece name, +void AddSectionEntry(base::ListValue* section_list, + const std::string& name, bool value) { base::Value::Dict entry; entry.Set("stat_name", name); entry.Set("stat_value", value); entry.Set("is_valid", true); - section_list->Append(std::move(entry)); + section_list->GetList().Append(std::move(entry)); } // Adds a string entry to a section (created with |AddSection| above). -void AddSectionEntry(base::Value::List* section_list, - base::StringPiece name, - base::StringPiece value) { +void AddSectionEntry(base::ListValue* section_list, + const std::string& name, + const std::string& value) { base::Value::Dict entry; entry.Set("stat_name", name); entry.Set("stat_value", value); entry.Set("is_valid", true); - section_list->Append(std::move(entry)); + section_list->GetList().Append(std::move(entry)); } std::string FilteringBehaviorToString( @@ -203,21 +202,21 @@ } void FamilyLinkUserInternalsMessageHandler::SendBasicInfo() { - base::Value::List section_list; + base::ListValue section_list; - base::Value::List* section_general = AddSection(§ion_list, "General"); + base::ListValue* section_general = AddSection(§ion_list, "General"); AddSectionEntry(section_general, "Child detection enabled", ChildAccountService::IsChildAccountDetectionEnabled()); Profile* profile = Profile::FromWebUI(web_ui()); - base::Value::List* section_profile = AddSection(§ion_list, "Profile"); + base::ListValue* section_profile = AddSection(§ion_list, "Profile"); AddSectionEntry(section_profile, "Account", profile->GetProfileUserName()); AddSectionEntry(section_profile, "Child", profile->IsChild()); SupervisedUserURLFilter* filter = GetSupervisedUserService()->GetURLFilter(); - base::Value::List* section_filter = AddSection(§ion_list, "Filter"); + base::ListValue* section_filter = AddSection(§ion_list, "Filter"); AddSectionEntry(section_filter, "Denylist active", filter->HasDenylist()); AddSectionEntry(section_filter, "Online checks active", filter->HasAsyncURLChecker()); @@ -232,7 +231,7 @@ for (const auto& account : identity_manager ->GetExtendedAccountInfoForAccountsWithRefreshToken()) { - base::Value::List* section_user = AddSection( + base::ListValue* section_user = AddSection( §ion_list, "User Information for " + account.full_name); AddSectionEntry(section_user, "Account id", account.account_id.ToString()); @@ -247,8 +246,8 @@ } } - base::Value::Dict result; - result.Set("sections", std::move(section_list)); + base::DictionaryValue result; + result.SetKey("sections", std::move(section_list)); FireWebUIListener("basic-info-received", result); // Trigger retrieval of the user settings @@ -272,10 +271,11 @@ SupervisedUserURLFilter::FilteringBehavior behavior, supervised_user_error_page::FilteringBehaviorReason reason, bool uncertain) { - base::Value::Dict result; - result.Set("allowResult", FilteringBehaviorToString(behavior, uncertain)); - result.Set("manual", reason == supervised_user_error_page::MANUAL && - behavior == SupervisedUserURLFilter::ALLOW); + base::DictionaryValue result; + result.SetStringKey("allowResult", + FilteringBehaviorToString(behavior, uncertain)); + result.SetBoolKey("manual", reason == supervised_user_error_page::MANUAL && + behavior == SupervisedUserURLFilter::ALLOW); ResolveJavascriptCallback(base::Value(callback_id), result); } @@ -287,9 +287,9 @@ supervised_user_error_page::FilteringBehaviorReason reason, bool uncertain) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - base::Value::Dict result; - result.Set("url", url.possibly_invalid_spec()); - result.Set("result", FilteringBehaviorToString(behavior, uncertain)); - result.Set("reason", FilteringBehaviorReasonToString(reason)); + base::DictionaryValue result; + result.SetStringKey("url", url.possibly_invalid_spec()); + result.SetStringKey("result", FilteringBehaviorToString(behavior, uncertain)); + result.SetStringKey("reason", FilteringBehaviorReasonToString(reason)); FireWebUIListener("filtering-result-received", result); }
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.cc b/chrome/browser/ui/webui/help/version_updater_chromeos.cc index 9b6c008..f89dae8 100644 --- a/chrome/browser/ui/webui/help/version_updater_chromeos.cc +++ b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
@@ -108,8 +108,8 @@ return false; } - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler* network_state_handler = + ash::NetworkHandler::Get()->network_state_handler(); const ash::NetworkState* network = network_state_handler->DefaultNetwork(); const bool metered = network_state_handler->default_network_is_metered(); // Don't allow an update if we're currently offline or connected
diff --git a/chrome/browser/ui/webui/management/management_ui_handler.cc b/chrome/browser/ui/webui/management/management_ui_handler.cc index abe2956..0bfb7d4 100644 --- a/chrome/browser/ui/webui/management/management_ui_handler.cc +++ b/chrome/browser/ui/webui/management/management_ui_handler.cc
@@ -724,18 +724,17 @@ void ManagementUIHandler::AddProxyServerPrivacyDisclosure( base::Value::Dict* response) const { bool showProxyDisclosure = false; - chromeos::NetworkHandler* network_handler = chromeos::NetworkHandler::Get(); + ash::NetworkHandler* network_handler = ash::NetworkHandler::Get(); base::Value proxy_settings(base::Value::Type::DICTIONARY); // |ui_proxy_config_service| may be missing in tests. If the device is offline // (no network connected) the |DefaultNetwork| is null. - if (chromeos::NetworkHandler::HasUiProxyConfigService() && + if (ash::NetworkHandler::HasUiProxyConfigService() && network_handler->network_state_handler()->DefaultNetwork()) { // Check if proxy is enforced by user policy, a forced install extension or // ONC policies. This will only read managed settings. - chromeos::NetworkHandler::GetUiProxyConfigService() - ->MergeEnforcedProxyConfig( - network_handler->network_state_handler()->DefaultNetwork()->guid(), - &proxy_settings); + ash::NetworkHandler::GetUiProxyConfigService()->MergeEnforcedProxyConfig( + network_handler->network_state_handler()->DefaultNetwork()->guid(), + &proxy_settings); } if (!proxy_settings.DictEmpty()) { // Proxies can be specified by web server url, via a PAC script or via the
diff --git a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc index f878429..ee9363d 100644 --- a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc +++ b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
@@ -1093,8 +1093,8 @@ ResetTestConfig(); // Set pref to use a proxy. PrefProxyConfigTrackerImpl::RegisterProfilePrefs(user_prefs_.registry()); - chromeos::NetworkHandler::Get()->InitializePrefServices(&user_prefs_, - &local_state_); + ash::NetworkHandler::Get()->InitializePrefServices(&user_prefs_, + &local_state_); base::Value policy_prefs_config = ProxyConfigDictionary::CreateAutoDetect(); user_prefs_.SetUserPref( proxy_config::prefs::kProxy, @@ -1111,16 +1111,15 @@ ResetTestConfig(); // Simulate network disconnected state. PrefProxyConfigTrackerImpl::RegisterProfilePrefs(user_prefs_.registry()); - chromeos::NetworkHandler::Get()->InitializePrefServices(&user_prefs_, - &local_state_); - chromeos::NetworkStateHandler::NetworkStateList networks; - chromeos::NetworkHandler::Get() - ->network_state_handler() - ->GetNetworkListByType(ash::NetworkTypePattern::Default(), - true, // configured_only - false, // visible_only, - 0, // no limit to number of results - &networks); + ash::NetworkHandler::Get()->InitializePrefServices(&user_prefs_, + &local_state_); + ash::NetworkStateHandler::NetworkStateList networks; + ash::NetworkHandler::Get()->network_state_handler()->GetNetworkListByType( + ash::NetworkTypePattern::Default(), + true, // configured_only + false, // visible_only, + 0, // no limit to number of results + &networks); chromeos::ShillServiceClient::TestInterface* service = chromeos::ShillServiceClient::Get()->GetTestInterface(); for (const auto* const network : networks) { @@ -1134,15 +1133,15 @@ EXPECT_FALSE(GetShowProxyServerPrivacyDisclosure()); - chromeos::NetworkHandler::Get()->NetworkHandler::ShutdownPrefServices(); + ash::NetworkHandler::Get()->NetworkHandler::ShutdownPrefServices(); } TEST_F(ManagementUIHandlerTests, HideProxyServerDisclosureForDirectProxy) { ResetTestConfig(); // Set pref not to use proxy. PrefProxyConfigTrackerImpl::RegisterProfilePrefs(user_prefs_.registry()); - chromeos::NetworkHandler::Get()->InitializePrefServices(&user_prefs_, - &local_state_); + ash::NetworkHandler::Get()->InitializePrefServices(&user_prefs_, + &local_state_); base::Value policy_prefs_config = ProxyConfigDictionary::CreateDirect(); user_prefs_.SetUserPref( proxy_config::prefs::kProxy, @@ -1154,7 +1153,7 @@ EXPECT_FALSE(GetShowProxyServerPrivacyDisclosure()); - chromeos::NetworkHandler::Get()->NetworkHandler::ShutdownPrefServices(); + ash::NetworkHandler::Get()->NetworkHandler::ShutdownPrefServices(); } #endif
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc index e3ab2f7c..6395ac0 100644 --- a/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -22,6 +22,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/thread_pool.h" #include "base/time/default_clock.h" +#include "base/values.h" #include "build/branding_buildflags.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -105,7 +106,7 @@ std::u16string GetAllowedConnectionTypesMessage() { if (help_utils_chromeos::IsUpdateOverCellularAllowed( /*interactive=*/true)) { - const bool metered = chromeos::NetworkHandler::Get() + const bool metered = ash::NetworkHandler::Get() ->network_state_handler() ->default_network_is_metered(); return metered @@ -200,12 +201,16 @@ return std::string(); } -base::Value::Dict GetVersionInfo() { - base::Value::Dict version_info; - version_info.Set("osVersion", chromeos::version_loader::GetVersion( - chromeos::version_loader::VERSION_FULL)); - version_info.Set("arcVersion", chromeos::version_loader::GetARCVersion()); - version_info.Set("osFirmware", chromeos::version_loader::GetFirmware()); +std::unique_ptr<base::DictionaryValue> GetVersionInfo() { + std::unique_ptr<base::DictionaryValue> version_info( + new base::DictionaryValue); + version_info->SetStringKey("osVersion", + chromeos::version_loader::GetVersion( + chromeos::version_loader::VERSION_FULL)); + version_info->SetStringKey("arcVersion", + chromeos::version_loader::GetARCVersion()); + version_info->SetStringKey("osFirmware", + chromeos::version_loader::GetFirmware()); return version_info; } @@ -480,8 +485,8 @@ CHECK_EQ(1U, args.size()); const std::string& callback_id = args[0].GetString(); - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler* network_state_handler = + ash::NetworkHandler::Get()->network_state_handler(); const ash::NetworkState* network = network_state_handler->DefaultNetwork(); ResolveJavascriptCallback(base::Value(callback_id), base::Value(network && network->IsOnline())); @@ -537,9 +542,10 @@ weak_factory_.GetWeakPtr(), callback_id)); } -void AboutHandler::OnGetVersionInfoReady(std::string callback_id, - base::Value::Dict version_info) { - ResolveJavascriptCallback(base::Value(callback_id), version_info); +void AboutHandler::OnGetVersionInfoReady( + std::string callback_id, + std::unique_ptr<base::DictionaryValue> version_info) { + ResolveJavascriptCallback(base::Value(callback_id), *version_info); } void AboutHandler::HandleGetFirmwareUpdateCount(const base::Value::List& args) { @@ -591,18 +597,19 @@ void AboutHandler::OnGetTargetChannel(std::string callback_id, const std::string& current_channel, const std::string& target_channel) { - base::Value::Dict channel_info; - channel_info.Set("currentChannel", current_channel); - channel_info.Set("targetChannel", target_channel); + std::unique_ptr<base::DictionaryValue> channel_info( + new base::DictionaryValue); + channel_info->SetStringKey("currentChannel", current_channel); + channel_info->SetStringKey("targetChannel", target_channel); // For the LTS pilot simply check whether the device policy is set and ignore // its value. std::string value; bool is_lts = ash::CrosSettings::Get()->GetString(ash::kReleaseLtsTag, &value); - channel_info.Set("isLts", is_lts); + channel_info->SetBoolKey("isLts", is_lts); - ResolveJavascriptCallback(base::Value(callback_id), channel_info); + ResolveJavascriptCallback(base::Value(callback_id), *channel_info); } void AboutHandler::HandleApplyDeferredUpdate(const base::Value::List& args) { @@ -643,9 +650,9 @@ void AboutHandler::RefreshTPMFirmwareUpdateStatus( const std::set<ash::tpm_firmware_update::Mode>& modes) { - base::Value::Dict event; - event.Set("updateAvailable", !modes.empty()); - FireWebUIListener("tpm-firmware-update-status-changed", event); + std::unique_ptr<base::DictionaryValue> event(new base::DictionaryValue); + event->SetBoolKey("updateAvailable", !modes.empty()); + FireWebUIListener("tpm-firmware-update-status-changed", *event); } void AboutHandler::HandleGetEndOfLifeInfo(const base::Value::List& args) { @@ -659,14 +666,14 @@ void AboutHandler::OnGetEndOfLifeInfo( std::string callback_id, ash::UpdateEngineClient::EolInfo eol_info) { - base::Value::Dict response; + base::Value response(base::Value::Type::DICTIONARY); if (!eol_info.eol_date.is_null()) { bool has_eol_passed = eol_info.eol_date <= clock_->Now(); - response.Set("hasEndOfLife", has_eol_passed); + response.SetBoolKey("hasEndOfLife", has_eol_passed); int eol_string_id = has_eol_passed ? IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_MESSAGE_PAST : IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_MESSAGE_FUTURE; - response.Set( + response.SetStringKey( "aboutPageEndOfLifeMessage", l10n_util::GetStringFUTF16( eol_string_id, @@ -675,8 +682,8 @@ base::ASCIIToUTF16(has_eol_passed ? chrome::kEolNotificationURL : chrome::kAutoUpdatePolicyURL))); } else { - response.Set("hasEndOfLife", false); - response.Set("aboutPageEndOfLifeMessage", ""); + response.SetBoolKey("hasEndOfLife", false); + response.SetStringKey("aboutPageEndOfLifeMessage", ""); } ResolveJavascriptCallback(base::Value(callback_id), response); } @@ -748,29 +755,29 @@ // Only UPDATING state should have progress set. DCHECK(status == VersionUpdater::UPDATING || progress == 0); - base::Value::Dict event; - event.Set("status", UpdateStatusToString(status)); - event.Set("message", message); - event.Set("progress", progress); - event.Set("rollback", rollback); - event.Set("powerwash", powerwash); - event.Set("version", version); + std::unique_ptr<base::DictionaryValue> event(new base::DictionaryValue); + event->SetStringKey("status", UpdateStatusToString(status)); + event->SetStringKey("message", message); + event->SetIntKey("progress", progress); + event->SetBoolKey("rollback", rollback); + event->SetBoolKey("powerwash", powerwash); + event->SetStringKey("version", version); // DictionaryValue does not support int64_t, so convert to string. - event.Set("size", base::NumberToString(size)); + event->SetStringKey("size", base::NumberToString(size)); #if BUILDFLAG(IS_CHROMEOS_ASH) if (status == VersionUpdater::FAILED_OFFLINE || status == VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED) { std::u16string types_msg = GetAllowedConnectionTypesMessage(); if (!types_msg.empty()) - event.Set("connectionTypes", types_msg); + event->SetStringKey("connectionTypes", types_msg); else - event.Set("connectionTypes", base::Value()); + event->Set("connectionTypes", std::make_unique<base::Value>()); } else { - event.Set("connectionTypes", base::Value()); + event->Set("connectionTypes", std::make_unique<base::Value>()); } #endif // BUILDFLAG(IS_CHROMEOS_ASH) - FireWebUIListener("update-status-changed", event); + FireWebUIListener("update-status-changed", *event); } #if BUILDFLAG(IS_MAC) @@ -790,12 +797,12 @@ else if (state == VersionUpdater::PROMOTED) text = l10n_util::GetStringUTF16(IDS_ABOUT_CHROME_AUTOUPDATE_ALL_IS_ON); - base::Value::Dict promo_state; - promo_state.Set("hidden", hidden); - promo_state.Set("disabled", disabled); - promo_state.Set("actionable", actionable); + base::DictionaryValue promo_state; + promo_state.SetBoolKey("hidden", hidden); + promo_state.SetBoolKey("disabled", disabled); + promo_state.SetBoolKey("actionable", actionable); if (!text.empty()) - promo_state.Set("text", text); + promo_state.SetStringKey("text", text); FireWebUIListener("promotion-state-changed", promo_state); } @@ -821,17 +828,19 @@ std::string callback_id, const base::FilePath& label_dir_path, const std::string& text) { - base::Value::Dict regulatory_info; + std::unique_ptr<base::DictionaryValue> regulatory_info( + new base::DictionaryValue); // Remove unnecessary whitespace. - regulatory_info.Set("text", base::CollapseWhitespaceASCII(text, true)); + regulatory_info->SetStringKey("text", + base::CollapseWhitespaceASCII(text, true)); std::string image_path = label_dir_path.AppendASCII(kRegulatoryLabelImageFilename).MaybeAsASCII(); std::string url = std::string("chrome://") + chrome::kChromeOSAssetHost + "/" + image_path; - regulatory_info.Set("url", url); + regulatory_info->SetStringKey("url", url); - ResolveJavascriptCallback(base::Value(callback_id), regulatory_info); + ResolveJavascriptCallback(base::Value(callback_id), *regulatory_info); } #endif // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/webui/settings/about_handler.h b/chrome/browser/ui/webui/settings/about_handler.h index e3ce694..090e1d0 100644 --- a/chrome/browser/ui/webui/settings/about_handler.h +++ b/chrome/browser/ui/webui/settings/about_handler.h
@@ -10,7 +10,6 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" -#include "base/values.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/ui/webui/help/version_updater.h" @@ -25,6 +24,7 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) namespace base { +class DictionaryValue; class FilePath; class Clock; } // namespace base @@ -102,8 +102,9 @@ // Retrieves OS, ARC and firmware versions. void HandleGetVersionInfo(const base::Value::List& args); - void OnGetVersionInfoReady(std::string callback_id, - base::Value::Dict version_info); + void OnGetVersionInfoReady( + std::string callback_id, + std::unique_ptr<base::DictionaryValue> version_info); // Retrieves the number of firmware updates available. void HandleGetFirmwareUpdateCount(const base::Value::List& args);
diff --git a/chrome/browser/ui/webui/settings/captions_handler.cc b/chrome/browser/ui/webui/settings/captions_handler.cc index ed49c21..ba3c326 100644 --- a/chrome/browser/ui/webui/settings/captions_handler.cc +++ b/chrome/browser/ui/webui/settings/captions_handler.cc
@@ -93,7 +93,9 @@ base::Value(speech::GetLanguageName(language_code))); } -void CaptionsHandler::OnSodaError(speech::LanguageCode language_code) { +void CaptionsHandler::OnSodaInstallError( + speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) { // If multi-language is disabled and the language code received is not for // Live Caption (perhaps it is downloading because another feature, such as // dictation on ChromeOS, has a different language selected), then return
diff --git a/chrome/browser/ui/webui/settings/captions_handler.h b/chrome/browser/ui/webui/settings/captions_handler.h index 421951d..104de16 100644 --- a/chrome/browser/ui/webui/settings/captions_handler.h +++ b/chrome/browser/ui/webui/settings/captions_handler.h
@@ -34,7 +34,8 @@ // SodaInstaller::Observer overrides: void OnSodaInstalled(speech::LanguageCode language_code) override; - void OnSodaError(speech::LanguageCode language_code) override; + void OnSodaInstallError(speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) override; void OnSodaProgress(speech::LanguageCode language_code, int progress) override;
diff --git a/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc b/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc index ec9aa61..3581c03 100644 --- a/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc +++ b/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc
@@ -61,13 +61,14 @@ return value; } -base::Value::Dict GetScannerResultsAsDictionary( +base::DictionaryValue GetScannerResultsAsDictionary( const safe_browsing::ChromeCleanerScannerResults& scanner_results, Profile* profile) { - base::Value::Dict value; - value.Set("files", GetFilesAsListStorage(scanner_results.files_to_delete())); - value.Set("registryKeys", - GetStringSetAsListStorage(scanner_results.registry_keys())); + base::DictionaryValue value; + value.GetDict().Set("files", + GetFilesAsListStorage(scanner_results.files_to_delete())); + value.GetDict().Set("registryKeys", GetStringSetAsListStorage( + scanner_results.registry_keys())); return value; }
diff --git a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc index 5b99d9a..659783d 100644 --- a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc
@@ -192,7 +192,9 @@ progress))); } -void AccessibilityHandler::OnSodaError(speech::LanguageCode language_code) { +void AccessibilityHandler::OnSodaInstallError( + speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) { if (language_code != speech::LanguageCode::kNone && language_code != GetDictationLocale()) { return;
diff --git a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h index b64f767..c21494b 100644 --- a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h
@@ -53,7 +53,8 @@ void OnSodaInstalled(speech::LanguageCode language_code) override; void OnSodaProgress(speech::LanguageCode language_code, int progress) override; - void OnSodaError(speech::LanguageCode language_code) override; + void OnSodaInstallError(speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) override; void MaybeAddDictationLocales(); speech::LanguageCode GetDictationLocale();
diff --git a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc index 234f5ae..c2dc469 100644 --- a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/ash/crostini/crostini_util.h" #include "chrome/browser/ash/file_manager/path_util.h" #include "chrome/browser/ash/guest_os/guest_os_pref_names.h" +#include "chrome/browser/ash/guest_os/guest_os_session_tracker.h" #include "chrome/browser/ash/guest_os/guest_os_terminal.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/lifetime/application_lifetime.h" @@ -765,8 +766,8 @@ base::Value::Dict container_info_value; container_info_value.Set(kIdKey, container_id.ToDictValue()); auto info = - crostini::CrostiniManager::GetForProfile(profile_)->GetContainerInfo( - container_id); + guest_os::GuestOsSessionTracker::GetForProfile(profile_)->GetInfo( + crostini::DefaultContainerId()); if (info) { container_info_value.Set(kIpv4Key, info->ipv4_address); }
diff --git a/chrome/browser/ui/webui/settings/downloads_handler.cc b/chrome/browser/ui/webui/settings/downloads_handler.cc index ed960d3..a918e80 100644 --- a/chrome/browser/ui/webui/settings/downloads_handler.cc +++ b/chrome/browser/ui/webui/settings/downloads_handler.cc
@@ -210,17 +210,17 @@ settings.value(), profile_->GetPrefs())) .has_value(); // Dict to match the fields used in downloads_page.html. - base::Value::Dict dict; - dict.Set("linked", got_linked_account); + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetBoolKey("linked", got_linked_account); if (got_linked_account) { - base::Value::Dict account; - account.Set("name", info->account_name); - account.Set("login", info->account_login); - dict.Set("account", std::move(account)); - base::Value::Dict folder; - folder.Set("name", info->folder_name); - folder.Set("link", info->folder_link); - dict.Set("folder", std::move(folder)); + base::Value account(base::Value::Type::DICTIONARY); + account.SetStringKey("name", info->account_name); + account.SetStringKey("login", info->account_login); + dict.SetKey("account", std::move(account)); + base::Value folder(base::Value::Type::DICTIONARY); + folder.SetStringKey("name", info->folder_name); + folder.SetStringKey("link", info->folder_link); + dict.SetKey("folder", std::move(folder)); } FireWebUIListener("downloads-connection-link-changed", dict); }
diff --git a/chrome/browser/ui/webui/settings/font_handler.cc b/chrome/browser/ui/webui/settings/font_handler.cc index e57acb5..9b7ac45 100644 --- a/chrome/browser/ui/webui/settings/font_handler.cc +++ b/chrome/browser/ui/webui/settings/font_handler.cc
@@ -74,7 +74,8 @@ base::Value::Dict response; response.Set("fontList", std::move(list)); - ResolveJavascriptCallback(base::Value(callback_id), response); + ResolveJavascriptCallback(base::Value(callback_id), + base::Value(std::move(response))); } } // namespace settings
diff --git a/chrome/browser/ui/webui/settings/import_data_handler.cc b/chrome/browser/ui/webui/settings/import_data_handler.cc index 042b1f1..1615e8d 100644 --- a/chrome/browser/ui/webui/settings/import_data_handler.cc +++ b/chrome/browser/ui/webui/settings/import_data_handler.cc
@@ -216,7 +216,8 @@ browser_profiles.Append(std::move(browser_profile)); } - ResolveJavascriptCallback(base::Value(callback_id), browser_profiles); + ResolveJavascriptCallback(base::Value(callback_id), + base::Value(std::move(browser_profiles))); } void ImportDataHandler::ImportStarted() {
diff --git a/chrome/browser/ui/webui/settings/incompatible_applications_handler_win.cc b/chrome/browser/ui/webui/settings/incompatible_applications_handler_win.cc index b960d6720..e0a91ae 100644 --- a/chrome/browser/ui/webui/settings/incompatible_applications_handler_win.cc +++ b/chrome/browser/ui/webui/settings/incompatible_applications_handler_win.cc
@@ -75,7 +75,7 @@ incompatible_applications = IncompatibleApplicationsUpdater::GetCachedApplications(); - base::Value::List application_list; + base::Value application_list(base::Value::Type::LIST); for (const auto& application : incompatible_applications) { // Set up a registry watcher for each problem application. @@ -99,10 +99,12 @@ } // Also add the application to the list that is passed to the javascript. - base::Value::Dict dict; - dict.Set("name", base::WideToUTF8(application.info.name)); - dict.Set("type", application.blocklist_action->message_type()); - dict.Set("url", application.blocklist_action->message_url()); + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetKey("name", base::Value(base::WideToUTF8(application.info.name))); + dict.SetKey("type", + base::Value(application.blocklist_action->message_type())); + dict.SetKey("url", + base::Value(application.blocklist_action->message_url())); application_list.Append(std::move(dict)); }
diff --git a/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc b/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc index 9b6206f..d5d9c0e 100644 --- a/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc +++ b/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc
@@ -60,21 +60,24 @@ AllowJavascript(); CHECK_GT(args.size(), 0u); const base::Value& callback_id = args[0]; - ResolveJavascriptCallback(callback_id, CreateMetricsReportingDict()); + ResolveJavascriptCallback(callback_id, *CreateMetricsReportingDict()); } -base::Value::Dict MetricsReportingHandler::CreateMetricsReportingDict() { - base::Value::Dict dict; - dict.Set("enabled", - ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled()); +std::unique_ptr<base::DictionaryValue> + MetricsReportingHandler::CreateMetricsReportingDict() { + std::unique_ptr<base::DictionaryValue> dict( + std::make_unique<base::DictionaryValue>()); + dict->SetBoolKey( + "enabled", + ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled()); #if BUILDFLAG(IS_CHROMEOS_LACROS) // To match the pre-Lacros settings UX, we show the managed icon if the ash // device-level metrics reporting pref is managed. https://crbug.com/1148604 bool managed = chromeos::BrowserParamsProxy::Get()->AshMetricsManaged() == crosapi::mojom::MetricsReportingManaged::kManaged; - dict.Set("managed", managed); + dict->SetBoolKey("managed", managed); #else - dict.Set("managed", IsMetricsReportingPolicyManaged()); + dict->SetBoolKey("managed", IsMetricsReportingPolicyManaged()); #endif return dict; } @@ -126,7 +129,7 @@ } void MetricsReportingHandler::SendMetricsReportingChange() { - FireWebUIListener("metrics-reporting-change", CreateMetricsReportingDict()); + FireWebUIListener("metrics-reporting-change", *CreateMetricsReportingDict()); } } // namespace settings
diff --git a/chrome/browser/ui/webui/settings/on_startup_handler.cc b/chrome/browser/ui/webui/settings/on_startup_handler.cc index f4227e3..dbc605a 100644 --- a/chrome/browser/ui/webui/settings/on_startup_handler.cc +++ b/chrome/browser/ui/webui/settings/on_startup_handler.cc
@@ -62,19 +62,20 @@ FireWebUIListener(kOnStartupNtpExtensionEventName, GetNtpExtension()); } -base::Value::Dict OnStartupHandler::GetNtpExtension() { +base::Value OnStartupHandler::GetNtpExtension() { const extensions::Extension* ntp_extension = extensions::GetExtensionOverridingNewTabPage(profile_); if (!ntp_extension) { - return base::Value::Dict(); + return base::Value(); } - base::Value::Dict dict; - dict.Set("id", ntp_extension->id()); - dict.Set("name", ntp_extension->name()); - dict.Set("canBeDisabled", !extensions::ExtensionSystem::Get(profile_) - ->management_policy() - ->MustRemainEnabled(ntp_extension, nullptr)); + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetStringKey("id", ntp_extension->id()); + dict.SetStringKey("name", ntp_extension->name()); + dict.SetBoolKey("canBeDisabled", + !extensions::ExtensionSystem::Get(profile_) + ->management_policy() + ->MustRemainEnabled(ntp_extension, nullptr)); return dict; }
diff --git a/chrome/browser/ui/webui/settings/on_startup_handler.h b/chrome/browser/ui/webui/settings/on_startup_handler.h index bc9fb7b7..98003851 100644 --- a/chrome/browser/ui/webui/settings/on_startup_handler.h +++ b/chrome/browser/ui/webui/settings/on_startup_handler.h
@@ -8,7 +8,6 @@ #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/scoped_observation.h" -#include "base/values.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry_observer.h" @@ -42,7 +41,7 @@ HandleValidateStartupPage_Invalid); // Info for extension controlling the NTP or empty value. - base::Value::Dict GetNtpExtension(); + base::Value GetNtpExtension(); // Handler for the "getNtpExtension" message. No arguments. void HandleGetNtpExtension(const base::Value::List& args);
diff --git a/chrome/browser/ui/webui/settings/search_engines_handler.cc b/chrome/browser/ui/webui/settings/search_engines_handler.cc index 5cd9340..cd480a2 100644 --- a/chrome/browser/ui/webui/settings/search_engines_handler.cc +++ b/chrome/browser/ui/webui/settings/search_engines_handler.cc
@@ -207,7 +207,8 @@ Profile* profile = Profile::FromWebUI(web_ui()); dict.Set("url", template_url->url_ref().DisplayURL(UIThreadSearchTermsData())); - dict.Set("urlLocked", template_url->prepopulate_id() > 0); + dict.Set("urlLocked", ((template_url->prepopulate_id() > 0) || + (template_url->starter_pack_id() > 0))); GURL icon_url = template_url->favicon_url(); if (icon_url.is_valid()) dict.Set("iconURL", icon_url.spec());
diff --git a/chrome/browser/vr/test/gl_test_environment.h b/chrome/browser/vr/test/gl_test_environment.h index 2cf3249..6a0101c 100644 --- a/chrome/browser/vr/test/gl_test_environment.h +++ b/chrome/browser/vr/test/gl_test_environment.h
@@ -12,8 +12,8 @@ #include "ui/gfx/geometry/size.h" namespace gl { -class GLSurface; class GLContext; +class GLSurface; } // namespace gl namespace gpu {
diff --git a/chrome/browser/vr/test/gl_test_environment_native_gl.cc b/chrome/browser/vr/test/gl_test_environment_native_gl.cc index 32369bd..4d308f1 100644 --- a/chrome/browser/vr/test/gl_test_environment_native_gl.cc +++ b/chrome/browser/vr/test/gl_test_environment_native_gl.cc
@@ -6,6 +6,7 @@ #include "ui/gl/gl_context.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/gl_version_info.h" #include "ui/gl/init/gl_factory.h" #include "ui/gl/test/gl_test_helper.h" @@ -14,7 +15,8 @@ GlTestEnvironment::GlTestEnvironment(const gfx::Size frame_buffer_size) { // Setup offscreen GL context. - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), gfx::Size()); context_ = gl::init::CreateGLContext(nullptr, surface_.get(), gl::GLContextAttribs()); context_->MakeCurrent(surface_.get());
diff --git a/chrome/browser/web_applications/app_service/README.md b/chrome/browser/web_applications/app_service/README.md index c4c8158..f032921 100644 --- a/chrome/browser/web_applications/app_service/README.md +++ b/chrome/browser/web_applications/app_service/README.md
@@ -2,7 +2,7 @@ This directory contains the App Service publisher classes for web apps (Desktop PWAs and shortcut apps). -App Service [publisher](../../../../components/services/app_service/public/cpp/publisher_base.h)s keep the App Service updates with the set of installed apps, and implement commands such as launching. +App Service [publishers](../../../../components/services/app_service/public/cpp/publisher_base.h) keep the App Service [updates](../../../../components/services/app_service/public/cpp/app_update.h) with the set of installed apps, and implement commands such as launching. For Ash, Linux, Mac and Windows, the publisher is [WebApps](web_apps.h). (This is currently also used to support the chrome://apps page in the Lacros browser.)
diff --git a/chrome/browser/web_applications/commands/install_isolated_app_command.cc b/chrome/browser/web_applications/commands/install_isolated_app_command.cc index b0f38c3b6..f549515a 100644 --- a/chrome/browser/web_applications/commands/install_isolated_app_command.cc +++ b/chrome/browser/web_applications/commands/install_isolated_app_command.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/web_applications/commands/install_isolated_app_command.h" +#include <string> #include <utility> #include "base/bind.h" @@ -12,21 +13,41 @@ #include "base/check.h" #include "base/containers/flat_set.h" #include "base/sequence_checker.h" +#include "base/strings/string_piece_forward.h" +#include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/web_applications/commands/web_app_command.h" #include "chrome/browser/web_applications/web_app_data_retriever.h" #include "chrome/browser/web_applications/web_app_id.h" #include "chrome/browser/web_applications/web_app_install_finalizer.h" #include "chrome/browser/web_applications/web_app_install_info.h" +#include "chrome/browser/web_applications/web_app_install_utils.h" #include "chrome/browser/web_applications/web_app_url_loader.h" #include "components/webapps/browser/install_result_code.h" #include "components/webapps/browser/installable/installable_metrics.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/manifest/manifest_util.h" #include "third_party/blink/public/mojom/manifest/manifest.mojom.h" #include "url/gurl.h" namespace web_app { +namespace { + +bool IsUrlLoadingResultSuccess(WebAppUrlLoader::Result result) { + return result == WebAppUrlLoader::Result::kUrlLoaded; +} + +absl::optional<std::string> UTF16ToUTF8(base::StringPiece16 src) { + std::string dest; + if (!base::UTF16ToUTF8(src.data(), src.length(), &dest)) { + return absl::nullopt; + } + return dest; +} + +} // namespace + InstallIsolatedAppCommand::InstallIsolatedAppCommand( base::StringPiece url, WebAppUrlLoader& url_loader, @@ -58,14 +79,6 @@ DCHECK(callback_.is_null()); } -namespace { - -bool IsUrlLoadingResultSuccess(WebAppUrlLoader::Result result) { - return result == WebAppUrlLoader::Result::kUrlLoaded; -} - -} // namespace - void InstallIsolatedAppCommand::Start() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -75,6 +88,12 @@ return; } + LoadUrl(url); +} + +void InstallIsolatedAppCommand::LoadUrl(GURL url) { + DCHECK(url.is_valid()); + url_loader_.LoadUrl(url, shared_web_contents(), WebAppUrlLoader::UrlComparison::kIgnoreQueryParamsAndRef, base::BindOnce(&InstallIsolatedAppCommand::OnLoadUrl, @@ -89,6 +108,10 @@ return; } + CheckInstallabilityAndRetrieveManifest(); +} + +void InstallIsolatedAppCommand::CheckInstallabilityAndRetrieveManifest() { // TODO(kuragin): Fix order of calls to the data retrieve. // // The order should be: @@ -106,6 +129,29 @@ weak_factory_.GetWeakPtr())); } +absl::optional<WebAppInstallInfo> +InstallIsolatedAppCommand::CreateInstallInfoFromManifest( + const blink::mojom::Manifest& manifest, + const GURL& manifest_url) { + WebAppInstallInfo info; + UpdateWebAppInfoFromManifest(manifest, manifest_url, &info); + + if (!manifest.id.has_value()) { + return absl::nullopt; + } + + // In other installations the best-effort encoding is fine, but for isolated + // apps we have the opportunity to report this error. + if (absl::optional<std::string> encoded_id = UTF16ToUTF8(*manifest.id); + encoded_id.has_value()) { + info.manifest_id = *encoded_id; + } else { + return absl::nullopt; + } + + return info; +} + void InstallIsolatedAppCommand::OnCheckInstallabilityAndRetrieveManifest( blink::mojom::ManifestPtr opt_manifest, const GURL& manifest_url, @@ -138,12 +184,18 @@ DCHECK(!manifest_url.is_empty()) << "must not be empty if manifest is not empty."; - FinalizeInstall(); + if (absl::optional<WebAppInstallInfo> install_info = + CreateInstallInfoFromManifest(*opt_manifest, manifest_url); + install_info.has_value()) { + FinalizeInstall(*install_info); + } else { + ReportFailure(); + } } -void InstallIsolatedAppCommand::FinalizeInstall() { +void InstallIsolatedAppCommand::FinalizeInstall(const WebAppInstallInfo& info) { install_finalizer_.FinalizeInstall( - WebAppInstallInfo{}, + info, // TODO(kuragin): Add Isolated app specific install source // `WebappInstallSource::ISOLATED_APP_DEV_INSTALL`. WebAppInstallFinalizer::FinalizeOptions{
diff --git a/chrome/browser/web_applications/commands/install_isolated_app_command.h b/chrome/browser/web_applications/commands/install_isolated_app_command.h index 465f63c..d7f49cb 100644 --- a/chrome/browser/web_applications/commands/install_isolated_app_command.h +++ b/chrome/browser/web_applications/commands/install_isolated_app_command.h
@@ -13,6 +13,8 @@ #include "base/strings/string_piece_forward.h" #include "base/values.h" #include "chrome/browser/web_applications/commands/web_app_command.h" +#include "chrome/browser/web_applications/web_app_install_info.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/mojom/manifest/manifest.mojom-forward.h" class GURL; @@ -57,13 +59,19 @@ void DownloadIcons(); + void LoadUrl(GURL url); void OnLoadUrl(WebAppUrlLoaderResult result); + + void CheckInstallabilityAndRetrieveManifest(); void OnCheckInstallabilityAndRetrieveManifest( blink::mojom::ManifestPtr opt_manifest, const GURL& manifest_url, bool valid_manifest_for_web_app, bool is_installable); - void FinalizeInstall(); + absl::optional<WebAppInstallInfo> CreateInstallInfoFromManifest( + const blink::mojom::Manifest& manifest, + const GURL& manifest_url); + void FinalizeInstall(const WebAppInstallInfo& info); SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chrome/browser/web_applications/commands/install_isolated_app_command_unittest.cc b/chrome/browser/web_applications/commands/install_isolated_app_command_unittest.cc index 6ec1f6d..5d32976 100644 --- a/chrome/browser/web_applications/commands/install_isolated_app_command_unittest.cc +++ b/chrome/browser/web_applications/commands/install_isolated_app_command_unittest.cc
@@ -14,6 +14,7 @@ #include "base/memory/raw_ptr.h" #include "base/strings/string_piece.h" #include "base/strings/string_piece_forward.h" +#include "base/test/bind.h" #include "base/test/gmock_callback_support.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/test_future.h" @@ -27,6 +28,7 @@ #include "chrome/browser/web_applications/web_app_data_retriever.h" #include "chrome/browser/web_applications/web_app_install_finalizer.h" #include "chrome/browser/web_applications/web_app_install_info.h" +#include "chrome/browser/web_applications/web_app_install_utils.h" #include "chrome/browser/web_applications/web_app_url_loader.h" #include "chrome/test/base/testing_profile.h" #include "components/webapps/browser/installable/installable_metrics.h" @@ -40,23 +42,31 @@ namespace web_app { namespace { +using ::base::BucketsAre; using ::base::test::IsNotNullCallback; using ::base::test::RunOnceCallback; using ::testing::_; +using ::testing::AllOf; using ::testing::Eq; using ::testing::Field; +using ::testing::IsEmpty; using ::testing::IsFalse; +using ::testing::IsNull; +using ::testing::IsTrue; using ::testing::NiceMock; using ::testing::Not; +using ::testing::Optional; using ::testing::Pair; +using ::testing::Pointee; using ::testing::UnorderedElementsAre; blink::mojom::ManifestPtr CreateDefaultManifest() { auto manifest = blink::mojom::Manifest::New(); - manifest->start_url = GURL{"http://test.com/"}, - manifest->scope = GURL{"http://test.com/scope"}, + manifest->id = u"some default test manifest id"; + manifest->start_url = GURL{"http://default-test.com/"}, + manifest->scope = GURL{"/scope"}, manifest->display = DisplayMode::kStandalone; - manifest->short_name = u"Manifest Name"; + manifest->short_name = u"test short manifest name"; return manifest; } @@ -145,6 +155,26 @@ return test_future.Get(); } + InstallIsolatedAppCommandResult ExecuteCommandWithManifest( + const blink::mojom::ManifestPtr& manifest) { + SetPrepareForLoadResultLoaded(); + + ExpectLoadedForURL("http://manifest-test-url.com"); + + std::unique_ptr<MockDataRetriever> fake_data_retriever = + std::make_unique<NiceMock<MockDataRetriever>>(); + + ON_CALL(*fake_data_retriever, + CheckInstallabilityAndRetrieveManifest(_, _, IsNotNullCallback())) + .WillByDefault(RunOnceCallback<2>( + /*manifest=*/manifest.Clone(), + /*manifest_url=*/CreateDefaultManifestURL(), + /*valid_manifest_for_web_app=*/true, + /*is_installable=*/true)); + return ExecuteCommand("http://manifest-test-url.com", + std::move(fake_data_retriever)); + } + TestingProfile* profile() const { return profile_.get(); } FakeInstallFinalizer& install_finalizer() { @@ -281,13 +311,95 @@ /*manifest=*/nullptr, /*manifest_url=*/CreateDefaultManifestURL(), /*valid_manifest_for_web_app=*/true, - /*is_installable=*/false)); + /*is_installable=*/true)); EXPECT_THAT(ExecuteCommand("http://test-url-example.com", std::move(fake_data_retriever)), Not(IsInstallationOk())); } +using InstallIsolatedAppCommandManifestTest = InstallIsolatedAppCommandTest; + +TEST_F(InstallIsolatedAppCommandManifestTest, + InstallationFailsWhenManifestHasNoId) { + blink::mojom::ManifestPtr manifest = CreateDefaultManifest(); + manifest->id = absl::nullopt; + + EXPECT_THAT(ExecuteCommandWithManifest(manifest.Clone()), + Not(IsInstallationOk())); + + EXPECT_THAT(install_finalizer().web_app_info(), IsNull()); +} + +TEST_F(InstallIsolatedAppCommandManifestTest, + FailsWhenManifestIdHasInvalidUTF8Character) { + blink::mojom::ManifestPtr manifest = CreateDefaultManifest(); + char16_t invalid_utf8_chars = {0xD801}; + manifest->id = std::u16string{invalid_utf8_chars}; + + EXPECT_THAT(ExecuteCommandWithManifest(manifest.Clone()), + Not(IsInstallationOk())); +} + +TEST_F(InstallIsolatedAppCommandManifestTest, PassesManifestIdToFinalizer) { + blink::mojom::ManifestPtr manifest = CreateDefaultManifest(); + manifest->id = u"test manifest id"; + + EXPECT_THAT(ExecuteCommandWithManifest(manifest.Clone()), IsInstallationOk()); + + EXPECT_THAT(install_finalizer().web_app_info(), + Pointee(Field(&WebAppInstallInfo::manifest_id, + Optional(std::string{"test manifest id"})))); +} + +TEST_F(InstallIsolatedAppCommandManifestTest, PassesManifestNameAsTitle) { + blink::mojom::ManifestPtr manifest = CreateDefaultManifest(); + manifest->name = u"test application name"; + + EXPECT_THAT(ExecuteCommandWithManifest(manifest.Clone()), IsInstallationOk()); + + EXPECT_THAT( + install_finalizer().web_app_info(), + Pointee(Field(&WebAppInstallInfo::title, u"test application name"))); +} + +TEST_F(InstallIsolatedAppCommandManifestTest, + UseShortNameAsTitleWhenNameIsNotPresent) { + blink::mojom::ManifestPtr manifest = CreateDefaultManifest(); + manifest->name = absl::nullopt; + manifest->short_name = u"test short name"; + + EXPECT_THAT(ExecuteCommandWithManifest(manifest.Clone()), IsInstallationOk()); + + EXPECT_THAT(install_finalizer().web_app_info(), + Pointee(Field(&WebAppInstallInfo::title, u"test short name"))); +} + +TEST_F(InstallIsolatedAppCommandManifestTest, + UseShortNameAsTitleWhenNameIsEmpty) { + blink::mojom::ManifestPtr manifest = CreateDefaultManifest(); + manifest->name = u""; + manifest->short_name = u"other test short name"; + + EXPECT_THAT(ExecuteCommandWithManifest(manifest.Clone()), IsInstallationOk()); + + EXPECT_THAT( + install_finalizer().web_app_info(), + Pointee(Field(&WebAppInstallInfo::title, u"other test short name"))); +} + +TEST_F(InstallIsolatedAppCommandManifestTest, + TitleIsmptyWhenNameAndShortNameAreNotPresent) { + blink::mojom::ManifestPtr manifest = CreateDefaultManifest(); + manifest->name = absl::nullopt; + manifest->short_name = absl::nullopt; + + EXPECT_THAT(ExecuteCommandWithManifest(manifest.Clone()), IsInstallationOk()); + + EXPECT_THAT(install_finalizer().web_app_info(), + Pointee(Field(&WebAppInstallInfo::title, IsEmpty()))); +} + using InstallIsolatedAppCommandMetricsTest = InstallIsolatedAppCommandTest; TEST_F(InstallIsolatedAppCommandMetricsTest, @@ -302,7 +414,7 @@ IsInstallationOk()); EXPECT_THAT(histogram_tester.GetAllSamples("WebApp.Install.Result"), - base::BucketsAre(base::Bucket(true, 1))); + BucketsAre(base::Bucket(true, 1))); } TEST_F(InstallIsolatedAppCommandMetricsTest, ReportFailureWhenURLIsInvalid) { @@ -314,7 +426,7 @@ Not(IsInstallationOk())); EXPECT_THAT(histogram_tester.GetAllSamples("WebApp.Install.Result"), - base::BucketsAre(base::Bucket(false, 1))); + BucketsAre(base::Bucket(false, 1))); } TEST_F(InstallIsolatedAppCommandMetricsTest, ReportErrorWhenUrlLoaderFails) { @@ -328,7 +440,7 @@ Not(IsInstallationOk())); EXPECT_THAT(histogram_tester.GetAllSamples("WebApp.Install.Result"), - base::BucketsAre(base::Bucket(false, 1))); + BucketsAre(base::Bucket(false, 1))); } TEST_F(InstallIsolatedAppCommandMetricsTest, @@ -356,7 +468,7 @@ Not(IsInstallationOk())); EXPECT_THAT(histogram_tester.GetAllSamples("WebApp.Install.Result"), - base::BucketsAre(base::Bucket(false, 1))); + BucketsAre(base::Bucket(false, 1))); } TEST_F(InstallIsolatedAppCommandMetricsTest, ReportFailureWhenManifestIsNull) { @@ -382,7 +494,7 @@ Not(IsInstallationOk())); EXPECT_THAT(histogram_tester.GetAllSamples("WebApp.Install.Result"), - base::BucketsAre(base::Bucket(false, 1))); + BucketsAre(base::Bucket(false, 1))); } } // namespace
diff --git a/chrome/browser/web_applications/externally_installed_web_app_prefs.cc b/chrome/browser/web_applications/externally_installed_web_app_prefs.cc index 29ce6c6..506c61e 100644 --- a/chrome/browser/web_applications/externally_installed_web_app_prefs.cc +++ b/chrome/browser/web_applications/externally_installed_web_app_prefs.cc
@@ -93,14 +93,6 @@ } // static -// TODO(crbug.com/1236159): Can be removed after M99. -void ExternallyInstalledWebAppPrefs::RemoveTerminalPWA( - PrefService* pref_service) { - DictionaryPrefUpdate update(pref_service, prefs::kWebAppsExtensionIDs); - update->RemoveKey("chrome-untrusted://terminal/html/pwa.html"); -} - -// static bool ExternallyInstalledWebAppPrefs::HasAppIdWithInstallSource( const PrefService* pref_service, const AppId& app_id,
diff --git a/chrome/browser/web_applications/externally_installed_web_app_prefs.h b/chrome/browser/web_applications/externally_installed_web_app_prefs.h index 0e9702c..bf22a0d 100644 --- a/chrome/browser/web_applications/externally_installed_web_app_prefs.h +++ b/chrome/browser/web_applications/externally_installed_web_app_prefs.h
@@ -44,9 +44,6 @@ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); - // Removes invalid registration for Terminal System App. - static void RemoveTerminalPWA(PrefService* pref_service); - explicit ExternallyInstalledWebAppPrefs(PrefService* pref_service); ExternallyInstalledWebAppPrefs(const ExternallyInstalledWebAppPrefs&) = delete;
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index afe437c4..ed7d5ac2 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1660046387-d50623958aedd9baa0527aeab3831bf051513904.profdata +chrome-mac-arm-main-1660067998-752bed295d7eb2a9aa79bdd97f2eed52f0d5dcdd.profdata
diff --git a/chrome/chrome_cleaner/test/test_util.cc b/chrome/chrome_cleaner/test/test_util.cc index f536c93b..bd5c85a6 100644 --- a/chrome/chrome_cleaner/test/test_util.cc +++ b/chrome/chrome_cleaner/test/test_util.cc
@@ -17,6 +17,7 @@ #include "base/base_paths.h" #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -166,7 +167,7 @@ argc, argv, /*parallel_jobs=*/1U, // Like LaunchUnitTestsSerially /*default_batch_limit=*/10, // Like LaunchUnitTestsSerially - use_job_objects, + use_job_objects, base::DoNothing(), base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite))); if (!IsSandboxedProcess())
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index c018b45..eb28697 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -3423,12 +3423,6 @@ // this pref is set to 0, the action happens immediately. const char kSecurityTokenSessionNotificationSeconds[] = "security_token_session_notification_seconds"; -// In addition to the notification described directly above, another -// notification will be displayed after the action happened. This only happens -// once for a user. This boolean pref saves whether this notification was -// already displayed for a user. -const char kSecurityTokenSessionNotificationDisplayed[] = - "security_token_session_notification_displayed"; // This string pref is set when the notification after the action mentioned // above is about to be displayed. It contains the domain that manages the user // who was logged out, to be used as part of the notification message.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 8b685ac..4d8afaaa 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -1190,7 +1190,6 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) extern const char kSecurityTokenSessionBehavior[]; extern const char kSecurityTokenSessionNotificationSeconds[]; -extern const char kSecurityTokenSessionNotificationDisplayed[]; extern const char kSecurityTokenSessionNotificationScheduledDomain[]; #endif
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index d20af19..90df675a 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3308,7 +3308,7 @@ "../browser/ui/views/extensions/extensions_request_access_dialog_view_browsertest.cc", "../browser/ui/views/extensions/media_galleries_dialog_views_browsertest.cc", "../browser/ui/views/extensions/reload_page_dialog_view_browsertest.cc", - "../browser/ui/views/extensions/settings_overridden_dialog_view_browsertest.cc", + "../browser/ui/views/extensions/settings_overridden_dialog_browsertest.cc", "../browser/ui/views/external_protocol_dialog_browsertest.cc", "../browser/ui/views/file_system_access/file_system_access_browsertest.cc", "../browser/ui/views/file_system_access/file_system_access_permission_view_browsertest.cc", @@ -8577,7 +8577,7 @@ "../browser/ui/views/extensions/extensions_toolbar_unittest.cc", "../browser/ui/views/extensions/extensions_toolbar_unittest.h", "../browser/ui/views/extensions/media_galleries_dialog_views_unittest.cc", - "../browser/ui/views/extensions/settings_overridden_dialog_view_unittest.cc", + "../browser/ui/views/extensions/settings_overridden_dialog_unittest.cc", "../browser/ui/views/frame/browser_non_client_frame_view_unittest.cc", "../browser/ui/views/frame/browser_view_layout_unittest.cc", "../browser/ui/views/frame/browser_view_unittest.cc",
diff --git a/chrome/test/data/extensions/api_test/request_quota_background/background.js b/chrome/test/data/extensions/api_test/request_quota_background/background.js index 2f14925f..93cc58c 100644 --- a/chrome/test/data/extensions/api_test/request_quota_background/background.js +++ b/chrome/test/data/extensions/api_test/request_quota_background/background.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -webkitStorageInfo.requestQuota(PERSISTENT, 1, pass, fail); +navigator.webkitPersistentStorage.requestQuota(1, pass, fail); function pass() { console.log("PASS");
diff --git a/chrome/test/data/extensions/platform_apps/web_view/filesystem/main/guest_main.html b/chrome/test/data/extensions/platform_apps/web_view/filesystem/main/guest_main.html index b499ebf..0991f07 100644 --- a/chrome/test/data/extensions/platform_apps/web_view/filesystem/main/guest_main.html +++ b/chrome/test/data/extensions/platform_apps/web_view/filesystem/main/guest_main.html
@@ -53,7 +53,7 @@ }; var requestFileSystemAccess = function() { - window.webkitStorageInfo.requestQuota(PERSISTENT, 1024 * 1024, + navigator.webkitPersistentStorage.requestQuota(1024 * 1024, function(grantedBytes) { window.console.log('request Quota granted.'); window.requestFileSystem(window.PERSISTENT, 1024*1024,
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index fde492a..15defc2 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -9301,6 +9301,7 @@ }, "prefs": { "security_token_session_behavior": { + "location": "local_state", "value": "LOGOUT" } } @@ -9309,6 +9310,7 @@ "policies": {}, "prefs": { "security_token_session_behavior": { + "location": "local_state", "default_value": "IGNORE" } } @@ -9326,6 +9328,7 @@ }, "prefs": { "security_token_session_notification_seconds": { + "location": "local_state", "value": 10 } } @@ -9334,6 +9337,7 @@ "policies": {}, "prefs": { "security_token_session_notification_seconds": { + "location": "local_state", "default_value": 0 } } @@ -19131,5 +19135,38 @@ } } ] + }, + "UnmanagedDeviceSignalsConsentFlowEnabled": { + "os": [ + "win", + "linux", + "mac" + ], + "policy_pref_mapping_tests": [ + { + "policies": {}, + "prefs": { + "device_signals.consent_collection_enabled": { + "default_value": false + } + } + }, + { + "policies": { "UnmanagedDeviceSignalsConsentFlowEnabled": false }, + "prefs": { + "device_signals.consent_collection_enabled": { + "value": false + } + } + }, + { + "policies": { "UnmanagedDeviceSignalsConsentFlowEnabled": true }, + "prefs": { + "device_signals.consent_collection_enabled": { + "value": true + } + } + } + ] } }
diff --git a/chrome/test/data/updater/puffin_patch_test/BUILD.gn b/chrome/test/data/updater/puffin_patch_test/BUILD.gn deleted file mode 100644 index 8911d0e..0000000 --- a/chrome/test/data/updater/puffin_patch_test/BUILD.gn +++ /dev/null
@@ -1,73 +0,0 @@ -# Copyright 2022 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("//components/crx_file/crx3.gni") - -group("puffin_patch_test_files") { - testonly = true - data_deps = [ - ":puff_patch_v1_to_v2", - ":puff_patch_v2_to_v1", - ":puffin_app_v1_crx", - ":puffin_app_v2_crx", - ] -} - -executable("puffin_app_v2") { - testonly = true - sources = [ "puffin_app_v2/main.cc" ] -} - -executable("puffin_app_v1") { - testonly = true - sources = [ "puffin_app_v1/main.cc" ] -} - -crx3("puffin_app_v1_crx") { - base_dir = "$root_build_dir" - key = "//chrome/updater/test/data/selfupdate_test_key.der" - output = "$root_build_dir/puffin_app_v1.crx3" - testonly = true - deps = [ ":puffin_app_v1" ] - if (is_win) { - inputs = [ "$root_build_dir/puffin_app_v1.exe" ] - } else { - inputs = [ "$root_build_dir/puffin_app_v1" ] - } -} - -copy("puff_patch_v1_to_v2") { - if (is_win) { - sources = [ "win_v1_to_v2.puff" ] - } else if (is_linux) { - sources = [ "linux_v1_to_v2.puff" ] - } else if (is_mac) { - sources = [ "mac_v1_to_v2.puff" ] - } - outputs = [ "$root_build_dir/puffin_app_v1_to_v2.puff" ] -} - -copy("puff_patch_v2_to_v1") { - if (is_win) { - sources = [ "win_v2_to_v1.puff" ] - } else if (is_linux) { - sources = [ "linux_v2_to_v1.puff" ] - } else if (is_mac) { - sources = [ "mac_v2_to_v1.puff" ] - } - outputs = [ "$root_build_dir/puffin_app_v2_to_v1.puff" ] -} - -crx3("puffin_app_v2_crx") { - base_dir = "$root_build_dir" - key = "//chrome/updater/test/data/selfupdate_test_key.der" - output = "$root_build_dir/puffin_app_v2.crx3" - testonly = true - deps = [ ":puffin_app_v2" ] - if (is_win) { - inputs = [ "$root_build_dir/puffin_app_v2.exe" ] - } else { - inputs = [ "$root_build_dir/puffin_app_v2" ] - } -}
diff --git a/chrome/test/data/updater/puffin_patch_test/README.md b/chrome/test/data/updater/puffin_patch_test/README.md deleted file mode 100644 index ce5d3b6a..0000000 --- a/chrome/test/data/updater/puffin_patch_test/README.md +++ /dev/null
@@ -1,47 +0,0 @@ -## How to regenerate linux, mac and windows test puff files: - -If changes are made to puffin_app_v1/main.cc or puffin_app_v2/main.cc, the various puff files which represent a patch between the crx's produced by each of these sources. Thus, we'll need to regenerate these on each platform. - -This README assumes you are already in your Chromium repo's src directory, that your gn args were generated in "out/Default", and that you are able to build the third_party/puffin:puffin target. Eventually, puffin will always be a valid target, but currently it requires you to link it into the build somehow. For now, you may need to temporarily add the following to your "//third_party/BUILD.gn" - - group("puffin") { - testonly = true - deps = [ "//third_party/puffin"] - } - -*Be careful not to submit this change in the final cl!* - -**Linux commands** - - autoninja -C out/Default puffin puffin_app_v1_crx puffin_app_v2_crx - rm chrome/test/data/updater/puffin_patch_test/linux_v1_to_v2.puff - rm chrome/test/data/updater/puffin_patch_test/linux_v2_to_v1.puff - out/Default/puffin -puffdiff out/Default/puffin_app_v1.crx3 out/Default/puffin_app_v2.crx3 chrome/test/data/updater/puffin_patch_test/linux_v1_to_v2.puff - out/Default/puffin -puffdiff out/Default/puffin_app_v2.crx3 out/Default/puffin_app_v1.crx3 chrome/test/data/updater/puffin_patch_test/linux_v2_to_v1.puff - -**Mac commands** - - autoninja -C out/Default puffin puffin_app_v1_crx puffin_app_v2_crx - rm chrome/test/data/updater/puffin_patch_test/mac_v1_to_v2.puff - rm chrome/test/data/updater/puffin_patch_test/mac_v2_to_v1.puff - out/Default/puffin -puffdiff out/Default/puffin_app_v1.crx3 out/Default/puffin_app_v2.crx3 chrome/test/data/updater/puffin_patch_test/mac_v1_to_v2.puff - out/Default/puffin -puffdiff out/Default/puffin_app_v2.crx3 out/Default/puffin_app_v1.crx3 chrome/test/data/updater/puffin_patch_test/mac_v2_to_v1.puff - -**Windows commands** - - autoninja -C out\Default puffin puffin_app_v1_crx puffin_app_v2_crx - del /f chrome\test\data\updater\puffin_patch_test\win_v1_to_v2.puff - del /f chrome\test\data\updater\puffin_patch_test\win_v2_to_v1.puff - out\Default\puffin.exe -puffdiff out\Default\puffin_app_v1.crx3 out\Default\puffin_app_v2.crx3 chrome\test\data\updater\puffin_patch_test\win_v1_to_v2.puff - out\Default\puffin.exe -puffdiff out\Default\puffin_app_v2.crx3 out\Default\puffin_app_v1.crx3 chrome\test\data\updater\puffin_patch_test\win_v2_to_v1.puff - -## Testing the new patches -You can test but running the following commands to verify if all tests pass, on each platform. Specifically the "PatchingTest.ApplyPuffPatchTest": - -**Mac and Linux:** - autoninja -C out/Default puffin_unittest - out/Default/puffin_unittest - -**Windows:** - autoninja -C out\Default puffin_unittest - out\Default\puffin_unittest.exe \ No newline at end of file
diff --git a/chrome/test/data/updater/puffin_patch_test/linux_v1_to_v2.puff b/chrome/test/data/updater/puffin_patch_test/linux_v1_to_v2.puff deleted file mode 100644 index 7aaef8b..0000000 --- a/chrome/test/data/updater/puffin_patch_test/linux_v1_to_v2.puff +++ /dev/null Binary files differ
diff --git a/chrome/test/data/updater/puffin_patch_test/linux_v2_to_v1.puff b/chrome/test/data/updater/puffin_patch_test/linux_v2_to_v1.puff deleted file mode 100644 index 418392a..0000000 --- a/chrome/test/data/updater/puffin_patch_test/linux_v2_to_v1.puff +++ /dev/null Binary files differ
diff --git a/chrome/test/data/updater/puffin_patch_test/mac_v1_to_v2.puff b/chrome/test/data/updater/puffin_patch_test/mac_v1_to_v2.puff deleted file mode 100644 index 059c122..0000000 --- a/chrome/test/data/updater/puffin_patch_test/mac_v1_to_v2.puff +++ /dev/null Binary files differ
diff --git a/chrome/test/data/updater/puffin_patch_test/mac_v2_to_v1.puff b/chrome/test/data/updater/puffin_patch_test/mac_v2_to_v1.puff deleted file mode 100644 index 91b92c52..0000000 --- a/chrome/test/data/updater/puffin_patch_test/mac_v2_to_v1.puff +++ /dev/null Binary files differ
diff --git a/chrome/test/data/updater/puffin_patch_test/win_v1_to_v2.puff b/chrome/test/data/updater/puffin_patch_test/win_v1_to_v2.puff deleted file mode 100644 index 617a490..0000000 --- a/chrome/test/data/updater/puffin_patch_test/win_v1_to_v2.puff +++ /dev/null Binary files differ
diff --git a/chrome/test/data/updater/puffin_patch_test/win_v2_to_v1.puff b/chrome/test/data/updater/puffin_patch_test/win_v2_to_v1.puff deleted file mode 100644 index 1449eac..0000000 --- a/chrome/test/data/updater/puffin_patch_test/win_v2_to_v1.puff +++ /dev/null Binary files differ
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/reimaging_calibration_failed_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/reimaging_calibration_failed_page_test.js index 53ddbe5..25658ad 100644 --- a/chrome/test/data/webui/chromeos/shimless_rma/reimaging_calibration_failed_page_test.js +++ b/chrome/test/data/webui/chromeos/shimless_rma/reimaging_calibration_failed_page_test.js
@@ -3,6 +3,7 @@ // found in the LICENSE file. import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js'; +import {getDeepActiveElement} from 'chrome://resources/js/util.m.js'; import {fakeCalibrationComponentsWithFails, fakeCalibrationComponentsWithoutFails} from 'chrome://shimless-rma/fake_data.js'; import {FakeShimlessRmaService} from 'chrome://shimless-rma/fake_shimless_rma_service.js'; import {setShimlessRmaServiceForTesting} from 'chrome://shimless-rma/mojo_interface_provider.js'; @@ -175,7 +176,7 @@ let startCalibrationCalls = 0; service.startCalibration = (components) => { - assertEquals(5, components.length); + assertEquals(7, components.length); components.forEach( component => assertEquals( component.component === ComponentType.kCamera ? @@ -302,4 +303,90 @@ component.removeEventListener('disable-next-button', disableHandler); }); + + test('CalibrationFailedPageKeyboardNavigationWorks', async () => { + await initializeCalibrationPage(fakeCalibrationComponentsWithFails); + + const componentLidAccelerometerButton = + component.shadowRoot.querySelector('#componentLidAccelerometer') + .shadowRoot.querySelector('#componentButton'); + const componentScreenButton = + component.shadowRoot.querySelector('#componentScreen') + .shadowRoot.querySelector('#componentButton'); + // There are two screens, so we can only get the first one by the id. We get + // the second one by the unique id. + const componentSecondScreenButton = + component.shadowRoot.querySelector('[unique-id="6"]') + .shadowRoot.querySelector('#componentButton'); + + await flushTasks(); + + // At the beginning we should be focused on the first clickable component, + // which is the camera. + assertDeepEquals(componentLidAccelerometerButton, getDeepActiveElement()); + // We are at the beginning of the list, so left arrow should do nothing. + window.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowLeft'})); + await flushTasks(); + assertDeepEquals(componentLidAccelerometerButton, getDeepActiveElement()); + + // Skip disabled buttons until an enable button is found. + window.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowRight'})); + await flushTasks(); + assertDeepEquals(componentScreenButton, getDeepActiveElement()); + + // If the next component is not disabled, we don't skip it. + window.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowRight'})); + await flushTasks(); + assertDeepEquals(componentSecondScreenButton, getDeepActiveElement()); + + // We have reached the end of the list, so we can't go any further. + window.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowRight'})); + await flushTasks(); + assertDeepEquals(componentSecondScreenButton, getDeepActiveElement()); + + // Check that we can go backwards the same way. + window.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowLeft'})); + await flushTasks(); + assertDeepEquals(componentScreenButton, getDeepActiveElement()); + window.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowLeft'})); + await flushTasks(); + assertDeepEquals(componentLidAccelerometerButton, getDeepActiveElement()); + + // Check that the down button navigates down the column. There is only one + // column, so it should be the same as the right button. + window.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'})); + await flushTasks(); + assertDeepEquals(componentScreenButton, getDeepActiveElement()); + window.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'})); + await flushTasks(); + assertDeepEquals(componentSecondScreenButton, getDeepActiveElement()); + + + // The up button should work in a similar way. + window.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowUp'})); + await flushTasks(); + assertDeepEquals(componentScreenButton, getDeepActiveElement()); + window.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowUp'})); + await flushTasks(); + assertDeepEquals(componentLidAccelerometerButton, getDeepActiveElement()); + + // Click on the screen button. It should come into focus. + componentScreenButton.click(); + await flushTasks(); + assertDeepEquals(componentScreenButton, getDeepActiveElement()); + + // Click on the battery button. It's disabled, so we shouldn't focus on it. + const componentBatteryButton = + component.shadowRoot.querySelector('#componentBattery') + .shadowRoot.querySelector('#componentButton'); + componentBatteryButton.click(); + await flushTasks(); + assertDeepEquals(componentScreenButton, getDeepActiveElement()); + + // Make sure we can bring both screens into focus, even though they have the + // same id. + componentSecondScreenButton.click(); + await flushTasks(); + assertDeepEquals(componentSecondScreenButton, getDeepActiveElement()); + }); }
diff --git a/chrome/test/data/webui/cr_elements/cr_action_menu_test.ts b/chrome/test/data/webui/cr_elements/cr_action_menu_test.ts index 65bef15..059c7c3 100644 --- a/chrome/test/data/webui/cr_elements/cr_action_menu_test.ts +++ b/chrome/test/data/webui/cr_elements/cr_action_menu_test.ts
@@ -3,10 +3,10 @@ // found in the LICENSE file. // clang-format off -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {AnchorAlignment, CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {isMac, isWindows} from 'chrome://resources/js/cr.m.js'; import {FocusOutlineManager} from 'chrome://resources/js/cr/ui/focus_outline_manager.m.js'; import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
diff --git a/chrome/test/data/webui/cr_elements/cr_checkbox_test.ts b/chrome/test/data/webui/cr_elements/cr_checkbox_test.ts index a085574..ee45be7 100644 --- a/chrome/test/data/webui/cr_elements/cr_checkbox_test.ts +++ b/chrome/test/data/webui/cr_elements/cr_checkbox_test.ts
@@ -3,11 +3,10 @@ // found in the LICENSE file. // clang-format off -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {keyDownOn, keyUpOn, pressAndReleaseKeyOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; - import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {eventToPromise} from 'chrome://webui-test/test_util.js';
diff --git a/chrome/test/data/webui/cr_elements/cr_lazy_render_tests.ts b/chrome/test/data/webui/cr_elements/cr_lazy_render_tests.ts index 40b7a27..61cb2d1 100644 --- a/chrome/test/data/webui/cr_elements/cr_lazy_render_tests.ts +++ b/chrome/test/data/webui/cr_elements/cr_lazy_render_tests.ts
@@ -4,7 +4,7 @@ // clang-format off import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; -import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
diff --git a/chrome/test/data/webui/settings/chromeos/fake_cros_audio_config.js b/chrome/test/data/webui/settings/chromeos/fake_cros_audio_config.js index fa60999..420cf7d 100644 --- a/chrome/test/data/webui/settings/chromeos/fake_cros_audio_config.js +++ b/chrome/test/data/webui/settings/chromeos/fake_cros_audio_config.js
@@ -140,7 +140,7 @@ } /** - * Sets the outputVolumePercent to the desired volume. + * Sets audioSystemProperties to the desired properties. * @param {!ash.audioConfig.mojom.AudioSystemProperties} properties */ setAudioSystemProperties(properties) { @@ -149,6 +149,15 @@ } /** + * Sets the outputVolumePercent to the desired volume. + * @param {!number} volume + */ + setOutputVolumePercent(volume) { + this.audioSystemProperties_.outputVolumePercent = volume; + this.notifyAudioSystemPropertiesUpdated_(); + } + + /** * @private * Notifies the observer list that audioSystemProperties_ has changed. */
diff --git a/chrome/test/data/webui/settings/chromeos/test_device_name_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_device_name_browser_proxy.js index 39d81379..91f9cf4 100644 --- a/chrome/test/data/webui/settings/chromeos/test_device_name_browser_proxy.js +++ b/chrome/test/data/webui/settings/chromeos/test_device_name_browser_proxy.js
@@ -6,7 +6,6 @@ import {TestBrowserProxy} from '../../test_browser_proxy.js'; -/** @implements {DeviceNameBrowserProxy} */ export class TestDeviceNameBrowserProxy extends TestBrowserProxy { constructor() { super([
diff --git a/chrome/test/data/webui/settings/spell_check_page_metrics_test_browser.ts b/chrome/test/data/webui/settings/spell_check_page_metrics_test_browser.ts index e45f142..5cbc764 100644 --- a/chrome/test/data/webui/settings/spell_check_page_metrics_test_browser.ts +++ b/chrome/test/data/webui/settings/spell_check_page_metrics_test_browser.ts
@@ -135,7 +135,7 @@ // <if expr="_google_chrome"> suite(spell_check_page_metrics_test_browser.TestNames.SpellCheckMetricsOfficialBuild, function() { - test('records when selecing basic spell check', async () => { + test('records when selecting basic spell check', async () => { spellCheckPage.setPrefValue('spellcheck.use_spelling_service', true); const basicServiceSelect = spellCheckPage.shadowRoot! .querySelector<HTMLElement>('#spellingServiceDisable'); @@ -148,7 +148,7 @@ await languageSettingsMetricsProxy.whenCalled('recordSettingsMetric')); }); - test('records when selecing enhanced spell check', async () => { + test('records when selecting enhanced spell check', async () => { spellCheckPage.setPrefValue('spellcheck.use_spelling_service', false); const enhancedServiceSelect = spellCheckPage.shadowRoot! .querySelector<HTMLElement>('#spellingServiceEnable');
diff --git a/chrome/test/data/webui/signin/enterprise_profile_welcome_test.ts b/chrome/test/data/webui/signin/enterprise_profile_welcome_test.ts index 3cb59ab..d31fd49 100644 --- a/chrome/test/data/webui/signin/enterprise_profile_welcome_test.ts +++ b/chrome/test/data/webui/signin/enterprise_profile_welcome_test.ts
@@ -6,7 +6,7 @@ import {EnterpriseProfileWelcomeAppElement} from 'chrome://enterprise-profile-welcome/enterprise_profile_welcome_app.js'; import {EnterpriseProfileInfo, EnterpriseProfileWelcomeBrowserProxyImpl} from 'chrome://enterprise-profile-welcome/enterprise_profile_welcome_browser_proxy.js'; -import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn index 8518d7d..9e592ac 100644 --- a/chrome/updater/BUILD.gn +++ b/chrome/updater/BUILD.gn
@@ -114,6 +114,8 @@ "prefs.cc", "prefs.h", "prefs_impl.h", + "refresh_dm_policies_task.cc", + "refresh_dm_policies_task.h", "registration_data.cc", "registration_data.h", "remove_uninstalled_apps_task.cc",
diff --git a/chrome/updater/configurator.cc b/chrome/updater/configurator.cc index 834f96c..1f648f7 100644 --- a/chrome/updater/configurator.cc +++ b/chrome/updater/configurator.cc
@@ -213,6 +213,10 @@ return policy_service_; } +void Configurator::ResetPolicyService() { + policy_service_ = PolicyService::Create(external_constants_); +} + crx_file::VerifierFormat Configurator::GetCrxVerifierFormat() const { return external_constants_->CrxVerifierFormat(); }
diff --git a/chrome/updater/configurator.h b/chrome/updater/configurator.h index 29558ae..443498af 100644 --- a/chrome/updater/configurator.h +++ b/chrome/updater/configurator.h
@@ -81,6 +81,9 @@ scoped_refptr<PolicyService> GetPolicyService() const; crx_file::VerifierFormat GetCrxVerifierFormat() const; + // This reloads the policy managers. + void ResetPolicyService(); + private: friend class base::RefCountedThreadSafe<Configurator>; ~Configurator() override;
diff --git a/chrome/updater/device_management/dm_storage.cc b/chrome/updater/device_management/dm_storage.cc index 58e27d1..1cfa1f3 100644 --- a/chrome/updater/device_management/dm_storage.cc +++ b/chrome/updater/device_management/dm_storage.cc
@@ -16,22 +16,16 @@ #include "base/files/important_file_writer.h" #include "base/memory/scoped_refptr.h" #include "base/notreached.h" -#include "base/path_service.h" #include "base/strings/sys_string_conversions.h" #include "build/build_config.h" #include "chrome/updater/device_management/dm_cached_policy_info.h" #include "chrome/updater/device_management/dm_message.h" #include "chrome/updater/protos/omaha_settings.pb.h" -#include "chrome/updater/updater_branding.h" #include "chrome/updater/updater_scope.h" #include "chrome/updater/util.h" #include "components/policy/proto/device_management_backend.pb.h" #include "third_party/abseil-cpp/absl/types/optional.h" -#if BUILDFLAG(IS_WIN) -#include "base/base_paths_win.h" -#endif // BUILDFLAG(IS_WIN) - namespace updater { namespace { @@ -51,9 +45,6 @@ // {policy_type} that it receives from the DMServer. constexpr char kPolicyFileName[] = "PolicyFetchResponse"; -// Policy subfolder in the updater installation path. -constexpr char kPolicyCacheSubfolder[] = "Policies"; - // Deletes the child directories in cache root if they do not appear in // set |policy_types_base64|. bool DeleteObsoletePolicies(const base::FilePath& cache_root, @@ -79,7 +70,7 @@ } // namespace #if BUILDFLAG(IS_LINUX) -// crbug.com/1276162 - implement. +// TODO(crbug.com/1276162) - implement. DMStorage::DMStorage(const base::FilePath& policy_cache_root) : policy_cache_root_(policy_cache_root) { NOTIMPLEMENTED(); @@ -216,28 +207,12 @@ return omaha_settings; } +#if BUILDFLAG(IS_LINUX) +// TODO(crbug.com/1276162) - implement. scoped_refptr<DMStorage> GetDefaultDMStorage() { -#if BUILDFLAG(IS_WIN) - base::FilePath program_filesx86_dir; - if (!base::PathService::Get(base::DIR_PROGRAM_FILESX86, - &program_filesx86_dir)) { - return nullptr; - } - - return base::MakeRefCounted<DMStorage>( - program_filesx86_dir.AppendASCII(COMPANY_SHORTNAME_STRING) - .AppendASCII(kPolicyCacheSubfolder)); - -#else // BUILDFLAG(IS_WIN) - - const absl::optional<base::FilePath> updater_versioned_path = - GetVersionedDataDirectory(GetUpdaterScope()); - if (!updater_versioned_path) - return nullptr; - base::FilePath policy_cache_folder = - updater_versioned_path->AppendASCII(kPolicyCacheSubfolder); - return base::MakeRefCounted<DMStorage>(policy_cache_folder); -#endif // BUILDFLAG(IS_WIN) + NOTIMPLEMENTED(); + return nullptr; } +#endif } // namespace updater
diff --git a/chrome/updater/device_management/dm_storage.h b/chrome/updater/device_management/dm_storage.h index dca25dd..f8987d1b 100644 --- a/chrome/updater/device_management/dm_storage.h +++ b/chrome/updater/device_management/dm_storage.h
@@ -145,9 +145,8 @@ }; // Returns the DMStorage under which the Device Management policies are -// persisted. For Windows, this is `%ProgramFiles(x86)%\{CompanyName}\Policies` -// for security. -// For other platforms, this is `{UpdaterVersionedPath}\Policies`. +// persisted. For Windows, this is `%ProgramFiles(x86)%\{CompanyName}\Policies`. +// For macOS, this is `/Library/{CompanyName}/{KEYSTONE_NAME}/DeviceManagement`. scoped_refptr<DMStorage> GetDefaultDMStorage(); } // namespace updater
diff --git a/chrome/updater/device_management/dm_storage_mac.mm b/chrome/updater/device_management/dm_storage_mac.mm index 725a27c4..303575f 100644 --- a/chrome/updater/device_management/dm_storage_mac.mm +++ b/chrome/updater/device_management/dm_storage_mac.mm
@@ -15,8 +15,10 @@ #include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_ioobject.h" #include "base/mac/scoped_nsobject.h" +#include "base/memory/scoped_refptr.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" +#include "chrome/updater/mac/mac_util.h" #include "chrome/updater/updater_branding.h" namespace updater { @@ -151,4 +153,16 @@ DMStorage::DMStorage(const base::FilePath& policy_cache_root) : DMStorage(policy_cache_root, std::make_unique<TokenService>()) {} +scoped_refptr<DMStorage> GetDefaultDMStorage() { + absl::optional<base::FilePath> sys_library_path = + GetLibraryFolderPath(UpdaterScope::kSystem); + if (!sys_library_path) + return nullptr; + + return base::MakeRefCounted<DMStorage>( + sys_library_path->AppendASCII(COMPANY_SHORTNAME_STRING) + .Append(FILE_PATH_LITERAL(KEYSTONE_NAME)) + .AppendASCII("DeviceManagement")); +} + } // namespace updater
diff --git a/chrome/updater/device_management/dm_storage_win.cc b/chrome/updater/device_management/dm_storage_win.cc index a0e2c5c4..3ee5082 100644 --- a/chrome/updater/device_management/dm_storage_win.cc +++ b/chrome/updater/device_management/dm_storage_win.cc
@@ -6,8 +6,13 @@ #include <string> +#include "base/base_paths_win.h" +#include "base/files/file_path.h" +#include "base/memory/scoped_refptr.h" +#include "base/path_service.h" #include "base/strings/sys_string_conversions.h" #include "base/win/registry.h" +#include "chrome/updater/updater_branding.h" #include "chrome/updater/win/win_constants.h" #include "chrome/updater/win/win_util.h" @@ -106,4 +111,16 @@ DMStorage::DMStorage(const base::FilePath& policy_cache_root) : DMStorage(policy_cache_root, std::make_unique<TokenService>()) {} +scoped_refptr<DMStorage> GetDefaultDMStorage() { + base::FilePath program_filesx86_dir; + if (!base::PathService::Get(base::DIR_PROGRAM_FILESX86, + &program_filesx86_dir)) { + return nullptr; + } + + return base::MakeRefCounted<DMStorage>( + program_filesx86_dir.AppendASCII(COMPANY_SHORTNAME_STRING) + .AppendASCII("Policies")); +} + } // namespace updater
diff --git a/chrome/updater/refresh_dm_policies_task.cc b/chrome/updater/refresh_dm_policies_task.cc new file mode 100644 index 0000000..46de97e --- /dev/null +++ b/chrome/updater/refresh_dm_policies_task.cc
@@ -0,0 +1,82 @@ +// Copyright 2022 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/updater/refresh_dm_policies_task.h" + +#include <vector> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/memory/scoped_refptr.h" +#include "base/sequence_checker.h" +#include "base/task/thread_pool.h" +#include "chrome/updater/configurator.h" +#include "chrome/updater/device_management/dm_client.h" +#include "chrome/updater/device_management/dm_response_validator.h" +#include "chrome/updater/device_management/dm_storage.h" +#include "chrome/updater/policy/service.h" + +#if BUILDFLAG(IS_WIN) +#include <shlobj.h> +#endif // BUILDFLAG(IS_WIN) + +namespace updater { + +RefreshDMPoliciesTask::RefreshDMPoliciesTask(scoped_refptr<Configurator> config) + : config_(config) {} + +RefreshDMPoliciesTask::~RefreshDMPoliciesTask() = default; + +void RefreshDMPoliciesTask::Run(base::OnceClosure callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + VLOG(1) << __func__; + +#if BUILDFLAG(IS_WIN) + // Returning early, because we cannot write to the DM cache in Windows under + // %ProgramFiles(x86)% without having administrative privileges. + if (!::IsUserAnAdmin()) { + std::move(callback).Run(); + return; + } + + FetchPolicy(); + std::move(callback).Run(); + return; + +#else // BUILDFLAG(IS_WIN) + + // `RefreshDMPoliciesTask::FetchPolicy` can block and therefore is running + // under a task runner with `base::MayBlock()`. + base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}) + ->PostTaskAndReply( + FROM_HERE, base::BindOnce(&RefreshDMPoliciesTask::FetchPolicy, this), + std::move(callback)); +#endif // BUILDFLAG(IS_WIN) +} + +void RefreshDMPoliciesTask::FetchPolicy() { + VLOG(1) << __func__; + + DMClient::FetchPolicy( + DMClient::CreateDefaultConfigurator(config_->GetPolicyService()), + GetDefaultDMStorage(), + base::BindOnce(&RefreshDMPoliciesTask::OnRequestComplete, this)); +} + +void RefreshDMPoliciesTask::OnRequestComplete( + DMClient::RequestResult result, + const std::vector<PolicyValidationResult>& validation_results) { + VLOG(1) << __func__; + + // TODO(crbug.com/1345407) : call ReportPolicyValidationErrors() when there's + // an error. + if (result != DMClient::RequestResult::kSuccess) + return; + + config_->ResetPolicyService(); + VLOG(1) << "Policies are now reloaded."; +} + +} // namespace updater
diff --git a/chrome/updater/refresh_dm_policies_task.h b/chrome/updater/refresh_dm_policies_task.h new file mode 100644 index 0000000..4b2697c --- /dev/null +++ b/chrome/updater/refresh_dm_policies_task.h
@@ -0,0 +1,44 @@ +// Copyright 2022 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_UPDATER_REFRESH_DM_POLICIES_TASK_H_ +#define CHROME_UPDATER_REFRESH_DM_POLICIES_TASK_H_ + +#include <vector> + +#include "base/callback_forward.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" +#include "base/sequence_checker.h" +#include "chrome/updater/configurator.h" +#include "chrome/updater/device_management/dm_client.h" +#include "chrome/updater/device_management/dm_response_validator.h" + +namespace updater { + +// The RefreshDMPolicies refreshes the DM policies from the DM server, and if +// successful, reloads the policy service with the new policies. +// TODO(crbug.com/1345407) : do device registration. +class RefreshDMPoliciesTask + : public base::RefCountedThreadSafe<RefreshDMPoliciesTask> { + public: + explicit RefreshDMPoliciesTask(scoped_refptr<Configurator> config); + void Run(base::OnceClosure callback); + + private: + friend class base::RefCountedThreadSafe<RefreshDMPoliciesTask>; + virtual ~RefreshDMPoliciesTask(); + + void FetchPolicy(); + void OnRequestComplete( + DMClient::RequestResult result, + const std::vector<PolicyValidationResult>& validation_results); + + SEQUENCE_CHECKER(sequence_checker_); + scoped_refptr<Configurator> config_; +}; + +} // namespace updater + +#endif // CHROME_UPDATER_REFRESH_DM_POLICIES_TASK_H_
diff --git a/chrome/updater/run_all_unittests.cc b/chrome/updater/run_all_unittests.cc index d526c98..697d27e 100644 --- a/chrome/updater/run_all_unittests.cc +++ b/chrome/updater/run_all_unittests.cc
@@ -14,6 +14,7 @@ #include "base/test/test_switches.h" #include "build/build_config.h" #include "chrome/common/chrome_paths.h" +#include "chrome/updater/test/integration_test_commands.h" #if BUILDFLAG(IS_WIN) #include <shlobj.h> @@ -102,7 +103,9 @@ base::TestSuite test_suite(argc, argv); chrome::RegisterPathProvider(); - return base::LaunchUnitTestsSerially( - argc, argv, + return base::LaunchUnitTestsWithOptions( + argc, argv, 1, 10, true, base::BindRepeating([]() { + updater::test::CreateIntegrationTestCommands()->PrintLog(); + }), base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite))); }
diff --git a/chrome/updater/update_service_impl.cc b/chrome/updater/update_service_impl.cc index 8fba9827..5b81e6bd 100644 --- a/chrome/updater/update_service_impl.cc +++ b/chrome/updater/update_service_impl.cc
@@ -38,6 +38,7 @@ #include "chrome/updater/persisted_data.h" #include "chrome/updater/policy/service.h" #include "chrome/updater/prefs.h" +#include "chrome/updater/refresh_dm_policies_task.h" #include "chrome/updater/registration_data.h" #include "chrome/updater/remove_uninstalled_apps_task.h" #include "chrome/updater/update_block_check.h" @@ -301,6 +302,9 @@ base::MakeRefCounted<UpdateUsageStatsTask>( GetUpdaterScope(), persisted_data_))); + new_tasks.push_back( + base::BindOnce(&RefreshDMPoliciesTask::Run, + base::MakeRefCounted<RefreshDMPoliciesTask>(config_))); new_tasks.push_back(base::BindOnce( &CheckForUpdatesTask::Run, base::MakeRefCounted<CheckForUpdatesTask>(
diff --git a/chrome/updater/zip.gni b/chrome/updater/zip.gni index 2b818442..2b718ac 100644 --- a/chrome/updater/zip.gni +++ b/chrome/updater/zip.gni
@@ -3,7 +3,7 @@ # found in the LICENSE file. import("//build/config/zip.gni") -import("//build/util/version.gni") +import("//chrome/version.gni") # Creates a zip archive of the inputs with a build information stamp. #
diff --git a/chromeos/ash/components/dbus/cicerone/fake_cicerone_client.cc b/chromeos/ash/components/dbus/cicerone/fake_cicerone_client.cc index 1910cb6..317ca20 100644 --- a/chromeos/ash/components/dbus/cicerone/fake_cicerone_client.cc +++ b/chromeos/ash/components/dbus/cicerone/fake_cicerone_client.cc
@@ -355,6 +355,7 @@ const vm_tools::cicerone::SetUpLxdContainerUserRequest& request, DBusMethodCallback<vm_tools::cicerone::SetUpLxdContainerUserResponse> callback) { + setup_lxd_container_user_request_ = request; last_container_username_ = request.container_username(); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE,
diff --git a/chromeos/ash/components/dbus/cicerone/fake_cicerone_client.h b/chromeos/ash/components/dbus/cicerone/fake_cicerone_client.h index 04709392..313ca60 100644 --- a/chromeos/ash/components/dbus/cicerone/fake_cicerone_client.h +++ b/chromeos/ash/components/dbus/cicerone/fake_cicerone_client.h
@@ -9,6 +9,7 @@ #include "base/observer_list.h" #include "base/time/time.h" #include "chromeos/ash/components/dbus/cicerone/cicerone_client.h" +#include "chromeos/ash/components/dbus/cicerone/cicerone_service.pb.h" namespace ash { @@ -408,6 +409,11 @@ send_stop_lxd_container_response_delay_ = delay; } + vm_tools::cicerone::SetUpLxdContainerUserRequest + get_setup_lxd_container_user_request() { + return setup_lxd_container_user_request_; + } + // Returns true if the method has been invoked at least once, false otherwise. bool configure_for_arc_sideload_called() { return configure_for_arc_sideload_called_; @@ -554,6 +560,9 @@ base::TimeDelta send_start_lxd_container_response_delay_; base::TimeDelta send_stop_lxd_container_response_delay_; + vm_tools::cicerone::SetUpLxdContainerUserRequest + setup_lxd_container_user_request_; + vm_tools::cicerone::OsRelease lxd_container_os_release_; LaunchContainerApplicationCallback launch_container_application_callback_;
diff --git a/chromeos/ash/components/network/cellular_metrics_logger_unittest.cc b/chromeos/ash/components/network/cellular_metrics_logger_unittest.cc index b382fc9..2d9d9aa 100644 --- a/chromeos/ash/components/network/cellular_metrics_logger_unittest.cc +++ b/chromeos/ash/components/network/cellular_metrics_logger_unittest.cc
@@ -100,7 +100,7 @@ cellular_inhibitor_ = std::make_unique<CellularInhibitor>(); mock_managed_network_configuration_manager_ = base::WrapUnique( - new testing::NiceMock<ash::MockManagedNetworkConfigurationHandler>); + new testing::NiceMock<MockManagedNetworkConfigurationHandler>); cellular_esim_profile_handler_ = std::make_unique<TestCellularESimProfileHandler>(); network_config_helper_ = std::make_unique< @@ -278,7 +278,7 @@ std::unique_ptr<TestCellularESimProfileHandler> cellular_esim_profile_handler_; std::unique_ptr<CellularMetricsLogger> cellular_metrics_logger_; - std::unique_ptr<ash::MockManagedNetworkConfigurationHandler> + std::unique_ptr<MockManagedNetworkConfigurationHandler> mock_managed_network_configuration_manager_; };
diff --git a/chromeos/ash/components/network/cellular_utils.cc b/chromeos/ash/components/network/cellular_utils.cc index b2ec46c..610cac5 100644 --- a/chromeos/ash/components/network/cellular_utils.cc +++ b/chromeos/ash/components/network/cellular_utils.cc
@@ -166,7 +166,7 @@ return euicc_paths[0]; bool use_second_euicc = - base::FeatureList::IsEnabled(chromeos::features::kCellularUseSecondEuicc); + base::FeatureList::IsEnabled(features::kCellularUseSecondEuicc); return use_second_euicc ? euicc_paths[1] : euicc_paths[0]; }
diff --git a/chromeos/ash/components/network/cellular_utils.h b/chromeos/ash/components/network/cellular_utils.h index 64a1e9c..b8d8ce9 100644 --- a/chromeos/ash/components/network/cellular_utils.h +++ b/chromeos/ash/components/network/cellular_utils.h
@@ -54,12 +54,9 @@ // TODO(https://crbug.com/1164001): remove when the migration is finished. namespace chromeos { -using ::ash::GenerateProfilesFromHermes; -using ::ash::GenerateStubCellularServicePath; using ::ash::GetCurrentEuiccPath; using ::ash::GetSimSlotInfosWithUpdatedEid; using ::ash::IsSimPrimary; -using ::ash::IsStubCellularServicePath; } // namespace chromeos #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_CELLULAR_UTILS_H_
diff --git a/chromeos/ash/components/network/cellular_utils_unittest.cc b/chromeos/ash/components/network/cellular_utils_unittest.cc index 2ecf668..85ca048a 100644 --- a/chromeos/ash/components/network/cellular_utils_unittest.cc +++ b/chromeos/ash/components/network/cellular_utils_unittest.cc
@@ -43,7 +43,7 @@ TEST_F(CellularUtilsTest, GetCurrentEuiccPath) { base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(ash::features::kCellularUseSecondEuicc); + feature_list.InitAndEnableFeature(features::kCellularUseSecondEuicc); HermesManagerClient::Get()->GetTestInterface()->ClearEuiccs(); EXPECT_FALSE(GetCurrentEuiccPath()); // Verify that use-second-euicc flag should be ignored when Hermes only
diff --git a/chromeos/ash/components/network/client_cert_util.h b/chromeos/ash/components/network/client_cert_util.h index 351a634..7351e91 100644 --- a/chromeos/ash/components/network/client_cert_util.h +++ b/chromeos/ash/components/network/client_cert_util.h
@@ -181,17 +181,4 @@ } // namespace ash::client_cert -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos::client_cert { -using ::ash::client_cert::ClientCertConfig; -using ::ash::client_cert::ConfigType; -using ::ash::client_cert::GetClientCertFromShillProperties; -using ::ash::client_cert::kDefaultTPMPin; -using ::ash::client_cert::OncToClientCertConfig; -using ::ash::client_cert::ResolvedCert; -using ::ash::client_cert::SetEmptyShillProperties; -using ::ash::client_cert::SetResolvedCertInOnc; -using ::ash::client_cert::SetShillProperties; -} // namespace chromeos::client_cert - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_CLIENT_CERT_UTIL_H_
diff --git a/chromeos/ash/components/network/fake_network_connection_handler.h b/chromeos/ash/components/network/fake_network_connection_handler.h index ae6a692..6ed2e53 100644 --- a/chromeos/ash/components/network/fake_network_connection_handler.h +++ b/chromeos/ash/components/network/fake_network_connection_handler.h
@@ -94,9 +94,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::FakeNetworkConnectionHandler; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_FAKE_NETWORK_CONNECTION_HANDLER_H_
diff --git a/chromeos/ash/components/network/fake_stub_cellular_networks_provider.h b/chromeos/ash/components/network/fake_stub_cellular_networks_provider.h index 27f1a685..ba18c1a 100644 --- a/chromeos/ash/components/network/fake_stub_cellular_networks_provider.h +++ b/chromeos/ash/components/network/fake_stub_cellular_networks_provider.h
@@ -60,9 +60,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::FakeStubCellularNetworksProvider; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_FAKE_STUB_CELLULAR_NETWORKS_PROVIDER_H_
diff --git a/chromeos/ash/components/network/hermes_metrics_util.h b/chromeos/ash/components/network/hermes_metrics_util.h index 24e9cb4..60b2ade 100644 --- a/chromeos/ash/components/network/hermes_metrics_util.h +++ b/chromeos/ash/components/network/hermes_metrics_util.h
@@ -30,9 +30,4 @@ } // namespace ash::hermes_metrics -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -namespace hermes_metrics = ::ash::hermes_metrics; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_HERMES_METRICS_UTIL_H_
diff --git a/chromeos/ash/components/network/managed_cellular_pref_handler.h b/chromeos/ash/components/network/managed_cellular_pref_handler.h index 35ff03b7..5f740a4 100644 --- a/chromeos/ash/components/network/managed_cellular_pref_handler.h +++ b/chromeos/ash/components/network/managed_cellular_pref_handler.h
@@ -70,9 +70,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::ManagedCellularPrefHandler; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_MANAGED_CELLULAR_PREF_HANDLER_H_
diff --git a/chromeos/ash/components/network/managed_state.h b/chromeos/ash/components/network/managed_state.h index 33e14c2..14a11ed 100644 --- a/chromeos/ash/components/network/managed_state.h +++ b/chromeos/ash/components/network/managed_state.h
@@ -148,9 +148,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::ManagedState; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_MANAGED_STATE_H_
diff --git a/chromeos/ash/components/network/metrics/connection_results.h b/chromeos/ash/components/network/metrics/connection_results.h index be2fb37f..4e68f9d 100644 --- a/chromeos/ash/components/network/metrics/connection_results.h +++ b/chromeos/ash/components/network/metrics/connection_results.h
@@ -133,9 +133,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::ShillConnectResult; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_METRICS_CONNECTION_RESULTS_H_
diff --git a/chromeos/ash/components/network/metrics/network_metrics_helper.h b/chromeos/ash/components/network/metrics/network_metrics_helper.h index ad30be4..5150c8e8 100644 --- a/chromeos/ash/components/network/metrics/network_metrics_helper.h +++ b/chromeos/ash/components/network/metrics/network_metrics_helper.h
@@ -61,9 +61,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::NetworkMetricsHelper; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_METRICS_NETWORK_METRICS_HELPER_H_
diff --git a/chromeos/ash/components/network/mock_network_state_handler.h b/chromeos/ash/components/network/mock_network_state_handler.h index 33ab04c..eda27ad9 100644 --- a/chromeos/ash/components/network/mock_network_state_handler.h +++ b/chromeos/ash/components/network/mock_network_state_handler.h
@@ -32,9 +32,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::MockNetworkStateHandler; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_MOCK_NETWORK_STATE_HANDLER_H_
diff --git a/chromeos/ash/components/network/network_name_util_unittest.cc b/chromeos/ash/components/network/network_name_util_unittest.cc index 4a2ff88..355ef8eb 100644 --- a/chromeos/ash/components/network/network_name_util_unittest.cc +++ b/chromeos/ash/components/network/network_name_util_unittest.cc
@@ -94,7 +94,7 @@ kTestServiceProviderName, hermes::profile::State::kActive, kTestESimCellularServicePath); - const chromeos::NetworkState* network = + const NetworkState* network = network_state_test_helper_.network_state_handler()->GetNetworkState( kTestESimCellularServicePath); @@ -107,7 +107,7 @@ TEST_F(NetworkNameUtilTest, EsimNetworNetworkNamePriority) { AddESimProfile("", "", kTestServiceProviderName, hermes::profile::State::kActive, kTestESimCellularServicePath); - const chromeos::NetworkState* network = + const NetworkState* network = network_state_test_helper_.network_state_handler()->GetNetworkState( kTestESimCellularServicePath); @@ -119,7 +119,7 @@ TEST_F(NetworkNameUtilTest, EthernetNetworkGetNetworkName) { AddEthernet(); - const chromeos::NetworkState* network = + const NetworkState* network = network_state_test_helper_.network_state_handler()->GetNetworkState( kTestEthServicePath); @@ -141,7 +141,7 @@ base::Value(kTestNameFromShill)); base::RunLoop().RunUntilIdle(); - const chromeos::NetworkState* network = + const NetworkState* network = network_state_test_helper_.network_state_handler()->GetNetworkState( kTestESimCellularServicePath);
diff --git a/chromeos/ash/components/network/network_profile_observer.h b/chromeos/ash/components/network/network_profile_observer.h index d9e27a9e..20c45e8 100644 --- a/chromeos/ash/components/network/network_profile_observer.h +++ b/chromeos/ash/components/network/network_profile_observer.h
@@ -22,9 +22,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::NetworkProfileObserver; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_PROFILE_OBSERVER_H_
diff --git a/chromeos/ash/components/network/network_state.cc b/chromeos/ash/components/network/network_state.cc index 8deef0f..9fd4cc5 100644 --- a/chromeos/ash/components/network/network_state.cc +++ b/chromeos/ash/components/network/network_state.cc
@@ -199,7 +199,7 @@ return true; } else if (key == shill::kUIDataProperty) { std::unique_ptr<NetworkUIData> ui_data = - chromeos::shill_property_util::GetUIDataFromValue(value); + shill_property_util::GetUIDataFromValue(value); if (!ui_data) return false; onc_source_ = ui_data->onc_source();
diff --git a/chromeos/ash/components/network/network_util.cc b/chromeos/ash/components/network/network_util.cc index 84dadf5..19ec9acd 100644 --- a/chromeos/ash/components/network/network_util.cc +++ b/chromeos/ash/components/network/network_util.cc
@@ -236,7 +236,7 @@ ->managed_network_configuration_handler() ->FindPolicyByGUID(user_id_hash, network->guid(), &onc_source); - base::Value onc_dictionary = TranslateShillServiceToONCPart( + base::Value onc_dictionary = onc::TranslateShillServiceToONCPart( shill_dictionary, onc_source, &onc::kNetworkWithStateSignature, network); // Remove IPAddressConfigType/NameServersConfigType as these were
diff --git a/chromeos/ash/components/network/network_util.h b/chromeos/ash/components/network/network_util.h index 3c1a2cee..17be181 100644 --- a/chromeos/ash/components/network/network_util.h +++ b/chromeos/ash/components/network/network_util.h
@@ -157,12 +157,6 @@ // TODO(https://crbug.com/1164001): remove when the migration is finished. namespace chromeos { -using ::ash::CellTower; -using ::ash::CellTowerVector; -using ::ash::CellularScanResult; -using ::ash::CellularSIMSlotInfo; -using ::ash::WifiAccessPoint; -using ::ash::WifiAccessPointVector; namespace network_util = ::ash::network_util; } // namespace chromeos
diff --git a/chromeos/ash/components/network/onc/network_onc_utils.h b/chromeos/ash/components/network/onc/network_onc_utils.h index 448754d..04c455f8 100644 --- a/chromeos/ash/components/network/onc/network_onc_utils.h +++ b/chromeos/ash/components/network/onc/network_onc_utils.h
@@ -99,8 +99,6 @@ // TODO(https://crbug.com/1164001): remove when the migration is finished. namespace chromeos::onc { -using ::ash::onc::ConvertOncProxySettingsToProxyConfig; -using ::ash::onc::GetPolicyForNetwork; using ::ash::onc::ImportNetworksForUser; using ::ash::onc::NetworkTypePatternFromOncType; } // namespace chromeos::onc
diff --git a/chromeos/ash/components/network/onc/onc_certificate_pattern.h b/chromeos/ash/components/network/onc/onc_certificate_pattern.h index dc6809d0..44d1ee1 100644 --- a/chromeos/ash/components/network/onc/onc_certificate_pattern.h +++ b/chromeos/ash/components/network/onc/onc_certificate_pattern.h
@@ -75,9 +75,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::OncCertificatePattern; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_ONC_ONC_CERTIFICATE_PATTERN_H_
diff --git a/chromeos/ash/components/network/onc/onc_merger.h b/chromeos/ash/components/network/onc/onc_merger.h index 9080565..0542040 100644 --- a/chromeos/ash/components/network/onc/onc_merger.h +++ b/chromeos/ash/components/network/onc/onc_merger.h
@@ -49,10 +49,4 @@ } // namespace ash::onc -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos::onc { -using ::ash::onc::MergeSettingsAndPoliciesToAugmented; -using ::ash::onc::MergeSettingsAndPoliciesToEffective; -} // namespace chromeos::onc - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_ONC_ONC_MERGER_H_
diff --git a/chromeos/ash/components/network/onc/onc_normalizer.h b/chromeos/ash/components/network/onc/onc_normalizer.h index c507811..0a247b7c 100644 --- a/chromeos/ash/components/network/onc/onc_normalizer.h +++ b/chromeos/ash/components/network/onc/onc_normalizer.h
@@ -56,9 +56,4 @@ } // namespace ash::onc -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos::onc { -using ::ash::onc::Normalizer; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_ONC_ONC_NORMALIZER_H_
diff --git a/chromeos/ash/components/network/onc/onc_translation_tables.h b/chromeos/ash/components/network/onc/onc_translation_tables.h index abbca77..a1eff4eb 100644 --- a/chromeos/ash/components/network/onc/onc_translation_tables.h +++ b/chromeos/ash/components/network/onc/onc_translation_tables.h
@@ -99,12 +99,9 @@ // TODO(https://crbug.com/1164001): remove when the migration is finished. namespace chromeos::onc { using ::ash::onc::kNetworkTechnologyTable; -using ::ash::onc::kNetworkTypeTable; using ::ash::onc::kVPNTypeTable; -using ::ash::onc::kWiFiSecurityTable; using ::ash::onc::StringTranslationEntry; using ::ash::onc::TranslateStringToONC; -using ::ash::onc::TranslateStringToShill; } // namespace chromeos::onc #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_ONC_ONC_TRANSLATION_TABLES_H_
diff --git a/chromeos/ash/components/network/onc/onc_translator.h b/chromeos/ash/components/network/onc/onc_translator.h index 1aece04..d0cf719 100644 --- a/chromeos/ash/components/network/onc/onc_translator.h +++ b/chromeos/ash/components/network/onc/onc_translator.h
@@ -53,10 +53,4 @@ } // namespace onc } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos::onc { -using ::ash::onc::TranslateONCObjectToShill; -using ::ash::onc::TranslateShillServiceToONCPart; -} // namespace chromeos::onc - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_ONC_ONC_TRANSLATOR_H_
diff --git a/chromeos/ash/components/network/portal_detector/network_portal_detector.h b/chromeos/ash/components/network/portal_detector/network_portal_detector.h index a3067ad..65f340a 100644 --- a/chromeos/ash/components/network/portal_detector/network_portal_detector.h +++ b/chromeos/ash/components/network/portal_detector/network_portal_detector.h
@@ -133,7 +133,10 @@ // TODO(https://crbug.com/1164001): remove when the migration is finished. namespace chromeos { using ::ash::NetworkPortalDetector; -namespace network_portal_detector = ::ash::network_portal_detector; +namespace network_portal_detector { +using ::ash::network_portal_detector::GetInstance; +using ::ash::network_portal_detector::InitializeForTesting; +} // namespace network_portal_detector } // namespace chromeos #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_PORTAL_DETECTOR_NETWORK_PORTAL_DETECTOR_H_
diff --git a/chromeos/ash/components/network/shill_property_handler.h b/chromeos/ash/components/network/shill_property_handler.h index 7398261..02b4849 100644 --- a/chromeos/ash/components/network/shill_property_handler.h +++ b/chromeos/ash/components/network/shill_property_handler.h
@@ -275,9 +275,4 @@ } // namespace ash::internal -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos::internal { -using ::ash::internal::ShillPropertyHandler; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_SHILL_PROPERTY_HANDLER_H_
diff --git a/chromeos/ash/components/network/shill_property_util.cc b/chromeos/ash/components/network/shill_property_util.cc index 05d628d..a6709bc 100644 --- a/chromeos/ash/components/network/shill_property_util.cc +++ b/chromeos/ash/components/network/shill_property_util.cc
@@ -229,7 +229,7 @@ // If the feature flag is not enabled, we set each MAC Address Policy // to Hardware (non-randomized). if (!base::FeatureList::IsEnabled( - chromeos::features::kWifiConnectMacAddressRandomization)) { + features::kWifiConnectMacAddressRandomization)) { shill_dictionary->SetKey(shill::kWifiRandomMACPolicy, base::Value(shill::kWifiRandomMacPolicyHardware)); return;
diff --git a/chromeos/ash/components/network/shill_property_util.h b/chromeos/ash/components/network/shill_property_util.h index bc028ac..26ae1adb 100644 --- a/chromeos/ash/components/network/shill_property_util.h +++ b/chromeos/ash/components/network/shill_property_util.h
@@ -98,9 +98,4 @@ } // namespace shill_property_util } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -namespace shill_property_util = ::ash::shill_property_util; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_SHILL_PROPERTY_UTIL_H_
diff --git a/chromeos/ash/components/network/system_token_cert_db_storage_test_util.h b/chromeos/ash/components/network/system_token_cert_db_storage_test_util.h index 75338e4..eb345a4 100644 --- a/chromeos/ash/components/network/system_token_cert_db_storage_test_util.h +++ b/chromeos/ash/components/network/system_token_cert_db_storage_test_util.h
@@ -71,10 +71,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::FakeSystemTokenCertDbStorageObserver; -using ::ash::GetSystemTokenCertDbCallbackWrapper; -} // namespace chromeos - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_SYSTEM_TOKEN_CERT_DB_STORAGE_TEST_UTIL_H_
diff --git a/chromeos/ash/components/network/test_cellular_esim_profile_handler.h b/chromeos/ash/components/network/test_cellular_esim_profile_handler.h index 62ecc1e..e87065a 100644 --- a/chromeos/ash/components/network/test_cellular_esim_profile_handler.h +++ b/chromeos/ash/components/network/test_cellular_esim_profile_handler.h
@@ -49,9 +49,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::TestCellularESimProfileHandler; -} - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_TEST_CELLULAR_ESIM_PROFILE_HANDLER_H_
diff --git a/chromeos/ash/components/network/tether_constants.h b/chromeos/ash/components/network/tether_constants.h index afab557..dd7fbed 100644 --- a/chromeos/ash/components/network/tether_constants.h +++ b/chromeos/ash/components/network/tether_constants.h
@@ -32,15 +32,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when the migration is finished. -namespace chromeos { -using ::ash::kTetherBatteryPercentage; -using ::ash::kTetherCarrier; -using ::ash::kTetherDeviceName; -using ::ash::kTetherDevicePath; -using ::ash::kTetherHasConnectedToHost; -using ::ash::kTetherSignalStrength; -using ::ash::kTypeTether; -} // namespace chromeos - #endif // CHROMEOS_ASH_COMPONENTS_NETWORK_TETHER_CONSTANTS_H_
diff --git a/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.cc b/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.cc index 961d9ce2..9b02cad 100644 --- a/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.cc +++ b/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.cc
@@ -19,15 +19,20 @@ } // namespace -TrashInfoParser::TrashInfoParser( - base::OnceCallback<void()> disconnect_callback) { +TrashInfoParser::TrashInfoParser() { auto trash_pending_remote = LaunchTrashService(); service_ = mojo::Remote<mojom::TrashService>(std::move(trash_pending_remote)); - service_.set_disconnect_handler(std::move(disconnect_callback)); } TrashInfoParser::~TrashInfoParser() = default; +void TrashInfoParser::SetDisconnectHandler( + base::OnceCallback<void()> disconnect_callback) { + if (service_) { + service_.set_disconnect_handler(std::move(disconnect_callback)); + } +} + void TrashInfoParser::ParseTrashInfoFile(const base::FilePath& path, ParseTrashInfoCallback callback) { if (!service_) {
diff --git a/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.h b/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.h index fe740252..b31ed83 100644 --- a/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.h +++ b/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.h
@@ -17,7 +17,7 @@ // A class that manages the lifetime and mojo connection of the Trash service. class TrashInfoParser { public: - explicit TrashInfoParser(base::OnceCallback<void()> disconnect_callback); + TrashInfoParser(); ~TrashInfoParser(); TrashInfoParser(const TrashInfoParser&) = delete; @@ -26,6 +26,8 @@ void ParseTrashInfoFile(const base::FilePath& path, ParseTrashInfoCallback callback); + void SetDisconnectHandler(base::OnceCallback<void()> disconnect_callback); + private: void OnGotFile(ParseTrashInfoCallback callback, base::File file);
diff --git a/components/BUILD.gn b/components/BUILD.gn index 1f658cf0..f40e4f5 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -540,6 +540,7 @@ deps += [ "//components/commerce/core:commerce_heuristics_data_unittests", "//components/commerce/core:feature_list_unittests", + "//components/commerce/core/subscriptions:subscriptions_unit_tests", ] }
diff --git a/components/browser_ui/media/android/BUILD.gn b/components/browser_ui/media/android/BUILD.gn index dc2781c..3ea9e3d 100644 --- a/components/browser_ui/media/android/BUILD.gn +++ b/components/browser_ui/media/android/BUILD.gn
@@ -40,34 +40,59 @@ sources = [ "java/res/drawable-hdpi/audio_playing.png", "java/res/drawable-hdpi/audio_playing_square.png", + "java/res/drawable-hdpi/ic_call_end_white_36dp.png", "java/res/drawable-hdpi/ic_fast_forward_white_36dp.png", "java/res/drawable-hdpi/ic_fast_rewind_white_36dp.png", + "java/res/drawable-hdpi/ic_mic_off_white_36dp.png", + "java/res/drawable-hdpi/ic_mic_white_36dp.png", "java/res/drawable-hdpi/ic_skip_next_white_36dp.png", "java/res/drawable-hdpi/ic_skip_previous_white_36dp.png", + "java/res/drawable-hdpi/ic_videocam_off_white_36dp.png", + "java/res/drawable-hdpi/ic_videocam_white_36dp.png", "java/res/drawable-mdpi/audio_playing.png", "java/res/drawable-mdpi/audio_playing_square.png", + "java/res/drawable-mdpi/ic_call_end_white_36dp.png", "java/res/drawable-mdpi/ic_fast_forward_white_36dp.png", "java/res/drawable-mdpi/ic_fast_rewind_white_36dp.png", + "java/res/drawable-mdpi/ic_mic_off_white_36dp.png", + "java/res/drawable-mdpi/ic_mic_white_36dp.png", "java/res/drawable-mdpi/ic_skip_next_white_36dp.png", "java/res/drawable-mdpi/ic_skip_previous_white_36dp.png", + "java/res/drawable-mdpi/ic_videocam_off_white_36dp.png", + "java/res/drawable-mdpi/ic_videocam_white_36dp.png", "java/res/drawable-xhdpi/audio_playing.png", "java/res/drawable-xhdpi/audio_playing_square.png", + "java/res/drawable-xhdpi/ic_call_end_white_36dp.png", "java/res/drawable-xhdpi/ic_fast_forward_white_36dp.png", "java/res/drawable-xhdpi/ic_fast_rewind_white_36dp.png", + "java/res/drawable-xhdpi/ic_mic_off_white_36dp.png", + "java/res/drawable-xhdpi/ic_mic_white_36dp.png", "java/res/drawable-xhdpi/ic_skip_next_white_36dp.png", "java/res/drawable-xhdpi/ic_skip_previous_white_36dp.png", + "java/res/drawable-xhdpi/ic_videocam_off_white_36dp.png", + "java/res/drawable-xhdpi/ic_videocam_white_36dp.png", "java/res/drawable-xxhdpi/audio_playing.png", "java/res/drawable-xxhdpi/audio_playing_square.png", + "java/res/drawable-xxhdpi/ic_call_end_white_36dp.png", "java/res/drawable-xxhdpi/ic_fast_forward_white_36dp.png", "java/res/drawable-xxhdpi/ic_fast_rewind_white_36dp.png", + "java/res/drawable-xxhdpi/ic_mic_off_white_36dp.png", + "java/res/drawable-xxhdpi/ic_mic_white_36dp.png", "java/res/drawable-xxhdpi/ic_skip_next_white_36dp.png", "java/res/drawable-xxhdpi/ic_skip_previous_white_36dp.png", + "java/res/drawable-xxhdpi/ic_videocam_off_white_36dp.png", + "java/res/drawable-xxhdpi/ic_videocam_white_36dp.png", "java/res/drawable-xxxhdpi/audio_playing.png", "java/res/drawable-xxxhdpi/audio_playing_square.png", + "java/res/drawable-xxxhdpi/ic_call_end_white_36dp.png", "java/res/drawable-xxxhdpi/ic_fast_forward_white_36dp.png", "java/res/drawable-xxxhdpi/ic_fast_rewind_white_36dp.png", + "java/res/drawable-xxxhdpi/ic_mic_off_white_36dp.png", + "java/res/drawable-xxxhdpi/ic_mic_white_36dp.png", "java/res/drawable-xxxhdpi/ic_skip_next_white_36dp.png", "java/res/drawable-xxxhdpi/ic_skip_previous_white_36dp.png", + "java/res/drawable-xxxhdpi/ic_videocam_off_white_36dp.png", + "java/res/drawable-xxxhdpi/ic_videocam_white_36dp.png", ] deps = [ "//components/browser_ui/strings/android:browser_ui_strings_grd",
diff --git a/components/browser_ui/media/android/java/res/drawable-hdpi/ic_call_end_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-hdpi/ic_call_end_white_36dp.png new file mode 100644 index 0000000..90773818 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-hdpi/ic_call_end_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-hdpi/ic_mic_off_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-hdpi/ic_mic_off_white_36dp.png new file mode 100644 index 0000000..c0e773b --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-hdpi/ic_mic_off_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-hdpi/ic_mic_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-hdpi/ic_mic_white_36dp.png new file mode 100644 index 0000000..2b377a74 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-hdpi/ic_mic_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-hdpi/ic_videocam_off_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-hdpi/ic_videocam_off_white_36dp.png new file mode 100644 index 0000000..fafc3a3 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-hdpi/ic_videocam_off_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-hdpi/ic_videocam_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-hdpi/ic_videocam_white_36dp.png new file mode 100644 index 0000000..5c99f19 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-hdpi/ic_videocam_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-mdpi/ic_call_end_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-mdpi/ic_call_end_white_36dp.png new file mode 100644 index 0000000..8fb6ffd --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-mdpi/ic_call_end_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-mdpi/ic_mic_off_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-mdpi/ic_mic_off_white_36dp.png new file mode 100644 index 0000000..153d979f --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-mdpi/ic_mic_off_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-mdpi/ic_mic_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-mdpi/ic_mic_white_36dp.png new file mode 100644 index 0000000..d3d9dc2b --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-mdpi/ic_mic_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-mdpi/ic_videocam_off_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-mdpi/ic_videocam_off_white_36dp.png new file mode 100644 index 0000000..b09d4dd3 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-mdpi/ic_videocam_off_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-mdpi/ic_videocam_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-mdpi/ic_videocam_white_36dp.png new file mode 100644 index 0000000..f4e905c --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-mdpi/ic_videocam_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_call_end_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_call_end_white_36dp.png new file mode 100644 index 0000000..ff84f1f --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_call_end_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_mic_off_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_mic_off_white_36dp.png new file mode 100644 index 0000000..89ec023 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_mic_off_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_mic_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_mic_white_36dp.png new file mode 100644 index 0000000..d79f5bb --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_mic_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_videocam_off_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_videocam_off_white_36dp.png new file mode 100644 index 0000000..b305b70 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_videocam_off_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_videocam_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_videocam_white_36dp.png new file mode 100644 index 0000000..646115b --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xhdpi/ic_videocam_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_call_end_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_call_end_white_36dp.png new file mode 100644 index 0000000..3213989 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_call_end_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_mic_off_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_mic_off_white_36dp.png new file mode 100644 index 0000000..03cb6a6 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_mic_off_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_mic_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_mic_white_36dp.png new file mode 100644 index 0000000..fc3b9246 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_mic_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_videocam_off_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_videocam_off_white_36dp.png new file mode 100644 index 0000000..54378c0 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_videocam_off_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_videocam_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_videocam_white_36dp.png new file mode 100644 index 0000000..60f37bc --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xxhdpi/ic_videocam_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_call_end_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_call_end_white_36dp.png new file mode 100644 index 0000000..ad9f949 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_call_end_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_mic_off_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_mic_off_white_36dp.png new file mode 100644 index 0000000..533c60e --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_mic_off_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_mic_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_mic_white_36dp.png new file mode 100644 index 0000000..5ec10394 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_mic_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_videocam_off_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_videocam_off_white_36dp.png new file mode 100644 index 0000000..59bc5fe065 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_videocam_off_white_36dp.png Binary files differ
diff --git a/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_videocam_white_36dp.png b/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_videocam_white_36dp.png new file mode 100644 index 0000000..3372697 --- /dev/null +++ b/components/browser_ui/media/android/java/res/drawable-xxxhdpi/ic_videocam_white_36dp.png Binary files differ
diff --git a/components/browser_ui/strings/android/browser_ui_strings.grd b/components/browser_ui/strings/android/browser_ui_strings.grd index 8936c88..69eacf0 100644 --- a/components/browser_ui/strings/android/browser_ui_strings.grd +++ b/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -712,6 +712,21 @@ <message name="IDS_ACCESSIBILITY_SEEK_BACKWARD" desc="The seek backward button that seeks media to an earlier position."> Seek backward </message> + <message name="IDS_ACCESSIBILITY_HANG_UP" desc="The hang up button that hangs up the video call."> + Hang up + </message> + <message name="IDS_ACCESSIBILITY_MUTE_MICROPHONE" desc="The mute microphone button that mutes the microphone of the video call."> + Mute microphone + </message> + <message name="IDS_ACCESSIBILITY_UNMUTE_MICROPHONE" desc="The unmute microphone button that unmutes the microphone of the video call."> + Unmute microphone + </message> + <message name="IDS_ACCESSIBILITY_TURN_ON_CAMERA" desc="The turn on camera button that turns on the camera of the video call."> + Turn on camera + </message> + <message name="IDS_ACCESSIBILITY_TURN_OFF_CAMERA" desc="The turn off camera button that turns off the camera of the video call."> + Turn off camera + </message> <message name="IDS_MEDIA_NOTIFICATION_INCOGNITO" desc="Text used as a placeholder for a media notification about playing media, when notification is shown from Incognito tab."> A site is playing media </message>
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_HANG_UP.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_HANG_UP.png.sha1 new file mode 100644 index 0000000..7550f63 --- /dev/null +++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_HANG_UP.png.sha1
@@ -0,0 +1 @@ +bc00ecb19f1574c5b10d6384f8a199cc363a0ce0 \ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_MUTE_MICROPHONE.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_MUTE_MICROPHONE.png.sha1 new file mode 100644 index 0000000..7550f63 --- /dev/null +++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_MUTE_MICROPHONE.png.sha1
@@ -0,0 +1 @@ +bc00ecb19f1574c5b10d6384f8a199cc363a0ce0 \ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TURN_OFF_CAMERA.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TURN_OFF_CAMERA.png.sha1 new file mode 100644 index 0000000..7550f63 --- /dev/null +++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TURN_OFF_CAMERA.png.sha1
@@ -0,0 +1 @@ +bc00ecb19f1574c5b10d6384f8a199cc363a0ce0 \ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TURN_ON_CAMERA.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TURN_ON_CAMERA.png.sha1 new file mode 100644 index 0000000..721f26830 --- /dev/null +++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TURN_ON_CAMERA.png.sha1
@@ -0,0 +1 @@ +830c38bed54a5c2b1783c150806cd5b13320d381 \ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_UNMUTE_MICROPHONE.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_UNMUTE_MICROPHONE.png.sha1 new file mode 100644 index 0000000..721f26830 --- /dev/null +++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_UNMUTE_MICROPHONE.png.sha1
@@ -0,0 +1 @@ +830c38bed54a5c2b1783c150806cd5b13320d381 \ No newline at end of file
diff --git a/components/captive_portal/core/captive_portal_detector.cc b/components/captive_portal/core/captive_portal_detector.cc index edf30b78..a931ee8d 100644 --- a/components/captive_portal/core/captive_portal_detector.cc +++ b/components/captive_portal/core/captive_portal_detector.cc
@@ -27,11 +27,10 @@ namespace { #if BUILDFLAG(IS_CHROMEOS_ASH) GURL GetProbeUrl(const GURL& default_url) { - DCHECK_EQ(chromeos::NetworkHandler::Get()->task_runner(), + DCHECK_EQ(ash::NetworkHandler::Get()->task_runner(), base::ThreadTaskRunnerHandle::Get().get()); - const ash::NetworkState* network = chromeos::NetworkHandler::Get() - ->network_state_handler() - ->DefaultNetwork(); + const ash::NetworkState* network = + ash::NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); return network && !network->probe_url().is_empty() ? network->probe_url() : default_url; } @@ -69,9 +68,9 @@ detection_callback_ = std::move(detection_callback); #if BUILDFLAG(IS_CHROMEOS_ASH) - if (chromeos::NetworkHandler::IsInitialized()) { + if (ash::NetworkHandler::IsInitialized()) { base::PostTaskAndReplyWithResult( - chromeos::NetworkHandler::Get()->task_runner(), FROM_HERE, + ash::NetworkHandler::Get()->task_runner(), FROM_HERE, base::BindOnce(&GetProbeUrl, url), base::BindOnce(&CaptivePortalDetector::StartProbe, weak_factory_.GetWeakPtr(), traffic_annotation));
diff --git a/components/commerce/core/subscriptions/BUILD.gn b/components/commerce/core/subscriptions/BUILD.gn index 3253156..b22a320 100644 --- a/components/commerce/core/subscriptions/BUILD.gn +++ b/components/commerce/core/subscriptions/BUILD.gn
@@ -24,3 +24,20 @@ "//services/network/public/cpp:cpp", ] } + +source_set("subscriptions_unit_tests") { + testonly = true + + sources = [ "subscriptions_manager_unittest.cc" ] + + deps = [ + ":subscriptions", + "//base/test:test_support", + "//components/commerce/core:feature_list", + "//components/signin/public/identity_manager:test_support", + "//services/network/public/cpp:cpp", + "//testing/gmock", + "//testing/gtest", + "//url:url", + ] +}
diff --git a/components/commerce/core/subscriptions/subscriptions_manager.cc b/components/commerce/core/subscriptions/subscriptions_manager.cc index 1912ab0c..3080571 100644 --- a/components/commerce/core/subscriptions/subscriptions_manager.cc +++ b/components/commerce/core/subscriptions/subscriptions_manager.cc
@@ -17,16 +17,27 @@ SubscriptionsManager::SubscriptionsManager( signin::IdentityManager* identity_manager, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) - : weak_ptr_factory_(this) { - server_proxy_ = std::make_unique<SubscriptionsServerProxy>( - identity_manager, std::move(url_loader_factory)); - storage_ = std::make_unique<SubscriptionsStorage>(); + : SubscriptionsManager(identity_manager, + std::make_unique<SubscriptionsServerProxy>( + identity_manager, + std::move(url_loader_factory)), + std::make_unique<SubscriptionsStorage>()) {} + +SubscriptionsManager::SubscriptionsManager( + signin::IdentityManager* identity_manager, + std::unique_ptr<SubscriptionsServerProxy> server_proxy, + std::unique_ptr<SubscriptionsStorage> storage) + : server_proxy_(std::move(server_proxy)), + storage_(std::move(storage)), + weak_ptr_factory_(this) { // Avoid duplicate server calls on android. Remove this after we integrate // android implementation to shopping service. #if !BUILDFLAG(IS_ANDROID) InitSubscriptions(); + scoped_identity_manager_observation_.Observe(identity_manager); #endif // !BUILDFLAG(IS_ANDROID) } + SubscriptionsManager::~SubscriptionsManager() = default; SubscriptionsManager::Request::Request(SubscriptionType type, @@ -84,6 +95,7 @@ void SubscriptionsManager::InitSubscriptions() { init_succeeded_ = false; + storage_->DeleteAll(); if (base::FeatureList::IsEnabled(commerce::kShoppingList)) { pending_requests_.push(Request( SubscriptionType::kPriceTrack, AsyncOperation::kInit, @@ -195,4 +207,22 @@ } } +void SubscriptionsManager::OnPrimaryAccountChanged( + const signin::PrimaryAccountChangeEvent& event_details) { + InitSubscriptions(); +} + +bool SubscriptionsManager::GetInitSucceededForTesting() { + return init_succeeded_; +} + +void SubscriptionsManager::SetHasRequestRunningForTesting( + bool has_request_running) { + has_request_running_ = has_request_running; +} + +bool SubscriptionsManager::HasPendingRequestsForTesting() { + return !pending_requests_.empty(); +} + } // namespace commerce
diff --git a/components/commerce/core/subscriptions/subscriptions_manager.h b/components/commerce/core/subscriptions/subscriptions_manager.h index 32388be..853a44f 100644 --- a/components/commerce/core/subscriptions/subscriptions_manager.h +++ b/components/commerce/core/subscriptions/subscriptions_manager.h
@@ -12,15 +12,14 @@ #include "base/callback.h" #include "base/check.h" #include "base/memory/scoped_refptr.h" +#include "base/scoped_observation.h" +#include "components/signin/public/identity_manager/identity_manager.h" +#include "components/signin/public/identity_manager/primary_account_change_event.h" namespace network { class SharedURLLoaderFactory; } // namespace network -namespace signin { -class IdentityManager; -} // namespace signin - namespace commerce { class SubscriptionsServerProxy; @@ -28,14 +27,19 @@ enum class SubscriptionType; struct CommerceSubscription; -class SubscriptionsManager { +class SubscriptionsManager : public signin::IdentityManager::Observer { public: SubscriptionsManager( signin::IdentityManager* identity_manager, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); + // Used for tests. The passed in objects are ordinarily created with + // parameters from the non-test constructor. + SubscriptionsManager(signin::IdentityManager* identity_manager, + std::unique_ptr<SubscriptionsServerProxy> server_proxy, + std::unique_ptr<SubscriptionsStorage> storage); SubscriptionsManager(const SubscriptionsManager&) = delete; SubscriptionsManager& operator=(const SubscriptionsManager&) = delete; - ~SubscriptionsManager(); + ~SubscriptionsManager() override; void Subscribe( std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, @@ -45,6 +49,15 @@ std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, base::OnceCallback<void(bool)> callback); + // For tests only, return init_succeeded_. + bool GetInitSucceededForTesting(); + + // For tests only, set has_request_running_. + void SetHasRequestRunningForTesting(bool has_request_running); + + // For tests only, return whether there are any pending requests. + bool HasPendingRequestsForTesting(); + private: enum class AsyncOperation { kInit = 0, @@ -99,6 +112,9 @@ base::OnceCallback<void(bool)> callback, bool succeeded); + void OnPrimaryAccountChanged( + const signin::PrimaryAccountChangeEvent& event_details) override; + // Hold coming requests until previous ones have finished to avoid race // conditions. std::queue<Request> pending_requests_; @@ -110,6 +126,10 @@ // Whether there is any request running. bool has_request_running_ = false; + base::ScopedObservation<signin::IdentityManager, + signin::IdentityManager::Observer> + scoped_identity_manager_observation_{this}; + std::unique_ptr<SubscriptionsServerProxy> server_proxy_; std::unique_ptr<SubscriptionsStorage> storage_;
diff --git a/components/commerce/core/subscriptions/subscriptions_manager_unittest.cc b/components/commerce/core/subscriptions/subscriptions_manager_unittest.cc new file mode 100644 index 0000000..2a26603 --- /dev/null +++ b/components/commerce/core/subscriptions/subscriptions_manager_unittest.cc
@@ -0,0 +1,510 @@ +// Copyright 2022 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 <queue> +#include <string> +#include <unordered_map> + +#include "base/callback.h" +#include "base/check.h" +#include "base/run_loop.h" +#include "base/test/scoped_feature_list.h" +#include "base/test/task_environment.h" +#include "components/commerce/core/commerce_feature_list.h" +#include "components/commerce/core/subscriptions/commerce_subscription.h" +#include "components/commerce/core/subscriptions/subscriptions_manager.h" +#include "components/commerce/core/subscriptions/subscriptions_server_proxy.h" +#include "components/commerce/core/subscriptions/subscriptions_storage.h" +#include "components/signin/public/identity_manager/identity_test_environment.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::InSequence; + +namespace { + +// Build a subscription list consisting of only one subscription. +std::unique_ptr<std::vector<commerce::CommerceSubscription>> BuildSubscriptions( + std::string subscription_id) { + auto subscriptions = + std::make_unique<std::vector<commerce::CommerceSubscription>>(); + subscriptions->push_back(commerce::CommerceSubscription( + commerce::SubscriptionType::kPriceTrack, + commerce::IdentifierType::kProductClusterId, subscription_id, + commerce::ManagementType::kUserManaged)); + return subscriptions; +} + +// Check whether the passing subscription list contains exactly one subscription +// with |expected_id|. +MATCHER_P(AreExpectedSubscriptions, expected_id, "") { + return (*arg).size() == 1 && (*arg)[0].id == expected_id; +} + +} // namespace + +namespace commerce { + +class MockSubscriptionsServerProxy : public SubscriptionsServerProxy { + public: + MockSubscriptionsServerProxy() : SubscriptionsServerProxy(nullptr, nullptr) {} + MockSubscriptionsServerProxy(const MockSubscriptionsServerProxy&) = delete; + MockSubscriptionsServerProxy operator=(const MockSubscriptionsServerProxy&) = + delete; + ~MockSubscriptionsServerProxy() override = default; + + MOCK_METHOD(void, + Create, + (std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, + ManageSubscriptionsFetcherCallback callback), + (override)); + MOCK_METHOD(void, + Delete, + (std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, + ManageSubscriptionsFetcherCallback callback), + (override)); + MOCK_METHOD(void, + Get, + (SubscriptionType type, GetSubscriptionsFetcherCallback callback), + (override)); + + // Mock the server responses for Create and Delete requests. + void MockManageResponses(bool succeeded) { + ON_CALL(*this, Create) + .WillByDefault( + [succeeded](std::unique_ptr<std::vector<CommerceSubscription>> + subscriptions, + ManageSubscriptionsFetcherCallback callback) { + std::move(callback).Run(succeeded); + }); + ON_CALL(*this, Delete) + .WillByDefault( + [succeeded](std::unique_ptr<std::vector<CommerceSubscription>> + subscriptions, + ManageSubscriptionsFetcherCallback callback) { + std::move(callback).Run(succeeded); + }); + } + + // Mock the server fetch responses for Get requests. |subscription_id| is used + // to generate a CommerceSubscription to be returned. + void MockGetResponses(std::string subscription_id) { + ON_CALL(*this, Get) + .WillByDefault( + [subscription_id](SubscriptionType type, + GetSubscriptionsFetcherCallback callback) { + std::move(callback).Run(BuildSubscriptions(subscription_id)); + }); + } +}; + +class MockSubscriptionsStorage : public SubscriptionsStorage { + public: + MockSubscriptionsStorage() = default; + MockSubscriptionsStorage(const MockSubscriptionsStorage&) = delete; + MockSubscriptionsStorage operator=(const MockSubscriptionsStorage&) = delete; + ~MockSubscriptionsStorage() override = default; + + MOCK_METHOD(void, + GetUniqueNonExistingSubscriptions, + (std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, + GetLocalSubscriptionsCallback callback), + (override)); + MOCK_METHOD(void, + GetUniqueExistingSubscriptions, + (std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, + GetLocalSubscriptionsCallback callback), + (override)); + MOCK_METHOD( + void, + UpdateStorage, + (SubscriptionType type, + base::OnceCallback<void(bool)> callback, + std::unique_ptr<std::vector<CommerceSubscription>> remote_subscriptions), + (override)); + MOCK_METHOD(void, DeleteAll, (), (override)); + + // Mock the local fetch responses for Get* requests. |subscription_id| is used + // to generate a CommerceSubscription to be returned. + void MockGetResponses(std::string subscription_id) { + ON_CALL(*this, GetUniqueNonExistingSubscriptions) + .WillByDefault( + [subscription_id](std::unique_ptr<std::vector<CommerceSubscription>> + subscriptions, + GetLocalSubscriptionsCallback callback) { + std::move(callback).Run(BuildSubscriptions(subscription_id)); + }); + ON_CALL(*this, GetUniqueExistingSubscriptions) + .WillByDefault( + [subscription_id](std::unique_ptr<std::vector<CommerceSubscription>> + subscriptions, + GetLocalSubscriptionsCallback callback) { + std::move(callback).Run(BuildSubscriptions(subscription_id)); + }); + } + + // Mock the responses for UpdateStorage requests. + void MockUpdateResponses(bool succeeded) { + ON_CALL(*this, UpdateStorage) + .WillByDefault( + [succeeded](SubscriptionType type, + base::OnceCallback<void(bool)> callback, + std::unique_ptr<std::vector<CommerceSubscription>> + remote_subscriptions) { + std::move(callback).Run(succeeded); + }); + } +}; + +class SubscriptionsManagerTest : public testing::Test { + public: + SubscriptionsManagerTest() + : mock_server_proxy_(std::make_unique<MockSubscriptionsServerProxy>()), + mock_storage_(std::make_unique<MockSubscriptionsStorage>()) { + test_features_.InitAndEnableFeature(commerce::kShoppingList); + } + ~SubscriptionsManagerTest() override = default; + + void CreateManagerAndVerify(bool init_succeeded) { + subscriptions_manager_ = std::make_unique<SubscriptionsManager>( + identity_test_env_.identity_manager(), std::move(mock_server_proxy_), + std::move(mock_storage_)); + ASSERT_EQ(init_succeeded, + subscriptions_manager_->GetInitSucceededForTesting()); + } + + void MockHasRequestRunning(bool has_request_running) { + subscriptions_manager_->SetHasRequestRunningForTesting(has_request_running); + } + + void VerifyHasPendingRequests(bool has_pending_requests) { + ASSERT_EQ(has_pending_requests, + subscriptions_manager_->HasPendingRequestsForTesting()); + } + + protected: + base::test::TaskEnvironment task_environment_; + signin::IdentityTestEnvironment identity_test_env_; + base::test::ScopedFeatureList test_features_; + std::unique_ptr<MockSubscriptionsServerProxy> mock_server_proxy_; + std::unique_ptr<MockSubscriptionsStorage> mock_storage_; + std::unique_ptr<SubscriptionsManager> subscriptions_manager_; +}; + +TEST_F(SubscriptionsManagerTest, TestInitSucceeded) { + mock_server_proxy_->MockGetResponses("111"); + mock_storage_->MockUpdateResponses(true); + EXPECT_CALL(*mock_storage_, DeleteAll).Times(1); + EXPECT_CALL(*mock_server_proxy_, Get).Times(1); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))) + .Times(1); + + CreateManagerAndVerify(true); +} + +TEST_F(SubscriptionsManagerTest, TestInitFailed) { + mock_server_proxy_->MockGetResponses("111"); + mock_storage_->MockUpdateResponses(false); + EXPECT_CALL(*mock_storage_, DeleteAll).Times(1); + EXPECT_CALL(*mock_server_proxy_, Get).Times(1); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))) + .Times(1); + + CreateManagerAndVerify(false); +} + +TEST_F(SubscriptionsManagerTest, TestSubscribe) { + mock_server_proxy_->MockGetResponses("111"); + mock_server_proxy_->MockManageResponses(true); + mock_storage_->MockGetResponses("222"); + mock_storage_->MockUpdateResponses(true); + + { + InSequence s; + EXPECT_CALL(*mock_storage_, DeleteAll); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + EXPECT_CALL(*mock_storage_, GetUniqueNonExistingSubscriptions( + AreExpectedSubscriptions("333"), _)); + EXPECT_CALL(*mock_server_proxy_, + Create(AreExpectedSubscriptions("222"), _)); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + } + + CreateManagerAndVerify(true); + bool callback_executed = false; + subscriptions_manager_->Subscribe( + BuildSubscriptions("333"), + base::BindOnce( + [](bool* callback_executed, bool succeeded) { + ASSERT_EQ(true, succeeded); + *callback_executed = true; + }, + &callback_executed)); + // Use a RunLoop in case the callback is posted on a different thread. + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(true, callback_executed); +} + +TEST_F(SubscriptionsManagerTest, TestSubscribe_ServerManageFailed) { + mock_server_proxy_->MockGetResponses("111"); + mock_server_proxy_->MockManageResponses(false); + mock_storage_->MockGetResponses("222"); + mock_storage_->MockUpdateResponses(true); + + { + InSequence s; + EXPECT_CALL(*mock_storage_, DeleteAll); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + EXPECT_CALL(*mock_storage_, GetUniqueNonExistingSubscriptions( + AreExpectedSubscriptions("333"), _)); + EXPECT_CALL(*mock_server_proxy_, + Create(AreExpectedSubscriptions("222"), _)); + EXPECT_CALL(*mock_server_proxy_, Get).Times(0); + EXPECT_CALL(*mock_storage_, UpdateStorage).Times(0); + } + + CreateManagerAndVerify(true); + bool callback_executed = false; + subscriptions_manager_->Subscribe( + BuildSubscriptions("333"), + base::BindOnce( + [](bool* callback_executed, bool succeeded) { + ASSERT_EQ(false, succeeded); + *callback_executed = true; + }, + &callback_executed)); + // Use a RunLoop in case the callback is posted on a different thread. + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(true, callback_executed); +} + +TEST_F(SubscriptionsManagerTest, TestSubscribe_InitFailed) { + mock_server_proxy_->MockGetResponses("111"); + mock_server_proxy_->MockManageResponses(true); + mock_storage_->MockGetResponses("222"); + mock_storage_->MockUpdateResponses(false); + + { + InSequence s; + EXPECT_CALL(*mock_storage_, DeleteAll); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + EXPECT_CALL(*mock_storage_, GetUniqueNonExistingSubscriptions).Times(0); + } + + CreateManagerAndVerify(false); + bool callback_executed = false; + subscriptions_manager_->Subscribe( + BuildSubscriptions("333"), + base::BindOnce( + [](bool* callback_executed, bool succeeded) { + ASSERT_EQ(false, succeeded); + *callback_executed = true; + }, + &callback_executed)); + // Use a RunLoop in case the callback is posted on a different thread. + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(true, callback_executed); +} + +TEST_F(SubscriptionsManagerTest, TestSubscribe_HasRequestRunning) { + mock_server_proxy_->MockGetResponses("111"); + mock_server_proxy_->MockManageResponses(true); + mock_storage_->MockGetResponses("222"); + mock_storage_->MockUpdateResponses(true); + + { + InSequence s; + EXPECT_CALL(*mock_storage_, DeleteAll); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + EXPECT_CALL(*mock_storage_, GetUniqueNonExistingSubscriptions).Times(0); + } + + CreateManagerAndVerify(true); + MockHasRequestRunning(true); + bool callback_executed = false; + subscriptions_manager_->Subscribe( + BuildSubscriptions("333"), + base::BindOnce([](bool* callback_executed, + bool succeeded) { *callback_executed = true; }, + &callback_executed)); + // Use a RunLoop in case the callback is posted on a different thread. + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(false, callback_executed); +} + +TEST_F(SubscriptionsManagerTest, TestSubscribe_HasPendingUnsubscribeRequest) { + mock_server_proxy_->MockGetResponses("111"); + mock_server_proxy_->MockManageResponses(true); + mock_storage_->MockGetResponses("222"); + mock_storage_->MockUpdateResponses(true); + + { + InSequence s; + // Init calls. + EXPECT_CALL(*mock_storage_, DeleteAll); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + // Unsubscribe calls. + EXPECT_CALL(*mock_storage_, GetUniqueExistingSubscriptions( + AreExpectedSubscriptions("333"), _)); + EXPECT_CALL(*mock_server_proxy_, + Delete(AreExpectedSubscriptions("222"), _)); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + // Subscribe calls. + EXPECT_CALL(*mock_storage_, GetUniqueNonExistingSubscriptions( + AreExpectedSubscriptions("444"), _)); + EXPECT_CALL(*mock_server_proxy_, + Create(AreExpectedSubscriptions("222"), _)); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + } + + CreateManagerAndVerify(true); + VerifyHasPendingRequests(false); + // First, we set has_request_running_ as true to hold on coming Unsubscribe + // request. + MockHasRequestRunning(true); + bool unsubscribe_callback_executed = false; + subscriptions_manager_->Unsubscribe( + BuildSubscriptions("333"), + base::BindOnce( + [](bool* callback_executed, bool succeeded) { + ASSERT_EQ(true, succeeded); + *callback_executed = true; + }, + &unsubscribe_callback_executed)); + // Use a RunLoop in case the callback is posted on a different thread. + base::RunLoop().RunUntilIdle(); + // This request won't be processed and will be held in pending_requests_. + ASSERT_EQ(false, unsubscribe_callback_executed); + VerifyHasPendingRequests(true); + + // Next, we set has_request_running_ as false and Subscribe. The previous + // Unsubscribe request should be processed first and once it finishes, this + // Subscribe request will be processed automatically. + MockHasRequestRunning(false); + bool subscribe_callback_executed = false; + subscriptions_manager_->Subscribe( + BuildSubscriptions("444"), + base::BindOnce( + [](bool* callback_executed, bool succeeded) { + ASSERT_EQ(true, succeeded); + *callback_executed = true; + }, + &subscribe_callback_executed)); + // Use a RunLoop in case the callback is posted on a different thread. + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(true, unsubscribe_callback_executed); + ASSERT_EQ(true, subscribe_callback_executed); + VerifyHasPendingRequests(false); +} + +TEST_F(SubscriptionsManagerTest, TestUnsubscribe) { + mock_server_proxy_->MockGetResponses("111"); + mock_server_proxy_->MockManageResponses(true); + mock_storage_->MockGetResponses("222"); + mock_storage_->MockUpdateResponses(true); + + { + InSequence s; + EXPECT_CALL(*mock_storage_, DeleteAll); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + EXPECT_CALL(*mock_storage_, GetUniqueExistingSubscriptions( + AreExpectedSubscriptions("333"), _)); + EXPECT_CALL(*mock_server_proxy_, + Delete(AreExpectedSubscriptions("222"), _)); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + } + + CreateManagerAndVerify(true); + bool callback_executed = false; + subscriptions_manager_->Unsubscribe( + BuildSubscriptions("333"), + base::BindOnce( + [](bool* callback_executed, bool succeeded) { + ASSERT_EQ(true, succeeded); + *callback_executed = true; + }, + &callback_executed)); + // Use a RunLoop in case the callback is posted on a different thread. + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(true, callback_executed); +} + +TEST_F(SubscriptionsManagerTest, TestUnsubscribe_InitFailed) { + mock_server_proxy_->MockGetResponses("111"); + mock_server_proxy_->MockManageResponses(true); + mock_storage_->MockGetResponses("222"); + mock_storage_->MockUpdateResponses(false); + + { + InSequence s; + EXPECT_CALL(*mock_storage_, DeleteAll); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + EXPECT_CALL(*mock_storage_, GetUniqueExistingSubscriptions).Times(0); + } + + CreateManagerAndVerify(false); + bool callback_executed = false; + subscriptions_manager_->Unsubscribe( + BuildSubscriptions("333"), + base::BindOnce( + [](bool* callback_executed, bool succeeded) { + ASSERT_EQ(false, succeeded); + *callback_executed = true; + }, + &callback_executed)); + // Use a RunLoop in case the callback is posted on a different thread. + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(true, callback_executed); +} + +TEST_F(SubscriptionsManagerTest, TestIdentityChange) { + mock_server_proxy_->MockGetResponses("111"); + mock_storage_->MockUpdateResponses(true); + + { + InSequence s; + // First init on manager instantiation. + EXPECT_CALL(*mock_storage_, DeleteAll); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + // Second init on primary account change. + EXPECT_CALL(*mock_storage_, DeleteAll); + EXPECT_CALL(*mock_server_proxy_, Get); + EXPECT_CALL(*mock_storage_, + UpdateStorage(_, _, AreExpectedSubscriptions("111"))); + } + + CreateManagerAndVerify(true); + identity_test_env_.MakePrimaryAccountAvailable("mock_email@gmail.com", + signin::ConsentLevel::kSync); +} + +} // namespace commerce
diff --git a/components/commerce/core/subscriptions/subscriptions_server_proxy.h b/components/commerce/core/subscriptions/subscriptions_server_proxy.h index 5563dec..1643037 100644 --- a/components/commerce/core/subscriptions/subscriptions_server_proxy.h +++ b/components/commerce/core/subscriptions/subscriptions_server_proxy.h
@@ -42,18 +42,21 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); SubscriptionsServerProxy(const SubscriptionsServerProxy&) = delete; SubscriptionsServerProxy& operator=(const SubscriptionsServerProxy&) = delete; - ~SubscriptionsServerProxy(); + virtual ~SubscriptionsServerProxy(); // Make an HTTPS call to backend to create the new |subscriptions|. - void Create(std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, - ManageSubscriptionsFetcherCallback callback); + virtual void Create( + std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, + ManageSubscriptionsFetcherCallback callback); // Make an HTTPS call to backend to delete the existing |subscriptions|. - void Delete(std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, - ManageSubscriptionsFetcherCallback callback); + virtual void Delete( + std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, + ManageSubscriptionsFetcherCallback callback); // Make an HTTP call to backend to get all subscriptions for specified type. - void Get(SubscriptionType type, GetSubscriptionsFetcherCallback callback); + virtual void Get(SubscriptionType type, + GetSubscriptionsFetcherCallback callback); private: std::unique_ptr<EndpointFetcher> CreateEndpointFetcher(
diff --git a/components/commerce/core/subscriptions/subscriptions_storage.cc b/components/commerce/core/subscriptions/subscriptions_storage.cc index 52d144c..494e9788 100644 --- a/components/commerce/core/subscriptions/subscriptions_storage.cc +++ b/components/commerce/core/subscriptions/subscriptions_storage.cc
@@ -31,4 +31,6 @@ base::OnceCallback<void(bool)> callback, std::unique_ptr<std::vector<CommerceSubscription>> remote_subscriptions) {} +void SubscriptionsStorage::DeleteAll() {} + } // namespace commerce
diff --git a/components/commerce/core/subscriptions/subscriptions_storage.h b/components/commerce/core/subscriptions/subscriptions_storage.h index 22fafbc..8d997e1 100644 --- a/components/commerce/core/subscriptions/subscriptions_storage.h +++ b/components/commerce/core/subscriptions/subscriptions_storage.h
@@ -25,28 +25,31 @@ SubscriptionsStorage(); SubscriptionsStorage(const SubscriptionsStorage&) = delete; SubscriptionsStorage& operator=(const SubscriptionsStorage&) = delete; - ~SubscriptionsStorage(); + virtual ~SubscriptionsStorage(); // Compare the provided subscriptions against local cache and return unique // subscriptions that are not in local cache. This is used for subscribe // operation. - void GetUniqueNonExistingSubscriptions( + virtual void GetUniqueNonExistingSubscriptions( std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, GetLocalSubscriptionsCallback callback); // Compare the provided subscriptions against local cache and return unique // subscriptions that are already in local cache. This is used for unsubscribe // operation. - void GetUniqueExistingSubscriptions( + virtual void GetUniqueExistingSubscriptions( std::unique_ptr<std::vector<CommerceSubscription>> subscriptions, GetLocalSubscriptionsCallback callback); // Update local cache to keep consistency with |remote_subscriptions| and // notify |callback| if it completes successfully. - void UpdateStorage( + virtual void UpdateStorage( SubscriptionType type, base::OnceCallback<void(bool)> callback, std::unique_ptr<std::vector<CommerceSubscription>> remote_subscriptions); + + // Delete all local subscriptions. + virtual void DeleteAll(); }; } // namespace commerce
diff --git a/components/contextual_search/core/browser/contextual_search_delegate.cc b/components/contextual_search/core/browser/contextual_search_delegate.cc index 9ee41758..f59065ab 100644 --- a/components/contextual_search/core/browser/contextual_search_delegate.cc +++ b/components/contextual_search/core/browser/contextual_search_delegate.cc
@@ -103,67 +103,65 @@ // Handles tasks for the ContextualSearchManager in a separable, testable way. ContextualSearchDelegate::ContextualSearchDelegate( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - TemplateURLService* template_url_service, - ContextualSearchDelegate::SearchTermResolutionCallback search_term_callback, - ContextualSearchDelegate::SurroundingTextCallback surrounding_text_callback) + TemplateURLService* template_url_service) : url_loader_factory_(std::move(url_loader_factory)), template_url_service_(template_url_service), - field_trial_(std::make_unique<ContextualSearchFieldTrial>()), - search_term_callback_(std::move(search_term_callback)), - surrounding_text_callback_(std::move(surrounding_text_callback)) {} + field_trial_(std::make_unique<ContextualSearchFieldTrial>()) {} ContextualSearchDelegate::~ContextualSearchDelegate() = default; void ContextualSearchDelegate::GatherAndSaveSurroundingText( - base::WeakPtr<ContextualSearchContext> contextual_search_context, - content::WebContents* web_contents) { + base::WeakPtr<ContextualSearchContext> context, + content::WebContents* web_contents, + SurroundingTextCallback callback) { DCHECK(web_contents); - blink::mojom::LocalFrame::GetTextSurroundingSelectionCallback callback = - base::BindOnce( + blink::mojom::LocalFrame::GetTextSurroundingSelectionCallback + get_text_callback = base::BindOnce( &ContextualSearchDelegate::OnTextSurroundingSelectionAvailable, - AsWeakPtr()); - context_ = contextual_search_context; - if (context_ == nullptr) + AsWeakPtr(), context, callback); + if (!context) return; - context_->SetBasePageEncoding(web_contents->GetEncoding()); - int surroundingTextSize = context_->CanResolve() + context->SetBasePageEncoding(web_contents->GetEncoding()); + int surroundingTextSize = context->CanResolve() ? field_trial_->GetResolveSurroundingSize() : field_trial_->GetSampleSurroundingSize(); RenderFrameHost* focused_frame = web_contents->GetFocusedFrame(); if (focused_frame) { - focused_frame->RequestTextSurroundingSelection(std::move(callback), + focused_frame->RequestTextSurroundingSelection(std::move(get_text_callback), surroundingTextSize); } else { - std::move(callback).Run(std::u16string(), 0, 0); + std::move(get_text_callback).Run(std::u16string(), 0, 0); } } void ContextualSearchDelegate::StartSearchTermResolutionRequest( - base::WeakPtr<ContextualSearchContext> contextual_search_context, - content::WebContents* web_contents) { + base::WeakPtr<ContextualSearchContext> context, + content::WebContents* web_contents, + SearchTermResolutionCallback callback) { DCHECK(web_contents); - if (context_ == nullptr) + if (!context) return; - DCHECK(context_.get() == contextual_search_context.get()); - DCHECK(context_->CanResolve()); + DCHECK(context->CanResolve()); // Immediately cancel any request that's in flight, since we're building a new // context (and the response disposes of any existing context). url_loader_.reset(); // Decide if the URL should be sent with the context. - if (context_->CanSendBasePageUrl()) - context_->SetBasePageUrl(web_contents->GetLastCommittedURL()); + if (context->CanSendBasePageUrl()) + context->SetBasePageUrl(web_contents->GetLastCommittedURL()); // Issue the resolve request. - ResolveSearchTermFromContext(); + ResolveSearchTermFromContext(context, std::move(callback)); } -void ContextualSearchDelegate::ResolveSearchTermFromContext() { - DCHECK(context_ != nullptr); - GURL request_url(BuildRequestUrl(context_.get())); +void ContextualSearchDelegate::ResolveSearchTermFromContext( + base::WeakPtr<ContextualSearchContext> context, + SearchTermResolutionCallback callback) { + DCHECK(context); + GURL request_url(BuildRequestUrl(context.get())); DCHECK(request_url.is_valid()); auto resource_request = std::make_unique<network::ResourceRequest>(); @@ -171,7 +169,7 @@ // Populates the discourse context and adds it to the HTTP header of the // search term resolution request. - resource_request->headers.CopyFrom(GetDiscourseContext(*context_)); + resource_request->headers.CopyFrom(GetDiscourseContext(*context)); // Disable cookies for this request. resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; @@ -219,12 +217,14 @@ url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( url_loader_factory_.get(), base::BindOnce(&ContextualSearchDelegate::OnUrlLoadComplete, - base::Unretained(this))); + base::Unretained(this), context, std::move(callback))); } void ContextualSearchDelegate::OnUrlLoadComplete( + base::WeakPtr<ContextualSearchContext> context, + SearchTermResolutionCallback callback, std::unique_ptr<std::string> response_body) { - if (!context_) + if (!context) return; int response_code = ResolvedSearchTerm::kResponseCodeUninitialized; @@ -236,16 +236,16 @@ std::make_unique<ResolvedSearchTerm>(response_code); if (response_body && response_code == net::HTTP_OK) { resolved_search_term = - GetResolvedSearchTermFromJson(response_code, *response_body); + GetResolvedSearchTermFromJson(*context, response_code, *response_body); } - search_term_callback_.Run(*resolved_search_term); + callback.Run(*resolved_search_term); } std::unique_ptr<ResolvedSearchTerm> ContextualSearchDelegate::GetResolvedSearchTermFromJson( + const ContextualSearchContext& context, int response_code, const std::string& json_string) { - DCHECK(context_ != nullptr); std::string search_term; std::string display_text; std::string alternate_term; @@ -278,13 +278,13 @@ // the new and old selection. if (mention_start >= mention_end || (mention_end - mention_start) > kContextualSearchMaxSelection || - mention_end <= context_->GetStartOffset() || - mention_start >= context_->GetEndOffset()) { + mention_end <= context.GetStartOffset() || + mention_start >= context.GetEndOffset()) { start_adjust = 0; end_adjust = 0; } else { - start_adjust = mention_start - context_->GetStartOffset(); - end_adjust = mention_end - context_->GetEndOffset(); + start_adjust = mention_start - context.GetStartOffset(); + end_adjust = mention_end - context.GetEndOffset(); } } bool is_invalid = @@ -325,7 +325,7 @@ } int mainFunctionVersion = kContextualSearchRequestVersion; - if (context_->GetRelatedSearches()) + if (context->GetRelatedSearches()) mainFunctionVersion = kRelatedSearchesVersion; TemplateURLRef::SearchTermsArgs::ContextualSearchParams params( @@ -358,16 +358,18 @@ } void ContextualSearchDelegate::OnTextSurroundingSelectionAvailable( + base::WeakPtr<ContextualSearchContext> context, + SurroundingTextCallback callback, const std::u16string& surrounding_text, uint32_t start_offset, uint32_t end_offset) { - if (context_ == nullptr) + if (!context) return; // Sometimes the surroundings are 0, 0, '', so run the callback with empty // data in that case. See https://crbug.com/393100. if (start_offset == 0 && end_offset == 0 && surrounding_text.length() == 0) { - surrounding_text_callback_.Run(std::string(), std::u16string(), 0, 0); + callback.Run(std::string(), std::u16string(), 0, 0); return; } @@ -378,8 +380,7 @@ start_offset = std::min(surrounding_length, start_offset); end_offset = std::min(surrounding_length, end_offset); - context_->SetSelectionSurroundings(start_offset, end_offset, - surrounding_text); + context->SetSelectionSurroundings(start_offset, end_offset, surrounding_text); // Call the Java surrounding callback with a shortened copy of the // surroundings to use as a sample of the surrounding text. @@ -393,9 +394,8 @@ SampleSurroundingText(surrounding_text, sample_padding_each_side, &selection_start, &selection_end); DCHECK(selection_start <= selection_end); - surrounding_text_callback_.Run(context_->GetBasePageEncoding(), - sample_surrounding_text, selection_start, - selection_end); + callback.Run(context->GetBasePageEncoding(), sample_surrounding_text, + selection_start, selection_end); } // Decodes the given response from the search term resolution request and sets @@ -531,7 +531,7 @@ void ContextualSearchDelegate::ExtractMentionsStartEnd( const base::Value::List& mentions_list, int* start_result, - int* end_result) { + int* end_result) const { if (mentions_list.size() >= 1 && mentions_list[0].is_int()) *start_result = std::max(0, mentions_list[0].GetInt()); if (mentions_list.size() >= 2 && mentions_list[1].is_int()) @@ -542,7 +542,7 @@ const std::u16string& surrounding_text, int padding_each_side, size_t* start, - size_t* end) { + size_t* end) const { std::u16string result_text = surrounding_text; size_t start_offset = *start; size_t end_offset = *end;
diff --git a/components/contextual_search/core/browser/contextual_search_delegate.h b/components/contextual_search/core/browser/contextual_search_delegate.h index 6cbdfc7..a13b252 100644 --- a/components/contextual_search/core/browser/contextual_search_delegate.h +++ b/components/contextual_search/core/browser/contextual_search_delegate.h
@@ -44,32 +44,32 @@ void(const std::string&, const std::u16string&, size_t, size_t)> SurroundingTextCallback; - // Constructs a delegate that will always call back to the given callbacks - // when search term resolution or surrounding text responses are available. + // Constructs a delegate that uses the given url_loader_factory and + // template_url_service for all contextual search requests. ContextualSearchDelegate( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - TemplateURLService* template_url_service, - SearchTermResolutionCallback search_term_callback, - SurroundingTextCallback surrounding_callback); + TemplateURLService* template_url_service); ContextualSearchDelegate(const ContextualSearchDelegate&) = delete; ContextualSearchDelegate& operator=(const ContextualSearchDelegate&) = delete; virtual ~ContextualSearchDelegate(); - // Gathers surrounding text and saves it locally in the given context. + // Gathers surrounding text and saves it in the given context. The given + // callback will be run when the surrounding text becomes available. void GatherAndSaveSurroundingText( base::WeakPtr<ContextualSearchContext> contextual_search_context, - content::WebContents* web_contents); + content::WebContents* web_contents, + SurroundingTextCallback callback); // Starts an asynchronous search term resolution request. - // The given context includes some content from a web page and must be able + // The given context may include some content from a web page and must be able // to resolve. - // When the response is available the callback specified in the constructor - // is run. + // When the response is available the given callback will be run. void StartSearchTermResolutionRequest( base::WeakPtr<ContextualSearchContext> contextual_search_context, - content::WebContents* web_contents); + content::WebContents* web_contents, + SearchTermResolutionCallback callback); private: // Friend our test which allows our private methods to be used in helper @@ -95,23 +95,31 @@ FRIEND_TEST_ALL_PREFIXES(ContextualSearchDelegateTest, DecodeSearchTermFromJsonResponse); - void OnUrlLoadComplete(std::unique_ptr<std::string> response_body); - // Resolves the search term specified by the current context. - // Only needed for tests. TODO(donnd): make private and friend? - void ResolveSearchTermFromContext(); + void ResolveSearchTermFromContext( + base::WeakPtr<ContextualSearchContext> context, + SearchTermResolutionCallback callback); + + // Handles the contextual search response included in |response_body|. Calls + // |callback| with the resulting ResolvedSearchTerm. + void OnUrlLoadComplete(base::WeakPtr<ContextualSearchContext> context, + SearchTermResolutionCallback callback, + std::unique_ptr<std::string> response_body); // Builds and returns the search term resolution request URL. // |context| is used to help build the query. std::string BuildRequestUrl(ContextualSearchContext* context); void OnTextSurroundingSelectionAvailable( + base::WeakPtr<ContextualSearchContext> context, + SurroundingTextCallback callback, const std::u16string& surrounding_text, uint32_t start_offset, uint32_t end_offset); // Builds a Resolved Search Term by decoding the given JSON string. std::unique_ptr<ResolvedSearchTerm> GetResolvedSearchTermFromJson( + const ContextualSearchContext& context, int response_code, const std::string& json_string); @@ -140,7 +148,7 @@ // |mentions_list| must be a list. void ExtractMentionsStartEnd(const base::Value::List& mentions_list, int* start_result, - int* end_result); + int* end_result) const; // Generates a subset of the given surrounding_text string, for usage from // Java. @@ -157,13 +165,7 @@ std::u16string SampleSurroundingText(const std::u16string& surrounding_text, int padding_each_side, size_t* start, - size_t* end); - - // For testing. - void SetContextForTesting( - const base::WeakPtr<ContextualSearchContext>& context) { - context_ = context; - } + size_t* end) const; // The current request in progress, or NULL. std::unique_ptr<network::SimpleURLLoader> url_loader_; @@ -176,16 +178,6 @@ // The field trial helper instance, always set up by the constructor. std::unique_ptr<ContextualSearchFieldTrial> field_trial_; - - // The callback for notifications of completed URL fetches. - SearchTermResolutionCallback search_term_callback_; - - // The callback for notifications of surrounding text being available. - SurroundingTextCallback surrounding_text_callback_; - - // Used to hold the context until an upcoming search term request is started. - // Owned by the Java ContextualSearchContext. - base::WeakPtr<ContextualSearchContext> context_; }; #endif // COMPONENTS_CONTEXTUAL_SEARCH_CORE_BROWSER_CONTEXTUAL_SEARCH_DELEGATE_H_
diff --git a/components/contextual_search/core/browser/contextual_search_delegate_unittest.cc b/components/contextual_search/core/browser/contextual_search_delegate_unittest.cc index 914d00b..476fc86 100644 --- a/components/contextual_search/core/browser/contextual_search_delegate_unittest.cc +++ b/components/contextual_search/core/browser/contextual_search_delegate_unittest.cc
@@ -14,6 +14,7 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/strings/escape.h" #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" @@ -73,13 +74,9 @@ &test_url_loader_factory_); template_url_service_.reset(CreateTemplateURLService()); delegate_ = std::make_unique<ContextualSearchDelegate>( - test_shared_url_loader_factory_, template_url_service_.get(), - base::BindRepeating( - &ContextualSearchDelegateTest::recordSearchTermResolutionResponse, - base::Unretained(this)), - base::BindRepeating( - &ContextualSearchDelegateTest::recordSampleSelectionAvailable, - base::Unretained(this))); + test_shared_url_loader_factory_, template_url_service_.get()); + + received_search_term_resolution_response_ = false; } void TearDown() override { @@ -117,12 +114,13 @@ int end_offset) { test_context_ = std::make_unique<WeakContextualSearchContext>( std::string(), GURL(kSomeSpecificBasePage), "utf-8"); - // ContextualSearchDelegate class takes ownership of the context. - delegate_->SetContextForTesting(test_context_->GetWeakPtr()); - test_context_->SetSelectionSurroundings(start_offset, end_offset, surrounding_text); - delegate_->ResolveSearchTermFromContext(); + delegate_->ResolveSearchTermFromContext( + test_context_->GetWeakPtr(), + base::BindRepeating( + &ContextualSearchDelegateTest::recordSearchTermResolutionResponse, + base::Unretained(this))); ASSERT_TRUE(test_url_loader_factory_.GetPendingRequest(0)); } @@ -154,7 +152,6 @@ void CreateTestContext() { test_context_ = std::make_unique<WeakContextualSearchContext>( std::string(), GURL(kSomeSpecificBasePage), "utf-8"); - delegate_->SetContextForTesting(test_context_->GetWeakPtr()); } void DestroyTestContext() { test_context_.reset(); } @@ -162,12 +159,23 @@ // Call the OnTextSurroundingSelectionAvailable. // Cannot be in an actual test because OnTextSurroundingSelectionAvailable // is private. - void CallOnTextSurroundingSelectionAvailable() { - delegate_->OnTextSurroundingSelectionAvailable(std::u16string(), 1, 2); + void CallOnTextSurroundingSelectionAvailable( + base::WeakPtr<ContextualSearchContext> context) { + delegate_->OnTextSurroundingSelectionAvailable( + context, + base::BindRepeating( + &ContextualSearchDelegateTest::recordSampleSelectionAvailable, + base::Unretained(this)), + std::u16string(), 1, 2); } - void CallResolveSearchTermFromContext() { - delegate_->ResolveSearchTermFromContext(); + void CallResolveSearchTermFromContext( + base::WeakPtr<ContextualSearchContext> context) { + delegate_->ResolveSearchTermFromContext( + context, + base::BindRepeating( + &ContextualSearchDelegateTest::recordSearchTermResolutionResponse, + base::Unretained(this))); } void SetResponseStringAndSimulateResponse(const std::string& selected_text, @@ -198,7 +206,6 @@ std::string(), GURL(kSomeSpecificBasePage), "utf-8"); test_context_->SetSelectionSurroundings(start_offset, end_offset, surrounding_text); - delegate_->SetContextForTesting(test_context_->GetWeakPtr()); } // Gets the Client Discourse Context proto from the request header. @@ -258,14 +265,21 @@ int coca_card_tag() { return coca_card_tag_; } std::string related_searches_json() { return related_searches_json_; } + bool received_search_term_resolution_response() { + return received_search_term_resolution_response_; + } + // The delegate under test. std::unique_ptr<ContextualSearchDelegate> delegate_; + std::unique_ptr<WeakContextualSearchContext> test_context_; network::TestURLLoaderFactory test_url_loader_factory_; private: void recordSearchTermResolutionResponse( const ResolvedSearchTerm& resolved_search_term) { + received_search_term_resolution_response_ = true; + is_invalid_ = resolved_search_term.is_invalid; response_code_ = resolved_search_term.response_code; search_term_ = resolved_search_term.search_term; @@ -313,6 +327,9 @@ int coca_card_tag_; std::string related_searches_json_; + // Tracks whether a response was received. + bool received_search_term_resolution_response_; + base::test::SingleThreadTaskEnvironment task_environment_{ base::test::SingleThreadTaskEnvironment::MainThreadType::IO}; variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ @@ -321,8 +338,6 @@ scoped_refptr<network::SharedURLLoaderFactory> test_shared_url_loader_factory_; - std::unique_ptr<WeakContextualSearchContext> test_context_; - // Features to enable base::test::ScopedFeatureList feature_list_; }; @@ -674,23 +689,24 @@ } // Test that we can destroy the context while resolving without a crash. -// Test is flaky: https://crbug.com/890427 -TEST_F(ContextualSearchDelegateTest, DISABLED_DestroyContextDuringResolve) { +TEST_F(ContextualSearchDelegateTest, DestroyContextDuringResolve) { CreateTestContext(); - CallResolveSearchTermFromContext(); + CallResolveSearchTermFromContext(test_context_->GetWeakPtr()); DestroyTestContext(); std::string response("Any response as it does not matter here."); SimulateResponseReturned(response); - EXPECT_TRUE(is_invalid()); + EXPECT_FALSE(received_search_term_resolution_response()); } // Test that we can destroy the context while gathering surrounding text. TEST_F(ContextualSearchDelegateTest, DestroyContextDuringGatherSurroundings) { CreateTestContext(); + base::WeakPtr<ContextualSearchContext> weak_context = + test_context_->GetWeakPtr(); DestroyTestContext(); - CallOnTextSurroundingSelectionAvailable(); + CallOnTextSurroundingSelectionAvailable(weak_context); } TEST_F(ContextualSearchDelegateTest, ResponseWithCocaCardTag) {
diff --git a/components/crash/core/app/crashpad.cc b/components/crash/core/app/crashpad.cc index 0d0a0ed..8c0ae200 100644 --- a/components/crash/core/app/crashpad.cc +++ b/components/crash/core/app/crashpad.cc
@@ -68,36 +68,6 @@ crashpad::CrashReportDatabase* g_database; -bool LogMessageHandler(int severity, - const char* file, - int line, - size_t message_start, - const std::string& string) { - // Only handle FATAL. - if (severity != logging::LOG_FATAL) { - return false; - } - - // In case of an out-of-memory condition, this code could be reentered when - // constructing and storing the key. Using a static is not thread-safe, but if - // multiple threads are in the process of a fatal crash at the same time, this - // should work. - static bool guarded = false; - if (guarded) { - return false; - } - base::AutoReset<bool> guard(&guarded, true); - - CHECK_LE(message_start, string.size()); - static crashpad::StringAnnotation<512> crash_key("LOG_FATAL"); - crash_key.Set(logging::LogMessage::BuildCrashString( - file, line, string.c_str() + message_start)); - - // Rather than including the code to force the crash here, allow the caller to - // do it. - return false; -} - void InitializeDatabasePath(const base::FilePath& database_path) { DCHECK(!g_database_path); @@ -198,8 +168,6 @@ platform.Set(base::SysInfo::HardwareModelName()); #endif // !BUILDFLAG(IS_IOS) - logging::SetLogMessageHandler(LogMessageHandler); - // If clients called CRASHPAD_SIMULATE_CRASH() instead of // base::debug::DumpWithoutCrashing(), these dumps would appear as crashes in // the correct function, at the correct file and line. This would be
diff --git a/components/device_signals/core/browser/BUILD.gn b/components/device_signals/core/browser/BUILD.gn index 01a1bd3a..abfd3a2d 100644 --- a/components/device_signals/core/browser/BUILD.gn +++ b/components/device_signals/core/browser/BUILD.gn
@@ -38,12 +38,18 @@ deps = [ "//components/device_signals/core/common", "//components/policy/core/common", + "//components/prefs", "//components/signin/public/identity_manager", ] if (is_win) { public_deps += [ "//components/device_signals/core/common/win" ] } + + if (is_win || is_linux || is_mac) { + public += [ "pref_names.h" ] + sources += [ "pref_names.cc" ] + } } static_library("test_support") {
diff --git a/components/device_signals/core/browser/DEPS b/components/device_signals/core/browser/DEPS index 97d436ae..b5db532 100644 --- a/components/device_signals/core/browser/DEPS +++ b/components/device_signals/core/browser/DEPS
@@ -2,4 +2,5 @@ "+components/keyed_service/core", "+components/signin/public", "+components/policy/core", + "+components/prefs", ]
diff --git a/components/device_signals/core/browser/pref_names.cc b/components/device_signals/core/browser/pref_names.cc new file mode 100644 index 0000000..d85093ee --- /dev/null +++ b/components/device_signals/core/browser/pref_names.cc
@@ -0,0 +1,23 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/device_signals/core/browser/pref_names.h" + +#include "components/prefs/pref_registry_simple.h" + +namespace device_signals { +namespace prefs { + +// Whether or not admin requires managed users to share device signals when they +// sign in on an unmanaged device +const char kUnmanagedDeviceSignalsConsentFlowEnabled[] = + "device_signals.consent_collection_enabled"; + +} // namespace prefs + +void RegisterProfilePrefs(PrefRegistrySimple* registry) { + registry->RegisterBooleanPref( + prefs::kUnmanagedDeviceSignalsConsentFlowEnabled, false); +} +} // namespace device_signals
diff --git a/components/device_signals/core/browser/pref_names.h b/components/device_signals/core/browser/pref_names.h new file mode 100644 index 0000000..ad1ffb22 --- /dev/null +++ b/components/device_signals/core/browser/pref_names.h
@@ -0,0 +1,19 @@ +// Copyright 2022 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_DEVICE_SIGNALS_CORE_BROWSER_PREF_NAMES_H_ +#define COMPONENTS_DEVICE_SIGNALS_CORE_BROWSER_PREF_NAMES_H_ + +class PrefRegistrySimple; + +namespace device_signals { +namespace prefs { +extern const char kUnmanagedDeviceSignalsConsentFlowEnabled[]; +} // namespace prefs + +// Registers user preferences related to Device Signal Sharing. +void RegisterProfilePrefs(PrefRegistrySimple* registry); +} // namespace device_signals + +#endif // COMPONENTS_DEVICE_SIGNALS_CORE_BROWSER_PREF_NAMES_H_
diff --git a/components/device_signals/core/common/signals_features.cc b/components/device_signals/core/common/signals_features.cc index 4da5464..cfb98c6 100644 --- a/components/device_signals/core/common/signals_features.cc +++ b/components/device_signals/core/common/signals_features.cc
@@ -18,6 +18,17 @@ const base::FeatureParam<bool> kDisableHotfix{&kNewEvSignalsEnabled, "DisableHotfix", false}; +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) +// Enables the consent promo for sharing device signal when a managed user +// signs in on an unmanaged device. This occurs after the sign-in intercept +// and before the sync promo (if enabled) +// This feature also requires UnmanagedDeviceSignalsConsentFlowEnabled policy to +// be enabled +const base::Feature kDeviceSignalsPromoAfterSigninIntercept{ + "DeviceSignalsPromoAfterSigninIntercept", + base::FEATURE_DISABLED_BY_DEFAULT}; +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) + bool IsNewFunctionEnabled(NewEvFunction new_ev_function) { if (!base::FeatureList::IsEnabled(kNewEvSignalsEnabled)) { return false;
diff --git a/components/device_signals/core/common/signals_features.h b/components/device_signals/core/common/signals_features.h index 07bf89d4c5..a3dc50a 100644 --- a/components/device_signals/core/common/signals_features.h +++ b/components/device_signals/core/common/signals_features.h
@@ -20,6 +20,10 @@ extern const base::FeatureParam<bool> kDisableAntiVirus; extern const base::FeatureParam<bool> kDisableHotfix; +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) +extern const base::Feature kDeviceSignalsPromoAfterSigninIntercept; +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) + // Enum used to map a given function to its kill switch. enum class NewEvFunction { kFileSystemInfo, kSettings, kAntiVirus, kHotfix };
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc index 37e04abe..ba2e3eb 100644 --- a/components/exo/wayland/clients/client_base.cc +++ b/components/exo/wayland/clients/client_base.cc
@@ -559,7 +559,7 @@ gl::GLDisplayEGL* display = static_cast<gl::GLDisplayEGL*>( gl::init::InitializeGLOneOff(/*system_device_id=*/0)); DCHECK(display); - gl_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + gl_surface_ = gl::init::CreateOffscreenGLSurface(display, gfx::Size()); gl_context_ = gl::init::CreateGLContext(nullptr, // share_group gl_surface_.get(), gl::GLContextAttribs());
diff --git a/components/exo/wayland/wayland_positioner.cc b/components/exo/wayland/wayland_positioner.cc index 8c28ce44..4aea1cc 100644 --- a/components/exo/wayland/wayland_positioner.cc +++ b/components/exo/wayland/wayland_positioner.cc
@@ -263,6 +263,7 @@ /*visibility=*/0}, /*position=*/{0, 0}, /*adjustment=*/ConstraintAdjustment{}}; + bool found_solution = false; for (uint32_t adjustment_bit_field = 0; adjustment_bit_field < 8; ++adjustment_bit_field) { // When several options tie for visibility, we preference based on the @@ -302,10 +303,25 @@ } if (is_better) { + found_solution = true; best = IntermediateAdjustmentResult{ {preferred, constrained, visibility}, position, adjustment}; } } + + // If no solution can be found, allow all transformations. Unfortunately the + // default setting is not valid, because it has a 0x0 dimension. + if (!found_solution) { + ConstraintAdjustment allow_all = { + .flip = true, + .slide = true, + .resize = true, + }; + return DetermineBestConstraintAdjustment(work_area, anchor_range, size, + offset, anchor, gravity, allow_all, + avoid_occlusion); + } + return {best.position, best.adjustment}; }
diff --git a/components/exo/wayland/wayland_positioner_unittest.cc b/components/exo/wayland/wayland_positioner_unittest.cc index 0787c96..41a3c21 100644 --- a/components/exo/wayland/wayland_positioner_unittest.cc +++ b/components/exo/wayland/wayland_positioner_unittest.cc
@@ -5,6 +5,7 @@ #include "components/exo/wayland/wayland_positioner.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect.h" #include "xdg-shell-server-protocol.h" #include "xdg-shell-unstable-v6-server-protocol.h" @@ -48,6 +49,11 @@ return *this; } + TestCaseBuilder& SetWorkArea(const gfx::Rect& rect) { + work_area = rect; + return *this; + } + TestCaseBuilder& SetSize(int w, int h) { positioner.SetSize({w, h}); return *this; @@ -232,6 +238,22 @@ gfx::Rect(1, 1, 4, 4)); } +TEST_F(WaylandPositionerTest, + AllowsAdditionalAdjustmentsIfNoSolutionCanBeFoundUnstable) { + EXPECT_EQ( + TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) + .SetWorkArea(gfx::Rect(5, 5)) + .SetSize(10, 10) + .SetAnchorRect(0, 0, 0, 0) + .SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | + ZXDG_POSITIONER_V6_GRAVITY_RIGHT) + // No solution should forcibly allow resize + .SetAdjustment(ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y) + .SolveToRect(), + gfx::Rect(0, 0, 5, 5)); +} + // Tests for the stable protocol. TEST_F(WaylandPositionerTest, UnconstrainedCases) { @@ -401,6 +423,20 @@ gfx::Rect(0, 2, 1, 3)); } +TEST_F(WaylandPositionerTest, + AllowsAdditionalAdjustmentsIfNoSolutionCanBeFound) { + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetWorkArea(gfx::Rect(5, 5)) + .SetSize(10, 10) + .SetAnchorRect(0, 0, 0, 0) + .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) + // No solution should forcibly allow resize + .SetAdjustment(XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) + .SolveToRect(), + gfx::Rect(0, 0, 5, 5)); +} + } // namespace } // namespace wayland } // namespace exo
diff --git a/components/global_media_controls/public/media_session_item_producer.cc b/components/global_media_controls/public/media_session_item_producer.cc index 358ee9d..b4e984a 100644 --- a/components/global_media_controls/public/media_session_item_producer.cc +++ b/components/global_media_controls/public/media_session_item_producer.cc
@@ -68,6 +68,13 @@ void MediaSessionItemProducer::Session::MediaSessionInfoChanged( media_session::mojom::MediaSessionInfoPtr session_info) { + if (session_info && session_info->has_presentation) { + // The presentation gets its own item, so this item has become redundant. + // |this| gets deleted here. + owner_->RemoveItem(id_); + return; + } + is_playing_ = session_info && session_info->playback_state == media_session::mojom::MediaPlaybackState::kPlaying;
diff --git a/components/global_media_controls/public/media_session_item_producer_unittest.cc b/components/global_media_controls/public/media_session_item_producer_unittest.cc index f475c29c..4bde307 100644 --- a/components/global_media_controls/public/media_session_item_producer_unittest.cc +++ b/components/global_media_controls/public/media_session_item_producer_unittest.cc
@@ -192,7 +192,17 @@ session_info->playback_state = playing ? media_session::mojom::MediaPlaybackState::kPlaying : media_session::mojom::MediaPlaybackState::kPaused; + SimulateMediaSessionInfoChanged(id, std::move(session_info)); + } + void SimulateSessionHasPresentation(const base::UnguessableToken& id) { + MediaSessionInfoPtr session_info(MediaSessionInfo::New()); + session_info->has_presentation = true; + SimulateMediaSessionInfoChanged(id, std::move(session_info)); + } + + void SimulateMediaSessionInfoChanged(const base::UnguessableToken& id, + MediaSessionInfoPtr session_info) { auto item_itr = sessions().find(id.ToString()); EXPECT_NE(sessions().end(), item_itr); item_itr->second.MediaSessionInfoChanged(std::move(session_info)); @@ -684,4 +694,13 @@ EXPECT_FALSE(HasActiveItems()); } +TEST_F(MediaSessionItemProducerTest, HidesSessionWithPresentation) { + const base::UnguessableToken id = SimulatePlayingControllableMedia(); + EXPECT_TRUE(HasActiveItems()); + SimulateSessionHasPresentation(id); + // The presentation gets its own item, so MediaSessionItemProducer's item has + // become redundant and gets hidden. + EXPECT_FALSE(HasActiveItems()); +} + } // namespace global_media_controls
diff --git a/components/history/core/browser/visit_annotations_database.cc b/components/history/core/browser/visit_annotations_database.cc index aea2f78..ff77a11 100644 --- a/components/history/core/browser/visit_annotations_database.cc +++ b/components/history/core/browser/visit_annotations_database.cc
@@ -64,16 +64,16 @@ return base::JoinString(serialized_categories, ","); } -// Converts the serialized related searches string into a vector of strings. -std::vector<std::string> GetRelatedSearchesFromStringColumn( +// Converts a serialized db string into a vector of strings. +std::vector<std::string> DeserializeFromStringColumn( const std::string& column_value) { using std::string_literals::operator""s; return base::SplitString(column_value, "\0"s, base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); } -// Serializes related searches into a string that can be stored in the database. -std::string ConvertRelatedSearchesToStringColumn( +// Serializes a vector of strings into a string that can be stored in the db. +std::string SerializeToStringColumn( const std::vector<std::string>& related_searches) { // Use the Null character as the separator to serialize the related searches. using std::string_literals::operator""s; @@ -232,8 +232,8 @@ statement.BindString( 5, ConvertCategoriesToStringColumn( visit_content_annotations.model_annotations.entities)); - statement.BindString(6, ConvertRelatedSearchesToStringColumn( - visit_content_annotations.related_searches)); + statement.BindString( + 6, SerializeToStringColumn(visit_content_annotations.related_searches)); statement.BindString(7, visit_content_annotations.search_normalized_url.spec()); statement.BindString16(8, visit_content_annotations.search_terms); @@ -293,8 +293,8 @@ statement.BindString( 4, ConvertCategoriesToStringColumn( visit_content_annotations.model_annotations.entities)); - statement.BindString(5, ConvertRelatedSearchesToStringColumn( - visit_content_annotations.related_searches)); + statement.BindString( + 5, SerializeToStringColumn(visit_content_annotations.related_searches)); statement.BindString(6, visit_content_annotations.search_normalized_url.spec()); statement.BindString16(7, visit_content_annotations.search_terms); @@ -361,7 +361,7 @@ out_content_annotations->model_annotations.entities = GetCategoriesFromStringColumn(statement.ColumnString(5)); out_content_annotations->related_searches = - GetRelatedSearchesFromStringColumn(statement.ColumnString(6)); + DeserializeFromStringColumn(statement.ColumnString(6)); out_content_annotations->search_normalized_url = GURL(statement.ColumnString(7)); out_content_annotations->search_terms = statement.ColumnString16(8); @@ -389,15 +389,8 @@ } auto cluster_id = GetClusterIdContainingVisit(visit_id); - if (cluster_id > 0 && GetVisitIdsInCluster(cluster_id).size() == 1) { - statement.Assign(GetDB().GetCachedStatement( - SQL_FROM_HERE, "DELETE FROM clusters WHERE cluster_id=?")); - statement.BindInt64(0, cluster_id); - if (!statement.Run()) { - DVLOG(0) << "Failed to execute clusters delete statement: " - << "visit_id = " << visit_id << ", cluster_id = " << cluster_id; - } - } + if (cluster_id > 0 && GetVisitIdsInCluster(cluster_id).size() == 1) + DeleteClusters({cluster_id}); statement.Assign(GetDB().GetCachedStatement( SQL_FROM_HERE, "DELETE FROM clusters_and_visits WHERE visit_id=?")); @@ -420,14 +413,16 @@ "VALUES(?,?,?)")); sql::Statement clusters_and_visits_statement(GetDB().GetCachedStatement( SQL_FROM_HERE, - "INSERT INTO " - "clusters_and_visits(cluster_id,visit_id,score," - "engagement_score,url_for_deduping,normalized_url,url_for_display)" + "INSERT INTO clusters_and_visits" + "(cluster_id,visit_id,score,engagement_score,url_for_deduping," + "normalized_url,url_for_display)" "VALUES(?,?,?,?,?,?,?)")); for (const auto& cluster : clusters) { if (cluster.visits.empty()) continue; + + // Insert the cluster into 'clusters'. clusters_statement.Reset(true); clusters_statement.BindBool(0, cluster.should_show_on_prominent_ui_surfaces); @@ -439,6 +434,8 @@ } const int64_t cluster_id = GetDB().GetLastInsertRowId(); DCHECK(cluster_id); + + // Insert each visit into 'clusters_and_visits'. base::ranges::for_each(cluster.visits, [&](const auto& cluster_visit) { const auto visit_id = cluster_visit.annotated_visit.visit_row.visit_id; clusters_and_visits_statement.Reset(true); @@ -611,9 +608,9 @@ // Not all version 43 history has the content_annotations table. So at this // point the content_annotations table may already have been initialized with - // the latest version with a annotation_flags column. + // the latest version with an annotation_flags column. if (!GetDB().DoesColumnExist("content_annotations", "annotation_flags")) { - // Add a annotation_flags column to the content_annotations table. + // Add an annotation_flags column to the content_annotations table. if (!GetDB().Execute("ALTER TABLE content_annotations ADD COLUMN " "annotation_flags INTEGER DEFAULT 0 NOT NULL")) { return false;
diff --git a/components/lens/OWNERS b/components/lens/OWNERS index a09d9e7..93aa6fa 100644 --- a/components/lens/OWNERS +++ b/components/lens/OWNERS
@@ -1,3 +1,4 @@ benwgold@google.com juanmojica@google.com -yusuyoutube@google.com \ No newline at end of file +stanfield@google.com +yusuyoutube@google.com
diff --git a/components/live_caption/live_caption_controller.cc b/components/live_caption/live_caption_controller.cc index c2f1f27..f6be626 100644 --- a/components/live_caption/live_caption_controller.cc +++ b/components/live_caption/live_caption_controller.cc
@@ -163,7 +163,9 @@ CreateUI(); } -void LiveCaptionController::OnSodaError(speech::LanguageCode language_code) { +void LiveCaptionController::OnSodaInstallError( + speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) { // Check that language code matches the selected language for Live Caption or // is LanguageCode::kNone (signifying the SODA binary failed). if (!prefs::IsLanguageCodeForLiveCaption(language_code, profile_prefs_) &&
diff --git a/components/live_caption/live_caption_controller.h b/components/live_caption/live_caption_controller.h index 42ce5dfd..a596011 100644 --- a/components/live_caption/live_caption_controller.h +++ b/components/live_caption/live_caption_controller.h
@@ -95,7 +95,8 @@ void OnSodaInstalled(speech::LanguageCode language_code) override; void OnSodaProgress(speech::LanguageCode language_code, int progress) override {} - void OnSodaError(speech::LanguageCode language_code) override; + void OnSodaInstallError(speech::LanguageCode language_code, + speech::SodaInstaller::ErrorCode error_code) override; // ui::NativeThemeObserver: void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override {}
diff --git a/components/media_router/common/mojom/media_router.mojom b/components/media_router/common/mojom/media_router.mojom index 6eabc09..38fe5be 100644 --- a/components/media_router/common/mojom/media_router.mojom +++ b/components/media_router/common/mojom/media_router.mojom
@@ -253,9 +253,9 @@ // may be overridden by a provider implementation. The presentation ID will // be used by the presentation API to refer to the created route. // - // |origin| and |tab_id| may be passed in for enforcing same-origin and/or - // same-tab scopes. Use -1 as |tab_id| in cases where the request is not - // made on behalf of a tab. + // |origin| and |frame_tree_node_id| may be passed in for enforcing + // same-origin and/or same-tab scopes. Use -1 as |frame_tree_node_id| in + // cases where the request is not made on behalf of a tab. // // If |timeout| is positive, it will be used in place of the default timeout // defined by Media Route Provider Manager. @@ -270,12 +270,13 @@ // // |result_code| will be set to OK if successful, or an error code if an error // occurred. - // TODO(btolsch): Consolidate result params into struct. + // TODO(crbug.com/1346066): Consolidate parameters into a struct. + // TODO(crbug.com/1351184): Make |frame_tree_node_id| optional. CreateRoute(string media_source, string sink_id, string original_presentation_id, url.mojom.Origin origin, - int32 tab_id, + int32 frame_tree_node_id, mojo_base.mojom.TimeDelta timeout, bool off_the_record) => (MediaRoute? route, @@ -286,8 +287,8 @@ // Requests a connection to an established route for |media_source| given // by |presentation_id|. // - // |origin| and |tab_id| are used for validating same-origin/tab scopes; - // see CreateRoute for additional documentation. + // |origin| and |frame_tree_node_id| are used for validating same-origin/tab + // scopes; see CreateRoute for additional documentation. // // If |timeout| is positive, it will be used in place of the default timeout // defined by Media Route Provider Manager. @@ -302,10 +303,12 @@ // // |result_code| will be set to OK if successful, or an error code if an error // occurred. + // TODO(crbug.com/1346066): Consolidate parameters into a struct. + // TODO(crbug.com/1351184): Make |frame_tree_node_id| optional. JoinRoute(string media_source, string presentation_id, url.mojom.Origin origin, - int32 tab_id, + int32 frame_tree_node_id, mojo_base.mojom.TimeDelta timeout, bool off_the_record) => (MediaRoute? route, @@ -447,10 +450,9 @@ GetLogsAsString() => (string logs); // Called to get a mirroring.mojom.MirroringServiceHost. - GetMirroringServiceHostForTab(int32 target_tab_id, + GetMirroringServiceHostForTab(int32 frame_tree_node_id, pending_receiver<mirroring.mojom.MirroringServiceHost> receiver); GetMirroringServiceHostForDesktop( - int32 initiator_tab_id, // The tab used to register the stream. string desktop_stream_id, pending_receiver<mirroring.mojom.MirroringServiceHost> receiver); GetMirroringServiceHostForOffscreenTab(
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn index b74b76b..f6b9545c 100644 --- a/components/metrics/BUILD.gn +++ b/components/metrics/BUILD.gn
@@ -51,8 +51,6 @@ "file_metrics_provider.h", "form_factor_metrics_provider.cc", "form_factor_metrics_provider.h", - "histogram_encoder.cc", - "histogram_encoder.h", "log_decoder.cc", "log_decoder.h", "log_store.h", @@ -122,6 +120,7 @@ ] deps = [ + ":library_support", "//base", "//base:base_static", "//build:branding_buildflags", @@ -267,14 +266,19 @@ } } +# Dependency for histogram manager users: cronet and ios/webview source_set("library_support") { - sources = [ - "library_support/histogram_manager.cc", + public = [ + "histogram_encoder.h", "library_support/histogram_manager.h", ] + sources = [ + "histogram_encoder.cc", + "library_support/histogram_manager.cc", + ] + deps = [ "//base", - "//components/metrics:metrics", "//third_party/metrics_proto", ] }
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 586ee57..83e94db 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -30476,6 +30476,39 @@ ''', }, { + 'name': 'UnmanagedDeviceSignalsConsentFlowEnabled', + 'owners': ['xzonghan@chromium.org', 'cbe-device-trust-eng@google.com'], + 'type': 'main', + 'schema': { 'type': 'boolean' }, + 'future_on': [ + 'chrome.*' + ], + 'features': { + 'dynamic_refresh': True, + 'per_profile': True, + }, + 'items': [ + { + 'value': True, + 'caption': 'Enable device signal consenting for managed users on unmanaged devices', + }, + { + 'value': False, + 'caption': 'Disable device signal consenting for managed users on unmanaged devices', + }, + ], + 'default': False, + 'example_value': True, + 'id': 1001, + 'caption': '''Ask for consent from managed users to share device signals on unmanaged devices to gain access''', + 'tags': [], + 'desc': ''' + Setting the policy to Enabled (True) lets <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> asks for managed users' consent prior to sharing device signals on unmanaged devices in order to gain access. + + Setting the policy to Disabled (False) or leaving it unset disallows <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> from collecting device signals + Examples of device signals include (but are not limited to) OS information, registry, file presesnce.''', + }, + { 'name': 'LockIconInAddressBarEnabled', 'owners': ['meacer@chromium.org', 'trusty-transport@chromium.org'], 'type': 'main', @@ -33528,6 +33561,6 @@ 'placeholders': [], 'deleted_policy_ids': [114, 115, 204, 205, 206, 341, 412, 438, 476, 544, 546, 562, 569, 578, 583, 585, 586, 587, 588, 589, 590, 591, 600, 668, 669, 872], 'deleted_atomic_policy_group_ids': [19], - 'highest_id_currently_used': 1000, + 'highest_id_currently_used': 1001, 'highest_atomic_group_id_currently_used': 43 }
diff --git a/components/power_bookmarks/core/BUILD.gn b/components/power_bookmarks/core/BUILD.gn index e8ff9fb8..57f07d7 100644 --- a/components/power_bookmarks/core/BUILD.gn +++ b/components/power_bookmarks/core/BUILD.gn
@@ -10,6 +10,9 @@ static_library("core") { sources = [ + "power_bookmark_data_provider.h", + "power_bookmark_service.cc", + "power_bookmark_service.h", "power_bookmark_utils.cc", "power_bookmark_utils.h", ] @@ -21,6 +24,7 @@ "//base:i18n", "//components/bookmarks/browser", "//components/commerce/core:proto", + "//components/keyed_service/core:core", "//ui/base", "//url", ]
diff --git a/components/power_bookmarks/core/DEPS b/components/power_bookmarks/core/DEPS index 61e1691d..228f1ea2 100644 --- a/components/power_bookmarks/core/DEPS +++ b/components/power_bookmarks/core/DEPS
@@ -1,4 +1,5 @@ include_rules = [ "+components/bookmarks", + "+components/keyed_service", "+ui/base", ] \ No newline at end of file
diff --git a/components/power_bookmarks/core/power_bookmark_data_provider.h b/components/power_bookmarks/core/power_bookmark_data_provider.h new file mode 100644 index 0000000..473e783 --- /dev/null +++ b/components/power_bookmarks/core/power_bookmark_data_provider.h
@@ -0,0 +1,27 @@ +// Copyright 2022 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_POWER_BOOKMARKS_CORE_POWER_BOOKMARK_DATA_PROVIDER_H_ +#define COMPONENTS_POWER_BOOKMARKS_CORE_POWER_BOOKMARK_DATA_PROVIDER_H_ + +namespace bookmarks { +class BookmarkNode; +} + +namespace power_bookmarks { + +class PowerBookmarkMeta; + +class PowerBookmarkDataProvider { + public: + // Allow features the opportunity to add metadata to `meta` when a bookmark + // `node` is created. The `meta` object is attached to and stored with the + // bookmark. + virtual void AttachMetadataForNewBookmark(const bookmarks::BookmarkNode* node, + PowerBookmarkMeta* meta) = 0; +}; + +} // namespace power_bookmarks + +#endif // COMPONENTS_POWER_BOOKMARKS_CORE_POWER_BOOKMARK_DATA_PROVIDER_H_ \ No newline at end of file
diff --git a/components/power_bookmarks/core/power_bookmark_service.cc b/components/power_bookmarks/core/power_bookmark_service.cc new file mode 100644 index 0000000..7b9b35a --- /dev/null +++ b/components/power_bookmarks/core/power_bookmark_service.cc
@@ -0,0 +1,25 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/power_bookmarks/core/power_bookmark_service.h" + +namespace power_bookmarks { + +PowerBookmarkService::PowerBookmarkService() = default; +PowerBookmarkService::~PowerBookmarkService() = default; + +void PowerBookmarkService::AddDataProvider( + PowerBookmarkDataProvider* data_provider) { + data_providers_.emplace_back(data_provider); +} + +void PowerBookmarkService::RemoveDataProvider( + PowerBookmarkDataProvider* data_provider) { + auto it = + std::find(data_providers_.begin(), data_providers_.end(), data_provider); + if (it != data_providers_.end()) + data_providers_.erase(it); +} + +} // namespace power_bookmarks \ No newline at end of file
diff --git a/components/power_bookmarks/core/power_bookmark_service.h b/components/power_bookmarks/core/power_bookmark_service.h new file mode 100644 index 0000000..277e571 --- /dev/null +++ b/components/power_bookmarks/core/power_bookmark_service.h
@@ -0,0 +1,32 @@ +// Copyright 2022 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_POWER_BOOKMARKS_CORE_POWER_BOOKMARK_SERVICE_H_ +#define COMPONENTS_POWER_BOOKMARKS_CORE_POWER_BOOKMARK_SERVICE_H_ + +#include <vector> + +#include "components/keyed_service/core/keyed_service.h" +#include "components/power_bookmarks/core/power_bookmark_data_provider.h" + +namespace power_bookmarks { + +class PowerBookmarkService : public KeyedService { + public: + PowerBookmarkService(); + ~PowerBookmarkService() override; + + // Allow features to receive notification when a bookmark node is created to + // add extra information. The `data_provider` can be removed with the remove + // method. + void AddDataProvider(PowerBookmarkDataProvider* data_provider); + void RemoveDataProvider(PowerBookmarkDataProvider* data_provider); + + private: + std::vector<PowerBookmarkDataProvider*> data_providers_; +}; + +} // namespace power_bookmarks + +#endif // COMPONENTS_POWER_BOOKMARKS_CORE_POWER_BOOKMARK_SERVICE_H_ \ No newline at end of file
diff --git a/components/reporting/README.md b/components/reporting/README.md index d0a577f..2a34368 100644 --- a/components/reporting/README.md +++ b/components/reporting/README.md
@@ -23,9 +23,22 @@ 1. Run `autoninja -C out/Default components_unittests` to build the components unit test executable. -1. Then, run `out/Default/components_unittests --gtest_filter='<target tests>'` to - run relevant tests. Here, `<target tests>` is a wildcard pattern (refer to +1. Then, run `out/Default/components_unittests --gtest_filter='<target tests>'` + to run relevant tests. Here, `<target tests>` is a wildcard pattern (refer to the document of gtest for more details). For example, to run all tests for `StorageQueue`, run $ out/Default/components_unittests --gtest_filter='*/StorageQueueTest.*' + + For another example, to run all tests in this directory, run + + $ tools/autotest.py -C out/Default --run_all components/reporting + + You can also append a filter such as `--gtest_filter='*/StorageQueueTest.*'` + to the line above. + + Another useful flag for dealing with flaky tests is `--gtest_repeat=`, which + repeats tests for multiple times. + + For more gtest features, check out + [the gtest document](https://google.github.io/googletest/advanced.html).
diff --git a/components/reporting/storage/storage_queue_unittest.cc b/components/reporting/storage/storage_queue_unittest.cc index d255a46..34d54f0 100644 --- a/components/reporting/storage/storage_queue_unittest.cc +++ b/components/reporting/storage/storage_queue_unittest.cc
@@ -1823,11 +1823,15 @@ CreateTestStorageQueueOrDie(BuildStorageQueueOptionsPeriodic()); WriteStringOrDie(kData[0]); + const auto original_total_memory = options_.memory_resource()->GetTotal(); + // Set uploader expectations. test::TestCallbackAutoWaiter waiter; EXPECT_CALL(set_mock_uploader_expectations_, Call(Eq(UploaderInterface::UploadReason::PERIODIC))) .WillOnce(Invoke([&waiter, this](UploaderInterface::UploadReason reason) { + // Update total memory to a low amount. + options_.memory_resource()->Test_SetTotal(100u); return TestUploader::SetUp(&waiter, this) .Complete(Status(error::RESOURCE_EXHAUSTED, "Insufficient memory for upload")); @@ -1835,21 +1839,19 @@ .RetiresOnSaturation(); EXPECT_CALL(set_mock_uploader_expectations_, Call(Eq(UploaderInterface::UploadReason::FAILURE_RETRY))) - .WillOnce(Invoke([&waiter, this](UploaderInterface::UploadReason reason) { + .WillOnce(Invoke([&waiter, &original_total_memory, + this](UploaderInterface::UploadReason reason) { + // Reset after running upload so it does not affect other tests. + options_.memory_resource()->Test_SetTotal(original_total_memory); return TestUploader::SetUp(&waiter, this) .Required(0, kData[0]) .Complete(); })) .RetiresOnSaturation(); - // Update total memory to a low amount. - const auto original_total_memory = options_.memory_resource()->GetTotal(); - options_.memory_resource()->Test_SetTotal(100); - // Trigger upload. + // Trigger upload which will experience insufficient memory. task_environment_.FastForwardBy(base::Seconds(1)); - // Reset after running upload so it does not affect other tests. - options_.memory_resource()->Test_SetTotal(original_total_memory); - // Trigger another upload. + // Trigger another upload resetting the memory resource. task_environment_.FastForwardBy(base::Seconds(1)); }
diff --git a/components/services/app_service/public/cpp/intent_util.cc b/components/services/app_service/public/cpp/intent_util.cc index 5f047360..9bed98f1 100644 --- a/components/services/app_service/public/cpp/intent_util.cc +++ b/components/services/app_service/public/cpp/intent_util.cc
@@ -96,6 +96,7 @@ const char kIntentActionPotentialFileHandler[] = "potential_file_handler"; const char kUseBrowserForLink[] = "use_browser"; +const char kGuestOsActivityName[] = "open-with"; apps::IntentPtr MakeShareIntent(const std::vector<GURL>& filesystem_urls, const std::vector<std::string>& mime_types) {
diff --git a/components/services/app_service/public/cpp/intent_util.h b/components/services/app_service/public/cpp/intent_util.h index 1afa5bd..fc17fad 100644 --- a/components/services/app_service/public/cpp/intent_util.h +++ b/components/services/app_service/public/cpp/intent_util.h
@@ -36,6 +36,10 @@ // will open the link, and that we should not prompt the user about it. extern const char kUseBrowserForLink[]; +// Activity name for GuestOS intent filters. TODO(crbug/1349974): Remove when +// default file handling preferences for Files App are migrated. +extern const char kGuestOsActivityName[]; + struct SharedText { std::string text; GURL url;
diff --git a/components/services/app_service/public/cpp/publisher_base.h b/components/services/app_service/public/cpp/publisher_base.h index d5e49519..a52540e8 100644 --- a/components/services/app_service/public/cpp/publisher_base.h +++ b/components/services/app_service/public/cpp/publisher_base.h
@@ -16,7 +16,7 @@ namespace apps { -// An publisher parent class (in the App Service sense) for all app publishers. +// A publisher parent class (in the App Service sense) for all app publishers. // This class has NOTIMPLEMENTED() implementations of mandatory methods from the // apps::mojom::Publisher class to simplify the process of adding a new // publisher.
diff --git a/components/services/patch/BUILD.gn b/components/services/patch/BUILD.gn index d0bb33f..a7ade6d 100644 --- a/components/services/patch/BUILD.gn +++ b/components/services/patch/BUILD.gn
@@ -1,6 +1,7 @@ # Copyright 2017 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//components/update_client/buildflags.gni") source_set("lib") { sources = [ @@ -11,10 +12,16 @@ deps = [ "//base", "//components/services/filesystem/public/mojom", + "//components/update_client:buildflags", "//courgette:courgette_lib", "//mojo/public/cpp/bindings", ] + if (enable_puffin_patches) { + include_dirs = [ "//third_party/puffin/src/include" ] + deps += [ "//third_party/puffin:libpuffpatch" ] + } + public_deps = [ "//components/services/patch/public/mojom" ] }
diff --git a/components/services/patch/DEPS b/components/services/patch/DEPS index 5b3aea1..f2759258 100644 --- a/components/services/patch/DEPS +++ b/components/services/patch/DEPS
@@ -2,4 +2,5 @@ "+components/update_client", "+courgette", "+mojo/public", + "+third_party/puffin", ]
diff --git a/components/services/patch/file_patcher_impl.cc b/components/services/patch/file_patcher_impl.cc index 1f0febc..6eca40e 100644 --- a/components/services/patch/file_patcher_impl.cc +++ b/components/services/patch/file_patcher_impl.cc
@@ -4,9 +4,20 @@ #include "components/services/patch/file_patcher_impl.h" +#include <utility> + +#include "base/callback.h" +#include "base/notreached.h" +#include "components/update_client/buildflags.h" #include "courgette/courgette.h" #include "courgette/third_party/bsdiff/bsdiff.h" +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) +// TODO(crbug.com/1349060) once Puffin patches are fully implemented, +// we should remove this #if +#include "third_party/puffin/puffin/src/include/puffin/puffpatch.h" +#endif + namespace patch { FilePatcherImpl::FilePatcherImpl() = default; @@ -17,6 +28,8 @@ FilePatcherImpl::~FilePatcherImpl() = default; +// TODO(crbug.com/1349158): Remove this function once PatchFilePuffPatch is +// implemented as this becomes obsolete. void FilePatcherImpl::PatchFileBsdiff(base::File input_file, base::File patch_file, base::File output_file, @@ -30,6 +43,8 @@ std::move(callback).Run(patch_result_status); } +// TODO(crbug.com/1349158): Remove this function once PatchFilePuffPatch is +// implemented as this becomes obsolete. void FilePatcherImpl::PatchFileCourgette(base::File input_file, base::File patch_file, base::File output_file, @@ -43,4 +58,19 @@ std::move(callback).Run(patch_result_status); } +void FilePatcherImpl::PatchFilePuffPatch(base::File input_file, + base::File patch_file, + base::File output_file, + PatchFilePuffPatchCallback callback) { +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) + // TODO(crbug.com/1349060) once Puffin patches are fully implemented, + // we should remove this #if. + const int patch_result_status = puffin::ApplyPuffPatch( + std::move(input_file), std::move(patch_file), std::move(output_file)); + std::move(callback).Run(patch_result_status); +#else + NOTREACHED(); +#endif +} + } // namespace patch
diff --git a/components/services/patch/file_patcher_impl.h b/components/services/patch/file_patcher_impl.h index 3b55121c..e0e3ebf 100644 --- a/components/services/patch/file_patcher_impl.h +++ b/components/services/patch/file_patcher_impl.h
@@ -10,6 +10,10 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" +namespace base { +class File; +} // namespace base + namespace patch { class FilePatcherImpl : public mojom::FilePatcher { @@ -36,6 +40,10 @@ base::File patch_file, base::File output_file, PatchFileCourgetteCallback callback) override; + void PatchFilePuffPatch(base::File input_file_path, + base::File patch_file_path, + base::File output_file_path, + PatchFilePuffPatchCallback callback) override; mojo::Receiver<mojom::FilePatcher> receiver_{this}; };
diff --git a/components/services/patch/public/cpp/BUILD.gn b/components/services/patch/public/cpp/BUILD.gn index 5dd93bb..922eb8f2 100644 --- a/components/services/patch/public/cpp/BUILD.gn +++ b/components/services/patch/public/cpp/BUILD.gn
@@ -12,4 +12,6 @@ "//components/services/patch/public/mojom", "//mojo/public/cpp/bindings", ] + + deps = [ "//components/update_client:buildflags" ] }
diff --git a/components/services/patch/public/cpp/patch.cc b/components/services/patch/public/cpp/patch.cc index e40a288..7bd6bd1 100644 --- a/components/services/patch/public/cpp/patch.cc +++ b/components/services/patch/public/cpp/patch.cc
@@ -11,10 +11,12 @@ #include "base/callback.h" #include "base/files/file.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" #include "base/task/sequenced_task_runner.h" #include "base/threading/sequenced_task_runner_handle.h" +#include "components/update_client/buildflags.h" #include "components/update_client/component_patcher_operation.h" // nogncheck #include "mojo/public/cpp/bindings/remote.h" @@ -57,6 +59,8 @@ } // namespace +// TODO(crbug.com/1349158): Remove this function once PatchFilePuffPatch is +// implemented as this becomes obsolete. void Patch(mojo::PendingRemote<mojom::FilePatcher> file_patcher, const std::string& operation, const base::FilePath& input_path, @@ -82,8 +86,8 @@ // In order to share |callback| between the connection error handler and the // FilePatcher calls, we have to use a context object. - scoped_refptr<PatchParams> patch_params = - new PatchParams(std::move(file_patcher), std::move(callback)); + scoped_refptr<PatchParams> patch_params = base::MakeRefCounted<PatchParams>( + std::move(file_patcher), std::move(callback)); patch_params->file_patcher().set_disconnect_handler( base::BindOnce(&PatchDone, patch_params, /*result=*/-1)); @@ -101,4 +105,26 @@ } } +void PuffPatch(mojo::PendingRemote<mojom::FilePatcher> file_patcher, + base::File input_file, + base::File patch_file, + base::File output_file, + PatchCallback callback) { +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) + // TODO(crbug.com/1349060) once Puffin patches are fully implemented, + // we should remove this #if. + + // Use a context object to share callback. + scoped_refptr<PatchParams> patch_params = base::MakeRefCounted<PatchParams>( + std::move(file_patcher), std::move(callback)); + + patch_params->file_patcher().set_disconnect_handler( + base::BindOnce(&PatchDone, patch_params, /*result=*/-1)); + + patch_params->file_patcher()->PatchFilePuffPatch( + std::move(input_file), std::move(patch_file), std::move(output_file), + base::BindOnce(&PatchDone, patch_params)); +#endif +} + } // namespace patch
diff --git a/components/services/patch/public/cpp/patch.h b/components/services/patch/public/cpp/patch.h index 94c0b197..ba1b404 100644 --- a/components/services/patch/public/cpp/patch.h +++ b/components/services/patch/public/cpp/patch.h
@@ -27,6 +27,14 @@ const base::FilePath& output_abs_path, PatchCallback callback); +// Patches |input_abs_path| with |patch_abs_path| using the |operation| +// algorithm and place the output in |output_abs_path|. +void PuffPatch(mojo::PendingRemote<mojom::FilePatcher> file_patcher, + base::File input_abs_path, + base::File patch_abs_path, + base::File output_abs_path, + PatchCallback callback); + } // namespace patch #endif // COMPONENTS_SERVICES_PATCH_PUBLIC_CPP_PATCH_H_
diff --git a/components/services/patch/public/mojom/file_patcher.mojom b/components/services/patch/public/mojom/file_patcher.mojom index 1bd048e..9850dfa 100644 --- a/components/services/patch/public/mojom/file_patcher.mojom +++ b/components/services/patch/public/mojom/file_patcher.mojom
@@ -6,6 +6,7 @@ import "mojo/public/mojom/base/file.mojom"; import "mojo/public/mojom/base/read_only_file.mojom"; +import "mojo/public/mojom/base/file_path.mojom"; import "sandbox/policy/mojom/sandbox.mojom"; // Interface to the out-of-process file patcher. The file patcher runs @@ -28,4 +29,12 @@ mojo_base.mojom.ReadOnlyFile input_file, mojo_base.mojom.ReadOnlyFile patch_file, mojo_base.mojom.File output_file) => (int32 result); + + // Patch |input_file_path| with |patch_file_path| using the Puffin PuffPatch + // algorithm and place the output in |output_file_path|. + // Returns |result| puffin::Status::P_OK on success. + PatchFilePuffPatch( + mojo_base.mojom.ReadOnlyFile input_file, + mojo_base.mojom.ReadOnlyFile patch_file, + mojo_base.mojom.File output_file) => (int32 result); };
diff --git a/components/soda/soda_installer.cc b/components/soda/soda_installer.cc index e2d99ea..c078994 100644 --- a/components/soda/soda_installer.cc +++ b/components/soda/soda_installer.cc
@@ -176,7 +176,8 @@ NotifyOnSodaInstalled(language_code); } -void SodaInstaller::NotifySodaErrorForTesting(LanguageCode language_code) { +void SodaInstaller::NotifySodaErrorForTesting(LanguageCode language_code, + ErrorCode error_code) { // TODO: Call the actual functions in SodaInstallerImpl and // SodaInstallerImpleChromeOS that do this logic rather than faking it. if (language_code == LanguageCode::kNone) { @@ -189,7 +190,7 @@ if (base::Contains(language_pack_progress_, language_code)) language_pack_progress_.erase(language_code); } - NotifyOnSodaError(language_code); + NotifyOnSodaInstallError(language_code, error_code); } void SodaInstaller::UninstallSodaForTesting() { @@ -236,9 +237,10 @@ observer.OnSodaInstalled(language_code); } -void SodaInstaller::NotifyOnSodaError(LanguageCode language_code) { +void SodaInstaller::NotifyOnSodaInstallError(LanguageCode language_code, + ErrorCode error_code) { for (Observer& observer : observers_) - observer.OnSodaError(language_code); + observer.OnSodaInstallError(language_code, error_code); } void SodaInstaller::NotifyOnSodaProgress(LanguageCode language_code,
diff --git a/components/soda/soda_installer.h b/components/soda/soda_installer.h index d406e25..7dc52b2 100644 --- a/components/soda/soda_installer.h +++ b/components/soda/soda_installer.h
@@ -25,6 +25,12 @@ // trying to access the SodaInstaller instance. class COMPONENT_EXPORT(SODA_INSTALLER) SodaInstaller { public: + // Error codes passed to the observers. + enum class ErrorCode { + kUnspecifiedError, // a default error. + kNeedsReboot, // libsoda requires an OS reboot on ChromeOS. + }; + // Observer of the SODA (Speech On-Device API) installation. class Observer : public base::CheckedObserver { public: @@ -35,7 +41,8 @@ // Called if there is an error in the SODA installation. If the language // code is LanguageCode::kNone, the error is for the SODA binary; otherwise // it is for the language pack. - virtual void OnSodaError(LanguageCode language_code) = 0; + virtual void OnSodaInstallError(LanguageCode language_code, + ErrorCode error_code) = 0; // Called during the SODA installation. Progress is the weighted average of // the combined download percentage of the SODA binary and the language pack @@ -113,7 +120,8 @@ void NotifySodaInstalledForTesting( LanguageCode language_code = LanguageCode::kNone); void NotifySodaErrorForTesting( - LanguageCode language_code = LanguageCode::kNone); + LanguageCode language_code = LanguageCode::kNone, + ErrorCode error = ErrorCode::kUnspecifiedError); void UninstallSodaForTesting(); void NotifySodaProgressForTesting( int progress, @@ -139,7 +147,8 @@ // Notifies the observers that there is an error in the SODA installation. // If the language code is LanguageCode::kNone, the error is for the SODA // binary; otherwise it is for the language pack. - void NotifyOnSodaError(LanguageCode language_code); + void NotifyOnSodaInstallError(LanguageCode language_code, + ErrorCode error_code); // Notifies the observers of the combined progress as the SODA binary and // language pack are installed. Progress is the download percentage out of
diff --git a/components/soda/soda_installer_impl_chromeos.cc b/components/soda/soda_installer_impl_chromeos.cc index 156f99d..37c3d510 100644 --- a/components/soda/soda_installer_impl_chromeos.cc +++ b/components/soda/soda_installer_impl_chromeos.cc
@@ -4,6 +4,8 @@ #include "components/soda/soda_installer_impl_chromeos.h" +#include <string> + #include "base/bind.h" #include "base/containers/contains.h" #include "base/feature_list.h" @@ -14,17 +16,23 @@ #include "components/live_caption/pref_names.h" #include "components/prefs/pref_service.h" #include "components/soda/pref_names.h" +#include "components/soda/soda_installer.h" #include "media/base/media_switches.h" #include "ui/base/l10n/l10n_util.h" +namespace speech { namespace { constexpr char kSodaDlcName[] = "libsoda"; constexpr char kSodaEnglishUsDlcName[] = "libsoda-model-en-us"; -} // namespace +SodaInstaller::ErrorCode DlcCodeToSodaErrorCode(const std::string& code) { + return (code == dlcservice::kErrorNeedReboot) + ? SodaInstaller::ErrorCode::kNeedsReboot + : SodaInstaller::ErrorCode::kUnspecifiedError; +} -namespace speech { +} // namespace SodaInstallerImplChromeOS::SodaInstallerImplChromeOS() = default; @@ -142,7 +150,8 @@ } else { soda_binary_installed_ = false; soda_progress_ = 0.0; - NotifyOnSodaError(LanguageCode::kNone); + NotifyOnSodaInstallError(LanguageCode::kNone, + DlcCodeToSodaErrorCode(install_result.error)); base::UmaHistogramTimes(kSodaBinaryInstallationFailureTimeTaken, base::Time::Now() - start_time); } @@ -169,7 +178,8 @@ } else { // TODO: Notify the observer of the specific language pack that failed // to install. ChromeOS currently only supports the en-US language pack. - NotifyOnSodaError(language_code); + NotifyOnSodaInstallError(language_code, + DlcCodeToSodaErrorCode(install_result.error)); base::UmaHistogramTimes( GetInstallationFailureTimeMetricForLanguagePack(language_code),
diff --git a/components/soda/soda_installer_impl_chromeos_unittest.cc b/components/soda/soda_installer_impl_chromeos_unittest.cc index d63efb72..8c00089 100644 --- a/components/soda/soda_installer_impl_chromeos_unittest.cc +++ b/components/soda/soda_installer_impl_chromeos_unittest.cc
@@ -9,7 +9,6 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" -#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dlcservice/fake_dlcservice_client.h" #include "components/live_caption/pref_names.h" #include "components/prefs/testing_pref_service.h" @@ -48,7 +47,6 @@ pref_service_->registry()->RegisterStringPref( prefs::kLiveCaptionLanguageCode, kUsEnglishLocale); - chromeos::DBusThreadManager::Initialize(); chromeos::DlcserviceClient::InitializeFake(); fake_dlcservice_client_ = static_cast<chromeos::FakeDlcserviceClient*>( chromeos::DlcserviceClient::Get()); @@ -57,7 +55,6 @@ void TearDown() override { soda_installer_impl_.reset(); pref_service_.reset(); - chromeos::DBusThreadManager::Shutdown(); chromeos::DlcserviceClient::Shutdown(); }
diff --git a/components/test/data/update_client/puffin_patch_test/BUILD.gn b/components/test/data/update_client/puffin_patch_test/BUILD.gn new file mode 100644 index 0000000..41c26bc --- /dev/null +++ b/components/test/data/update_client/puffin_patch_test/BUILD.gn
@@ -0,0 +1,71 @@ +# Copyright 2022 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("//components/crx_file/crx3.gni") + +group("puffin_patch_test_files") { + testonly = true + data_deps = [ + ":puff_patch_v1_to_v2", + ":puff_patch_v2_to_v1", + ":puffin_app_v1_crx", + ":puffin_app_v2_crx", + ] +} + +executable("puffin_app_v1_binary") { + testonly = true + sources = [ "puffin_app_v1/main.cc" ] +} + +executable("puffin_app_v2_binary") { + testonly = true + sources = [ "puffin_app_v2/main.cc" ] +} + +crx3("puffin_app_v1") { + base_dir = "$root_build_dir" + key = "//chrome/updater/test/data/selfupdate_test_key.der" + output = "$root_build_dir/puffin_app_v1_crx.crx3" + testonly = true + deps = [ ":puffin_app_v1_binary" ] + if (is_win) { + inputs = [ "$root_build_dir/puffin_app_v1_binary.exe" ] + } else { + inputs = [ "$root_build_dir/puffin_app_v1_binary" ] + } +} + +crx3("puffin_app_v2") { + base_dir = "$root_build_dir" + key = "//chrome/updater/test/data/selfupdate_test_key.der" + output = "$root_build_dir/puffin_app_v2_crx.crx3" + testonly = true + deps = [ ":puffin_app_v2_binary" ] + if (is_win) { + inputs = [ "$root_build_dir/puffin_app_v2_binary.exe" ] + } else { + inputs = [ "$root_build_dir/puffin_app_v2_binary" ] + } +} + +copy("puffin_app_v1_crx") { + sources = [ "puffin_app_v1.crx3" ] + outputs = [ "$root_build_dir/puffin_app_v1.crx3" ] +} + +copy("puffin_app_v2_crx") { + sources = [ "puffin_app_v2.crx3" ] + outputs = [ "$root_build_dir/puffin_app_v2.crx3" ] +} + +copy("puff_patch_v1_to_v2") { + sources = [ "puffin_app_v1_to_v2.puff" ] + outputs = [ "$root_build_dir/puffin_app_v1_to_v2.puff" ] +} + +copy("puff_patch_v2_to_v1") { + sources = [ "puffin_app_v2_to_v1.puff" ] + outputs = [ "$root_build_dir/puffin_app_v2_to_v1.puff" ] +}
diff --git a/components/test/data/update_client/puffin_patch_test/README.md b/components/test/data/update_client/puffin_patch_test/README.md new file mode 100644 index 0000000..cff9844 --- /dev/null +++ b/components/test/data/update_client/puffin_patch_test/README.md
@@ -0,0 +1,40 @@ +## How to regenerate linux, mac and windows test puff files: + +If changes are made to puffin_app_v1/main.cc or puffin_app_v2/main.cc, the various puff files which represent a patch between the crx's produced by each of these sources. Thus, we'll need to regenerate these on each platform. + +This README assumes you are already in your Chromium repo's src directory, that your gn args were generated in "src/out/Default", and that you are able to build the third_party/puffin:puffin target. To make sure puffin is building, for the time being we have to add the following to our gn args: + + enable_puffin_patches = true + +<!-- TODO(crbug.com/1349060) once the enable_puffin_patches build argument is removed, we should update this documentation. --> + +**Linux and Mac commands** + + autoninja -C out/Default puffin puffin_app_v1 puffin_app_v2 + rm components/test/data/update_client/puffin_patch_test/puffin_app_v1_to_v2.puff + rm components/test/data/update_client/puffin_patch_test/puffin_app_v2_to_v1.puff + out/Default/puffin -puffdiff out/Default/puffin_app_v1.crx3 out/Default/puffin_app_v2.crx3 components/test/data/update_client/puffin_patch_test/puffin_app_v1_to_v2.puff + out/Default/puffin -puffdiff out/Default/puffin_app_v2.crx3 out/Default/puffin_app_v1.crx3 components/test/data/update_client/puffin_patch_test/puffin_app_v2_to_v1.puff + cp out/Default/puffin_app_v1_crx.crx3 components/test/data/update_client/puffin_patch_test/puffin_app_v1.crx3 + cp out/Default/puffin_app_v2_crx.crx3 components/test/data/update_client/puffin_patch_test/puffin_app_v2.crx3 + +**Windows commands** + + autoninja -C out\Default puffin puffin_app_v1_crx puffin_app_v2_crx + del /f components\test\data\update_client\puffin_patch_test\puffin_app_v1_to_v2.puff + del /f components\test\data\update_client\puffin_patch_test\puffin_app_v2_to_v1.puff + out\Default\puffin.exe -puffdiff out\Default\puffin_app_v1.crx3 out\Default\puffin_app_v2.crx3 chrome\test\data\updater\puffin_patch_test\puffin_app_v1_to_v2.puff + out\Default\puffin.exe -puffdiff out\Default\puffin_app_v2.crx3 out\Default\puffin_app_v1.crx3 chrome\test\data\updater\puffin_patch_test\puffin_app_v2_to_v1.puff + cp out\Default\puffin_app_v1_crx.crx3 components\test\data\update_client\puffin_patch_test\puffin_app_v1.crx3 + cp out\Default\puffin_app_v2_crx.crx3 components\test\data\update_client\puffin_patch_test\puffin_app_v2.crx3 + +## Testing the new patches +You can test but running the following commands to verify if all tests pass, on each platform. Specifically the "PatchingTest.ApplyPuffPatchTest": + +**Mac and Linux:** + autoninja -C out/Default puffin_unittest + out/Default/puffin_unittest + +**Windows:** + autoninja -C out\Default puffin_unittest + out\Default\puffin_unittest.exe
diff --git a/components/test/data/update_client/puffin_patch_test/puffin_app_v1.crx3 b/components/test/data/update_client/puffin_patch_test/puffin_app_v1.crx3 new file mode 100644 index 0000000..d609bfdc --- /dev/null +++ b/components/test/data/update_client/puffin_patch_test/puffin_app_v1.crx3 Binary files differ
diff --git a/chrome/test/data/updater/puffin_patch_test/puffin_app_v1/main.cc b/components/test/data/update_client/puffin_patch_test/puffin_app_v1/main.cc similarity index 88% rename from chrome/test/data/updater/puffin_patch_test/puffin_app_v1/main.cc rename to components/test/data/update_client/puffin_patch_test/puffin_app_v1/main.cc index d85be81..263ac30 100644 --- a/chrome/test/data/updater/puffin_patch_test/puffin_app_v1/main.cc +++ b/components/test/data/update_client/puffin_patch_test/puffin_app_v1/main.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// The puffin patch test app is a do-nothing application "installer" that is +// The Puffin patch test app is a do-nothing application "installer" that is // embedded in an update CRX. This is version 1, version 2 is located at // ../puffin_app_v2. if you apply the puffpatch puffin_app_v1_to_v2.puff to // puffin_app_v1.crx3, it produces puffin_app_v2.crx3. See
diff --git a/components/test/data/update_client/puffin_patch_test/puffin_app_v1_to_v2.puff b/components/test/data/update_client/puffin_patch_test/puffin_app_v1_to_v2.puff new file mode 100644 index 0000000..88171d1e --- /dev/null +++ b/components/test/data/update_client/puffin_patch_test/puffin_app_v1_to_v2.puff Binary files differ
diff --git a/components/test/data/update_client/puffin_patch_test/puffin_app_v2.crx3 b/components/test/data/update_client/puffin_patch_test/puffin_app_v2.crx3 new file mode 100644 index 0000000..6b15b7f --- /dev/null +++ b/components/test/data/update_client/puffin_patch_test/puffin_app_v2.crx3 Binary files differ
diff --git a/chrome/test/data/updater/puffin_patch_test/puffin_app_v2/main.cc b/components/test/data/update_client/puffin_patch_test/puffin_app_v2/main.cc similarity index 88% rename from chrome/test/data/updater/puffin_patch_test/puffin_app_v2/main.cc rename to components/test/data/update_client/puffin_patch_test/puffin_app_v2/main.cc index f55c947..d682acc 100644 --- a/chrome/test/data/updater/puffin_patch_test/puffin_app_v2/main.cc +++ b/components/test/data/update_client/puffin_patch_test/puffin_app_v2/main.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// The puffin patch test app is a do-nothing application "installer" that is +// The Puffin patch test app is a do-nothing application "installer" that is // embedded in an update CRX. This is version 2, version 1 is located at // ../puffin_app_v1. If you apply the // puffpatch puffin_app_v1_to_v2.puff to puffin_app_v1.crx3, it produces
diff --git a/components/test/data/update_client/puffin_patch_test/puffin_app_v2_to_v1.puff b/components/test/data/update_client/puffin_patch_test/puffin_app_v2_to_v1.puff new file mode 100644 index 0000000..8101ef9 --- /dev/null +++ b/components/test/data/update_client/puffin_patch_test/puffin_app_v2_to_v1.puff Binary files differ
diff --git a/components/update_client/BUILD.gn b/components/update_client/BUILD.gn index 6b4f654..e24cc2f0 100644 --- a/components/update_client/BUILD.gn +++ b/components/update_client/BUILD.gn
@@ -2,9 +2,16 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/buildflag_header.gni") +import("//components/update_client/buildflags.gni") import("//net/features.gni") import("//testing/libfuzzer/fuzzer_test.gni") +buildflag_header("buildflags") { + header = "buildflags.h" + flags = [ "ENABLE_PUFFIN_PATCHES=$enable_puffin_patches" ] +} + source_set("network_impl") { sources = [ "net/network_chromium.h", @@ -39,6 +46,7 @@ "patch/in_process_patcher.h", ] deps = [ + ":buildflags", ":update_client", "//base", "//courgette:bsdiff", @@ -63,6 +71,7 @@ "patch/patch_impl.h", ] deps = [ + ":buildflags", ":update_client", "//build:chromeos_buildflags", "//components/services/patch/public/cpp", @@ -165,6 +174,18 @@ "background_downloader_win.h", ] } + + # TODO(crbug.com/1349060) once Puffin patches are fully implemented, + # we should remove the enable_puffin_patches flag. + if (enable_puffin_patches) { + include_dirs = [ "//third_party/puffin/src/include" ] + sources += [ + "puffin_component_unpacker.cc", + "puffin_component_unpacker.h", + "puffin_patcher.cc", + "puffin_patcher.h", + ] + } } static_library("test_support") { @@ -276,6 +297,17 @@ "//testing/gtest", "//third_party/re2", ] + + # TODO(crbug.com/1349060) once Puffin patches are fully implemented, + # we should remove the enable_puffin_patches flag. + if (enable_puffin_patches) { + sources += [ + "puffin_component_unpacker_unittest.cc", + "puffin_patcher_unittest.cc", + ] + deps += [ "//third_party/puffin:libpuffpatch" ] + data_deps = [ "//components/test/data/update_client/puffin_patch_test:puffin_patch_test_files" ] + } } fuzzer_test("update_client_protocol_serializer_fuzzer") {
diff --git a/components/update_client/DEPS b/components/update_client/DEPS index f226ca9..6878ba4 100644 --- a/components/update_client/DEPS +++ b/components/update_client/DEPS
@@ -8,6 +8,7 @@ "+courgette", "+crypto", "+mojo/public", + "+third_party/puffin", "+third_party/re2", "+third_party/zlib", ]
diff --git a/components/update_client/buildflags.gni b/components/update_client/buildflags.gni new file mode 100644 index 0000000..fdbc7e1 --- /dev/null +++ b/components/update_client/buildflags.gni
@@ -0,0 +1,9 @@ +# Copyright 2022 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. + +declare_args() { + # Whether to enable the Puffin PuffPatch feature which is currently still + # in development. + enable_puffin_patches = false +}
diff --git a/components/update_client/component_patcher.h b/components/update_client/component_patcher.h index 8b01f7fa..41dc3f11 100644 --- a/components/update_client/component_patcher.h +++ b/components/update_client/component_patcher.h
@@ -34,6 +34,9 @@ #include "base/values.h" #include "components/update_client/component_unpacker.h" +// TODO(crbug.com/1349158): Remove this class once Puffin patches are fully +// implemented. + namespace base { class FilePath; }
diff --git a/components/update_client/component_patcher_operation.h b/components/update_client/component_patcher_operation.h index 66d4447a..78e4fa2 100644 --- a/components/update_client/component_patcher_operation.h +++ b/components/update_client/component_patcher_operation.h
@@ -13,6 +13,9 @@ #include "components/update_client/component_patcher.h" #include "components/update_client/component_unpacker.h" +// TODO(crbug.com/1349158): Remove this file once Puffin patches are fully +// implemented. + namespace base { class DictionaryValue; } // namespace base
diff --git a/components/update_client/component_patcher_unittest.h b/components/update_client/component_patcher_unittest.h index 3299619..ba9b780 100644 --- a/components/update_client/component_patcher_unittest.h +++ b/components/update_client/component_patcher_unittest.h
@@ -13,6 +13,9 @@ #include "courgette/third_party/bsdiff/bsdiff.h" #include "testing/gtest/include/gtest/gtest.h" +// TODO(crbug.com/1349158): Remove this file once Puffin patches are fully +// implemented. + namespace update_client { class ReadOnlyTestInstaller;
diff --git a/components/update_client/component_unpacker.h b/components/update_client/component_unpacker.h index 1a735471..a68e3a9 100644 --- a/components/update_client/component_unpacker.h +++ b/components/update_client/component_unpacker.h
@@ -16,6 +16,9 @@ #include "base/memory/ref_counted.h" #include "components/update_client/update_client_errors.h" +// TODO(crbug.com/1349158): Remove this class once Puffin patches are fully +// implemented. + namespace crx_file { enum class VerifierFormat; }
diff --git a/components/update_client/patch/in_process_patcher.cc b/components/update_client/patch/in_process_patcher.cc index 17d6c99..c3afd2e 100644 --- a/components/update_client/patch/in_process_patcher.cc +++ b/components/update_client/patch/in_process_patcher.cc
@@ -10,6 +10,8 @@ #include "base/files/file.h" #include "base/files/file_path.h" #include "base/memory/scoped_refptr.h" +#include "base/notreached.h" +#include "components/update_client/buildflags.h" #include "courgette/courgette.h" #include "courgette/third_party/bsdiff/bsdiff.h" @@ -21,6 +23,8 @@ public: InProcessPatcher() = default; + // TODO(crbug.com/1349158): Remove this function once PatchPuffPatch is + // implemented as this becomes obsolete. void PatchBsdiff(const base::FilePath& input_path, const base::FilePath& patch_path, const base::FilePath& output_path, @@ -41,6 +45,8 @@ std::move(input_file), std::move(patch_file), std::move(output_file))); } + // TODO(crbug.com/1349158): Remove this function once PatchPuffPatch is + // implemented as this becomes obsolete. void PatchCourgette(const base::FilePath& input_path, const base::FilePath& patch_path, const base::FilePath& output_path, @@ -61,6 +67,20 @@ std::move(input_file), std::move(patch_file), std::move(output_file))); } + void PatchPuffPatch(base::File input_file, + base::File patch_file, + base::File output_file, + PatchCompleteCallback callback) const override { +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) + // TODO(crbug.com/1349060) once Puffin patches are fully implemented, + // we should remove this #if. + std::move(callback).Run(puffin::ApplyPuffPatch( + std::move(input_file), std::move(patch_file), std::move(output_file))); +#else + NOTREACHED(); +#endif + } + protected: ~InProcessPatcher() override = default; };
diff --git a/components/update_client/patch/patch_impl.cc b/components/update_client/patch/patch_impl.cc index 599101f..9c020a9 100644 --- a/components/update_client/patch/patch_impl.cc +++ b/components/update_client/patch/patch_impl.cc
@@ -4,7 +4,11 @@ #include "components/update_client/patch/patch_impl.h" +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/notreached.h" #include "components/services/patch/public/cpp/patch.h" +#include "components/update_client/buildflags.h" #include "components/update_client/component_patcher_operation.h" namespace update_client { @@ -32,6 +36,21 @@ patch_file, destination, std::move(callback)); } + void PatchPuffPatch(base::File old_file, + base::File patch_file, + base::File destination_file, + PatchCompleteCallback callback) const override { +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) + // TODO(crbug.com/1349060) once Puffin patches are fully implemented, + // we should remove this #if. + patch::PuffPatch(callback_.Run(), std::move(old_file), + std::move(patch_file), std::move(destination_file), + std::move(callback)); +#else + NOTREACHED(); +#endif + } + protected: ~PatcherImpl() override = default;
diff --git a/components/update_client/patcher.h b/components/update_client/patcher.h index 604c2b2..55eea78 100644 --- a/components/update_client/patcher.h +++ b/components/update_client/patcher.h
@@ -10,6 +10,7 @@ namespace base { class FilePath; +class File; } // namespace base namespace update_client { @@ -31,6 +32,11 @@ const base::FilePath& destination, PatchCompleteCallback callback) const = 0; + virtual void PatchPuffPatch(base::File input_file_path, + base::File patch_file_path, + base::File output_file_path, + PatchCompleteCallback callback) const = 0; + protected: friend class base::RefCountedThreadSafe<Patcher>; Patcher() = default;
diff --git a/components/update_client/puffin_component_unpacker.cc b/components/update_client/puffin_component_unpacker.cc new file mode 100644 index 0000000..973bd09 --- /dev/null +++ b/components/update_client/puffin_component_unpacker.cc
@@ -0,0 +1,121 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/update_client/puffin_component_unpacker.h" + +#include <stdint.h> +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/memory/scoped_refptr.h" +#include "base/sequence_checker.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "components/crx_file/crx_verifier.h" +#include "components/update_client/unzipper.h" +#include "components/update_client/update_client.h" +#include "components/update_client/update_client_errors.h" + +namespace update_client { + +PuffinComponentUnpacker::Result::Result() = default; + +PuffinComponentUnpacker::PuffinComponentUnpacker( + const std::vector<uint8_t>& pk_hash, + const base::FilePath& path, + std::unique_ptr<Unzipper> unzipper, + crx_file::VerifierFormat crx_format, + base::OnceCallback<void(const Result& result)> callback) + : pk_hash_(pk_hash), + path_(path), + unzipper_(std::move(unzipper)), + crx_format_(crx_format), + callback_(std::move(callback)) {} + +PuffinComponentUnpacker::~PuffinComponentUnpacker() = default; + +void PuffinComponentUnpacker::Unpack( + const std::vector<uint8_t>& pk_hash, + const base::FilePath& path, + std::unique_ptr<Unzipper> unzipper, + crx_file::VerifierFormat crx_format, + base::OnceCallback<void(const Result& result)> callback) { + scoped_refptr<PuffinComponentUnpacker> unpacker = + base::WrapRefCounted(new PuffinComponentUnpacker( + pk_hash, path, std::move(unzipper), crx_format, std::move(callback))); + unpacker->Verify(); +} + +void PuffinComponentUnpacker::Verify() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + VLOG(1) << "Verifying component: " << path_.value(); + if (path_.empty()) { + EndUnpacking(UnpackerError::kInvalidParams, 0); + return; + } + std::vector<std::vector<uint8_t>> required_keys; + if (!pk_hash_.empty()) + required_keys.push_back(pk_hash_); + const crx_file::VerifierResult result = crx_file::Verify( + path_, crx_format_, required_keys, std::vector<uint8_t>(), &public_key_, + /*crx_id=*/nullptr, /*compressed_verified_contents=*/nullptr); + if (result != crx_file::VerifierResult::OK_FULL) { + EndUnpacking(UnpackerError::kInvalidFile, static_cast<int>(result)); + return; + } + VLOG(2) << "Verification successful: " << path_.value(); + BeginUnzipping(); +} + +void PuffinComponentUnpacker::BeginUnzipping() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + base::FilePath& destination = unpack_path_; + if (!base::CreateNewTempDirectory(base::FilePath::StringType(), + &destination)) { + VLOG(1) << "Unable to create temporary directory for unpacking."; + EndUnpacking(UnpackerError::kUnzipPathError, 0); + return; + } + VLOG(1) << "Unpacking in: " << destination.value(); + unzipper_->Unzip( + path_, destination, + base::BindOnce(&PuffinComponentUnpacker::EndUnzipping, this)); +} + +void PuffinComponentUnpacker::EndUnzipping(bool result) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!result) { + VLOG(1) << "Unzipping failed."; + EndUnpacking(UnpackerError::kUnzipFailed, 0); + return; + } + VLOG(2) << "Unzipped successfully"; + EndUnpacking(UnpackerError::kNone, 0); +} + +void PuffinComponentUnpacker::EndUnpacking(UnpackerError error, + int extended_error) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (error != UnpackerError::kNone && !unpack_path_.empty()) + base::DeletePathRecursively(unpack_path_); + + Result result; + result.error = error; + result.extended_error = extended_error; + if (error == UnpackerError::kNone) { + VLOG(2) << "Unpacked successfully"; + result.unpack_path = unpack_path_; + result.public_key = public_key_; + } + + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback_), result)); +} + +} // namespace update_client
diff --git a/components/update_client/puffin_component_unpacker.h b/components/update_client/puffin_component_unpacker.h new file mode 100644 index 0000000..c70140b --- /dev/null +++ b/components/update_client/puffin_component_unpacker.h
@@ -0,0 +1,119 @@ +// Copyright 2022 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_UPDATE_CLIENT_PUFFIN_COMPONENT_UNPACKER_H_ +#define COMPONENTS_UPDATE_CLIENT_PUFFIN_COMPONENT_UNPACKER_H_ + +#include <stdint.h> + +#include <memory> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/sequence_checker.h" +#include "components/update_client/update_client_errors.h" + +namespace crx_file { +enum class VerifierFormat; +} + +namespace update_client { + +class Unzipper; + +// Unpacks the component CRX package and verifies that it is +// well formed and the cryptographic signature is correct. +// +// This class is only used by the component updater. It is inspired by +// and overlaps with code in the extension's SandboxedUnpacker. +// The main differences are: +// - The public key hash is SHA256. +// - Does not use a sandboxed unpacker. A valid component is fully trusted. +// - The manifest can have different attributes and resources are not +// transcoded. +// +// This is an updated version of ComponentUnpacker that leverages the new +// Puffin-based puffpatch CRX-diff format, rather than the legacy +// courgette/bsdiff per-file CRXD format. Puffin patches the CRX before +// unpacking, changing the order of operations such that patching needs to occur +// before verifying and unpacking. Unlike the original implementation, by the +// time we unpack, the patching has already occurred. +class PuffinComponentUnpacker + : public base::RefCountedThreadSafe<PuffinComponentUnpacker> { + public: + // Contains the result of the unpacking. + struct Result { + Result(); + + // Unpack error: 0 indicates success. + UnpackerError error = UnpackerError::kNone; + + // Additional error information, such as errno or last error. + int extended_error = 0; + + // Path of the unpacked files if the unpacking was successful. + base::FilePath unpack_path; + + // The extracted public key of the package if the unpacking was successful. + std::string public_key; + }; + + PuffinComponentUnpacker(const PuffinComponentUnpacker&) = delete; + PuffinComponentUnpacker& operator=(const PuffinComponentUnpacker&) = delete; + + // Begins the actual unpacking of the files. Calls `callback` with the result. + static void Unpack(const std::vector<uint8_t>& pk_hash, + const base::FilePath& path, + std::unique_ptr<Unzipper> unzipper, + crx_file::VerifierFormat crx_format, + base::OnceCallback<void(const Result& result)> callback); + + private: + friend class base::RefCountedThreadSafe<PuffinComponentUnpacker>; + + // Constructs an unpacker for a specific component unpacking operation. + // `pk_hash` is the expected public developer key's SHA256 hash. If empty, + // the unpacker accepts any developer key. `path` is the current location + // of the CRX. + PuffinComponentUnpacker( + const std::vector<uint8_t>& pk_hash, + const base::FilePath& path, + std::unique_ptr<Unzipper> unzipper, + crx_file::VerifierFormat crx_format, + base::OnceCallback<void(const Result& result)> callback); + + virtual ~PuffinComponentUnpacker(); + + // The first step of unpacking is to verify the file. Triggers + // `BeginUnzipping` if successful. Triggers `EndUnpacking` if an early error + // is encountered. + void Verify(); + + // The next step of unpacking is to unzip. Triggers `EndUnzipping` if + // successful. Triggers `EndUnpacking` if an early error is encountered. + void BeginUnzipping(); + void EndUnzipping(bool error); + + // The final step is to do clean-up for things that can't be tidied as we go. + // If there is an error at any step, the remaining steps are skipped and + // `EndUnpacking` is called. `EndUnpacking` is responsible for calling the + // callback provided in `Unpack`. + void EndUnpacking(UnpackerError error, int extended_error); + + std::vector<uint8_t> pk_hash_; + base::FilePath path_; + std::unique_ptr<Unzipper> unzipper_; + crx_file::VerifierFormat crx_format_; + base::OnceCallback<void(const Result& result)> callback_; + base::FilePath unpack_path_; + std::string public_key_; + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace update_client + +#endif // COMPONENTS_UPDATE_CLIENT_PUFFIN_COMPONENT_UNPACKER_H_
diff --git a/components/update_client/puffin_component_unpacker_unittest.cc b/components/update_client/puffin_component_unpacker_unittest.cc new file mode 100644 index 0000000..10b25bc --- /dev/null +++ b/components/update_client/puffin_component_unpacker_unittest.cc
@@ -0,0 +1,131 @@ +// Copyright 2022 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 <iterator> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "components/crx_file/crx_verifier.h" +#include "components/update_client/puffin_component_unpacker.h" +#include "components/update_client/test_configurator.h" +#include "components/update_client/unzipper.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +base::FilePath TestFile(const char* file) { + base::FilePath path; + base::PathService::Get(base::DIR_SOURCE_ROOT, &path); + return path.AppendASCII("components") + .AppendASCII("test") + .AppendASCII("data") + .AppendASCII("update_client") + .AppendASCII(file); +} + +} // namespace + +namespace update_client { + +class PuffinComponentUnpackerTest : public testing::Test { + public: + PuffinComponentUnpackerTest() = default; + ~PuffinComponentUnpackerTest() override = default; + + void UnpackComplete(const PuffinComponentUnpacker::Result& result); + + protected: + base::test::TaskEnvironment env_; +}; + +TEST_F(PuffinComponentUnpackerTest, UnpackFullCrx) { + auto config = base::MakeRefCounted<TestConfigurator>(); + SEQUENCE_CHECKER(sequence_checker); + base::RunLoop loop; + PuffinComponentUnpacker::Unpack( + std::vector<uint8_t>(std::begin(jebg_hash), std::end(jebg_hash)), + TestFile("jebgalgnebhfojomionfpkfelancnnkf.crx"), + config->GetUnzipperFactory()->Create(), crx_file::VerifierFormat::CRX3, + base::BindLambdaForTesting( + [&loop, + &sequence_checker](const PuffinComponentUnpacker::Result& result) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker); + EXPECT_EQ(result.error, UnpackerError::kNone); + EXPECT_EQ(result.extended_error, 0); + + base::FilePath unpack_path = result.unpack_path; + EXPECT_TRUE(base::DirectoryExists(unpack_path)); + EXPECT_EQ(result.public_key, jebg_public_key); + + int64_t file_size = 0; + EXPECT_TRUE(base::GetFileSize( + unpack_path.AppendASCII("component1.dll"), &file_size)); + EXPECT_EQ(file_size, 1024); + EXPECT_TRUE(base::GetFileSize( + unpack_path.AppendASCII("manifest.json"), &file_size)); + EXPECT_EQ(file_size, 169); + + EXPECT_TRUE(base::DeletePathRecursively(unpack_path)); + loop.Quit(); + })); + loop.Run(); + DETACH_FROM_SEQUENCE(sequence_checker); +} + +TEST_F(PuffinComponentUnpackerTest, UnpackFileNotFound) { + SEQUENCE_CHECKER(sequence_checker); + base::RunLoop loop; + PuffinComponentUnpacker::Unpack( + std::vector<uint8_t>(std::begin(jebg_hash), std::end(jebg_hash)), + TestFile("file_not_found.crx"), nullptr, crx_file::VerifierFormat::CRX3, + base::BindLambdaForTesting( + [&loop, + &sequence_checker](const PuffinComponentUnpacker::Result& result) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker); + EXPECT_EQ(result.error, UnpackerError::kInvalidFile); + EXPECT_EQ(result.extended_error, + static_cast<int>( + crx_file::VerifierResult::ERROR_FILE_NOT_READABLE)); + EXPECT_TRUE(result.unpack_path.empty()); + EXPECT_TRUE(result.public_key.empty()); + loop.Quit(); + })); + loop.Run(); + DETACH_FROM_SEQUENCE(sequence_checker); +} + +// Tests a mismatch between the public key hash and the id of the component. +TEST_F(PuffinComponentUnpackerTest, UnpackFileHashMismatch) { + SEQUENCE_CHECKER(sequence_checker); + base::RunLoop loop; + PuffinComponentUnpacker::Unpack( + std::vector<uint8_t>(std::begin(abag_hash), std::end(abag_hash)), + TestFile("jebgalgnebhfojomionfpkfelancnnkf.crx"), nullptr, + crx_file::VerifierFormat::CRX3, + base::BindLambdaForTesting( + [&loop, + &sequence_checker](const PuffinComponentUnpacker::Result& result) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker); + EXPECT_EQ(result.error, UnpackerError::kInvalidFile); + EXPECT_EQ( + result.extended_error, + static_cast<int>( + crx_file::VerifierResult::ERROR_REQUIRED_PROOF_MISSING)); + EXPECT_TRUE(result.unpack_path.empty()); + EXPECT_TRUE(result.public_key.empty()); + loop.Quit(); + })); + loop.Run(); + DETACH_FROM_SEQUENCE(sequence_checker); +} + +} // namespace update_client
diff --git a/components/update_client/puffin_patcher.cc b/components/update_client/puffin_patcher.cc new file mode 100644 index 0000000..490f85a --- /dev/null +++ b/components/update_client/puffin_patcher.cc
@@ -0,0 +1,90 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/update_client/puffin_patcher.h" + +#include <string> +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/memory/scoped_refptr.h" +#include "base/sequence_checker.h" +#include "base/task/task_runner.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "components/update_client/component_patcher_operation.h" +#include "components/update_client/patcher.h" +#include "components/update_client/update_client.h" +#include "components/update_client/update_client_errors.h" +#include "third_party/puffin/puffin/src/include/puffin/puffpatch.h" + +namespace update_client { + +PuffinPatcher::PuffinPatcher( + base::File old_crx_file, + base::File puff_patch_file, + base::File new_crx_output, + scoped_refptr<Patcher> patcher, + base::OnceCallback<void(UnpackerError, int)> callback) + : old_crx_file_(std::move(old_crx_file)), + puff_patch_file_(std::move(puff_patch_file)), + new_crx_output_file_(std::move(new_crx_output)), + patcher_(patcher), + callback_(std::move(callback)) {} + +PuffinPatcher::~PuffinPatcher() = default; + +void PuffinPatcher::Patch( + base::File old_crx_file, + base::File puff_patch_file, + base::File new_crx_output, + scoped_refptr<Patcher> patcher, + base::OnceCallback<void(UnpackerError, int)> callback) { + scoped_refptr<PuffinPatcher> puffin_patcher = + base::WrapRefCounted(new PuffinPatcher( + std::move(old_crx_file), std::move(puff_patch_file), + std::move(new_crx_output), patcher, std::move(callback))); + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&PuffinPatcher::StartPatching, puffin_patcher)); +} + +void PuffinPatcher::StartPatching() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!old_crx_file_.IsValid()) { + DonePatching(UnpackerError::kInvalidParams, 0); + } else if (!puff_patch_file_.IsValid()) { + DonePatching(UnpackerError::kInvalidParams, 0); + } else if (!new_crx_output_file_.IsValid()) { + DonePatching(UnpackerError::kInvalidParams, 0); + } else { + PatchCrx(); + } +} + +void PuffinPatcher::PatchCrx() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + patcher_->PatchPuffPatch(std::move(old_crx_file_), + std::move(puff_patch_file_), + std::move(new_crx_output_file_), + base::BindOnce(&PuffinPatcher::DonePatch, this)); +} + +void PuffinPatcher::DonePatch(int extended_error) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (extended_error != puffin::P_OK) { + DonePatching(UnpackerError::kDeltaOperationFailure, extended_error); + } else { + DonePatching(UnpackerError::kNone, 0); + } +} + +void PuffinPatcher::DonePatching(UnpackerError error, int extended_error) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DETACH_FROM_SEQUENCE(sequence_checker_); + std::move(callback_).Run(error, extended_error); +} + +} // namespace update_client
diff --git a/components/update_client/puffin_patcher.h b/components/update_client/puffin_patcher.h new file mode 100644 index 0000000..4f43e791 --- /dev/null +++ b/components/update_client/puffin_patcher.h
@@ -0,0 +1,87 @@ +// Copyright 2022 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. + +// Component updates can be either differential updates or full updates. +// Full updates come in CRX format; differential puffdiff updates come in *.puff +// files, with a different magic number. They describe a bsdiff diff generated +// by Puffin. The patcher takes the previous version of this binary, applies +// puffpatch and generates the newest version of the CRX. +// +// The component updater attempts a differential update if it is available +// and allowed to, and fall back to a full update if it fails. +// +// After installation (diff or full), the component updater records "fp", the +// fingerprint of the installed files, to later identify the existing files to +// the server so that a proper differential update can be provided next cycle. + +#ifndef COMPONENTS_UPDATE_CLIENT_PUFFIN_PATCHER_H_ +#define COMPONENTS_UPDATE_CLIENT_PUFFIN_PATCHER_H_ + +#include "base/callback_forward.h" +#include "base/files/file.h" +#include "base/memory/ref_counted.h" +#include "base/sequence_checker.h" +#include "base/values.h" +#include "components/update_client/component_unpacker.h" + +namespace base { +class File; +} + +namespace update_client { + +class Patcher; + +// Encapsulates a task for applying a differential update to a component. +class PuffinPatcher : public base::RefCountedThreadSafe<PuffinPatcher> { + public: + PuffinPatcher(const PuffinPatcher&) = delete; + PuffinPatcher& operator=(const PuffinPatcher&) = delete; + + // Takes a full CRX `old_crx_file` and a Puffin puffpatch file + // `puff_patch_file`, and sets up the class to create a new full + // If `in_process` is true, patching is done completely within the + // existing process. Otherwise, some steps of patching may be done + // out-of-process. Then, it starts patching files. + // + // This static function returns immediately, after posting a task + // to do the patching. When patching has been completed, + // `callback` is called with the error codes if any error codes were + // encountered. + static void Patch(base::File old_crx_file, + base::File puff_patch_file, + base::File new_crx_output, + scoped_refptr<Patcher> patcher, + base::OnceCallback<void(UnpackerError, int)> callback); + + private: + friend class base::RefCountedThreadSafe<PuffinPatcher>; + + PuffinPatcher(base::File old_crx_file, + base::File puff_patch_file, + base::File new_crx_output, + scoped_refptr<Patcher> patcher, + base::OnceCallback<void(UnpackerError, int)> callback); + + virtual ~PuffinPatcher(); + + void StartPatching(); + + void PatchCrx(); + + void DonePatch(int extended_error); + + void DonePatching(UnpackerError error, int extended_error); + + base::File old_crx_file_; + base::File puff_patch_file_; + base::File new_crx_output_file_; + scoped_refptr<Patcher> patcher_; + base::OnceCallback<void(UnpackerError, int)> callback_; + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace update_client + +#endif // COMPONENTS_UPDATE_CLIENT_PUFFIN_PATCHER_H_
diff --git a/components/update_client/puffin_patcher_unittest.cc b/components/update_client/puffin_patcher_unittest.cc new file mode 100644 index 0000000..48bf253 --- /dev/null +++ b/components/update_client/puffin_patcher_unittest.cc
@@ -0,0 +1,110 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/update_client/puffin_patcher.h" + +#include "base/base_paths.h" +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/memory/scoped_refptr.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/sequence_checker.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "base/values.h" +#include "components/services/patch/in_process_file_patcher.h" +#include "components/update_client/patch/patch_impl.h" +#include "components/update_client/test_installer.h" +#include "components/update_client/update_client_errors.h" +#include "courgette/courgette.h" +#include "courgette/third_party/bsdiff/bsdiff.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace update_client { + +namespace { + +base::FilePath OutTestFile(const char* file) { + base::FilePath path; + base::PathService::Get(base::DIR_GEN_TEST_DATA_ROOT, &path); + return path.AppendASCII(file); +} + +} // namespace + +class PuffinPatcherTest : public testing::Test { + public: + PuffinPatcherTest() = default; + ~PuffinPatcherTest() override = default; + + protected: + base::test::TaskEnvironment env_; +}; + +TEST_F(PuffinPatcherTest, CheckPuffPatch) { + // The operation needs a Patcher to access the PatchService. + scoped_refptr<Patcher> patcher = + base::MakeRefCounted<PatchChromiumFactory>( + base::BindRepeating(&patch::LaunchInProcessFilePatcher)) + ->Create(); + + base::FilePath out_file = OutTestFile("puffin_app_v1_to_v2.crx3"); + EXPECT_TRUE(base::DeleteFile(out_file)); + SEQUENCE_CHECKER(sequence_checker); + { + base::File input_file(OutTestFile("puffin_app_v1.crx3"), + base::File::FLAG_OPEN | base::File::FLAG_READ); + base::File patch_file(OutTestFile("puffin_app_v1_to_v2.puff"), + base::File::FLAG_OPEN | base::File::FLAG_READ); + base::File output_file(out_file, base::File::FLAG_CREATE | + base::File::FLAG_WRITE | + base::File::FLAG_WIN_EXCLUSIVE_WRITE); + base::RunLoop loop; + PuffinPatcher::Patch( + std::move(input_file), std::move(patch_file), std::move(output_file), + patcher, + base::BindLambdaForTesting( + [&loop, &sequence_checker](UnpackerError error, int extra_code) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker); + EXPECT_EQ(error, UnpackerError::kNone); + EXPECT_EQ(extra_code, 0); + loop.Quit(); + })); + loop.Run(); + } + + EXPECT_TRUE(base::ContentsEqual(OutTestFile("puffin_app_v2.crx3"), out_file)); + + out_file = OutTestFile("puffin_app_v2_to_v1.crx3"); + EXPECT_TRUE(base::DeleteFile(out_file)); + { + base::File input_file(OutTestFile("puffin_app_v2.crx3"), + base::File::FLAG_OPEN | base::File::FLAG_READ); + base::File patch_file(OutTestFile("puffin_app_v2_to_v1.puff"), + base::File::FLAG_OPEN | base::File::FLAG_READ); + base::File output_file(out_file, base::File::FLAG_CREATE | + base::File::FLAG_WRITE | + base::File::FLAG_WIN_EXCLUSIVE_WRITE); + base::RunLoop loop; + PuffinPatcher::Patch( + std::move(input_file), std::move(patch_file), std::move(output_file), + patcher, + base::BindLambdaForTesting( + [&loop, &sequence_checker](UnpackerError error, int extra_code) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker); + EXPECT_EQ(error, UnpackerError::kNone); + EXPECT_EQ(extra_code, 0); + loop.Quit(); + })); + loop.Run(); + } + + DETACH_FROM_SEQUENCE(sequence_checker); + EXPECT_TRUE(base::ContentsEqual(OutTestFile("puffin_app_v1.crx3"), out_file)); +} + +} // namespace update_client
diff --git a/components/user_notes/browser/user_note_service.cc b/components/user_notes/browser/user_note_service.cc index 015ef7f2..6f08bf3 100644 --- a/components/user_notes/browser/user_note_service.cc +++ b/components/user_notes/browser/user_note_service.cc
@@ -14,6 +14,7 @@ #include "components/user_notes/interfaces/user_notes_ui.h" #include "components/user_notes/user_notes_features.h" #include "content/public/browser/render_frame_host.h" +#include "content/public/browser/weak_document_ptr.h" #include "ui/gfx/geometry/rect.h" namespace user_notes { @@ -68,12 +69,12 @@ DCHECK(UserNoteManager::GetForPage(rfh->GetPage())); - std::vector<content::RenderFrameHost*> frames = {rfh}; + std::vector<content::WeakDocumentPtr> frames = {rfh->GetWeakDocumentPtr()}; UserNoteStorage::UrlSet urls = {rfh->GetLastCommittedURL()}; storage_->GetNoteMetadataForUrls( std::move(urls), base::BindOnce(&UserNoteService::OnNoteMetadataFetchedForNavigation, - weak_ptr_factory_.GetWeakPtr(), frames, rfh)); + weak_ptr_factory_.GetWeakPtr(), frames)); } void UserNoteService::OnNoteInstanceAddedToPage( @@ -259,15 +260,18 @@ std::vector<content::RenderFrameHost*> all_frames = delegate_->GetAllFramesForUserNotes(); UserNoteStorage::UrlSet urls; + std::vector<content::WeakDocumentPtr> all_frames_weak; + all_frames_weak.reserve(all_frames.size()); for (content::RenderFrameHost* frame : all_frames) { urls.emplace(frame->GetLastCommittedURL()); + all_frames_weak.emplace_back(frame->GetWeakDocumentPtr()); } storage_->GetNoteMetadataForUrls( std::move(urls), base::BindOnce(&UserNoteService::OnNoteMetadataFetched, - weak_ptr_factory_.GetWeakPtr(), all_frames)); + weak_ptr_factory_.GetWeakPtr(), all_frames_weak)); } void UserNoteService::InitializeNewNoteForCreation( @@ -378,13 +382,19 @@ } void UserNoteService::OnNoteMetadataFetchedForNavigation( - const std::vector<content::RenderFrameHost*>& all_frames, - const content::RenderFrameHost* navigated_frame, + const std::vector<content::WeakDocumentPtr>& all_frames, UserNoteMetadataSnapshot metadata_snapshot) { DCHECK(all_frames.size() == 1u); - if (delegate_->IsFrameInActiveTab(all_frames[0])) { - UserNotesUI* ui = delegate_->GetUICoordinatorForFrame(all_frames[0]); + content::RenderFrameHost* rfh = all_frames[0].AsRenderFrameHostIfValid(); + + if (!rfh) { + // The navigated frame is no longer valid. + return; + } + + if (delegate_->IsFrameInActiveTab(rfh)) { + UserNotesUI* ui = delegate_->GetUICoordinatorForFrame(rfh); DCHECK(ui); // TODO(crbug.com/1313967): For now, always invalidate the UI if the tab is @@ -415,7 +425,7 @@ } void UserNoteService::OnNoteMetadataFetched( - const std::vector<content::RenderFrameHost*>& all_frames, + const std::vector<content::WeakDocumentPtr>& all_frames, UserNoteMetadataSnapshot metadata_snapshot) { std::vector<std::unique_ptr<FrameUserNoteChanges>> note_changes = CalculateNoteChanges(*this, all_frames, metadata_snapshot);
diff --git a/components/user_notes/browser/user_note_service.h b/components/user_notes/browser/user_note_service.h index 03bd34c0..dbd76e1 100644 --- a/components/user_notes/browser/user_note_service.h +++ b/components/user_notes/browser/user_note_service.h
@@ -145,11 +145,10 @@ // Private helpers used when processing note storage changes. Marked virtual // for tests to override. virtual void OnNoteMetadataFetchedForNavigation( - const std::vector<content::RenderFrameHost*>& all_frames, - const content::RenderFrameHost* navigated_frame, + const std::vector<content::WeakDocumentPtr>& all_frames, UserNoteMetadataSnapshot metadata_snapshot); virtual void OnNoteMetadataFetched( - const std::vector<content::RenderFrameHost*>& all_frames, + const std::vector<content::WeakDocumentPtr>& all_frames, UserNoteMetadataSnapshot metadata_snapshot); virtual void OnNoteModelsFetched( const IdSet& new_notes,
diff --git a/components/user_notes/browser/user_note_service_unittest.cc b/components/user_notes/browser/user_note_service_unittest.cc index 2ba12d5..d5904cb 100644 --- a/components/user_notes/browser/user_note_service_unittest.cc +++ b/components/user_notes/browser/user_note_service_unittest.cc
@@ -140,13 +140,12 @@ MOCK_METHOD(void, OnNoteMetadataFetchedForNavigation, - (const std::vector<content::RenderFrameHost*>& all_frames, - const content::RenderFrameHost* navigated_frame, + (const std::vector<content::WeakDocumentPtr>& all_frames, UserNoteMetadataSnapshot metadata_snapshot), (override)); MOCK_METHOD(void, OnNoteMetadataFetched, - (const std::vector<content::RenderFrameHost*>& all_frames, + (const std::vector<content::WeakDocumentPtr>& all_frames, UserNoteMetadataSnapshot metadata_snapshot), (override)); MOCK_METHOD(void, @@ -172,15 +171,14 @@ } void CallBaseClassOnNoteMetadataFetchedForNavigation( - const std::vector<content::RenderFrameHost*>& all_frames, - const content::RenderFrameHost* navigated_frame, + const std::vector<content::WeakDocumentPtr>& all_frames, UserNoteMetadataSnapshot metadata_snapshot) { UserNoteService::OnNoteMetadataFetchedForNavigation( - all_frames, navigated_frame, std::move(metadata_snapshot)); + all_frames, std::move(metadata_snapshot)); } void CallBaseClassOnNoteMetadataFetched( - const std::vector<content::RenderFrameHost*>& all_frames, + const std::vector<content::WeakDocumentPtr>& all_frames, UserNoteMetadataSnapshot metadata_snapshot) { UserNoteService::OnNoteMetadataFetched(all_frames, std::move(metadata_snapshot)); @@ -285,6 +283,14 @@ return frames; } + std::vector<content::WeakDocumentPtr> GetAllFramesInUseAsWeakPtr() { + std::vector<content::WeakDocumentPtr> weak_documents; + for (content::RenderFrameHost* rfh : GetAllFramesInUse()) { + weak_documents.emplace_back(rfh->GetWeakDocumentPtr()); + } + return weak_documents; + } + raw_ptr<MockUserNoteService> mock_service_; raw_ptr<MockUserNoteServiceDelegate> service_delegate_; raw_ptr<MockUserNoteStorage> storage_; @@ -531,15 +537,12 @@ EXPECT_CALL(*storage_, GetNotesById).Times(0); // Configure service mock. - std::vector<content::RenderFrameHost*> all_frames_result; - const content::RenderFrameHost* navigated_frame_result; + std::vector<content::WeakDocumentPtr> all_frames_result; EXPECT_CALL(*mock_service_, OnNoteMetadataFetchedForNavigation) .Times(1) - .WillOnce([&](const std::vector<content::RenderFrameHost*>& all_frames, - const content::RenderFrameHost* navigated_frame, + .WillOnce([&](const std::vector<content::WeakDocumentPtr>& all_frames, UserNoteMetadataSnapshot metadata_snapshot) { all_frames_result.assign(all_frames.begin(), all_frames.end()); - navigated_frame_result = navigated_frame; }); EXPECT_CALL(*mock_service_, OnNoteMetadataFetched).Times(0); EXPECT_CALL(*mock_service_, OnNoteModelsFetched).Times(0); @@ -553,8 +556,10 @@ // Mocks ensure callbacks are invoked synchronously, so expectations can be // immediately verified. ASSERT_EQ(all_frames_result.size(), 1u); - EXPECT_EQ(all_frames_result[0], frame); - EXPECT_EQ(navigated_frame_result, frame); + content::RenderFrameHost* rfh = + all_frames_result[0].AsRenderFrameHostIfValid(); + EXPECT_NE(rfh, nullptr); + EXPECT_EQ(rfh, frame); const UserNoteStorage::UrlSet& requested_urls = storage_->requested_metadata_urls(); @@ -621,7 +626,7 @@ // Simulate the service receiving the metadata snapshot after a navigation. note_service_->OnNoteMetadataFetchedForNavigation( - GetAllFramesInUse(), GetAllFramesInUse()[0], std::move(snapshot)); + GetAllFramesInUseAsWeakPtr(), std::move(snapshot)); } // After a navigation to a document that has user notes, but isn't in the @@ -672,7 +677,7 @@ // Simulate the service receiving the metadata snapshot after a navigation. note_service_->OnNoteMetadataFetchedForNavigation( - GetAllFramesInUse(), GetAllFramesInUse()[0], std::move(snapshot)); + GetAllFramesInUseAsWeakPtr(), std::move(snapshot)); } // After a navigation to a document that doesn't have user notes but is in the @@ -735,7 +740,7 @@ // Simulate the service receiving the empty metadata snapshot after a // navigation. note_service_->OnNoteMetadataFetchedForNavigation( - GetAllFramesInUse(), GetAllFramesInUse()[0], UserNoteMetadataSnapshot()); + GetAllFramesInUseAsWeakPtr(), UserNoteMetadataSnapshot()); } // After a navigation to a document that doesn't have user notes, but isn't in @@ -788,7 +793,7 @@ // Simulate the service receiving the empty metadata snapshot after a // navigation. note_service_->OnNoteMetadataFetchedForNavigation( - GetAllFramesInUse(), GetAllFramesInUse()[0], UserNoteMetadataSnapshot()); + GetAllFramesInUseAsWeakPtr(), UserNoteMetadataSnapshot()); } // Tests that the service requests the right models from the storage after @@ -868,7 +873,7 @@ // Simulate the storage returning the metadata snapshot to the service // callback. - note_service_->OnNoteMetadataFetched(GetAllFramesInUse(), + note_service_->OnNoteMetadataFetched(GetAllFramesInUseAsWeakPtr(), std::move(snapshot)); // Mocks ensure callbacks are invoked synchronously, so expectations can be
diff --git a/components/user_notes/browser/user_note_utils.cc b/components/user_notes/browser/user_note_utils.cc index 2e6f029..f60da07e 100644 --- a/components/user_notes/browser/user_note_utils.cc +++ b/components/user_notes/browser/user_note_utils.cc
@@ -11,13 +11,14 @@ #include "components/user_notes/interfaces/user_note_metadata_snapshot.h" #include "components/user_notes/model/user_note_metadata.h" #include "content/public/browser/render_frame_host.h" +#include "content/public/browser/weak_document_ptr.h" #include "url/gurl.h" namespace user_notes { std::vector<std::unique_ptr<FrameUserNoteChanges>> CalculateNoteChanges( const UserNoteService& note_service, - const std::vector<content::RenderFrameHost*>& rfhs, + const std::vector<content::WeakDocumentPtr>& documents, const UserNoteMetadataSnapshot& metadata_snapshot) { std::vector<std::unique_ptr<FrameUserNoteChanges>> result; @@ -25,7 +26,14 @@ // where there's no entry in the metadata snapshot for a frame's URL. UserNoteMetadataSnapshot::IdToMetadataMap empty_map; - for (content::RenderFrameHost* rfh : rfhs) { + for (const content::WeakDocumentPtr& document : documents) { + content::RenderFrameHost* rfh = document.AsRenderFrameHostIfValid(); + + if (!rfh) { + // The frame is no longer valid. + continue; + } + // Notes should only be processed for the primary page. DCHECK(rfh->GetMainFrame()->IsInPrimaryMainFrame());
diff --git a/components/user_notes/browser/user_note_utils.h b/components/user_notes/browser/user_note_utils.h index 1b190d56..ecc95c8 100644 --- a/components/user_notes/browser/user_note_utils.h +++ b/components/user_notes/browser/user_note_utils.h
@@ -10,7 +10,7 @@ #include <vector> namespace content { -class RenderFrameHost; +class WeakDocumentPtr; } // namespace content namespace user_notes { @@ -25,7 +25,7 @@ // don't match the metadata. std::vector<std::unique_ptr<FrameUserNoteChanges>> CalculateNoteChanges( const UserNoteService& note_service, - const std::vector<content::RenderFrameHost*>& rfhs, + const std::vector<content::WeakDocumentPtr>& documents, const UserNoteMetadataSnapshot& metadata_snapshot); } // namespace user_notes
diff --git a/components/user_notes/browser/user_note_utils_unittest.cc b/components/user_notes/browser/user_note_utils_unittest.cc index c0ca8b3..7600daa 100644 --- a/components/user_notes/browser/user_note_utils_unittest.cc +++ b/components/user_notes/browser/user_note_utils_unittest.cc
@@ -693,16 +693,16 @@ } // Round up the test frames as if they were the user's open tabs. - std::vector<content::RenderFrameHost*> frame_hosts; - frame_hosts.reserve(frame_to_config_.size()); + std::vector<content::WeakDocumentPtr> weak_documents; + weak_documents.reserve(frame_to_config_.size()); for (const auto& config_it : frame_to_config_) { - frame_hosts.push_back(config_it.first); + weak_documents.emplace_back(config_it.first->GetWeakDocumentPtr()); } // Calculate the diff between the notes in the frames and the notes in the // metadata. const std::vector<std::unique_ptr<FrameUserNoteChanges>>& actual_diffs = - CalculateNoteChanges(*note_service_, frame_hosts, metadata_snapshot); + CalculateNoteChanges(*note_service_, weak_documents, metadata_snapshot); std::unordered_set<content::RenderFrameHost*> frames_with_diff; for (const std::unique_ptr<FrameUserNoteChanges>& diff : actual_diffs) {
diff --git a/components/variations/service/variations_service.cc b/components/variations/service/variations_service.cc index bc93203..03c100c 100644 --- a/components/variations/service/variations_service.cc +++ b/components/variations/service/variations_service.cc
@@ -350,18 +350,14 @@ local_state_(local_state), state_manager_(state_manager), policy_pref_service_(local_state), - initial_request_completed_(false), - delta_error_since_last_success_(false), resource_request_allowed_notifier_(std::move(notifier)), - request_count_(0), safe_seed_manager_(local_state), field_trial_creator_(client_.get(), std::make_unique<VariationsSeedStore>( local_state, MaybeImportFirstRunSeed(local_state), /*signature_verification_enabled=*/true), - ui_string_overrider), - last_request_was_http_retry_(false) { + ui_string_overrider) { DCHECK(client_); DCHECK(resource_request_allowed_notifier_); @@ -764,6 +760,13 @@ const bool is_first_request = !initial_request_completed_; initial_request_completed_ = true; + const base::TimeTicks now = base::TimeTicks::Now(); + if (is_first_request && + !local_state_->HasPrefPath(prefs::kVariationsSeedSignature)) { + base::UmaHistogramTimes("Variations.SeedFetchTimeOnFirstRun", + now - last_request_started_time_); + } + const network::mojom::URLResponseHead* response_info = pending_seed_request_->ResponseInfo(); const scoped_refptr<net::HttpResponseHeaders> headers = @@ -819,7 +822,6 @@ if (headers->GetDateValue(&response_date)) { DCHECK(!response_date.is_null()); - const base::TimeTicks now = base::TimeTicks::Now(); const base::TimeDelta latency = now - last_request_started_time_; client_->GetNetworkTimeTracker()->UpdateNetworkTime( response_date, base::Seconds(kServerTimeResolutionInSeconds), latency,
diff --git a/components/variations/service/variations_service.h b/components/variations/service/variations_service.h index 60a8332..22a625ce 100644 --- a/components/variations/service/variations_service.h +++ b/components/variations/service/variations_service.h
@@ -384,11 +384,11 @@ GURL insecure_variations_server_url_; // Tracks whether the initial request to the variations server had completed. - bool initial_request_completed_; + bool initial_request_completed_ = false; // Tracks whether any errors resolving delta compression were encountered // since the last time a seed was fetched successfully. - bool delta_error_since_last_success_; + bool delta_error_since_last_success_ = false; // Helper class used to tell this service if it's allowed to make network // resource requests. @@ -400,7 +400,7 @@ base::TimeTicks last_request_started_time_; // The number of requests to the variations server that have been performed. - int request_count_; + int request_count_ = 0; // List of observers of the VariationsService. base::ObserverList<Observer>::Unchecked observer_list_; @@ -412,7 +412,7 @@ VariationsFieldTrialCreator field_trial_creator_; // True if the last request was a retry over http. - bool last_request_was_http_retry_; + bool last_request_was_http_retry_ = false; // When not empty, contains an override for the os name in the variations // server url.
diff --git a/components/viz/service/display_embedder/compositor_gpu_thread.cc b/components/viz/service/display_embedder/compositor_gpu_thread.cc index a93e1095..8ba3ef7 100644 --- a/components/viz/service/display_embedder/compositor_gpu_thread.cc +++ b/components/viz/service/display_embedder/compositor_gpu_thread.cc
@@ -23,6 +23,7 @@ #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_surface_egl.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #if BUILDFLAG(ENABLE_VULKAN) @@ -108,7 +109,8 @@ // Create a new share group. Note that this share group is different from the // share group which gpu main thread uses. auto share_group = base::MakeRefCounted<gl::GLShareGroup>(); - auto surface = gl::init::CreateOffscreenGLSurface(gfx::Size()); + auto surface = + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), gfx::Size()); const auto& gpu_preferences = gpu_channel_manager_->gpu_preferences();
diff --git a/components/viz/service/display_embedder/skia_output_surface_dependency.h b/components/viz/service/display_embedder/skia_output_surface_dependency.h index 0683b7e..25deb86f 100644 --- a/components/viz/service/display_embedder/skia_output_surface_dependency.h +++ b/components/viz/service/display_embedder/skia_output_surface_dependency.h
@@ -6,6 +6,7 @@ #define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_DEPENDENCY_H_ #include <memory> +#include <utility> #include "base/callback.h" #include "base/callback_helpers.h"
diff --git a/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc b/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc index 2f76fe7..c372de46 100644 --- a/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc +++ b/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc
@@ -17,6 +17,7 @@ #include "gpu/command_buffer/service/scheduler.h" #include "gpu/command_buffer/service/scheduler_sequence.h" #include "gpu/ipc/service/image_transport_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace viz { @@ -107,10 +108,11 @@ base::WeakPtr<gpu::ImageTransportSurfaceDelegate> stub, gl::GLSurfaceFormat format) { if (IsOffscreen()) { - return gl::init::CreateOffscreenGLSurfaceWithFormat(gfx::Size(), format); + return gl::init::CreateOffscreenGLSurfaceWithFormat(gl::GetDefaultDisplay(), + gfx::Size(), format); } else { return gpu::ImageTransportSurface::CreateNativeSurface( - stub, surface_handle_, format); + gl::GetDefaultDisplay(), stub, surface_handle_, format); } }
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h index 784ba0b..117cdbd 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -5,13 +5,14 @@ #ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_ON_GPU_H_ #define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_ON_GPU_H_ -#include <deque> -#include <map> #include <memory> #include <utility> #include <vector> #include "base/callback_forward.h" +#include "base/containers/circular_deque.h" +#include "base/containers/flat_map.h" +#include "base/containers/flat_set.h" #include "base/containers/span.h" #include "base/memory/raw_ptr.h" #include "base/threading/thread_checker.h" @@ -507,7 +508,7 @@ // Overlayed render passes need to keep their write access open until after // submit. These will be set in FinishPaintRenderPass() if |is_overlay| is // true and destroyed in PostSubmit(). - std::map<gpu::Mailbox, OverlayPassAccess> overlay_pass_accesses_; + base::flat_map<gpu::Mailbox, OverlayPassAccess> overlay_pass_accesses_; absl::optional<OverlayProcessorInterface::OutputSurfaceOverlayPlane> output_surface_plane_; @@ -532,7 +533,7 @@ // Pending release fence callbacks. These callbacks can be delayed if Vulkan // external semaphore type has copy transference, which means importing // semaphores has to be delayed until submission. - std::deque<std::pair<GrBackendSemaphore, + base::circular_deque<std::pair<GrBackendSemaphore, base::OnceCallback<void(gfx::GpuFenceHandle)>>> pending_release_fence_cbs_;
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index 8412124..0278b27 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -509,7 +509,7 @@ void GpuServiceImpl::UpdateGPUInfoGL() { DCHECK(main_runner_->BelongsToCurrentThread()); - gpu::CollectGraphicsInfoGL(&gpu_info_); + gpu::CollectGraphicsInfoGL(&gpu_info_, gl::GetDefaultDisplay()); gpu_host_->DidUpdateGPUInfo(gpu_info_); }
diff --git a/components/viz/service/gl/gpu_service_impl_unittest.cc b/components/viz/service/gl/gpu_service_impl_unittest.cc index 00b1846..290b0e4 100644 --- a/components/viz/service/gl/gpu_service_impl_unittest.cc +++ b/components/viz/service/gl/gpu_service_impl_unittest.cc
@@ -23,6 +23,7 @@ #include "services/viz/public/mojom/gpu.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace viz { @@ -133,7 +134,7 @@ std::ignore = gpu_host_proxy.InitWithNewPipeAndPassReceiver(); gpu_service()->InitializeWithHost( std::move(gpu_host_proxy), gpu::GpuProcessActivityFlags(), - gl::init::CreateOffscreenGLSurface(gfx::Size()), + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), gfx::Size()), /*sync_point_manager=*/nullptr, /*shared_image_manager=*/nullptr, /*shutdown_event=*/nullptr); gpu_service_remote.FlushForTesting(); @@ -167,7 +168,7 @@ std::ignore = gpu_host_proxy.InitWithNewPipeAndPassReceiver(); gpu_service()->InitializeWithHost( std::move(gpu_host_proxy), gpu::GpuProcessActivityFlags(), - gl::init::CreateOffscreenGLSurface(gfx::Size()), + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), gfx::Size()), /*sync_point_manager=*/nullptr, /*shared_image_manager=*/nullptr, /*shutdown_event=*/nullptr); gpu_service_remote.FlushForTesting();
diff --git a/components/viz/test/test_gpu_service_holder.cc b/components/viz/test/test_gpu_service_holder.cc index 6460c2b..4c9da0b 100644 --- a/components/viz/test/test_gpu_service_holder.cc +++ b/components/viz/test/test_gpu_service_holder.cc
@@ -27,6 +27,7 @@ #include "gpu/ipc/service/gpu_watchdog_thread.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #if BUILDFLAG(ENABLE_VULKAN) @@ -306,7 +307,7 @@ std::ignore = gpu_host_proxy.InitWithNewPipeAndPassReceiver(); gpu_service_->InitializeWithHost( std::move(gpu_host_proxy), gpu::GpuProcessActivityFlags(), - gl::init::CreateOffscreenGLSurface(gfx::Size()), + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), gfx::Size()), /*sync_point_manager=*/nullptr, /*shared_image_manager=*/nullptr, /*shutdown_event=*/nullptr);
diff --git a/content/browser/interest_group/ad_auction_service_impl.cc b/content/browser/interest_group/ad_auction_service_impl.cc index f6205a9..c5177c9 100644 --- a/content/browser/interest_group/ad_auction_service_impl.cc +++ b/content/browser/interest_group/ad_auction_service_impl.cc
@@ -4,8 +4,11 @@ #include "content/browser/interest_group/ad_auction_service_impl.h" +#include <map> #include <set> #include <string> +#include <utility> +#include <vector> #include "base/check.h" #include "base/containers/contains.h" @@ -19,13 +22,17 @@ #include "content/browser/interest_group/auction_runner.h" #include "content/browser/interest_group/auction_worklet_manager.h" #include "content/browser/interest_group/interest_group_manager_impl.h" +#include "content/browser/private_aggregation/private_aggregation_manager.h" #include "content/browser/renderer_host/page_impl.h" #include "content/browser/renderer_host/render_frame_host_impl.h" +#include "content/common/aggregatable_report.mojom.h" +#include "content/common/private_aggregation_host.mojom.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/content_client.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/http/http_response_headers.h" @@ -400,7 +407,9 @@ &GetInterestGroupManager().auction_process_manager(), GetTopWindowOrigin(), origin(), - this) {} + this), + private_aggregation_manager_(PrivateAggregationManager::GetManager( + *render_frame_host.GetBrowserContext())) {} AdAuctionServiceImpl::~AdAuctionServiceImpl() { while (!auctions_.empty()) { @@ -448,6 +457,34 @@ origin); } +void AdAuctionServiceImpl::SendPrivateAggregationRequests( + std::map<url::Origin, + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>> + private_aggregation_requests) const { + if (!private_aggregation_manager_) { + return; + } + + for (auto& [origin, requests] : private_aggregation_requests) { + mojo::Remote<mojom::PrivateAggregationHost> remote; + if (!private_aggregation_manager_->BindNewReceiver( + origin, PrivateAggregationBudgetKey::Api::kFledge, + remote.BindNewPipeAndPassReceiver())) { + continue; + } + + for (auction_worklet::mojom::PrivateAggregationRequestPtr& request : + requests) { + DCHECK(request); + std::vector<mojom::AggregatableReportHistogramContributionPtr> + contributions; + contributions.push_back(std::move(request->contribution)); + remote->SendHistogramReport(std::move(contributions), + request->aggregation_mode); + } + } +} + void AdAuctionServiceImpl::OnAuctionComplete( RunAdAuctionCallback callback, AuctionRunner* auction, @@ -458,6 +495,9 @@ std::vector<GURL> debug_loss_report_urls, std::vector<GURL> debug_win_report_urls, ReportingMetadata ad_beacon_map, + std::map<url::Origin, + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>> + private_aggregation_requests, std::vector<std::string> errors) { // Delete the AuctionRunner. Since all arguments are passed by value, they're // all safe to used after this has been done. @@ -472,6 +512,8 @@ base::StrCat({"Worklet error: ", error})); } + SendPrivateAggregationRequests(std::move(private_aggregation_requests)); + auto* auction_result_metrics = AdAuctionResultMetrics::GetForPage(render_frame_host().GetPage());
diff --git a/content/browser/interest_group/ad_auction_service_impl.h b/content/browser/interest_group/ad_auction_service_impl.h index 81e9d91..236de404 100644 --- a/content/browser/interest_group/ad_auction_service_impl.h +++ b/content/browser/interest_group/ad_auction_service_impl.h
@@ -5,16 +5,20 @@ #ifndef CONTENT_BROWSER_INTEREST_GROUP_AD_AUCTION_SERVICE_IMPL_H_ #define CONTENT_BROWSER_INTEREST_GROUP_AD_AUCTION_SERVICE_IMPL_H_ +#include <map> #include <memory> #include <set> +#include <vector> #include "base/containers/unique_ptr_adapters.h" +#include "base/memory/raw_ptr.h" #include "content/browser/fenced_frame/fenced_frame_url_mapping.h" #include "content/browser/interest_group/auction_runner.h" #include "content/browser/interest_group/auction_worklet_manager.h" #include "content/common/content_export.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/document_service.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom-forward.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/network/public/cpp/wrapper_shared_url_loader_factory.h" @@ -32,6 +36,7 @@ class InterestGroupManagerImpl; class RenderFrameHost; class RenderFrameHostImpl; +class PrivateAggregationManager; // Implements the AdAuctionService service called by Blink code. class CONTENT_EXPORT AdAuctionServiceImpl final @@ -102,6 +107,15 @@ interest_group_api_operation, const url::Origin& origin) const; + // Sends requests for the Private Aggregation API to its manager. Does nothing + // if the manager is unavailable. The map should be keyed by reporting origin + // of the corresponding requests. + void SendPrivateAggregationRequests( + std::map< + url::Origin, + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>> + private_aggregation_requests) const; + // Deletes `auction`. void OnAuctionComplete( RunAdAuctionCallback callback, @@ -113,6 +127,10 @@ std::vector<GURL> debug_loss_report_urls, std::vector<GURL> debug_win_report_urls, ReportingMetadata ad_beacon_map, + std::map< + url::Origin, + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>> + private_aggregation_requests, std::vector<std::string> errors); InterestGroupManagerImpl& GetInterestGroupManager() const; @@ -139,6 +157,10 @@ AuctionWorkletManager auction_worklet_manager_; std::set<std::unique_ptr<AuctionRunner>, base::UniquePtrComparator> auctions_; + + // Safe to keep as it will outlive the associated `RenderFrameHost` and + // therefore `this`, being tied to the lifetime of the `StoragePartition`. + const raw_ptr<PrivateAggregationManager> private_aggregation_manager_; }; } // namespace content
diff --git a/content/browser/interest_group/ad_auction_service_impl_unittest.cc b/content/browser/interest_group/ad_auction_service_impl_unittest.cc index afea172a..347a6eb 100644 --- a/content/browser/interest_group/ad_auction_service_impl_unittest.cc +++ b/content/browser/interest_group/ad_auction_service_impl_unittest.cc
@@ -19,15 +19,19 @@ #include "base/synchronization/lock.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" #include "base/thread_annotations.h" #include "base/time/time.h" #include "build/build_config.h" #include "build/buildflag.h" +#include "content/browser/aggregation_service/aggregatable_report.h" #include "content/browser/fenced_frame/fenced_frame_url_mapping.h" #include "content/browser/interest_group/auction_process_manager.h" #include "content/browser/interest_group/interest_group_manager_impl.h" #include "content/browser/interest_group/interest_group_storage.h" +#include "content/browser/private_aggregation/private_aggregation_manager_impl.h" +#include "content/browser/private_aggregation/private_aggregation_test_utils.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/storage_partition_impl.h" #include "content/public/browser/browser_context.h" @@ -4967,6 +4971,82 @@ EXPECT_EQ(99, GetPriority(kOriginA, kInterestGroupName)); } +TEST_F(AdAuctionServiceImplTest, PrivateAggregationReportForwarded) { + constexpr char kBiddingScript[] = R"( +function generateBid( + interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals, + browserSignals) { + privateAggregation.sendHistogramReport({bucket: 1, value: 2}); + return {'ad': 'example', 'bid': 1, 'render': 'https://example.com/render'}; +} +)"; + + constexpr char kDecisionScript[] = R"( +function scoreAd( + adMetadata, bid, auctionConfig, trustedScoringSignals, browserSignals) { + return bid; +} +)"; + + class TestPrivateAggregationManagerImpl + : public PrivateAggregationManagerImpl { + public: + TestPrivateAggregationManagerImpl( + std::unique_ptr<PrivateAggregationBudgeter> budgeter, + std::unique_ptr<PrivateAggregationHost> host) + : PrivateAggregationManagerImpl(std::move(budgeter), + std::move(host), + /*storage_partition=*/nullptr) {} + }; + + base::MockRepeatingCallback<void(AggregatableReportRequest, + PrivateAggregationBudgetKey)> + mock_callback; + + static_cast<StoragePartitionImpl*>( + browser_context()->GetDefaultStoragePartition()) + ->OverridePrivateAggregationManagerForTesting( + std::make_unique<TestPrivateAggregationManagerImpl>( + std::make_unique<MockPrivateAggregationBudgeter>(), + std::make_unique<PrivateAggregationHost>( + /*on_report_request_received=*/mock_callback.Get()))); + + network_responder_->RegisterScriptResponse(kBiddingUrlPath, kBiddingScript); + network_responder_->RegisterScriptResponse(kDecisionUrlPath, kDecisionScript); + + blink::InterestGroup interest_group = CreateInterestGroup(); + interest_group.bidding_url = kUrlA.Resolve(kBiddingUrlPath); + interest_group.priority = 2; + interest_group.ads.emplace(); + blink::InterestGroup::Ad ad( + /*render_url=*/GURL("https://example.com/render"), + /*metadata=*/absl::nullopt); + interest_group.ads->emplace_back(std::move(ad)); + JoinInterestGroupAndFlush(interest_group); + + blink::AuctionConfig auction_config; + auction_config.seller = kOriginA; + auction_config.decision_logic_url = kUrlA.Resolve(kDecisionUrlPath); + auction_config.non_shared_params.interest_group_buyers = {kOriginA}; + + EXPECT_CALL(mock_callback, Run) + .WillRepeatedly( + testing::Invoke([this](AggregatableReportRequest request, + PrivateAggregationBudgetKey budget_key) { + ASSERT_EQ(request.payload_contents().contributions.size(), 1u); + EXPECT_EQ(request.payload_contents().contributions[0].bucket, 1); + EXPECT_EQ(request.payload_contents().contributions[0].value, 2); + EXPECT_EQ(request.shared_info().reporting_origin, kOriginA); + EXPECT_EQ(budget_key.api(), + PrivateAggregationBudgetKey::Api::kFledge); + EXPECT_EQ(budget_key.origin(), kOriginA); + })); + + absl::optional<GURL> auction_result = + RunAdAuctionAndFlush(std::move(auction_config)); + ASSERT_NE(auction_result, absl::nullopt); +} + class AdAuctionServiceImplNumAuctionLimitTest : public AdAuctionServiceImplTest { public:
diff --git a/content/browser/interest_group/auction_runner.cc b/content/browser/interest_group/auction_runner.cc index fa20501..2c205f4 100644 --- a/content/browser/interest_group/auction_runner.cc +++ b/content/browser/interest_group/auction_runner.cc
@@ -7,6 +7,7 @@ #include <stdint.h> #include <string> +#include <utility> #include <vector> #include "base/callback.h" @@ -14,6 +15,7 @@ #include "base/time/time.h" #include "content/browser/interest_group/interest_group_manager_impl.h" #include "content/public/browser/content_browser_client.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h" #include "services/network/public/mojom/client_security_state.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/interest_group/auction_config.h" @@ -54,13 +56,14 @@ UpdateInterestGroupsPostAuction(); - std::move(callback_).Run(this, /*render_url=*/absl::nullopt, - /*winning_group_key=*/absl::nullopt, - /*ad_component_urls=*/{}, - /*report_urls=*/{}, - std::move(debug_loss_report_urls), - std::move(debug_win_report_urls), - /*ad_beacon_map=*/{}, auction_.TakeErrors()); + std::move(callback_).Run( + this, /*render_url=*/absl::nullopt, + /*winning_group_key=*/absl::nullopt, + /*ad_component_urls=*/{}, + /*report_urls=*/{}, std::move(debug_loss_report_urls), + std::move(debug_win_report_urls), + /*ad_beacon_map=*/{}, auction_.TakePrivateAggregationRequests(), + auction_.TakeErrors()); } AuctionRunner::AuctionRunner( @@ -156,7 +159,8 @@ this, std::move(winning_group_key), auction_.top_bid()->bid->render_url, auction_.top_bid()->bid->ad_components, auction_.TakeReportUrls(), std::move(debug_loss_report_urls), std::move(debug_win_report_urls), - auction_.TakeAdBeaconMap(), auction_.TakeErrors()); + auction_.TakeAdBeaconMap(), auction_.TakePrivateAggregationRequests(), + auction_.TakeErrors()); } void AuctionRunner::UpdateInterestGroupsPostAuction() {
diff --git a/content/browser/interest_group/auction_runner.h b/content/browser/interest_group/auction_runner.h index 04a872d8..8c2b9d9 100644 --- a/content/browser/interest_group/auction_runner.h +++ b/content/browser/interest_group/auction_runner.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_BROWSER_INTEREST_GROUP_AUCTION_RUNNER_H_ #define CONTENT_BROWSER_INTEREST_GROUP_AUCTION_RUNNER_H_ +#include <map> #include <memory> #include <string> #include <vector> @@ -14,6 +15,7 @@ #include "content/browser/interest_group/auction_worklet_manager.h" #include "content/browser/interest_group/interest_group_auction.h" #include "content/common/content_export.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom-forward.h" #include "services/network/public/mojom/client_security_state.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/interest_group/interest_group.h" @@ -38,6 +40,9 @@ // the code to assign unique tracing IDs is not threadsafe. class CONTENT_EXPORT AuctionRunner { public: + using PrivateAggregationRequests = + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>; + // Invoked when a FLEDGE auction is complete. // // `winning_group_id` owner and name of the winning interest group (if any). @@ -68,6 +73,8 @@ std::vector<GURL> debug_loss_report_urls, std::vector<GURL> debug_win_report_urls, ReportingMetadata ad_beacon_map, + std::map<url::Origin, PrivateAggregationRequests> + private_aggregation_requests, std::vector<std::string> errors)>; // Returns true if `origin` is allowed to use the interest group API. Will be
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc index 00e7062..94107522 100644 --- a/content/browser/interest_group/auction_runner_unittest.cc +++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -34,12 +34,14 @@ #include "content/browser/interest_group/interest_group_auction.h" #include "content/browser/interest_group/interest_group_manager_impl.h" #include "content/browser/interest_group/interest_group_storage.h" +#include "content/common/aggregatable_report.mojom-shared.h" #include "content/public/browser/site_instance.h" #include "content/public/test/test_renderer_host.h" #include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/auction_worklet_service_impl.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h" #include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" #include "content/services/auction_worklet/worklet_devtools_debug_test_util.h" #include "content/services/auction_worklet/worklet_test_util.h" @@ -64,6 +66,7 @@ using InterestGroupKey = blink::InterestGroupKey; using PostAuctionSignals = InterestGroupAuction::PostAuctionSignals; using blink::mojom::ReportingDestination; +using PrivateAggregationRequests = AuctionRunner::PrivateAggregationRequests; const std::string kBidder1Name{"Ad Platform"}; const char kBidder1DebugLossReportUrl[] = @@ -99,6 +102,49 @@ "topLevelWinningBid=${topLevelWinningBid}," "topLevelMadeWinningBid=${topLevelMadeWinningBid}"; +const auction_worklet::mojom::PrivateAggregationRequestPtr + kExpectedGenerateBidPrivateAggregationRequest = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/1, + /*value=*/2), + content::mojom::AggregationServiceMode::kDefault); + +const auction_worklet::mojom::PrivateAggregationRequestPtr + kExpectedReportWinPrivateAggregationRequest = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/3, + /*value=*/4), + content::mojom::AggregationServiceMode::kDefault); + +const auction_worklet::mojom::PrivateAggregationRequestPtr + kExpectedScoreAdPrivateAggregationRequest = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/5, + /*value=*/6), + content::mojom::AggregationServiceMode::kDefault); + +const auction_worklet::mojom::PrivateAggregationRequestPtr + kExpectedReportResultPrivateAggregationRequest = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/7, + /*value=*/8), + content::mojom::AggregationServiceMode::kDefault); + +// Helper to avoid excess boilerplate. +template <typename... Ts> +auto ElementsAreRequests(Ts&... requests) { + static_assert( + std::conjunction<std::is_same< + std::remove_const_t<Ts>, + auction_worklet::mojom::PrivateAggregationRequestPtr>...>::value); + // Need to use `std::ref` as `mojo::StructPtr`s are move-only. + return testing::UnorderedElementsAre(testing::Eq(std::ref(requests))...); +} + // 0 `num_component_urls` means no component URLs, as opposed to an empty list // (which isn't tested at this layer). std::string MakeBidScript(const url::Origin& seller, @@ -236,6 +282,7 @@ } if (browserSignals.dataVersion !== undefined) throw new Error(`wrong dataVersion (${browserSignals.dataVersion})`); + privateAggregation.sendHistogramReport({bucket: 1, value: 2}); return result; } @@ -321,6 +368,7 @@ registerAdBeacon({ "click": "https://buyer-reporting.example.com/" + 2*bid, }); + privateAggregation.sendHistogramReport({bucket: 3, value: 4}); } )"; return base::StringPrintf( @@ -460,6 +508,7 @@ forDebuggingOnly.reportAdAuctionWin( buildDebugReportUrl(debugWinReportUrl) + bid); } + privateAggregation.sendHistogramReport({bucket: 5, value: 6}); adMetadata.fromComponentAuction = true; @@ -544,6 +593,8 @@ } sendReportTo(sendReportUrl + browserSignals.bid); } + privateAggregation.sendHistogramReport({bucket: 7, value: 8}); + return browserSignals; } @@ -600,6 +651,7 @@ const char kAuctionScriptRejects2[] = R"( function scoreAd(adMetadata, bid, auctionConfig, browserSignals) { + privateAggregation.sendHistogramReport({bucket: 5, value: 6}); if (bid === 2) return -1; return bid + 1; @@ -608,6 +660,7 @@ const char kBasicReportResult[] = R"( function reportResult(auctionConfig, browserSignals) { + privateAggregation.sendHistogramReport({bucket: 7, value: 8}); sendReportTo("https://reporting.example.com/" + browserSignals.bid); registerAdBeacon({ "click": "https://reporting.example.com/" + 2*browserSignals.bid, @@ -905,7 +958,8 @@ const absl::optional<uint32_t>& bidding_signals_data_version = absl::nullopt, const absl::optional<GURL>& debug_loss_report_url = absl::nullopt, - const absl::optional<GURL>& debug_win_report_url = absl::nullopt) { + const absl::optional<GURL>& debug_win_report_url = absl::nullopt, + PrivateAggregationRequests pa_requests = {}) { WaitForGenerateBid(); if (!bid.has_value()) { @@ -917,6 +971,7 @@ /*debug_win_report_url=*/absl::nullopt, /*set_priority=*/0, /*has_set_priority=*/false, + /*pa_requests=*/std::move(pa_requests), /*errors=*/std::vector<std::string>()); return; } @@ -929,6 +984,7 @@ debug_win_report_url, /*set_priority=*/0, /*has_set_priority=*/false, + /*pa_requests=*/std::move(pa_requests), /*errors=*/std::vector<std::string>()); } @@ -945,10 +1001,11 @@ void InvokeReportWinCallback( absl::optional<GURL> report_url = absl::nullopt, - base::flat_map<std::string, GURL> ad_beacon_map = {}) { + base::flat_map<std::string, GURL> ad_beacon_map = {}, + PrivateAggregationRequests pa_requests = {}) { DCHECK(report_win_callback_); std::move(report_win_callback_) - .Run(report_url, ad_beacon_map, + .Run(report_url, ad_beacon_map, std::move(pa_requests), /*errors=*/std::vector<std::string>()); } @@ -1109,11 +1166,12 @@ void InvokeReportResultCallback( absl::optional<GURL> report_url = absl::nullopt, base::flat_map<std::string, GURL> ad_beacon_map = {}, + PrivateAggregationRequests pa_requests = {}, std::vector<std::string> errors = {}) { DCHECK(report_result_callback_); std::move(report_result_callback_) .Run(/*signals_for_winner=*/absl::nullopt, std::move(report_url), - ad_beacon_map, errors); + ad_beacon_map, std::move(pa_requests), errors); } void Flush() { receiver_.FlushForTesting(); } @@ -1421,6 +1479,8 @@ std::vector<GURL> debug_loss_report_urls; std::vector<GURL> debug_win_report_urls; ReportingMetadata ad_beacon_map; + std::map<url::Origin, PrivateAggregationRequests> + private_aggregation_requests; std::vector<std::string> errors; @@ -1601,6 +1661,8 @@ std::vector<GURL> debug_loss_report_urls, std::vector<GURL> debug_win_report_urls, ReportingMetadata ad_beacon_map, + std::map<url::Origin, PrivateAggregationRequests> + private_aggregation_requests, std::vector<std::string> errors) { DCHECK(auction_run_loop_); DCHECK(!auction_complete_); @@ -1622,6 +1684,8 @@ result_.debug_loss_report_urls = std::move(debug_loss_report_urls); result_.debug_win_report_urls = std::move(debug_win_report_urls); result_.ad_beacon_map = std::move(ad_beacon_map); + result_.private_aggregation_requests = + std::move(private_aggregation_requests); // Retrieve bid count and previous wins for kBidder1 (and subsequently // kBidder2). @@ -2422,6 +2486,23 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + + EXPECT_THAT( + res.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); + EXPECT_EQ(6, res.bidder1_bid_count); EXPECT_EQ(3u, res.bidder1_prev_wins.size()); EXPECT_EQ(6, res.bidder2_bid_count); @@ -2595,6 +2676,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair( + kSeller, ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); } } @@ -2663,6 +2759,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); } TEST_F(AuctionRunnerTest, PauseSeller) { @@ -2726,6 +2837,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); } // A component auction with two successful bids from different components. @@ -2761,6 +2887,28 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair( + kComponentSeller1, + ElementsAreRequests(kExpectedScoreAdPrivateAggregationRequest)), + testing::Pair(kComponentSeller2, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(6, result_.bidder2_bid_count); @@ -2801,6 +2949,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(6, result_.bidder2_bid_count); @@ -2873,6 +3036,24 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair( + kComponentSeller1, + ElementsAreRequests(kExpectedScoreAdPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(6, result_.bidder2_bid_count); @@ -2918,6 +3099,25 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair(kComponentSeller1, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(6, result_.bidder2_bid_count); @@ -2947,6 +3147,7 @@ const char kBidScript[] = R"( function generateBid(interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals, browserSignals) { + privateAggregation.sendHistogramReport({bucket: 1, value: 2}); if (browserSignals.seller == "https://component.seller1.test") { return {ad: [], bid: 1, render: "https://component-bid.test/", allowComponentAuction: true}; @@ -2965,6 +3166,7 @@ registerAdBeacon({ "click": "https://buyer-reporting.example.com/" + 2*browserSignals.bid, }); + privateAggregation.sendHistogramReport({bucket: 3, value: 4}); } )"; @@ -2972,6 +3174,7 @@ // on bid and seller, to make sure correct values are plumbed through. const std::string kSellerScript = R"( function scoreAd(adMetadata, bid, auctionConfig, browserSignals) { + privateAggregation.sendHistogramReport({bucket: 5, value: 6}); if (auctionConfig.seller == "https://adstuff.publisher1.com") return {desirability: 20 + bid, allowComponentAuction: true}; return {desirability: 10 + bid, allowComponentAuction: true}; @@ -2983,6 +3186,7 @@ registerAdBeacon({ "click": auctionConfig.seller + "/" + 2*browserSignals.desirability, }); + privateAggregation.sendHistogramReport({bucket: 7, value: 8}); } )"; @@ -3032,6 +3236,22 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair( + kComponentSeller1, + ElementsAreRequests(kExpectedScoreAdPrivateAggregationRequest)))); // Bid count should only be incremented by 1. EXPECT_EQ(6, result_.bidder1_bid_count); ASSERT_EQ(4u, result_.bidder1_prev_wins.size()); @@ -3089,6 +3309,28 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/6")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedGenerateBidPrivateAggregationRequest, + kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair( + kComponentSeller1, + ElementsAreRequests(kExpectedScoreAdPrivateAggregationRequest)), + testing::Pair(kComponentSeller2, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); // Bid count should only be incremented by 1. EXPECT_EQ(6, result_.bidder1_bid_count); ASSERT_EQ(4u, result_.bidder1_prev_wins.size()); @@ -3197,6 +3439,25 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/2")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair(kComponentSeller1, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); ASSERT_EQ(4u, result_.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", @@ -3216,6 +3477,7 @@ const char kBidScript[] = R"( function generateBid(interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals, browserSignals) { + privateAggregation.sendHistogramReport({bucket: 1, value: 2}); return {ad: [], bid: 2, render: interestGroup.ads[0].renderUrl, allowComponentAuction: true}; } @@ -3226,6 +3488,7 @@ registerAdBeacon({ "click": "https://buyer-reporting.example.com/" + 2*browserSignals.bid, }); + privateAggregation.sendHistogramReport({bucket: 3, value: 4}); } )"; @@ -3233,6 +3496,7 @@ // top-level seller signals are null. const std::string kComponentSellerScript = R"( function scoreAd(adMetadata, bid, auctionConfig, browserSignals) { + privateAggregation.sendHistogramReport({bucket: 5, value: 6}); return {desirability: 10, allowComponentAuction: true}; } @@ -3243,6 +3507,7 @@ "click": auctionConfig.seller + "/" + (browserSignals.topLevelSellerSignals === null), }); + privateAggregation.sendHistogramReport({bucket: 7, value: 8}); } )"; @@ -3250,6 +3515,7 @@ // value. const std::string kTopLevelSellerScript = R"( function scoreAd(adMetadata, bid, auctionConfig, browserSignals) { + privateAggregation.sendHistogramReport({bucket: 5, value: 6}); return {desirability: 10, allowComponentAuction: true}; } @@ -3258,6 +3524,7 @@ registerAdBeacon({ "click": auctionConfig.seller + "/" + 2 * browserSignals.bid, }); + privateAggregation.sendHistogramReport({bucket: 7, value: 8}); // Note that there's no return value here. } )"; @@ -3303,6 +3570,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair(kComponentSeller1, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); CheckHistograms(InterestGroupAuction::AuctionResult::kSuccess, /*expected_interest_groups=*/1, /*expected_owners=*/1, /*expected_sellers=*/2); @@ -3402,6 +3684,7 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); CheckHistograms(InterestGroupAuction::AuctionResult::kSuccess, /*expected_interest_groups=*/1, /*expected_owners=*/1, /*expected_sellers=*/2); @@ -3422,6 +3705,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -3455,6 +3739,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -3509,6 +3794,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/2")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair(kComponentSeller1, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); ASSERT_EQ(4u, result_.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", @@ -3536,6 +3836,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -3589,6 +3890,17 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/2")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); ASSERT_EQ(4u, result_.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", @@ -3625,6 +3937,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -3674,6 +3987,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/2")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair(kComponentSeller1, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); ASSERT_EQ(4u, result_.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", @@ -3764,6 +4092,17 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/2")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, res.bidder1_bid_count); ASSERT_EQ(4u, res.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", @@ -3826,6 +4165,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/2")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair(kComponentSeller1, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); // The bid send to the failing component seller worklet isn't counted, // regardless of whether the bid completed before the worklet failed to load. @@ -3879,6 +4233,17 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/2")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, res.bidder1_bid_count); ASSERT_EQ(4u, res.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", @@ -3916,6 +4281,7 @@ EXPECT_TRUE(res.ad_component_urls.empty()); EXPECT_THAT(res.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(res.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(res.private_aggregation_requests.empty()); EXPECT_EQ(5, res.bidder1_bid_count); EXPECT_EQ(3u, res.bidder1_prev_wins.size()); EXPECT_EQ(5, res.bidder2_bid_count); @@ -3957,6 +4323,7 @@ EXPECT_TRUE(res.ad_component_urls.empty()); EXPECT_THAT(res.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(res.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(res.private_aggregation_requests.empty()); EXPECT_EQ(5, res.bidder1_bid_count); EXPECT_EQ(3u, res.bidder1_prev_wins.size()); EXPECT_EQ(5, res.bidder2_bid_count); @@ -4006,6 +4373,15 @@ EXPECT_TRUE(res.ad_component_urls.empty()); EXPECT_THAT(res.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(res.ad_beacon_map.metadata.empty()); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)))); EXPECT_EQ(6, res.bidder1_bid_count); EXPECT_EQ(3u, res.bidder1_prev_wins.size()); EXPECT_EQ(6, res.bidder2_bid_count); @@ -4064,6 +4440,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/2")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, res.bidder1_bid_count); ASSERT_EQ(4u, res.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", @@ -4087,6 +4478,7 @@ EXPECT_TRUE(res.ad_component_urls.empty()); EXPECT_THAT(res.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(res.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(res.private_aggregation_requests.empty()); EXPECT_EQ(0, url_loader_factory_.NumPending()); EXPECT_EQ(5, res.bidder1_bid_count); @@ -4144,6 +4536,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, res.bidder1_bid_count); EXPECT_EQ(3u, res.bidder1_prev_wins.size()); EXPECT_EQ(6, res.bidder2_bid_count); @@ -4196,6 +4603,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, res.bidder1_bid_count); EXPECT_EQ(3u, res.bidder1_prev_wins.size()); EXPECT_EQ(6, res.bidder2_bid_count); @@ -4254,6 +4676,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, res.bidder1_bid_count); EXPECT_EQ(3u, res.bidder1_prev_wins.size()); EXPECT_EQ(6, res.bidder2_bid_count); @@ -4305,6 +4742,21 @@ ReportingDestination::kSeller, testing::ElementsAre(testing::Pair( "click", GURL("https://reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + // ReportWin script override doesn't send a report + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, res.bidder1_bid_count); EXPECT_EQ(3u, res.bidder1_prev_wins.size()); EXPECT_EQ(6, res.bidder2_bid_count); @@ -4351,6 +4803,21 @@ res.ad_component_urls); EXPECT_THAT(res.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(res.ad_beacon_map.metadata.empty()); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + // ReportWin script override doesn't send a report + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, res.bidder1_bid_count); EXPECT_EQ(3u, res.bidder1_prev_wins.size()); EXPECT_EQ(6, res.bidder2_bid_count); @@ -4405,6 +4872,16 @@ EXPECT_THAT(res.report_urls, testing::UnorderedElementsAre(GURL( "https://seller.signals.were.null.test/"))); EXPECT_TRUE(res.ad_beacon_map.metadata.empty()); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + // ReportWin script override doesn't send a report + kExpectedGenerateBidPrivateAggregationRequest)))); EXPECT_EQ(6, res.bidder1_bid_count); EXPECT_EQ(3u, res.bidder1_prev_wins.size()); EXPECT_EQ(6, res.bidder2_bid_count); @@ -4533,6 +5010,17 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/2")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + // Overridden script functions don't send reports + testing::UnorderedElementsAre( + testing::Pair( + kBidder1, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(4u, result_.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", @@ -4691,6 +5179,22 @@ testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair( + kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(6, result_.bidder2_bid_count); @@ -4867,6 +5371,29 @@ testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair( + kSeller, ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair(kComponentSeller1, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest)), + testing::Pair( + kComponentSeller2, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); CheckHistograms(InterestGroupAuction::AuctionResult::kSuccess, /*expected_interest_groups=*/2, /*expected_owners=*/2, /*expected_sellers=*/3); @@ -5020,6 +5547,21 @@ ReportingDestination::kBuyer, testing::ElementsAre(testing::Pair( "click", GURL("https://buyer-reporting.example.com/4")))))); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair( + kBidder2, + ElementsAreRequests(kExpectedGenerateBidPrivateAggregationRequest, + kExpectedReportWinPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)), + testing::Pair(kComponentSeller2, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); CheckHistograms(InterestGroupAuction::AuctionResult::kSuccess, /*expected_interest_groups=*/2, /*expected_owners=*/2, /*expected_sellers=*/3); @@ -5106,6 +5648,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); } TEST_F(AuctionRunnerTest, AllBiddersCrashBeforeBidding) { @@ -5163,6 +5706,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -5239,7 +5783,8 @@ /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Finish the auction. seller_worklet->WaitForReportResult(); @@ -5264,6 +5809,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(6, result_.bidder2_bid_count); @@ -5290,13 +5836,32 @@ mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url); ASSERT_TRUE(bidder2_worklet); - bidder1_worklet->InvokeGenerateBidCallback(/*bid=*/7, - GURL("https://ad1.com/")); + PrivateAggregationRequests bidder_1_pa_requests; + bidder_1_pa_requests.push_back( + kExpectedGenerateBidPrivateAggregationRequest.Clone()); + bidder1_worklet->InvokeGenerateBidCallback( + /*bid=*/7, GURL("https://ad1.com/"), + /*ad_component_urls=*/absl::nullopt, + /*duration=*/base::TimeDelta(), + /*bidding_signals_data_version=*/ + absl::nullopt, + /*debug_loss_report_url=*/absl::nullopt, + /*debug_win_report_url=*/absl::nullopt, std::move(bidder_1_pa_requests)); // The bidder pipe should be closed after it bids. EXPECT_TRUE(bidder1_worklet->PipeIsClosed()); bidder1_worklet.reset(); - bidder2_worklet->InvokeGenerateBidCallback(/*bid=*/5, - GURL("https://ad2.com/")); + + PrivateAggregationRequests bidder_2_pa_requests; + bidder_2_pa_requests.push_back( + kExpectedGenerateBidPrivateAggregationRequest.Clone()); + bidder2_worklet->InvokeGenerateBidCallback( + /*bid=*/5, GURL("https://ad2.com/"), + /*ad_component_urls=*/absl::nullopt, + /*duration=*/base::TimeDelta(), + /*bidding_signals_data_version=*/ + absl::nullopt, + /*debug_loss_report_url=*/absl::nullopt, + /*debug_win_report_url=*/absl::nullopt, std::move(bidder_2_pa_requests)); // The bidder pipe should be closed after it bids. EXPECT_TRUE(bidder2_worklet->PipeIsClosed()); bidder2_worklet.reset(); @@ -5305,27 +5870,43 @@ auto score_ad_params = seller_worklet->WaitForScoreAd(); EXPECT_EQ(kBidder1, score_ad_params.interest_group_owner); EXPECT_EQ(7, score_ad_params.bid); + PrivateAggregationRequests score_ad_1_pa_requests; + score_ad_1_pa_requests.push_back( + kExpectedScoreAdPrivateAggregationRequest.Clone()); std::move(score_ad_params.callback) .Run(/*score=*/11, auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, + std::move(score_ad_1_pa_requests), + /*errors=*/{}); // Score Bidder2's bid. score_ad_params = seller_worklet->WaitForScoreAd(); EXPECT_EQ(kBidder2, score_ad_params.interest_group_owner); EXPECT_EQ(5, score_ad_params.bid); + PrivateAggregationRequests score_ad_2_pa_requests; + score_ad_2_pa_requests.push_back( + kExpectedScoreAdPrivateAggregationRequest.Clone()); std::move(score_ad_params.callback) .Run(/*score=*/10, auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, + std::move(score_ad_2_pa_requests), + /*errors=*/{}); + + PrivateAggregationRequests report_result_pa_requests; + report_result_pa_requests.push_back( + kExpectedReportResultPrivateAggregationRequest.Clone()); // Bidder1 crashes while running ReportWin. seller_worklet->WaitForReportResult(); - seller_worklet->InvokeReportResultCallback(); + seller_worklet->InvokeReportResultCallback( + /*report_url=*/absl::nullopt, + /*ad_beacon_map=*/{}, std::move(report_result_pa_requests)); mock_auction_process_manager_->WaitForWinningBidderReload(); bidder1_worklet = mock_auction_process_manager_->TakeBidderWorklet(kBidder1Url); @@ -5342,6 +5923,20 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_THAT( + result_.private_aggregation_requests, + testing::UnorderedElementsAre( + testing::Pair(kBidder1, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kBidder2, + ElementsAreRequests( + kExpectedGenerateBidPrivateAggregationRequest)), + testing::Pair(kSeller, + ElementsAreRequests( + kExpectedScoreAdPrivateAggregationRequest, + kExpectedScoreAdPrivateAggregationRequest, + kExpectedReportResultPrivateAggregationRequest)))); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(6, result_.bidder2_bid_count); @@ -5443,7 +6038,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Score Bidder2's bid. EXPECT_EQ(kBidder2, score_ad_params2.interest_group_owner); @@ -5453,7 +6049,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); seller_worklet->WaitForReportResult(); DCHECK_EQ(CrashPhase::kReportResult, crash_phase); @@ -5472,6 +6069,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); if (crash_phase != CrashPhase::kReportResult) { EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); @@ -5565,7 +6163,7 @@ /*has_bid=*/false), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, /*errors=*/{}); // Top-level seller worklet scores the bid. @@ -5580,7 +6178,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Top-level seller worklet returns a report url. top_level_seller_worklet->WaitForReportResult(); @@ -5677,7 +6276,8 @@ /*has_bid=*/false), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Top-level seller worklet scores the bid. auto top_level_seller_worklet = @@ -5691,7 +6291,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Top-level seller worklet returns a report url. top_level_seller_worklet->WaitForReportResult(); @@ -5755,7 +6356,8 @@ const char kScriptError[] = "Script error"; component_seller_worklet->InvokeReportResultCallback( - /*report_url=*/absl::nullopt, /*ad_beacon_map=*/{}, {kScriptError}); + /*report_url=*/absl::nullopt, /*ad_beacon_map=*/{}, + /*pa_requests=*/{}, {kScriptError}); // Winning bidder worklet should be reloaded and ReportWin() invoked. mock_auction_process_manager_->WaitForWinningBidderReload(); @@ -5893,7 +6495,7 @@ .Run(/*score=*/3, test_case.params.Clone(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, /*errors=*/{}); // The auction fails, because of the bad ComponentAuctionModifiedBidParams. @@ -5951,7 +6553,7 @@ /*has_bid=*/false), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, /*errors=*/{}); auction_run_loop_->Run(); @@ -6015,7 +6617,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Finish the auction. seller_worklet->WaitForReportResult(); @@ -6035,6 +6638,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(6, result_.bidder1_bid_count); ASSERT_EQ(4u, result_.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", @@ -6056,6 +6660,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); CheckHistograms(InterestGroupAuction::AuctionResult::kNoBids, @@ -6106,7 +6711,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Finish the auction. seller_worklet->WaitForReportResult(); @@ -6126,6 +6732,7 @@ EXPECT_EQ(ad_component_urls, result_.ad_component_urls); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(6, result_.bidder1_bid_count); ASSERT_EQ(4u, result_.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", @@ -6147,6 +6754,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); CheckHistograms(InterestGroupAuction::AuctionResult::kNoBids, @@ -6298,6 +6906,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -6336,7 +6945,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Bidder1 never gets to report anything, since the seller providing a bad // report URL aborts the auction. @@ -6353,6 +6963,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -6390,7 +7001,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Bidder1 never gets to report anything, since the seller providing a bad // report URL aborts the auction. @@ -6409,6 +7021,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -6457,7 +7070,8 @@ /*has_bid=*/false), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Top-level seller scores the bid. score_ad_params = seller_worklet->WaitForScoreAd(); @@ -6468,7 +7082,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Top-level seller worklet returns a valid HTTPS report URL. seller_worklet->WaitForReportResult(); @@ -6495,6 +7110,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -6532,7 +7148,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); seller_worklet->WaitForReportResult(); seller_worklet->InvokeReportResultCallback( @@ -6553,6 +7170,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -6590,7 +7208,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); seller_worklet->WaitForReportResult(); seller_worklet->InvokeReportResultCallback( @@ -6613,6 +7232,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(5, result_.bidder2_bid_count); @@ -6653,7 +7273,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Finish the auction. seller_worklet->WaitForReportResult(); @@ -6672,6 +7293,7 @@ EXPECT_TRUE(result_.ad_component_urls.empty()); EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(5, result_.bidder1_bid_count); EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); EXPECT_EQ(6, result_.bidder2_bid_count); @@ -6713,7 +7335,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Bidder2 returns a bid, which is then scored. bidder2_worklet->InvokeGenerateBidCallback(/*bid=*/5, @@ -6726,7 +7349,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Need to flush the service pipe to make sure the AuctionRunner has // received the score. seller_worklet->Flush(); @@ -6779,6 +7403,7 @@ EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre()); EXPECT_TRUE(result_.ad_beacon_map.metadata.empty()); + EXPECT_TRUE(result_.private_aggregation_requests.empty()); EXPECT_EQ(6, result_.bidder1_bid_count); EXPECT_EQ(6, result_.bidder2_bid_count); CheckHistograms(InterestGroupAuction::AuctionResult::kSuccess, @@ -6856,7 +7481,8 @@ ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, /*errors=*/{}); + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, + /*errors=*/{}); // Wait for the AuctionRunner to receive the score. task_environment_.RunUntilIdle(); break; @@ -6868,7 +7494,7 @@ /*data_version=*/0, /*has_data_version=*/false, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, + /*debug_win_report_url=*/absl::nullopt, /*pa_requests=*/{}, /*errors=*/{}); // Wait for the AuctionRunner to receive the score. task_environment_.RunUntilIdle(); @@ -8170,7 +8796,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, test_case.seller_debug_loss_report_url, - test_case.seller_debug_win_report_url, /*errors=*/{}); + test_case.seller_debug_win_report_url, /*pa_requests=*/{}, + /*errors=*/{}); auction_run_loop_->Run(); EXPECT_EQ(test_case.expected_error_message, TakeBadMessage()); @@ -8229,7 +8856,8 @@ auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr(), /*data_version=*/0, /*has_data_version=*/false, GURL("https://seller-debug-loss-reporting.com/1"), - GURL("https://seller-debug-win-reporting.com/1"), /*errors=*/{}); + GURL("https://seller-debug-win-reporting.com/1"), /*pa_requests=*/{}, + /*errors=*/{}); seller_worklet->WaitForReportResult(); seller_worklet->InvokeReportResultCallback();
diff --git a/content/browser/interest_group/interest_group_auction.cc b/content/browser/interest_group/interest_group_auction.cc index be448413..1f88eab 100644 --- a/content/browser/interest_group/interest_group_auction.cc +++ b/content/browser/interest_group/interest_group_auction.cc
@@ -7,16 +7,20 @@ #include <stdint.h> #include <algorithm> +#include <iterator> #include <string> +#include <utility> #include <vector> #include "base/callback.h" +#include "base/check.h" #include "base/containers/cxx20_erase_vector.h" #include "base/location.h" #include "base/memory/ptr_util.h" #include "base/memory/raw_ptr.h" #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" +#include "base/ranges/algorithm.h" #include "base/strings/escape.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" @@ -32,6 +36,7 @@ #include "content/browser/interest_group/storage_interest_group.h" #include "content/public/browser/content_browser_client.h" #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h" #include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" #include "services/network/public/mojom/client_security_state.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom-forward.h" @@ -357,19 +362,21 @@ /*debug_win_report_url=*/absl::nullopt, /*set_priority=*/0, /*has_set_priority=*/false, + /*pa_requests=*/{}, {base::StrCat({bid_state->bidder.interest_group.bidding_url->spec(), " crashed while trying to run generateBid()."})}); return; } // Otherwise, use error message from the worklet. - OnGenerateBidComplete( - bid_state, auction_worklet::mojom::BidderWorkletBidPtr(), - /*bidding_signals_data_version=*/0, - /*has_bidding_signals_data_version=*/false, - /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, - /*set_priority=*/0, /*has_set_priority=*/false, errors); + OnGenerateBidComplete(bid_state, + auction_worklet::mojom::BidderWorkletBidPtr(), + /*bidding_signals_data_version=*/0, + /*has_bidding_signals_data_version=*/false, + /*debug_loss_report_url=*/absl::nullopt, + /*debug_win_report_url=*/absl::nullopt, + /*set_priority=*/0, /*has_set_priority=*/false, + /*pa_requests=*/{}, errors); } // Invoked whenever the AuctionWorkletManager has provided a BidderWorket @@ -426,6 +433,7 @@ const absl::optional<GURL>& debug_win_report_url, double set_priority, bool has_set_priority, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { DCHECK(!state->made_bid); DCHECK_GT(num_outstanding_bids_, 0); @@ -444,6 +452,19 @@ set_priority); } + DCHECK(base::ranges::none_of( + pa_requests, + [](const auction_worklet::mojom::PrivateAggregationRequestPtr& + request_ptr) { return request_ptr.is_null(); })); + if (!pa_requests.empty()) { + PrivateAggregationRequests& pa_requests_for_bidder = + auction_->private_aggregation_requests_[state->bidder.interest_group + .owner]; + pa_requests_for_bidder.insert(pa_requests_for_bidder.end(), + std::move_iterator(pa_requests.begin()), + std::move_iterator(pa_requests.end())); + } + auction_->errors_.insert(auction_->errors_.end(), errors.begin(), errors.end()); @@ -959,6 +980,23 @@ return std::move(report_urls_); } +std::map<url::Origin, InterestGroupAuction::PrivateAggregationRequests> +InterestGroupAuction::TakePrivateAggregationRequests() { + for (auto& component_auction : component_auctions_) { + std::map<url::Origin, PrivateAggregationRequests> requests_map = + component_auction->TakePrivateAggregationRequests(); + for (auto& [origin, requests] : requests_map) { + DCHECK(!requests.empty()); + PrivateAggregationRequests& destination_vector = + private_aggregation_requests_[origin]; + destination_vector.insert(destination_vector.end(), + std::move_iterator(requests.begin()), + std::move_iterator(requests.end())); + } + } + return std::move(private_aggregation_requests_); +} + std::vector<std::string> InterestGroupAuction::TakeErrors() { for (auto& component_auction : component_auctions_) { std::vector<std::string> errors = component_auction->TakeErrors(); @@ -1259,6 +1297,7 @@ bool has_data_version, const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { DCHECK_GT(bids_being_scored_, 0); TRACE_EVENT_NESTABLE_ASYNC_END0("fledge", "seller_worklet_score_ad", @@ -1267,6 +1306,19 @@ --bids_being_scored_; + DCHECK(base::ranges::none_of( + pa_requests, + [](const auction_worklet::mojom::PrivateAggregationRequestPtr& + request_ptr) { return request_ptr.is_null(); })); + if (!pa_requests.empty()) { + DCHECK(config_); + PrivateAggregationRequests& pa_requests_for_seller = + private_aggregation_requests_[config_->seller]; + pa_requests_for_seller.insert(pa_requests_for_seller.end(), + std::move_iterator(pa_requests.begin()), + std::move_iterator(pa_requests.end())); + } + // If `debug_loss_report_url` or `debug_win_report_url` is not a valid HTTPS // URL, the auction should fail because the worklet is compromised. if (debug_loss_report_url.has_value() && @@ -1539,6 +1591,7 @@ const absl::optional<std::string>& signals_for_winner, const absl::optional<GURL>& seller_report_url, const base::flat_map<std::string, GURL>& seller_ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { TRACE_EVENT_NESTABLE_ASYNC_END0("fledge", "seller_worklet_report_result", trace_id_); @@ -1552,6 +1605,19 @@ // an error if it crashes at this point, failing the auction unnecessarily. seller_worklet_handle_.reset(); + DCHECK(base::ranges::none_of( + pa_requests, + [](const auction_worklet::mojom::PrivateAggregationRequestPtr& + request_ptr) { return request_ptr.is_null(); })); + if (!pa_requests.empty()) { + DCHECK(config_); + PrivateAggregationRequests& pa_requests_for_seller = + private_aggregation_requests_[config_->seller]; + pa_requests_for_seller.insert(pa_requests_for_seller.end(), + std::move_iterator(pa_requests.begin()), + std::move_iterator(pa_requests.end())); + } + if (!seller_ad_beacon_map.empty()) { for (const auto& element : seller_ad_beacon_map) { if (!IsUrlValid(element.second)) { @@ -1640,6 +1706,7 @@ void InterestGroupAuction::OnReportBidWinComplete( const absl::optional<GURL>& bidder_report_url, const base::flat_map<std::string, GURL>& bidder_ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { // There should be at most one other report URL at this point. DCHECK_LE(report_urls_.size(), 1u); @@ -1651,6 +1718,19 @@ // fatal error notification. top_bid_->bid->bid_state->worklet_handle.reset(); + DCHECK(base::ranges::none_of( + pa_requests, + [](const auction_worklet::mojom::PrivateAggregationRequestPtr& + request_ptr) { return request_ptr.is_null(); })); + if (!pa_requests.empty()) { + DCHECK(config_); + PrivateAggregationRequests& pa_requests_for_bidder = + private_aggregation_requests_[top_bid_->bid->interest_group->owner]; + pa_requests_for_bidder.insert(pa_requests_for_bidder.end(), + std::move_iterator(pa_requests.begin()), + std::move_iterator(pa_requests.end())); + } + if (!bidder_ad_beacon_map.empty()) { for (const auto& element : bidder_ad_beacon_map) { if (!IsUrlValid(element.second)) { @@ -1695,7 +1775,8 @@ // currently fail the auction. OnReportSellerResultComplete(/*signals_for_winner=*/absl::nullopt, /*seller_report_url=*/absl::nullopt, - /*seller_ad_beacon_map=*/{}, errors); + /*seller_ad_beacon_map=*/{}, + /*pa_requests=*/{}, errors); } } @@ -1715,7 +1796,8 @@ // An error while reloading the worklet to call ReportWin() does not // currently fail the auction. OnReportBidWinComplete(/*bidder_report_url=*/absl::nullopt, - /*bidder_ad_beacon_map=*/{}, errors); + /*bidder_ad_beacon_map=*/{}, + /*pa_requests=*/{}, errors); } }
diff --git a/content/browser/interest_group/interest_group_auction.h b/content/browser/interest_group/interest_group_auction.h index 3844153..474947c 100644 --- a/content/browser/interest_group/interest_group_auction.h +++ b/content/browser/interest_group/interest_group_auction.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include <map> #include <memory> #include <string> #include <vector> @@ -23,6 +24,7 @@ #include "content/common/content_export.h" #include "content/public/browser/content_browser_client.h" #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom-forward.h" #include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" #include "services/network/public/mojom/client_security_state.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -292,6 +294,9 @@ // Always invoked asynchronously. using AuctionPhaseCompletionCallback = base::OnceCallback<void(bool success)>; + using PrivateAggregationRequests = + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>; + // All passed in raw pointers must remain valid until the InterestGroupAuction // is destroyed. `config` is typically owned by the AuctionRunner's // `owned_auction_config_` field. `parent` should be the parent @@ -386,6 +391,14 @@ // URLs. std::vector<GURL> TakeReportUrls(); + // Retrieves all requests to the Private Aggregation API returned by + // GenerateBid(), ScoreAd(), ReportWin() and ReportResult(). The return value + // is keyed by reporting origin of the associated requests. May only be called + // after an auction has completed (successfully or not). May only be called + // once, since it takes ownership of stored reporting URLs. + std::map<url::Origin, PrivateAggregationRequests> + TakePrivateAggregationRequests(); + // Retrieves any errors from the auction. May only be called once, since it // takes ownership of stored errors. std::vector<std::string> TakeErrors(); @@ -497,6 +510,7 @@ bool has_scoring_signals_data_version, const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors); // Invoked when the bid becomes the new highest scoring other bid, to handle @@ -531,12 +545,14 @@ const absl::optional<std::string>& signals_for_winner, const absl::optional<GURL>& seller_report_url, const base::flat_map<std::string, GURL>& seller_ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& error_msgs); void LoadBidderWorkletToReportBidWin(const std::string& signals_for_winner); void ReportBidWin(const std::string& signals_for_winner); void OnReportBidWinComplete( const absl::optional<GURL>& bidder_report_url, const base::flat_map<std::string, GURL>& bidder_ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& error_msgs); // Called when the component SellerWorklet with the bidder that won an @@ -719,6 +735,12 @@ // auction itself can be deleted at the end of the auction. std::vector<GURL> report_urls_; + // Stores all pending Private Aggregation API report requests until they have + // been flushed. Keyed by the origin of the script that issued the request + // (i.e. the reporting origin). + std::map<url::Origin, PrivateAggregationRequests> + private_aggregation_requests_; + // All errors reported by worklets thus far. std::vector<std::string> errors_;
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc index 71836df..2096290 100644 --- a/content/browser/media/session/media_session_impl.cc +++ b/content/browser/media/session/media_session_impl.cc
@@ -304,6 +304,9 @@ one_shot_players_.clear(); AbandonSystemAudioFocusIfNeeded(); + + content::GetContentClient()->browser()->RemovePresentationObserver( + this, web_contents()); } void MediaSessionImpl::RenderFrameDeleted(RenderFrameHost* rfh) { @@ -999,6 +1002,14 @@ DCHECK(web_contents()); DidUpdateFaviconURL(web_contents()->GetPrimaryMainFrame(), web_contents()->GetFaviconURLs()); + + content::GetContentClient()->browser()->AddPresentationObserver( + this, web_contents()); +} + +void MediaSessionImpl::OnPresentationsChanged(bool has_presentation) { + has_presentation_ = has_presentation; + RebuildAndNotifyMediaSessionInfoChanged(); } AudioFocusDelegate::AudioFocusResult MediaSessionImpl::RequestSystemAudioFocus( @@ -1107,6 +1118,7 @@ } info->muted = is_muted_; + info->has_presentation = has_presentation_; return info; }
diff --git a/content/browser/media/session/media_session_impl.h b/content/browser/media/session/media_session_impl.h index 583375d5..cfb53aa 100644 --- a/content/browser/media/session/media_session_impl.h +++ b/content/browser/media/session/media_session_impl.h
@@ -22,6 +22,7 @@ #include "content/common/content_export.h" #include "content/public/browser/media_session.h" #include "content/public/browser/page_user_data.h" +#include "content/public/browser/presentation_observer.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -71,7 +72,8 @@ // work with it. class MediaSessionImpl : public MediaSession, public WebContentsObserver, - public WebContentsUserData<MediaSessionImpl> { + public WebContentsUserData<MediaSessionImpl>, + public PresentationObserver { public: enum class State { ACTIVE, SUSPENDED, INACTIVE }; @@ -287,6 +289,9 @@ // Mute or unmute the media player. void SetMute(bool mute) override; + // PresentationObserver: + void OnPresentationsChanged(bool has_presentation) override; + // Downloads the bitmap version of a MediaImage at least |minimum_size_px| // and closest to |desired_size_px|. If the download failed, was too small or // the image did not come from the media session then returns a null image. @@ -596,6 +601,9 @@ bool should_throttle_duration_update_ = false; + // Whether the associated WebContents is connected to a presentation. + bool has_presentation_ = false; + absl::optional<PlayerIdentifier> guarding_player_id_; WEB_CONTENTS_USER_DATA_KEY_DECL();
diff --git a/content/browser/media/session/media_session_impl_unittest.cc b/content/browser/media/session/media_session_impl_unittest.cc index dc3b70e..2a3497b6 100644 --- a/content/browser/media/session/media_session_impl_unittest.cc +++ b/content/browser/media/session/media_session_impl_unittest.cc
@@ -734,6 +734,19 @@ EXPECT_FALSE(info->audio_sink_id.has_value()); } +TEST_F(MediaSessionImplTest, SessionInfoPresentation) { + EXPECT_FALSE(media_session::test::GetMediaSessionInfoSync(GetMediaSession()) + ->has_presentation); + + GetMediaSession()->OnPresentationsChanged(true); + EXPECT_TRUE(media_session::test::GetMediaSessionInfoSync(GetMediaSession()) + ->has_presentation); + + GetMediaSession()->OnPresentationsChanged(false); + EXPECT_FALSE(media_session::test::GetMediaSessionInfoSync(GetMediaSession()) + ->has_presentation); +} + TEST_F(MediaSessionImplTest, RaiseActivatesWebContents) { MockWebContentsDelegate delegate; web_contents()->SetDelegate(&delegate);
diff --git a/content/browser/private_aggregation/private_aggregation_manager.cc b/content/browser/private_aggregation/private_aggregation_manager.cc index 1597b0d..da93ddf 100644 --- a/content/browser/private_aggregation/private_aggregation_manager.cc +++ b/content/browser/private_aggregation/private_aggregation_manager.cc
@@ -11,9 +11,9 @@ namespace content { PrivateAggregationManager* PrivateAggregationManager::GetManager( - BrowserContext* browser_context) { + BrowserContext& browser_context) { return static_cast<StoragePartitionImpl*>( - browser_context->GetDefaultStoragePartition()) + browser_context.GetDefaultStoragePartition()) ->GetPrivateAggregationManager(); }
diff --git a/content/browser/private_aggregation/private_aggregation_manager.h b/content/browser/private_aggregation/private_aggregation_manager.h index c50766c..d57a75f06 100644 --- a/content/browser/private_aggregation/private_aggregation_manager.h +++ b/content/browser/private_aggregation/private_aggregation_manager.h
@@ -23,7 +23,7 @@ public: virtual ~PrivateAggregationManager() = default; - static PrivateAggregationManager* GetManager(BrowserContext* browser_context); + static PrivateAggregationManager* GetManager(BrowserContext& browser_context); // Binds a new pending receiver for a worklet, allowing messages to be sent // and processed. However, the receiver is not bound if the `worklet_origin`
diff --git a/content/browser/private_aggregation/private_aggregation_manager_impl_unittest.cc b/content/browser/private_aggregation/private_aggregation_manager_impl_unittest.cc index d72d74afa..2650f1e5 100644 --- a/content/browser/private_aggregation/private_aggregation_manager_impl_unittest.cc +++ b/content/browser/private_aggregation/private_aggregation_manager_impl_unittest.cc
@@ -46,30 +46,6 @@ constexpr char kExampleOriginUrl[] = "https://origin.example"; -class MockPrivateAggregationBudgeter : public PrivateAggregationBudgeter { - public: - MOCK_METHOD(void, - ConsumeBudget, - (int, - const PrivateAggregationBudgetKey&, - base::OnceCallback<void(bool)>), - (override)); -}; - -class MockPrivateAggregationHost : public PrivateAggregationHost { - public: - MockPrivateAggregationHost() - : PrivateAggregationHost( - /*on_report_request_received=*/base::DoNothing()) {} - - MOCK_METHOD(bool, - BindNewReceiver, - (url::Origin, - PrivateAggregationBudgetKey::Api, - mojo::PendingReceiver<mojom::PrivateAggregationHost>), - (override)); -}; - class PrivateAggregationManagerImplUnderTest : public PrivateAggregationManagerImpl { public:
diff --git a/content/browser/private_aggregation/private_aggregation_test_utils.cc b/content/browser/private_aggregation/private_aggregation_test_utils.cc index 2c2d650..a079968 100644 --- a/content/browser/private_aggregation/private_aggregation_test_utils.cc +++ b/content/browser/private_aggregation/private_aggregation_test_utils.cc
@@ -6,10 +6,20 @@ #include <tuple> +#include "base/callback_helpers.h" #include "content/browser/private_aggregation/private_aggregation_budget_key.h" namespace content { +MockPrivateAggregationBudgeter::MockPrivateAggregationBudgeter() = default; +MockPrivateAggregationBudgeter::~MockPrivateAggregationBudgeter() = default; + +MockPrivateAggregationHost::MockPrivateAggregationHost() + : PrivateAggregationHost( + /*on_report_request_received=*/base::DoNothing()) {} + +MockPrivateAggregationHost::~MockPrivateAggregationHost() = default; + bool operator==(const PrivateAggregationBudgetKey::TimeWindow& a, const PrivateAggregationBudgetKey::TimeWindow& b) { return a.start_time() == b.start_time();
diff --git a/content/browser/private_aggregation/private_aggregation_test_utils.h b/content/browser/private_aggregation/private_aggregation_test_utils.h index a4b3aae..08ae5f1 100644 --- a/content/browser/private_aggregation/private_aggregation_test_utils.h +++ b/content/browser/private_aggregation/private_aggregation_test_utils.h
@@ -5,10 +5,55 @@ #ifndef CONTENT_BROWSER_PRIVATE_AGGREGATION_PRIVATE_AGGREGATION_TEST_UTILS_H_ #define CONTENT_BROWSER_PRIVATE_AGGREGATION_PRIVATE_AGGREGATION_TEST_UTILS_H_ +#include <vector> + +#include "base/callback_forward.h" +#include "content/browser/aggregation_service/aggregatable_report.h" #include "content/browser/private_aggregation/private_aggregation_budget_key.h" +#include "content/browser/private_aggregation/private_aggregation_budgeter.h" +#include "content/browser/private_aggregation/private_aggregation_host.h" +#include "content/common/aggregatable_report.mojom-forward.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace url { +class Origin; +} namespace content { +class MockPrivateAggregationBudgeter : public PrivateAggregationBudgeter { + public: + MockPrivateAggregationBudgeter(); + ~MockPrivateAggregationBudgeter() override; + + MOCK_METHOD(void, + ConsumeBudget, + (int, + const PrivateAggregationBudgetKey&, + base::OnceCallback<void(bool)>), + (override)); +}; + +class MockPrivateAggregationHost : public PrivateAggregationHost { + public: + MockPrivateAggregationHost(); + ~MockPrivateAggregationHost() override; + + MOCK_METHOD(bool, + BindNewReceiver, + (url::Origin, + PrivateAggregationBudgetKey::Api, + mojo::PendingReceiver<mojom::PrivateAggregationHost>), + (override)); + + MOCK_METHOD(void, + SendHistogramReport, + (std::vector<mojom::AggregatableReportHistogramContributionPtr>, + mojom::AggregationServiceMode aggregation_mode), + (override)); +}; + bool operator==(const PrivateAggregationBudgetKey::TimeWindow&, const PrivateAggregationBudgetKey::TimeWindow&);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index bd8d4be3..564a3ac 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -112,6 +112,7 @@ #include "content/public/test/test_utils.h" #include "content/public/test/url_loader_interceptor.h" #include "content/shell/browser/shell.h" +#include "content/shell/common/main_frame_counter_test_impl.h" #include "content/shell/common/shell_switches.h" #include "content/test/content_browser_test_utils_internal.h" #include "content/test/did_commit_navigation_interceptor.h" @@ -195,6 +196,20 @@ namespace { +void VerifyChildProcessHasMainFrame( + mojo::Remote<mojom::MainFrameCounterTest>& main_frame_counter, + bool expected_state) { + main_frame_counter.FlushForTesting(); + base::RunLoop run_loop; + main_frame_counter->HasMainFrame(base::BindOnce( + [](base::RunLoop* loop, bool expected_state, bool has_main_frame) { + EXPECT_EQ(expected_state, has_main_frame); + loop->Quit(); + }, + &run_loop, expected_state)); + run_loop.Run(); +} + using CrashVisibility = CrossProcessFrameConnector::CrashVisibility; // Helper function to send a postMessage and wait for a reply message. The @@ -586,6 +601,17 @@ web_contents()->GetRenderWidgetHostViewsInWebContentsTree(); EXPECT_EQ(2U, views_set.size()); } + mojo::Remote<mojom::MainFrameCounterTest> main_frame_counter; + shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()->BindReceiver( + main_frame_counter.BindNewPipeAndPassReceiver()); + + VerifyChildProcessHasMainFrame(main_frame_counter, true); + + mojo::Remote<mojom::MainFrameCounterTest> main_frame_counter_child; + rph->BindReceiver(main_frame_counter_child.BindNewPipeAndPassReceiver()); + + VerifyChildProcessHasMainFrame(main_frame_counter_child, false); + RenderFrameProxyHost* proxy_to_parent = child->render_manager()->GetProxyToParent(); EXPECT_TRUE(proxy_to_parent); @@ -632,6 +658,7 @@ EXPECT_NE(shell()->web_contents()->GetPrimaryMainFrame()->GetProcess(), child->current_frame_host()->GetProcess()); EXPECT_NE(rph, child->current_frame_host()->GetProcess()); + VerifyChildProcessHasMainFrame(main_frame_counter, true); { std::set<RenderWidgetHostViewBase*> views_set = web_contents()->GetRenderWidgetHostViewsInWebContentsTree(); @@ -656,6 +683,61 @@ DepictFrameTree(root)); } +// Ensure that processes for iframes correctly track whether or not they have a +// local main frame. +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, + CrossSiteIframeMainFrameCount) { + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(a,a,a(a,a))")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root(); + + TestNavigationObserver observer(shell()->web_contents()); + + EXPECT_EQ( + " Site A\n" + " |--Site A\n" + " |--Site A\n" + " +--Site A\n" + " |--Site A\n" + " +--Site A\n" + "Where A = http://a.com/", + DepictFrameTree(root)); + + mojo::Remote<mojom::MainFrameCounterTest> main_frame_counter; + shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()->BindReceiver( + main_frame_counter.BindNewPipeAndPassReceiver()); + VerifyChildProcessHasMainFrame(main_frame_counter, true); + + GURL url = embedded_test_server()->GetURL( + "b.com", "/cross_site_iframe_factory.html?b(a,a)"); + { + RenderFrameDeletedObserver deleted_observer( + root->child_at(2)->current_frame_host()); + EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(2), url)); + deleted_observer.WaitUntilDeleted(); + } + + EXPECT_EQ( + " Site A ------------ proxies for B\n" + " |--Site A ------- proxies for B\n" + " |--Site A ------- proxies for B\n" + " +--Site B ------- proxies for A\n" + " |--Site A -- proxies for B\n" + " +--Site A -- proxies for B\n" + "Where A = http://a.com/\n" + " B = http://b.com/", + DepictFrameTree(root)); + + VerifyChildProcessHasMainFrame(main_frame_counter, true); + + mojo::Remote<mojom::MainFrameCounterTest> main_frame_counter_child; + root->child_at(2)->current_frame_host()->GetProcess()->BindReceiver( + main_frame_counter_child.BindNewPipeAndPassReceiver()); + VerifyChildProcessHasMainFrame(main_frame_counter_child, false); +} + // Ensure that title updates affect the correct NavigationEntry after a new // subframe navigation with an out-of-process iframe. https://crbug.com/616609. IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, TitleAfterCrossSiteIframe) {
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index 2af1689..9606e4c 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -2823,6 +2823,13 @@ attribution_manager_ = std::move(attribution_manager); } +void StoragePartitionImpl::OverridePrivateAggregationManagerForTesting( + std::unique_ptr<PrivateAggregationManagerImpl> + private_aggregation_manager) { + DCHECK(initialized_); + private_aggregation_manager_ = std::move(private_aggregation_manager); +} + void StoragePartitionImpl::GetQuotaSettings( storage::OptionalQuotaSettingsCallback callback) { if (g_test_quota_settings) {
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h index 7d74987..4890af4d 100644 --- a/content/browser/storage_partition_impl.h +++ b/content/browser/storage_partition_impl.h
@@ -144,6 +144,9 @@ std::unique_ptr<AggregationService> aggregation_service); void OverrideAttributionManagerForTesting( std::unique_ptr<AttributionManager> attribution_manager); + void OverridePrivateAggregationManagerForTesting( + std::unique_ptr<PrivateAggregationManagerImpl> + private_aggregation_manager); // Returns the StoragePartitionConfig that represents this StoragePartition. const StoragePartitionConfig& GetConfig();
diff --git a/content/browser/webid/fedcm_metrics.h b/content/browser/webid/fedcm_metrics.h index a3a809b..6352cae 100644 --- a/content/browser/webid/fedcm_metrics.h +++ b/content/browser/webid/fedcm_metrics.h
@@ -50,8 +50,9 @@ kManifestListTooBig, kDisabledEmbargo, kUserInterfaceTimedOut, // obsolete + kRpPageNotVisible, - kMaxValue = kUserInterfaceTimedOut + kMaxValue = kRpPageNotVisible }; // This enum describes whether user sign-in states between IDP and browser
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc index 0c10cd2..0ff5566 100644 --- a/content/browser/webid/federated_auth_request_impl.cc +++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -695,6 +695,8 @@ // Does not show the dialog if the user has left the page. e.g. they may // open a new tab before browser is ready to show the dialog. if (!is_visible) { + fedcm_metrics_->RecordRequestTokenStatus( + TokenStatus::kRpPageNotVisible); CompleteRequest(FederatedAuthRequestResult::kError, "", /*should_delay_callback=*/true); return;
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 02ba386f..4c19dbd0 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -399,8 +399,6 @@ kThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes}, {"TopicsAPI", features::kPrivacySandboxAdsAPIsOverride, kSetOnlyIfOverridden}, - {"TouchActionEffectiveAtPointerDown", - features::kVirtualKeyboardMultitouch}, {"UserAgentClientHint", blink::features::kUserAgentClientHint}, {"ViewportHeightClientHintHeader", blink::features::kViewportHeightClientHintHeader},
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index c5a9654..aca90ff 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -410,6 +410,17 @@ } } +# This is used by content/shell as well, which we don't want to depend on the +# entire content/common. +component("main_frame_counter") { + defines = [ "IS_MAIN_FRAME_COUNTER_IMPL" ] + sources = [ + "main_frame_counter.cc", + "main_frame_counter.h", + ] + deps = [ "//base:base" ] +} + if (is_linux || is_chromeos) { source_set("set_process_title_linux") { public = [ "set_process_title_linux.h" ]
diff --git a/content/common/main_frame_counter.cc b/content/common/main_frame_counter.cc new file mode 100644 index 0000000..08a19b9 --- /dev/null +++ b/content/common/main_frame_counter.cc
@@ -0,0 +1,30 @@ +// Copyright 2022 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/common/main_frame_counter.h" +#include "base/check_op.h" + +namespace content { + +// static +size_t MainFrameCounter::main_frame_count_ = 0; + +// static +bool MainFrameCounter::has_main_frame() { + return main_frame_count_ > 0; +} + +// static +void MainFrameCounter::IncrementCount() { + main_frame_count_++; +} + +// static +void MainFrameCounter::DecrementCount() { + // If this check fails, we have miscounted somewhere. + DCHECK_GT(main_frame_count_, 0u); + main_frame_count_--; +} + +}; // namespace content
diff --git a/content/common/main_frame_counter.h b/content/common/main_frame_counter.h new file mode 100644 index 0000000..2feecc14 --- /dev/null +++ b/content/common/main_frame_counter.h
@@ -0,0 +1,38 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_MAIN_FRAME_COUNTER_H_ +#define CONTENT_COMMON_MAIN_FRAME_COUNTER_H_ + +#include <stddef.h> + +#include "base/component_export.h" + +namespace content { + +// This should only be used from the Renderer process, but is placed in common +// so the Browser process can access it for testing only. +// +// This keeps track of how many main frames exist in the current Renderer +// process. +// +// This is for an ongoing experiment to reduce memory usage in Renderers that +// only contain subframes; it should be removed if the experiment does not +// end up shipping. See: crbug.com/1331368 for tracking. +class COMPONENT_EXPORT(MAIN_FRAME_COUNTER) MainFrameCounter final { + public: + static bool has_main_frame(); + + private: + friend class RenderFrameImpl; + + static void IncrementCount(); + static void DecrementCount(); + + static size_t main_frame_count_; +}; + +} // namespace content + +#endif // CONTENT_COMMON_MAIN_FRAME_COUNTER_H_
diff --git a/content/common/partition_alloc_support.cc b/content/common/partition_alloc_support.cc index eafb934..8836c94 100644 --- a/content/common/partition_alloc_support.cc +++ b/content/common/partition_alloc_support.cc
@@ -25,6 +25,7 @@ #include "base/no_destructor.h" #include "base/time/time.h" #include "build/build_config.h" +#include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #if BUILDFLAG(IS_ANDROID) @@ -454,7 +455,7 @@ } } -void PartitionAllocSupport::OnForegrounded() { +void PartitionAllocSupport::OnForegrounded(bool has_main_frame) { #if defined(PA_THREAD_CACHE_SUPPORTED) && \ BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) { @@ -463,7 +464,10 @@ return; } - ::partition_alloc::ThreadCache::SetLargestCachedSize(largest_cached_size_); + if (!base::FeatureList::IsEnabled( + features::kLowerMemoryLimitForNonMainRenderers) || + has_main_frame) + ::partition_alloc::ThreadCache::SetLargestCachedSize(largest_cached_size_); #endif // defined(PA_THREAD_CACHE_SUPPORTED) && // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) }
diff --git a/content/common/partition_alloc_support.h b/content/common/partition_alloc_support.h index 21ceeca9..9da58fa 100644 --- a/content/common/partition_alloc_support.h +++ b/content/common/partition_alloc_support.h
@@ -47,7 +47,8 @@ void ReconfigureAfterFeatureListInit(const std::string& process_type); void ReconfigureAfterTaskRunnerInit(const std::string& process_type); - void OnForegrounded(); + // |has_main_frame| tells us if the renderer contains a main frame. + void OnForegrounded(bool has_main_frame); void OnBackgrounded(); static PartitionAllocSupport* Get() {
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 82a07cf..af3a1acc 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -749,6 +749,14 @@ return nullptr; } +void ContentBrowserClient::AddPresentationObserver( + PresentationObserver* observer, + WebContents* web_contents) {} + +void ContentBrowserClient::RemovePresentationObserver( + PresentationObserver* observer, + WebContents* web_contents) {} + void ContentBrowserClient::OpenURL( content::SiteInstance* site_instance, const content::OpenURLParams& params,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 2f47543..c58c09df 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -216,6 +216,7 @@ class NavigationThrottle; class NavigationUIData; class PrefetchServiceDelegate; +class PresentationObserver; class QuotaPermissionContext; class ReceiverPresentationServiceDelegate; class RenderFrameHost; @@ -1248,6 +1249,12 @@ virtual ReceiverPresentationServiceDelegate* GetReceiverPresentationServiceDelegate(WebContents* web_contents); + // Add or remove an observer for presentations associated with `web_contents`. + virtual void AddPresentationObserver(PresentationObserver* observer, + WebContents* web_contents); + virtual void RemovePresentationObserver(PresentationObserver* observer, + WebContents* web_contents); + // Allows programmatic opening of a new tab/window without going through // another WebContents. For example, from a Worker. |site_instance| // describes the context initiating the navigation. |callback| will be
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 317cf5b..80661db1 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -533,6 +533,11 @@ #endif }; +// Configures whether we set a lower limit for renderers that do not have a main +// frame, similar to the limit that is already done for backgrounded renderers. +const base::Feature kLowerMemoryLimitForNonMainRenderers{ + "LowerMemoryLimitForNonMainRenderers", base::FEATURE_DISABLED_BY_DEFAULT}; + // The MBI mode controls whether or not communication over the // AgentSchedulingGroup is ordered with respect to the render-process-global // legacy IPC channel, as well as the granularity of AgentSchedulingGroup
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 65f451c..080db50 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -141,6 +141,7 @@ CONTENT_EXPORT extern const base::Feature kLazyInitializeMediaControls; CONTENT_EXPORT extern const base::Feature kLegacyWindowsDWriteFontFallback; CONTENT_EXPORT extern const base::Feature kLogJsConsoleMessages; +CONTENT_EXPORT extern const base::Feature kLowerMemoryLimitForNonMainRenderers; CONTENT_EXPORT extern const base::Feature kMBIMode; enum class MBIMode { // In this mode, the AgentSchedulingGroup will use the process-wide legacy IPC
diff --git a/content/public/test/unittest_test_suite.cc b/content/public/test/unittest_test_suite.cc index ce01728..ba4ef98 100644 --- a/content/public/test/unittest_test_suite.cc +++ b/content/public/test/unittest_test_suite.cc
@@ -135,13 +135,7 @@ listeners.Append(CreateTestEventListener()); listeners.Append(new CheckForLeakedWebUIRegistrations); - // The ThreadPool created by the test launcher is never destroyed. - // Similarly, the FeatureList created here is never destroyed so it - // can safely be accessed by the ThreadPool. - std::unique_ptr<base::FeatureList> feature_list = - std::make_unique<base::FeatureList>(); - feature_list->InitializeFromCommandLine(enabled, disabled); - base::FeatureList::SetInstance(std::move(feature_list)); + scoped_feature_list_.InitFromCommandLine(enabled, disabled); // Do this here even though TestBlinkWebUnitTestSupport calls it since a // multi process unit test won't get to create TestBlinkWebUnitTestSupport.
diff --git a/content/public/test/unittest_test_suite.h b/content/public/test/unittest_test_suite.h index 27f1984..57506b4 100644 --- a/content/public/test/unittest_test_suite.h +++ b/content/public/test/unittest_test_suite.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/callback.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" namespace base { @@ -69,6 +70,8 @@ std::unique_ptr<TestHostResolver> test_host_resolver_; base::RepeatingCallback<std::unique_ptr<ContentClients>()> create_clients_; + + base::test::ScopedFeatureList scoped_feature_list_; }; } // namespace content
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index ac56b78..e77edb5 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -252,6 +252,7 @@ "//content/child", "//content/common", "//content/common:buildflags", + "//content/common:main_frame_counter", "//content/gpu:gpu_sources", "//content/public/child:child_sources", "//content/services/auction_worklet:auction_worklet",
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 9d47696..a2ff3043 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -58,6 +58,7 @@ #include "content/common/debug_utils.h" #include "content/common/frame.mojom.h" #include "content/common/frame_messages.mojom.h" +#include "content/common/main_frame_counter.h" #include "content/common/navigation_client.mojom.h" #include "content/common/navigation_gesture.h" #include "content/common/navigation_params_utils.h" @@ -1886,6 +1887,9 @@ web_media_stream_device_observer_.reset(); + if (initialized_ && is_main_frame_) + MainFrameCounter::DecrementCount(); + base::trace_event::TraceLog::GetInstance()->RemoveProcessLabel(routing_id_); g_routing_id_frame_map.Get().erase(routing_id_); agent_scheduling_group_.RemoveRoute(routing_id_); @@ -1894,6 +1898,8 @@ void RenderFrameImpl::Initialize(blink::WebFrame* parent) { initialized_ = true; is_main_frame_ = !parent; + if (is_main_frame_) + MainFrameCounter::IncrementCount(); TRACE_EVENT1("navigation,rail", "RenderFrameImpl::Initialize", "routing_id", routing_id_);
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index c68231a..a15cfb2 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -68,6 +68,7 @@ #include "content/common/buildflags.h" #include "content/common/content_constants_internal.h" #include "content/common/content_switches_internal.h" +#include "content/common/main_frame_counter.h" #include "content/common/partition_alloc_support.h" #include "content/common/process_visibility_tracker.h" #include "content/common/pseudonymization_salt.h" @@ -78,6 +79,7 @@ #include "content/public/common/gpu_stream_constants.h" #include "content/public/common/url_constants.h" #include "content/public/renderer/content_renderer_client.h" +#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_thread_observer.h" #include "content/renderer/agent_scheduling_group.h" #include "content/renderer/browser_exposed_renderer_interfaces.h" @@ -1690,7 +1692,8 @@ void RenderThreadImpl::OnRendererForegrounded() { main_thread_scheduler_->SetRendererBackgrounded(false); discardable_memory_allocator_->OnForegrounded(); - internal::PartitionAllocSupport::Get()->OnForegrounded(); + internal::PartitionAllocSupport::Get()->OnForegrounded( + MainFrameCounter::has_main_frame()); process_foregrounded_count_++; }
diff --git a/content/services/auction_worklet/BUILD.gn b/content/services/auction_worklet/BUILD.gn index 7ee1910..8b61840 100644 --- a/content/services/auction_worklet/BUILD.gn +++ b/content/services/auction_worklet/BUILD.gn
@@ -52,6 +52,8 @@ "debug_command_queue.h", "for_debugging_only_bindings.cc", "for_debugging_only_bindings.h", + "private_aggregation_bindings.cc", + "private_aggregation_bindings.h", "register_ad_beacon_bindings.cc", "register_ad_beacon_bindings.h", "report_bindings.cc",
diff --git a/content/services/auction_worklet/bidder_worklet.cc b/content/services/auction_worklet/bidder_worklet.cc index 0c29b6e..244363c 100644 --- a/content/services/auction_worklet/bidder_worklet.cc +++ b/content/services/auction_worklet/bidder_worklet.cc
@@ -24,7 +24,9 @@ #include "base/trace_event/trace_event.h" #include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/for_debugging_only_bindings.h" +#include "content/services/auction_worklet/private_aggregation_bindings.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h" #include "content/services/auction_worklet/register_ad_beacon_bindings.h" #include "content/services/auction_worklet/report_bindings.h" #include "content/services/auction_worklet/set_bid_bindings.h" @@ -356,6 +358,7 @@ ContextRecycler context_recycler(v8_helper_.get()); context_recycler.AddReportBindings(); context_recycler.AddRegisterAdBeaconBindings(); + context_recycler.AddPrivateAggregationBindings(); ContextRecyclerScope context_recycler_scope(context_recycler); v8::Local<v8::Context> context = context_recycler_scope.GetContext(); @@ -365,9 +368,10 @@ !AppendJsonValueOrNull(v8_helper_.get(), context, per_buyer_signals_json, &args) || !v8_helper_->AppendJsonValue(context, seller_signals_json, &args)) { - PostReportWinCallbackToUserThread( - std::move(callback), /*report_url=*/absl::nullopt, - /*ad_beacon_map=*/{}, /*errors=*/std::vector<std::string>()); + PostReportWinCallbackToUserThread(std::move(callback), + /*report_url=*/absl::nullopt, + /*ad_beacon_map=*/{}, /*pa_requests=*/{}, + /*errors=*/std::vector<std::string>()); return; } @@ -396,9 +400,10 @@ (bidding_signals_data_version.has_value() && !browser_signals_dict.Set("dataVersion", bidding_signals_data_version.value()))) { - PostReportWinCallbackToUserThread( - std::move(callback), /*report_url=*/absl::nullopt, - /*ad_beacon_map=*/{}, /*errors=*/std::vector<std::string>()); + PostReportWinCallbackToUserThread(std::move(callback), + /*report_url=*/absl::nullopt, + /*ad_beacon_map=*/{}, /*pa_requests=*/{}, + /*errors=*/std::vector<std::string>()); return; } args.push_back(browser_signals); @@ -419,9 +424,14 @@ TRACE_EVENT_NESTABLE_ASYNC_END0("fledge", "report_win", trace_id); if (script_failed) { + // Keep Private Aggregation API requests since `reportWin()` might use it to + // detect script timeout or failures. PostReportWinCallbackToUserThread( std::move(callback), /*report_url=*/absl::nullopt, - /*ad_beacon_map=*/{}, std::move(errors_out)); + /*ad_beacon_map=*/{}, + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(), + std::move(errors_out)); return; } @@ -430,6 +440,8 @@ PostReportWinCallbackToUserThread( std::move(callback), context_recycler.report_bindings()->report_url(), context_recycler.register_ad_beacon_bindings()->TakeAdBeaconMap(), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(), std::move(errors_out)); } @@ -461,6 +473,7 @@ // repeated calls to this worklet, or to calls to any other worklet. ContextRecycler context_recycler(v8_helper_.get()); context_recycler.AddForDebuggingOnlyBindings(); + context_recycler.AddPrivateAggregationBindings(); context_recycler.AddSetBidBindings(); context_recycler.AddSetPriorityBindings(); @@ -638,11 +651,13 @@ if (!context_recycler.set_bid_bindings()->has_bid()) { // If we either don't have a valid return value, or we have no return value // and no intermediate result was given through setBid, return an error. - // Keep debug loss reports since `generateBid()` might use it to detect - // script timeout or failures. + // Keep debug loss reports and Private Aggregation API requests since + // `generateBid()` might use them to detect script timeout or failures. PostErrorBidCallbackToUserThread( std::move(callback), std::move(errors_out), - context_recycler.for_debugging_only_bindings()->TakeLossReportUrl()); + context_recycler.for_debugging_only_bindings()->TakeLossReportUrl(), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests()); return; } @@ -654,6 +669,8 @@ context_recycler.for_debugging_only_bindings()->TakeLossReportUrl(), context_recycler.for_debugging_only_bindings()->TakeWinReportUrl(), context_recycler.set_priority_bindings()->set_priority(), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(), std::move(errors_out))); } @@ -688,17 +705,20 @@ ReportWinCallbackInternal callback, const absl::optional<GURL>& report_url, base::flat_map<std::string, GURL> ad_beacon_map, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors) { DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_); user_thread_->PostTask( FROM_HERE, base::BindOnce(std::move(callback), std::move(report_url), - std::move(ad_beacon_map), std::move(errors))); + std::move(ad_beacon_map), + std::move(pa_requests), std::move(errors))); } void BidderWorklet::V8State::PostErrorBidCallbackToUserThread( GenerateBidCallbackInternal callback, std::vector<std::string> error_msgs, - absl::optional<GURL> debug_loss_report_url) { + absl::optional<GURL> debug_loss_report_url, + PrivateAggregationRequests private_aggregation_requests) { DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_); user_thread_->PostTask( FROM_HERE, @@ -706,7 +726,9 @@ /*bidding_signals_data_version=*/absl::nullopt, /*debug_loss_report_url=*/std::move(debug_loss_report_url), /*debug_win_report_url=*/absl::nullopt, - /*set_priority=*/absl::nullopt, std::move(error_msgs))); + /*set_priority=*/absl::nullopt, + std::move(private_aggregation_requests), + std::move(error_msgs))); } void BidderWorklet::ResumeIfPaused() { @@ -899,6 +921,7 @@ absl::optional<GURL> debug_loss_report_url, absl::optional<GURL> debug_win_report_url, absl::optional<double> set_priority, + PrivateAggregationRequests pa_requests, std::vector<std::string> error_msgs) { DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_); @@ -912,7 +935,7 @@ .Run(std::move(bid), bidding_signals_data_version.value_or(0), bidding_signals_data_version.has_value(), debug_loss_report_url, debug_win_report_url, set_priority.value_or(0), - set_priority.has_value(), error_msgs); + set_priority.has_value(), std::move(pa_requests), error_msgs); generate_bid_tasks_.erase(task); } @@ -920,12 +943,14 @@ ReportWinTaskList::iterator task, absl::optional<GURL> report_url, base::flat_map<std::string, GURL> ad_beacon_map, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors) { DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_); errors.insert(errors.end(), load_code_error_msgs_.begin(), load_code_error_msgs_.end()); std::move(task->callback) - .Run(std::move(report_url), std::move(ad_beacon_map), errors); + .Run(std::move(report_url), std::move(ad_beacon_map), + std::move(pa_requests), std::move(errors)); report_win_tasks_.erase(task); }
diff --git a/content/services/auction_worklet/bidder_worklet.h b/content/services/auction_worklet/bidder_worklet.h index 5ada948..7d45cfb 100644 --- a/content/services/auction_worklet/bidder_worklet.h +++ b/content/services/auction_worklet/bidder_worklet.h
@@ -22,6 +22,7 @@ #include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom-forward.h" #include "content/services/auction_worklet/trusted_signals.h" #include "content/services/auction_worklet/trusted_signals_request_manager.h" #include "content/services/auction_worklet/worklet_loader.h" @@ -64,6 +65,9 @@ using ClosePipeCallback = base::OnceCallback<void(const std::string& description)>; + using PrivateAggregationRequests = + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>; + // Starts loading the worklet script on construction, as well as the trusted // bidding data, if necessary. Will then call the script's generateBid() // function and invoke the callback with the results. Callback will always be @@ -203,10 +207,12 @@ absl::optional<GURL> debug_loss_report_url, absl::optional<GURL> debug_win_report_url, absl::optional<double> set_priority, + PrivateAggregationRequests pa_requests, std::vector<std::string> error_msgs)>; using ReportWinCallbackInternal = base::OnceCallback<void(absl::optional<GURL> report_url, base::flat_map<std::string, GURL> ad_beacon_map, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors)>; void ReportWin(const std::string& interest_group_name, @@ -251,12 +257,14 @@ ReportWinCallbackInternal callback, const absl::optional<GURL>& report_url, base::flat_map<std::string, GURL> ad_beacon_map, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors); void PostErrorBidCallbackToUserThread( GenerateBidCallbackInternal callback, std::vector<std::string> error_msgs = std::vector<std::string>(), - absl::optional<GURL> debug_loss_report_url = absl::nullopt); + absl::optional<GURL> debug_loss_report_url = absl::nullopt, + PrivateAggregationRequests private_aggregation_requests = {}); static void PostResumeToUserThread( base::WeakPtr<BidderWorklet> parent, @@ -316,6 +324,7 @@ absl::optional<GURL> debug_loss_report_url, absl::optional<GURL> debug_win_report_url, absl::optional<double> set_priority, + PrivateAggregationRequests pa_requests, std::vector<std::string> error_msgs); // Invokes the `callback` of `task` with the provided values, and removes @@ -324,6 +333,7 @@ ReportWinTaskList::iterator task, absl::optional<GURL> report_url, base::flat_map<std::string, GURL> ad_beacon_map, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors); // Returns true if unpaused and the script and WASM helper (if needed) have
diff --git a/content/services/auction_worklet/bidder_worklet_unittest.cc b/content/services/auction_worklet/bidder_worklet_unittest.cc index 9d402d6..41e1cb2 100644 --- a/content/services/auction_worklet/bidder_worklet_unittest.cc +++ b/content/services/auction_worklet/bidder_worklet_unittest.cc
@@ -23,6 +23,7 @@ #include "base/time/time.h" #include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h" #include "content/services/auction_worklet/worklet_devtools_debug_test_util.h" #include "content/services/auction_worklet/worklet_test_util.h" #include "content/services/auction_worklet/worklet_v8_debug_test_util.h" @@ -33,6 +34,7 @@ #include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/numeric/int128.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/interest_group/ad_auction_constants.h" @@ -47,6 +49,8 @@ namespace auction_worklet { namespace { +using PrivateAggregationRequests = BidderWorklet::PrivateAggregationRequests; + // This was produced by running wat2wasm on this: // (module // (global (export "test_const") i32 (i32.const 123)) @@ -185,11 +189,13 @@ const absl::optional<GURL>& expected_debug_loss_report_url = absl::nullopt, const absl::optional<GURL>& expected_debug_win_report_url = absl::nullopt, - const absl::optional<double> expected_set_priority = absl::nullopt) { + const absl::optional<double> expected_set_priority = absl::nullopt, + PrivateAggregationRequests expected_pa_requests = {}) { RunGenerateBidWithJavascriptExpectingResult( CreateGenerateBidScript(raw_return_value), std::move(expected_bid), expected_data_version, expected_errors, expected_debug_loss_report_url, - expected_debug_win_report_url, expected_set_priority); + expected_debug_win_report_url, expected_set_priority, + std::move(expected_pa_requests)); } // Configures `url_loader_factory_` to return a script with the specified @@ -202,14 +208,15 @@ const absl::optional<GURL>& expected_debug_loss_report_url = absl::nullopt, const absl::optional<GURL>& expected_debug_win_report_url = absl::nullopt, - const absl::optional<double> expected_set_priority = absl::nullopt) { + const absl::optional<double> expected_set_priority = absl::nullopt, + PrivateAggregationRequests expected_pa_requests = {}) { SCOPED_TRACE(javascript); AddJavascriptResponse(&url_loader_factory_, interest_group_bidding_url_, javascript); RunGenerateBidExpectingResult( std::move(expected_bid), expected_data_version, expected_errors, expected_debug_loss_report_url, expected_debug_win_report_url, - expected_set_priority); + expected_set_priority, std::move(expected_pa_requests)); } // Loads and runs a generateBid() script, expecting the provided result. @@ -220,7 +227,8 @@ const absl::optional<GURL>& expected_debug_loss_report_url = absl::nullopt, const absl::optional<GURL>& expected_debug_win_report_url = absl::nullopt, - const absl::optional<double> expected_set_priority = absl::nullopt) { + const absl::optional<double> expected_set_priority = absl::nullopt, + PrivateAggregationRequests expected_pa_requests = {}) { auto bidder_worklet = CreateWorkletAndGenerateBid(); EXPECT_EQ(expected_bid.is_null(), bid_.is_null()); @@ -238,6 +246,7 @@ EXPECT_EQ(expected_data_version, data_version_); EXPECT_EQ(expected_debug_loss_report_url, bid_debug_loss_report_url_); EXPECT_EQ(expected_debug_win_report_url, bid_debug_win_report_url_); + EXPECT_EQ(expected_pa_requests, pa_requests_); EXPECT_EQ(expected_errors, bid_errors_); EXPECT_EQ(expected_set_priority, set_priority_); } @@ -249,11 +258,13 @@ const absl::optional<GURL>& expected_report_url, const base::flat_map<std::string, GURL>& expected_ad_beacon_map = base::flat_map<std::string, GURL>(), + PrivateAggregationRequests expected_pa_requests = {}, const std::vector<std::string>& expected_errors = std::vector<std::string>()) { RunReportWinWithJavascriptExpectingResult( CreateReportWinScript(function_body), expected_report_url, - expected_ad_beacon_map, expected_errors); + expected_ad_beacon_map, std::move(expected_pa_requests), + expected_errors); } // Configures `url_loader_factory_` to return a reportWin() script with the @@ -263,12 +274,14 @@ const absl::optional<GURL>& expected_report_url, const base::flat_map<std::string, GURL>& expected_ad_beacon_map = base::flat_map<std::string, GURL>(), + PrivateAggregationRequests expected_pa_requests = {}, const std::vector<std::string>& expected_errors = std::vector<std::string>()) { SCOPED_TRACE(javascript); AddJavascriptResponse(&url_loader_factory_, interest_group_bidding_url_, javascript); RunReportWinExpectingResult(expected_report_url, expected_ad_beacon_map, + std::move(expected_pa_requests), expected_errors); } @@ -279,6 +292,7 @@ mojom::BidderWorklet* bidder_worklet, const absl::optional<GURL>& expected_report_url, const base::flat_map<std::string, GURL>& expected_ad_beacon_map, + PrivateAggregationRequests expected_pa_requests, const std::vector<std::string>& expected_errors, base::OnceClosure done_closure) { bidder_worklet->ReportWin( @@ -292,17 +306,21 @@ base::BindOnce( [](const absl::optional<GURL>& expected_report_url, const base::flat_map<std::string, GURL>& expected_ad_beacon_map, + PrivateAggregationRequests expected_pa_requests, const std::vector<std::string>& expected_errors, base::OnceClosure done_closure, const absl::optional<GURL>& report_url, const base::flat_map<std::string, GURL>& ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ(expected_report_url, report_url); EXPECT_EQ(expected_errors, errors); EXPECT_EQ(expected_ad_beacon_map, ad_beacon_map); + EXPECT_EQ(expected_pa_requests, pa_requests); std::move(done_closure).Run(); }, - expected_report_url, expected_ad_beacon_map, expected_errors, + expected_report_url, expected_ad_beacon_map, + std::move(expected_pa_requests), expected_errors, std::move(done_closure))); } @@ -312,6 +330,7 @@ const absl::optional<GURL>& expected_report_url, const base::flat_map<std::string, GURL>& expected_ad_beacon_map = base::flat_map<std::string, GURL>(), + PrivateAggregationRequests expected_pa_requests = {}, const std::vector<std::string>& expected_errors = std::vector<std::string>()) { auto bidder_worklet = CreateWorklet(); @@ -319,8 +338,9 @@ base::RunLoop run_loop; RunReportWinExpectingResultAsync(bidder_worklet.get(), expected_report_url, - expected_ad_beacon_map, expected_errors, - run_loop.QuitClosure()); + expected_ad_beacon_map, + std::move(expected_pa_requests), + expected_errors, run_loop.QuitClosure()); run_loop.Run(); } @@ -401,6 +421,7 @@ const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, double set_priority, bool has_set_priority, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { ADD_FAILURE() << "Callback should not be invoked."; })); @@ -427,6 +448,7 @@ const absl::optional<GURL>& debug_win_report_url, double set_priority, bool has_set_priority, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { absl::optional<uint32_t> maybe_data_version; if (has_data_version) @@ -439,6 +461,7 @@ bid_debug_loss_report_url_ = debug_loss_report_url; bid_debug_win_report_url_ = debug_win_report_url; set_priority_ = maybe_set_priority; + pa_requests_ = std::move(pa_requests); bid_errors_ = errors; load_script_run_loop_->Quit(); } @@ -534,6 +557,7 @@ absl::optional<GURL> bid_debug_loss_report_url_; absl::optional<GURL> bid_debug_win_report_url_; absl::optional<double> set_priority_; + PrivateAggregationRequests pa_requests_; std::vector<std::string> bid_errors_; network::TestURLLoaderFactory url_loader_factory_; @@ -1562,6 +1586,7 @@ const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, double set_priority, bool has_set_priority, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ(bid_value, bid->bid); EXPECT_EQ(base::NumberToString(bid_value), bid->ad); @@ -1655,6 +1680,7 @@ const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, double set_priority, bool has_set_priority, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ(base::NumberToString(i), bid->ad); EXPECT_EQ(i + 1, bid->bid); @@ -1756,6 +1782,7 @@ const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, double set_priority, bool has_set_priority, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ(base::NumberToString(i), bid->ad); EXPECT_EQ(i + 1, bid->bid); @@ -1863,6 +1890,7 @@ const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, double set_priority, bool has_set_priority, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ(base::NumberToString(i), bid->ad); EXPECT_EQ(i + 1, bid->bid); @@ -1949,6 +1977,7 @@ const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, double set_priority, bool has_set_priority, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ(base::NumberToString(i), bid->ad); EXPECT_EQ(i + 1, bid->bid); @@ -2358,6 +2387,7 @@ base::BindLambdaForTesting( [&run_loop](const absl::optional<GURL>& report_url, const base::flat_map<std::string, GURL>& ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { run_loop.Quit(); })); @@ -2389,6 +2419,7 @@ RunReportWinExpectingResultAsync( bidder_worklet.get(), GURL("https://foo.test"), /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, /*expected_errors=*/{}, base::BindLambdaForTesting([&run_loop]() { run_loop.Quit(); })); task_environment_.RunUntilIdle(); @@ -2833,6 +2864,138 @@ /*expected_set_priority=*/9.0); } +TEST_F(BidderWorkletTest, GenerateBidPrivateAggregationRequests) { + auction_worklet::mojom::PrivateAggregationRequestPtr kExpectedRequest1 = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/123, + /*value=*/45), + content::mojom::AggregationServiceMode::kDefault); + auction_worklet::mojom::PrivateAggregationRequestPtr kExpectedRequest2 = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/absl::MakeInt128(/*high=*/1, /*low=*/0), + /*value=*/1), + content::mojom::AggregationServiceMode::kDefault); + + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunGenerateBidWithJavascriptExpectingResult( + CreateGenerateBidScript( + R"({ad: "ad", bid:1, render:"https://response.test/" })", + /*extra_code=*/R"( + privateAggregation.sendHistogramReport({bucket: 123, value: 45}); + )"), + /*expected_bid=*/ + mojom::BidderWorkletBid::New( + "\"ad\"", 1, GURL("https://response.test/"), + /*ad_components=*/absl::nullopt, base::TimeDelta()), + /*expected_data_version=*/absl::nullopt, + /*expected_errors=*/{}, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_set_priority=*/absl::nullopt, + std::move(expected_pa_requests)); + } + + // BigInt bucket + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunGenerateBidWithJavascriptExpectingResult( + CreateGenerateBidScript( + R"({ad: "ad", bid:1, render:"https://response.test/" })", + /*extra_code=*/R"( + privateAggregation.sendHistogramReport({bucket: 123n, value: 45}); + )"), + /*expected_bid=*/ + mojom::BidderWorkletBid::New( + "\"ad\"", 1, GURL("https://response.test/"), + /*ad_components=*/absl::nullopt, base::TimeDelta()), + /*expected_data_version=*/absl::nullopt, + /*expected_errors=*/{}, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_set_priority=*/absl::nullopt, + std::move(expected_pa_requests)); + } + + // Large bucket + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest2.Clone()); + + RunGenerateBidWithJavascriptExpectingResult( + CreateGenerateBidScript( + R"({ad: "ad", bid:1, render:"https://response.test/" })", + /*extra_code=*/R"( + privateAggregation.sendHistogramReport( + {bucket: 18446744073709551616n, value: 1}); + )"), + /*expected_bid=*/ + mojom::BidderWorkletBid::New( + "\"ad\"", 1, GURL("https://response.test/"), + /*ad_components=*/absl::nullopt, base::TimeDelta()), + /*expected_data_version=*/absl::nullopt, + /*expected_errors=*/{}, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_set_priority=*/absl::nullopt, + std::move(expected_pa_requests)); + } + + // Multiple requests + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + expected_pa_requests.push_back(kExpectedRequest2.Clone()); + + RunGenerateBidWithJavascriptExpectingResult( + CreateGenerateBidScript( + R"({ad: "ad", bid:1, render:"https://response.test/" })", + /*extra_code=*/R"( + privateAggregation.sendHistogramReport({bucket: 123, value: 45}); + privateAggregation.sendHistogramReport( + {bucket: 18446744073709551616n, value: 1}); + )"), + /*expected_bid=*/ + mojom::BidderWorkletBid::New( + "\"ad\"", 1, GURL("https://response.test/"), + /*ad_components=*/absl::nullopt, base::TimeDelta()), + /*expected_data_version=*/absl::nullopt, + /*expected_errors=*/{}, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_set_priority=*/absl::nullopt, + std::move(expected_pa_requests)); + } + + // An unrelated exception after sendHistogramReport shouldn't block the report + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunGenerateBidWithJavascriptExpectingResult( + CreateGenerateBidScript( + R"({ad: "ad", bid:1, render:"https://response.test/" })", + /*extra_code=*/R"( + privateAggregation.sendHistogramReport({bucket: 123, value: 45}); + error; + )"), + /*expected_bid=*/mojom::BidderWorkletBidPtr(), + /*expected_data_version=*/absl::nullopt, + /*expected_errors=*/ + {"https://url.test/:6 Uncaught ReferenceError: error is not defined."}, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_set_priority=*/absl::nullopt, + std::move(expected_pa_requests)); + } +} + TEST_F(BidderWorkletTest, ReportWin) { RunReportWinWithFunctionBodyExpectingResult( "", /*expected_report_url =*/absl::nullopt); @@ -2849,24 +3012,28 @@ R"(sendReportTo("http://http.not.allowed.test"))", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught TypeError: sendReportTo must be passed a " "valid HTTPS url."}); RunReportWinWithFunctionBodyExpectingResult( R"(sendReportTo("file:///file.not.allowed.test"))", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught TypeError: sendReportTo must be passed a " "valid HTTPS url."}); RunReportWinWithFunctionBodyExpectingResult( R"(sendReportTo(""))", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught TypeError: sendReportTo must be passed a " "valid HTTPS url."}); RunReportWinWithFunctionBodyExpectingResult( R"(sendReportTo("https://foo.test");sendReportTo("https://foo.test"))", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught TypeError: sendReportTo may be called at " "most once."}); } @@ -2908,6 +3075,7 @@ /*trace_id=*/1, base::BindOnce([](const absl::optional<GURL>& report_url, const base::flat_map<std::string, GURL>& ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { ADD_FAILURE() << "Callback should not be invoked since worklet deleted"; })); @@ -2953,6 +3121,7 @@ [&run_loop, &num_report_win_calls, i]( const absl::optional<GURL>& report_url, const base::flat_map<std::string, GURL>& ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ(GURL(base::StringPrintf("https://foo.test/%zu", i)), report_url); @@ -2995,6 +3164,7 @@ base::BindOnce( [](const absl::optional<GURL>& report_url, const base::flat_map<std::string, GURL>& ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { ADD_FAILURE() << "Callback should not be invoked."; })); @@ -3014,6 +3184,7 @@ R"(sendReportTo("https://foo.test/" + Date().toString()))", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught ReferenceError: Date is not defined."}); } @@ -3207,6 +3378,7 @@ base::BindLambdaForTesting( [&run_loop](const absl::optional<GURL>& report_url, const base::flat_map<std::string, GURL>& ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ(GURL("https://23.test/"), report_url); EXPECT_TRUE(errors.empty()); @@ -3637,7 +3809,7 @@ // Now ask for reporting. This should hit the other breakpoint. base::RunLoop run_loop; RunReportWinExpectingResultAsync(worklet.get(), GURL("https://foo.test/"), {}, - {}, run_loop.QuitClosure()); + {}, {}, run_loop.QuitClosure()); TestDevToolsAgentClient::Event breakpoint_hit2 = debug.WaitForMethodNotification("Debugger.paused"); @@ -3896,6 +4068,7 @@ registerAdBeacon())", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:14 Uncaught TypeError: registerAdBeacon may be " "called at most once."}); @@ -3924,6 +4097,7 @@ R"(registerAdBeacon())", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught TypeError: registerAdBeacon requires 1 " "object parameter."}); @@ -3932,6 +4106,7 @@ R"(registerAdBeacon("foo"))", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught TypeError: registerAdBeacon requires 1 " "object parameter."}); @@ -3940,6 +4115,7 @@ R"(registerAdBeacon("foo"))", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught TypeError: registerAdBeacon requires 1 " "object parameter."}); @@ -3951,6 +4127,7 @@ }))", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught TypeError: registerAdBeacon object " "attributes must be strings."}); @@ -3962,6 +4139,7 @@ }))", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught TypeError: registerAdBeacon invalid " "reporting url for key 'view': 'gopher://view.example.com/'."}); @@ -3973,9 +4151,101 @@ }))", /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught TypeError: registerAdBeacon invalid " "reporting url for key 'view': 'http://view.example.com/'."}); } +TEST_F(BidderWorkletTest, ReportWinPrivateAggregationRequests) { + auction_worklet::mojom::PrivateAggregationRequestPtr kExpectedRequest1 = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/123, + /*value=*/45), + content::mojom::AggregationServiceMode::kDefault); + auction_worklet::mojom::PrivateAggregationRequestPtr kExpectedRequest2 = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/absl::MakeInt128(/*high=*/1, /*low=*/0), + /*value=*/1), + content::mojom::AggregationServiceMode::kDefault); + + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunReportWinWithFunctionBodyExpectingResult( + R"( + privateAggregation.sendHistogramReport({bucket: 123, value: 45}); + )", + /*expected_report_url =*/absl::nullopt, + /*expected_ad_beacon_map=*/{}, std::move(expected_pa_requests), + /*expected_errors=*/{}); + } + + // BigInt bucket + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunReportWinWithFunctionBodyExpectingResult( + R"( + privateAggregation.sendHistogramReport({bucket: 123n, value: 45}); + )", + /*expected_report_url =*/absl::nullopt, + /*expected_ad_beacon_map=*/{}, std::move(expected_pa_requests), + /*expected_errors=*/{}); + } + + // Large bucket + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest2.Clone()); + + RunReportWinWithFunctionBodyExpectingResult( + R"( + privateAggregation.sendHistogramReport({bucket: 18446744073709551616n, + value: 1}); + )", + /*expected_report_url =*/absl::nullopt, + /*expected_ad_beacon_map=*/{}, std::move(expected_pa_requests), + /*expected_errors=*/{}); + } + + // Multiple requests + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + expected_pa_requests.push_back(kExpectedRequest2.Clone()); + + RunReportWinWithFunctionBodyExpectingResult( + R"( + privateAggregation.sendHistogramReport({bucket: 123, value: 45}); + privateAggregation.sendHistogramReport({bucket: 18446744073709551616n, + value: 1}); + )", + /*expected_report_url =*/absl::nullopt, + /*expected_ad_beacon_map=*/{}, std::move(expected_pa_requests), + /*expected_errors=*/{}); + } + + // An unrelated exception after sendHistogramReport shouldn't block the report + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunReportWinWithFunctionBodyExpectingResult( + R"( + privateAggregation.sendHistogramReport({bucket: 123, value: 45}); + error; + )", + /*expected_report_url =*/absl::nullopt, + /*expected_ad_beacon_map=*/{}, std::move(expected_pa_requests), + /*expected_errors=*/ + {"https://url.test/:12 Uncaught ReferenceError: error is not " + "defined."}); + } +} + } // namespace } // namespace auction_worklet
diff --git a/content/services/auction_worklet/context_recycler.cc b/content/services/auction_worklet/context_recycler.cc index fcdc8f9..dd6b4711 100644 --- a/content/services/auction_worklet/context_recycler.cc +++ b/content/services/auction_worklet/context_recycler.cc
@@ -4,8 +4,12 @@ #include "content/services/auction_worklet/context_recycler.h" +#include <memory> + #include "base/check.h" +#include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/for_debugging_only_bindings.h" +#include "content/services/auction_worklet/private_aggregation_bindings.h" #include "content/services/auction_worklet/register_ad_beacon_bindings.h" #include "content/services/auction_worklet/report_bindings.h" #include "content/services/auction_worklet/set_bid_bindings.h" @@ -29,6 +33,13 @@ AddBindings(for_debugging_only_bindings_.get()); } +void ContextRecycler::AddPrivateAggregationBindings() { + DCHECK(!private_aggregation_bindings_); + private_aggregation_bindings_ = + std::make_unique<PrivateAggregationBindings>(v8_helper_); + AddBindings(private_aggregation_bindings_.get()); +} + void ContextRecycler::AddRegisterAdBeaconBindings() { DCHECK(!register_ad_beacon_bindings_); register_ad_beacon_bindings_ =
diff --git a/content/services/auction_worklet/context_recycler.h b/content/services/auction_worklet/context_recycler.h index 48ed970..07dd960 100644 --- a/content/services/auction_worklet/context_recycler.h +++ b/content/services/auction_worklet/context_recycler.h
@@ -16,6 +16,7 @@ namespace auction_worklet { class ForDebuggingOnlyBindings; +class PrivateAggregationBindings; class RegisterAdBeaconBindings; class ReportBindings; class SetBidBindings; @@ -51,6 +52,11 @@ return for_debugging_only_bindings_.get(); } + void AddPrivateAggregationBindings(); + PrivateAggregationBindings* private_aggregation_bindings() { + return private_aggregation_bindings_.get(); + } + void AddRegisterAdBeaconBindings(); RegisterAdBeaconBindings* register_ad_beacon_bindings() { return register_ad_beacon_bindings_.get(); @@ -84,6 +90,7 @@ v8::Global<v8::Context> context_; std::unique_ptr<ForDebuggingOnlyBindings> for_debugging_only_bindings_; + std::unique_ptr<PrivateAggregationBindings> private_aggregation_bindings_; std::unique_ptr<RegisterAdBeaconBindings> register_ad_beacon_bindings_; std::unique_ptr<ReportBindings> report_bindings_; std::unique_ptr<SetBidBindings> set_bid_bindings_;
diff --git a/content/services/auction_worklet/context_recycler_unittest.cc b/content/services/auction_worklet/context_recycler_unittest.cc index a782e08..213be81c 100644 --- a/content/services/auction_worklet/context_recycler_unittest.cc +++ b/content/services/auction_worklet/context_recycler_unittest.cc
@@ -13,9 +13,13 @@ #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/threading/thread_task_runner_handle.h" +#include "content/common/aggregatable_report.mojom-shared.h" +#include "content/common/aggregatable_report.mojom.h" #include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/for_debugging_only_bindings.h" +#include "content/services/auction_worklet/private_aggregation_bindings.h" #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h" #include "content/services/auction_worklet/register_ad_beacon_bindings.h" #include "content/services/auction_worklet/report_bindings.h" #include "content/services/auction_worklet/set_bid_bindings.h" @@ -24,9 +28,11 @@ #include "gin/dictionary.h" #include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/numeric/int128.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/interest_group/interest_group.h" #include "v8/include/v8-context.h" +#include "v8/include/v8-primitive.h" using testing::ElementsAre; using testing::Pair; @@ -503,4 +509,354 @@ } } +// Exercise PrivateAggregationBindings, and make sure they reset properly. +TEST_F(ContextRecyclerTest, PrivateAggregationBindings) { + using PrivateAggregationRequests = + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>; + + const char kScript[] = R"( + function test(args) { + // Passing BigInts in directly is complicated so we construct them from + // strings. + if (typeof args.bucket === "string") { + args.bucket = BigInt(args.bucket); + } + privateAggregation.sendHistogramReport(args); + } + )"; + + v8::Local<v8::UnboundScript> script = Compile(kScript); + ASSERT_FALSE(script.IsEmpty()); + + ContextRecycler context_recycler(helper_.get()); + context_recycler.AddPrivateAggregationBindings(); + + // Basic test + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", 123); + dict.Set("value", 45); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT(error_msgs, ElementsAre()); + + content::mojom::AggregatableReportHistogramContribution + expected_contribution(/*bucket=*/123, /*value=*/45); + auction_worklet::mojom::PrivateAggregationRequest expected_request( + expected_contribution.Clone(), + content::mojom::AggregationServiceMode::kDefault); + + PrivateAggregationRequests pa_requests = + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(); + ASSERT_EQ(pa_requests.size(), 1u); + EXPECT_EQ(pa_requests[0], expected_request.Clone()); + } + + // BigInt bucket + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", std::string("123")); + dict.Set("value", 45); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT(error_msgs, ElementsAre()); + + content::mojom::AggregatableReportHistogramContribution + expected_contribution(/*bucket=*/123, /*value=*/45); + auction_worklet::mojom::PrivateAggregationRequest expected_request( + expected_contribution.Clone(), + content::mojom::AggregationServiceMode::kDefault); + + PrivateAggregationRequests pa_requests = + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(); + ASSERT_EQ(pa_requests.size(), 1u); + EXPECT_EQ(pa_requests[0], expected_request.Clone()); + } + + // Large bucket + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", std::string("18446744073709551616")); + dict.Set("value", 45); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT(error_msgs, ElementsAre()); + + content::mojom::AggregatableReportHistogramContribution + expected_contribution( + /*bucket=*/absl::MakeUint128(/*high=*/1, /*low=*/0), /*value=*/45); + auction_worklet::mojom::PrivateAggregationRequest expected_request( + expected_contribution.Clone(), + content::mojom::AggregationServiceMode::kDefault); + + PrivateAggregationRequests pa_requests = + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(); + ASSERT_EQ(pa_requests.size(), 1u); + EXPECT_EQ(pa_requests[0], expected_request.Clone()); + } + + // Maximum bucket + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", std::string("340282366920938463463374607431768211455")); + dict.Set("value", 45); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT(error_msgs, ElementsAre()); + + content::mojom::AggregatableReportHistogramContribution + expected_contribution(/*bucket=*/absl::Uint128Max(), /*value=*/45); + auction_worklet::mojom::PrivateAggregationRequest expected_request( + expected_contribution.Clone(), + content::mojom::AggregationServiceMode::kDefault); + + PrivateAggregationRequests pa_requests = + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(); + ASSERT_EQ(pa_requests.size(), 1u); + EXPECT_EQ(pa_requests[0], expected_request.Clone()); + } + + // Zero bucket + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", 0); + dict.Set("value", 45); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT(error_msgs, ElementsAre()); + + content::mojom::AggregatableReportHistogramContribution + expected_contribution(/*bucket=*/0, /*value=*/45); + auction_worklet::mojom::PrivateAggregationRequest expected_request( + expected_contribution.Clone(), + content::mojom::AggregationServiceMode::kDefault); + + PrivateAggregationRequests pa_requests = + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(); + ASSERT_EQ(pa_requests.size(), 1u); + EXPECT_EQ(pa_requests[0], expected_request.Clone()); + } + + // Zero value + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", 123); + dict.Set("value", 0); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT(error_msgs, ElementsAre()); + + content::mojom::AggregatableReportHistogramContribution + expected_contribution(/*bucket=*/123, /*value=*/0); + auction_worklet::mojom::PrivateAggregationRequest expected_request( + expected_contribution.Clone(), + content::mojom::AggregationServiceMode::kDefault); + + PrivateAggregationRequests pa_requests = + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(); + ASSERT_EQ(pa_requests.size(), 1u); + EXPECT_EQ(pa_requests[0], expected_request.Clone()); + } + + // Multiple requests + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + { + gin::Dictionary dict_1 = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict_1.Set("bucket", 123); + dict_1.Set("value", 45); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict_1)); + EXPECT_THAT(error_msgs, ElementsAre()); + } + { + gin::Dictionary dict_2 = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict_2.Set("bucket", 678); + dict_2.Set("value", 90); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict_2)); + EXPECT_THAT(error_msgs, ElementsAre()); + } + + content::mojom::AggregatableReportHistogramContribution + expected_contribution_1(/*bucket=*/123, /*value=*/45); + auction_worklet::mojom::PrivateAggregationRequest expected_request_1( + expected_contribution_1.Clone(), + content::mojom::AggregationServiceMode::kDefault); + + content::mojom::AggregatableReportHistogramContribution + expected_contribution_2(/*bucket=*/678, /*value=*/90); + auction_worklet::mojom::PrivateAggregationRequest expected_request_2( + expected_contribution_2.Clone(), + content::mojom::AggregationServiceMode::kDefault); + + PrivateAggregationRequests pa_requests = + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(); + ASSERT_EQ(pa_requests.size(), 2u); + EXPECT_EQ(pa_requests[0], expected_request_1.Clone()); + EXPECT_EQ(pa_requests[1], expected_request_2.Clone()); + } + + // Non-integer bucket + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", 12.3); + dict.Set("value", 45); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT( + error_msgs, + ElementsAre("https://example.org/script.js:8 Uncaught TypeError: " + "Bucket must be either an integer Number or BigInt.")); + + EXPECT_TRUE(context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests() + .empty()); + } + + // Non-integer value + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", 123); + dict.Set("value", 4.5); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT( + error_msgs, + ElementsAre("https://example.org/script.js:8 Uncaught TypeError: " + "Value must be an integer Number.")); + + EXPECT_TRUE(context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests() + .empty()); + } + + // Too large bucket + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", std::string("340282366920938463463374607431768211456")); + dict.Set("value", 45); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT( + error_msgs, + ElementsAre("https://example.org/script.js:8 Uncaught TypeError: " + "BigInt is too large.")); + + EXPECT_TRUE(context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests() + .empty()); + } + + // Negative bucket + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", -1); + dict.Set("value", 45); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT( + error_msgs, + ElementsAre("https://example.org/script.js:8 Uncaught TypeError: " + "Bucket must be either an integer Number or BigInt.")); + + EXPECT_TRUE(context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests() + .empty()); + } + + // Negative BigInt bucket + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", std::string("-1")); + dict.Set("value", 45); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT( + error_msgs, + ElementsAre("https://example.org/script.js:8 Uncaught TypeError: " + "BigInt must be non-negative.")); + + EXPECT_TRUE(context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests() + .empty()); + } + + // Negative value + { + ContextRecyclerScope scope(context_recycler); + std::vector<std::string> error_msgs; + + gin::Dictionary dict = gin::Dictionary::CreateEmpty(helper_->isolate()); + dict.Set("bucket", 123); + dict.Set("value", -1); + + Run(scope, script, "test", error_msgs, + gin::ConvertToV8(helper_->isolate(), dict)); + EXPECT_THAT( + error_msgs, + ElementsAre("https://example.org/script.js:8 Uncaught TypeError: " + "Value must be non-negative.")); + + EXPECT_TRUE(context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests() + .empty()); + } +} + } // namespace auction_worklet
diff --git a/content/services/auction_worklet/private_aggregation_bindings.cc b/content/services/auction_worklet/private_aggregation_bindings.cc new file mode 100644 index 0000000..3b1694d --- /dev/null +++ b/content/services/auction_worklet/private_aggregation_bindings.cc
@@ -0,0 +1,217 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/services/auction_worklet/private_aggregation_bindings.h" + +#include <stdint.h> + +#include <memory> +#include <string> +#include <utility> + +#include "base/strings/string_util.h" +#include "content/common/aggregatable_report.mojom.h" +#include "content/services/auction_worklet/auction_v8_helper.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h" +#include "gin/converter.h" +#include "gin/dictionary.h" +#include "third_party/abseil-cpp/absl/numeric/int128.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "v8/include/v8-context.h" +#include "v8/include/v8-exception.h" +#include "v8/include/v8-external.h" +#include "v8/include/v8-function-callback.h" +#include "v8/include/v8-local-handle.h" +#include "v8/include/v8-object.h" +#include "v8/include/v8-template.h" + +namespace auction_worklet { + +namespace { + +// If returns `absl::nullopt`, will output an error to `error_out`. +absl::optional<absl::uint128> ConvertBigIntToUint128( + v8::MaybeLocal<v8::BigInt> maybe_bigint, + std::string* error_out) { + if (maybe_bigint.IsEmpty()) { + *error_out = "Failed to interpret as BigInt"; + return absl::nullopt; + } + + v8::Local<v8::BigInt> local_bigint = maybe_bigint.ToLocalChecked(); + if (local_bigint.IsEmpty()) { + *error_out = "Failed to interpret as BigInt"; + return absl::nullopt; + } + if (local_bigint->WordCount() > 2) { + *error_out = "BigInt is too large"; + return absl::nullopt; + } + // Signals the size of the `words` array to `ToWordsArray()`. The number of + // elements actually used is then written here by the function. + int word_count = 2; + int sign_bit = 0; + uint64_t words[2]; // Least significant to most significant. + local_bigint->ToWordsArray(&sign_bit, &word_count, words); + if (sign_bit) { + *error_out = "BigInt must be non-negative"; + return absl::nullopt; + } + if (word_count == 0) { + words[0] = 0; + } + if (word_count <= 1) { + words[1] = 0; + } + + return absl::MakeUint128(words[1], words[0]); +} + +} // namespace + +PrivateAggregationBindings::PrivateAggregationBindings( + AuctionV8Helper* v8_helper) + : v8_helper_(v8_helper) {} + +PrivateAggregationBindings::~PrivateAggregationBindings() = default; + +void PrivateAggregationBindings::FillInGlobalTemplate( + v8::Local<v8::ObjectTemplate> global_template) { + v8::Local<v8::External> v8_this = + v8::External::New(v8_helper_->isolate(), this); + + v8::Local<v8::ObjectTemplate> private_aggregation_template = + v8::ObjectTemplate::New(v8_helper_->isolate()); + v8::Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New( + v8_helper_->isolate(), &PrivateAggregationBindings::SendHistogramReport, + v8_this); + function_template->RemovePrototype(); + + private_aggregation_template->Set( + v8_helper_->CreateStringFromLiteral("sendHistogramReport"), + function_template); + + global_template->Set( + v8_helper_->CreateStringFromLiteral("privateAggregation"), + private_aggregation_template); +} + +void PrivateAggregationBindings::Reset() { + private_aggregation_requests_.clear(); +} + +std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr> +PrivateAggregationBindings::TakePrivateAggregationRequests() { + return std::move(private_aggregation_requests_); +} + +void PrivateAggregationBindings::SendHistogramReport( + const v8::FunctionCallbackInfo<v8::Value>& args) { + PrivateAggregationBindings* bindings = + static_cast<PrivateAggregationBindings*>( + v8::External::Cast(*args.Data())->Value()); + v8::Isolate* isolate = args.GetIsolate(); + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + AuctionV8Helper* v8_helper = bindings->v8_helper_; + + if (args.Length() != 1 || args[0].IsEmpty() || !args[0]->IsObject()) { + isolate->ThrowException( + v8::Exception::TypeError(v8_helper->CreateStringFromLiteral( + "sendHistogramReport requires 1 object parameter"))); + return; + } + + gin::Dictionary dict(isolate); + + if (!gin::ConvertFromV8(isolate, args[0], &dict)) { + isolate->ThrowException( + v8::Exception::TypeError(v8_helper->CreateStringFromLiteral( + "Invalid argument in sendHistogramReport"))); + return; + } + + v8::Local<v8::Value> js_bucket; + v8::Local<v8::Value> js_value; + + if (!dict.Get("bucket", &js_bucket) || js_bucket.IsEmpty()) { + isolate->ThrowException( + v8::Exception::TypeError(v8_helper->CreateStringFromLiteral( + "Invalid or missing bucket in sendHistogramReport argument"))); + return; + } + + if (!dict.Get("value", &js_value) || js_value.IsEmpty()) { + isolate->ThrowException( + v8::Exception::TypeError(v8_helper->CreateStringFromLiteral( + "Invalid or missing value in sendHistogramReport argument"))); + return; + } + + absl::uint128 bucket; + int value; + + if (js_bucket->IsUint32()) { + v8::Maybe<uint32_t> maybe_bucket = js_bucket->Uint32Value(context); + if (maybe_bucket.IsNothing()) { + isolate->ThrowException( + v8::Exception::TypeError(v8_helper->CreateStringFromLiteral( + "Failed to interpret value as integer"))); + return; + } + bucket = maybe_bucket.ToChecked(); + } else if (js_bucket->IsBigInt()) { + std::string error; + absl::optional<absl::uint128> maybe_bucket = + ConvertBigIntToUint128(js_bucket->ToBigInt(context), &error); + if (!maybe_bucket.has_value()) { + DCHECK(base::IsStringUTF8(error)); + isolate->ThrowException(v8::Exception::TypeError( + v8_helper->CreateUtf8String(error).ToLocalChecked())); + return; + } + bucket = maybe_bucket.value(); + } else { + isolate->ThrowException( + v8::Exception::TypeError(v8_helper->CreateStringFromLiteral( + "Bucket must be either an integer Number or BigInt"))); + return; + } + + if (js_value->IsInt32()) { + v8::Maybe<int32_t> maybe_value = js_value->Int32Value(context); + if (maybe_value.IsNothing()) { + isolate->ThrowException( + v8::Exception::TypeError(v8_helper->CreateStringFromLiteral( + "Failed to interpret value as integer"))); + return; + } + value = maybe_value.ToChecked(); + } else if (js_value->IsBigInt()) { + isolate->ThrowException(v8::Exception::TypeError( + v8_helper->CreateStringFromLiteral("Value cannot be a BigInt"))); + return; + } else { + isolate->ThrowException(v8::Exception::TypeError( + v8_helper->CreateStringFromLiteral("Value must be an integer Number"))); + return; + } + + if (value < 0) { + isolate->ThrowException(v8::Exception::TypeError( + v8_helper->CreateStringFromLiteral("Value must be non-negative"))); + return; + } + + content::mojom::AggregatableReportHistogramContributionPtr contribution = + content::mojom::AggregatableReportHistogramContribution::New(bucket, + value); + + bindings->private_aggregation_requests_.push_back( + auction_worklet::mojom::PrivateAggregationRequest::New( + std::move(contribution), + // TODO(alexmt): consider allowing this to be set + content::mojom::AggregationServiceMode::kDefault)); +} + +} // namespace auction_worklet
diff --git a/content/services/auction_worklet/private_aggregation_bindings.h b/content/services/auction_worklet/private_aggregation_bindings.h new file mode 100644 index 0000000..b04e844 --- /dev/null +++ b/content/services/auction_worklet/private_aggregation_bindings.h
@@ -0,0 +1,52 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SERVICES_AUCTION_WORKLET_PRIVATE_AGGREGATION_BINDINGS_H_ +#define CONTENT_SERVICES_AUCTION_WORKLET_PRIVATE_AGGREGATION_BINDINGS_H_ + +#include <vector> + +#include "base/memory/raw_ptr.h" +#include "content/common/content_export.h" +#include "content/services/auction_worklet/context_recycler.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom-forward.h" +#include "v8/include/v8-forward.h" + +namespace auction_worklet { + +class AuctionV8Helper; + +// Class to manage bindings for the Private Aggregation API. Expected to be used +// for a context managed by `ContextRecycler`. Throws exceptions when invalid +// arguments are detected. +class CONTENT_EXPORT PrivateAggregationBindings : public Bindings { + public: + explicit PrivateAggregationBindings(AuctionV8Helper* v8_helper); + PrivateAggregationBindings(const PrivateAggregationBindings&) = delete; + PrivateAggregationBindings& operator=(const PrivateAggregationBindings&) = + delete; + ~PrivateAggregationBindings() override; + + // Add privateAggregation object to `global_template`. `this` must outlive the + // template. + void FillInGlobalTemplate( + v8::Local<v8::ObjectTemplate> global_template) override; + void Reset() override; + + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr> + TakePrivateAggregationRequests(); + + private: + static void SendHistogramReport( + const v8::FunctionCallbackInfo<v8::Value>& args); + + const raw_ptr<AuctionV8Helper> v8_helper_; + + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr> + private_aggregation_requests_; +}; + +} // namespace auction_worklet + +#endif // CONTENT_SERVICES_AUCTION_WORKLET_PRIVATE_AGGREGATION_BINDINGS_H_
diff --git a/content/services/auction_worklet/public/mojom/BUILD.gn b/content/services/auction_worklet/public/mojom/BUILD.gn index d52f717..9b4b558 100644 --- a/content/services/auction_worklet/public/mojom/BUILD.gn +++ b/content/services/auction_worklet/public/mojom/BUILD.gn
@@ -11,9 +11,11 @@ sources = [ "auction_worklet_service.mojom", "bidder_worklet.mojom", + "private_aggregation_request.mojom", "seller_worklet.mojom", ] deps = [ + "//content/common:mojo_bindings", "//mojo/public/mojom/base", "//sandbox/policy/mojom", "//services/network/public/mojom",
diff --git a/content/services/auction_worklet/public/mojom/bidder_worklet.mojom b/content/services/auction_worklet/public/mojom/bidder_worklet.mojom index 0f4a825..000c034d 100644 --- a/content/services/auction_worklet/public/mojom/bidder_worklet.mojom +++ b/content/services/auction_worklet/public/mojom/bidder_worklet.mojom
@@ -4,6 +4,7 @@ module auction_worklet.mojom; +import "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom"; import "mojo/public/mojom/base/time.mojom"; import "services/network/public/mojom/url_loader_factory.mojom"; import "third_party/blink/public/mojom/devtools/devtools_agent.mojom"; @@ -161,6 +162,8 @@ // update to the interest group priority. // TODO(https://crbug.com/657632): Update when optional integers supported. // + // `pa_requests` The various requests made to the Private Aggregation API. + // // `errors` The various error messages to be used for debugging. These are too // sensitive for the renderer to see. There may be errors even when a bid // is offered, and there may be no errors when there's no bid. Includes @@ -182,6 +185,7 @@ url.mojom.Url? debug_win_report_url, double set_priority, bool has_set_priority, + array<PrivateAggregationRequest> pa_requests, array<string> errors); // Sends pending bidding signals URL requests, if any. Unlike with @@ -252,6 +256,8 @@ // `ad_beacon_map` The map of ad reporting events to URLs for fenced frame // reporting. // + // `pa_requests` The various requests made to the Private Aggregation API. + // // `errors` is an array of any errors that occurred while attempting // to run the worklet's reportWin() method. These are too sensitive for // the renderer to see. There may be errors even when a `report_url` is @@ -272,6 +278,7 @@ uint64 trace_id) => ( url.mojom.Url? report_url, map<string, url.mojom.Url> ad_beacon_map, + array<PrivateAggregationRequest> pa_requests, array<string> errors); // Establishes a debugger connection to the worklet.
diff --git a/content/services/auction_worklet/public/mojom/private_aggregation_request.mojom b/content/services/auction_worklet/public/mojom/private_aggregation_request.mojom new file mode 100644 index 0000000..6326a63a --- /dev/null +++ b/content/services/auction_worklet/public/mojom/private_aggregation_request.mojom
@@ -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. + +module auction_worklet.mojom; + +import "content/common/aggregatable_report.mojom"; + +// Represents a request made to the Private Aggregation API (e.g. via +// `privateAggregation.sendHistogramReport()`). +struct PrivateAggregationRequest { + content.mojom.AggregatableReportHistogramContribution contribution; + content.mojom.AggregationServiceMode aggregation_mode; +};
diff --git a/content/services/auction_worklet/public/mojom/seller_worklet.mojom b/content/services/auction_worklet/public/mojom/seller_worklet.mojom index 0358716..6265c844 100644 --- a/content/services/auction_worklet/public/mojom/seller_worklet.mojom +++ b/content/services/auction_worklet/public/mojom/seller_worklet.mojom
@@ -4,6 +4,7 @@ module auction_worklet.mojom; +import "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom"; import "mojo/public/mojom/base/time.mojom"; import "services/network/public/mojom/url_loader_factory.mojom"; import "third_party/blink/public/mojom/devtools/devtools_agent.mojom"; @@ -134,6 +135,8 @@ // API that will be replaced with standardized reporting APIs once available. // It must be a valid HTTPS URL. // + // `pa_requests` The various requests made to the Private Aggregation API. + // // `errors` are various error messages to be used for debugging. These are too // sensitive for the renderers to see. `errors` should not be assumed to be // empty if `score` is positive, nor should it be assumed to be non-empty if @@ -156,6 +159,7 @@ bool has_scoring_signals_data_version, url.mojom.Url? debug_loss_report_url, url.mojom.Url? debug_win_report_url, + array<PrivateAggregationRequest> pa_requests, array<string> errors); // Hint to the worklet to send a network request for any needed trusted @@ -222,6 +226,8 @@ // `ad_beacon_map` The map of ad reporting events to URLs for fenced frame // reporting. // + // `pa_requests` The various requests made to the Private Aggregation API. + // // `errors` are various error messages to be used for debugging. These are too // sensitive for the renderers to see. `errors` should not be assumed to be // empty if the other values are populated, nor should it be assumed to be @@ -243,6 +249,7 @@ (string? signals_for_winner, url.mojom.Url? report_url, map<string, url.mojom.Url> ad_beacon_map, + array<PrivateAggregationRequest> pa_requests, array<string> error_msgs); // Establishes a debugger connection to the worklet.
diff --git a/content/services/auction_worklet/seller_worklet.cc b/content/services/auction_worklet/seller_worklet.cc index aa72572..e3d9e14 100644 --- a/content/services/auction_worklet/seller_worklet.cc +++ b/content/services/auction_worklet/seller_worklet.cc
@@ -23,6 +23,7 @@ #include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/context_recycler.h" #include "content/services/auction_worklet/for_debugging_only_bindings.h" +#include "content/services/auction_worklet/private_aggregation_bindings.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" #include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" #include "content/services/auction_worklet/register_ad_beacon_bindings.h" @@ -449,6 +450,7 @@ // repeated calls to this worklet, or to calls to any other worklet. ContextRecycler context_recycler(v8_helper_.get()); context_recycler.AddForDebuggingOnlyBindings(); + context_recycler.AddPrivateAggregationBindings(); ContextRecyclerScope context_recycler_scope(context_recycler); v8::Local<v8::Context> context = context_recycler_scope.GetContext(); @@ -529,15 +531,18 @@ TRACE_EVENT_NESTABLE_ASYNC_END0("fledge", "score_ad", trace_id); if (!got_return_value) { - // Keep debug loss reports since `scoreAd()` might use it to detect script - // timeout or failures. + // Keep debug loss reports and Private Aggregation API requests since + // `scoreAd()` might use them to detect script timeout or failures. PostScoreAdCallbackToUserThread( std::move(callback), /*score=*/0, /*component_auction_modified_bid_params=*/nullptr, /*scoring_signals_data_version=*/absl::nullopt, /*debug_loss_report_url=*/ context_recycler.for_debugging_only_bindings()->TakeLossReportUrl(), - /*debug_win_report_url=*/absl::nullopt, std::move(errors_out)); + /*debug_win_report_url=*/absl::nullopt, + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(), + std::move(errors_out)); return; } @@ -554,8 +559,10 @@ errors_out.push_back( base::StrCat({decision_logic_url_.spec(), " scoreAd() did not return an object or a number."})); - PostScoreAdCallbackToUserThreadOnError(std::move(callback), - std::move(errors_out)); + PostScoreAdCallbackToUserThreadOnError( + std::move(callback), std::move(errors_out), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests()); return; } @@ -565,8 +572,10 @@ errors_out.push_back( base::StrCat({decision_logic_url_.spec(), " scoreAd() return value has incorrect structure."})); - PostScoreAdCallbackToUserThreadOnError(std::move(callback), - std::move(errors_out)); + PostScoreAdCallbackToUserThreadOnError( + std::move(callback), std::move(errors_out), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests()); return; } @@ -604,8 +613,10 @@ {decision_logic_url_.spec(), " scoreAd() return value does not have allowComponentAuction set to " "true. Ad dropped from component auction."})); - PostScoreAdCallbackToUserThreadOnError(std::move(callback), - std::move(errors_out)); + PostScoreAdCallbackToUserThreadOnError( + std::move(callback), std::move(errors_out), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests()); return; } @@ -613,8 +624,10 @@ if (std::isnan(score) || !std::isfinite(score)) { errors_out.push_back(base::StrCat( {decision_logic_url_.spec(), " scoreAd() returned an invalid score."})); - PostScoreAdCallbackToUserThreadOnError(std::move(callback), - std::move(errors_out)); + PostScoreAdCallbackToUserThreadOnError( + std::move(callback), std::move(errors_out), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests()); return; } @@ -627,6 +640,8 @@ scoring_signals_data_version, context_recycler.for_debugging_only_bindings()->TakeLossReportUrl(), context_recycler.for_debugging_only_bindings()->TakeWinReportUrl(), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(), std::move(errors_out)); return; } @@ -641,8 +656,10 @@ component_auction_modified_bid_params->bid <= 0.0) { errors_out.push_back(base::StrCat( {decision_logic_url_.spec(), " scoreAd() returned an invalid bid."})); - PostScoreAdCallbackToUserThreadOnError(std::move(callback), - std::move(errors_out)); + PostScoreAdCallbackToUserThreadOnError( + std::move(callback), std::move(errors_out), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests()); return; } } @@ -653,6 +670,8 @@ scoring_signals_data_version, context_recycler.for_debugging_only_bindings()->TakeLossReportUrl(), context_recycler.for_debugging_only_bindings()->TakeWinReportUrl(), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(), std::move(errors_out)); } @@ -681,6 +700,7 @@ ContextRecycler context_recycler(v8_helper_.get()); context_recycler.AddReportBindings(); context_recycler.AddRegisterAdBeaconBindings(); + context_recycler.AddPrivateAggregationBindings(); ContextRecyclerScope context_recycler_scope(context_recycler); v8::Local<v8::Context> context = context_recycler_scope.GetContext(); @@ -692,6 +712,7 @@ /*signals_for_winner=*/absl::nullopt, /*report_url=*/absl::nullopt, /*ad_beacon_map=*/{}, + /*pa_requests=*/{}, /*errors=*/std::vector<std::string>()); return; } @@ -718,6 +739,7 @@ /*signals_for_winner=*/absl::nullopt, /*report_url=*/absl::nullopt, /*ad_beacon_map=*/{}, + /*pa_requests=*/{}, /*errors=*/std::vector<std::string>()); return; } @@ -738,6 +760,7 @@ /*signals_for_winner=*/absl::nullopt, /*report_url=*/absl::nullopt, /*ad_beacon_map=*/{}, + /*pa_requests=*/{}, /*errors=*/std::vector<std::string>()); return; } @@ -759,9 +782,13 @@ TRACE_EVENT_NESTABLE_ASYNC_END0("fledge", "report_result", trace_id); if (!got_return_value) { + // Keep Private Aggregation API requests since `reportReport()` might use it + // to detect script timeout or failures. PostReportResultCallbackToUserThread( std::move(callback), /*signals_for_winner=*/absl::nullopt, /*report_url=*/absl::nullopt, /*ad_beacon_map=*/{}, + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(), std::move(errors_out)); return; } @@ -778,6 +805,8 @@ std::move(callback), std::move(signals_for_winner), context_recycler.report_bindings()->report_url(), context_recycler.register_ad_beacon_bindings()->TakeAdBeaconMap(), + context_recycler.private_aggregation_bindings() + ->TakePrivateAggregationRequests(), std::move(errors_out)); } @@ -810,13 +839,15 @@ void SellerWorklet::V8State::PostScoreAdCallbackToUserThreadOnError( ScoreAdCallbackInternal callback, - std::vector<std::string> errors) { + std::vector<std::string> errors, + PrivateAggregationRequests pa_requests) { PostScoreAdCallbackToUserThread( std::move(callback), /*score=*/0, /*component_auction_modified_bid_params=*/nullptr, /*scoring_signals_data_version=*/absl::nullopt, /*debug_loss_report_url=*/absl::nullopt, - /*debug_win_report_url=*/absl::nullopt, std::move(errors)); + /*debug_win_report_url=*/absl::nullopt, std::move(pa_requests), + std::move(errors)); } void SellerWorklet::V8State::PostScoreAdCallbackToUserThread( @@ -827,6 +858,7 @@ absl::optional<uint32_t> scoring_signals_data_version, absl::optional<GURL> debug_loss_report_url, absl::optional<GURL> debug_win_report_url, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors) { DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_); user_thread_->PostTask( @@ -835,7 +867,8 @@ std::move(component_auction_modified_bid_params), scoring_signals_data_version, std::move(debug_loss_report_url), - std::move(debug_win_report_url), std::move(errors))); + std::move(debug_win_report_url), std::move(pa_requests), + std::move(errors))); } void SellerWorklet::V8State::PostReportResultCallbackToUserThread( @@ -843,13 +876,14 @@ absl::optional<std::string> signals_for_winner, absl::optional<GURL> report_url, base::flat_map<std::string, GURL> ad_beacon_map, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors) { DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_); user_thread_->PostTask( FROM_HERE, base::BindOnce(std::move(callback), std::move(signals_for_winner), std::move(report_url), std::move(ad_beacon_map), - std::move(errors))); + std::move(pa_requests), std::move(errors))); } void SellerWorklet::ResumeIfPaused() { @@ -965,6 +999,7 @@ absl::optional<uint32_t> scoring_signals_data_version, absl::optional<GURL> debug_loss_report_url, absl::optional<GURL> debug_win_report_url, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors) { DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_); @@ -977,7 +1012,7 @@ .Run(score, std::move(component_auction_modified_bid_params), scoring_signals_data_version.value_or(0), scoring_signals_data_version.has_value(), debug_loss_report_url, - debug_win_report_url, errors); + debug_win_report_url, std::move(pa_requests), std::move(errors)); score_ad_tasks_.erase(task); } @@ -1012,6 +1047,7 @@ const absl::optional<std::string> signals_for_winner, const absl::optional<GURL> report_url, base::flat_map<std::string, GURL> ad_beacon_map, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors) { DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_); @@ -1019,7 +1055,8 @@ errors.insert(errors.begin(), load_script_error_msg_.value()); std::move(task->callback) - .Run(signals_for_winner, report_url, ad_beacon_map, errors); + .Run(signals_for_winner, report_url, ad_beacon_map, + std::move(pa_requests), std::move(errors)); report_result_tasks_.erase(task); }
diff --git a/content/services/auction_worklet/seller_worklet.h b/content/services/auction_worklet/seller_worklet.h index 33980aa..fc8d24a5 100644 --- a/content/services/auction_worklet/seller_worklet.h +++ b/content/services/auction_worklet/seller_worklet.h
@@ -21,6 +21,7 @@ #include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom-forward.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h" #include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" #include "content/services/auction_worklet/trusted_signals.h" #include "content/services/auction_worklet/trusted_signals_request_manager.h" @@ -52,6 +53,9 @@ using ClosePipeCallback = base::OnceCallback<void(const std::string& description)>; + using PrivateAggregationRequests = + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>; + // Starts loading the worklet script on construction. SellerWorklet(scoped_refptr<AuctionV8Helper> v8_helper, bool pause_for_debugger_on_start, @@ -190,11 +194,13 @@ absl::optional<uint32_t> scoring_signals_data_version, absl::optional<GURL> debug_loss_report_url, absl::optional<GURL> debug_win_report_url, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors)>; using ReportResultCallbackInternal = base::OnceCallback<void(absl::optional<std::string> signals_for_winner, absl::optional<GURL> report_url, base::flat_map<std::string, GURL> ad_beacon_map, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors)>; V8State(scoped_refptr<AuctionV8Helper> v8_helper, @@ -251,7 +257,8 @@ // report URLs, even if the methods to set them have been invoked. void PostScoreAdCallbackToUserThreadOnError( ScoreAdCallbackInternal callback, - std::vector<std::string> errors); + std::vector<std::string> errors, + PrivateAggregationRequests pa_requests = {}); void PostScoreAdCallbackToUserThread( ScoreAdCallbackInternal callback, @@ -261,6 +268,7 @@ absl::optional<uint32_t> scoring_signals_data_version, absl::optional<GURL> debug_loss_report_url, absl::optional<GURL> debug_win_report_url, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors); void PostReportResultCallbackToUserThread( @@ -268,6 +276,7 @@ absl::optional<std::string> signals_for_winner, absl::optional<GURL> report_url, base::flat_map<std::string, GURL> ad_beacon_map, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors); static void PostResumeToUserThread( @@ -318,6 +327,7 @@ absl::optional<uint32_t> scoring_signals_data_version, absl::optional<GURL> debug_loss_report_url, absl::optional<GURL> debug_win_report_url, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors); // Runs the specified queued ReportWinTask. All code must already be loaded by @@ -329,6 +339,7 @@ absl::optional<std::string> signals_for_winner, absl::optional<GURL> report_url, base::flat_map<std::string, GURL> ad_beacon_map, + PrivateAggregationRequests pa_requests, std::vector<std::string> errors); // Returns true if unpaused and the script has loaded.
diff --git a/content/services/auction_worklet/seller_worklet_unittest.cc b/content/services/auction_worklet/seller_worklet_unittest.cc index 78077162..5c743df8 100644 --- a/content/services/auction_worklet/seller_worklet_unittest.cc +++ b/content/services/auction_worklet/seller_worklet_unittest.cc
@@ -40,6 +40,9 @@ namespace auction_worklet { namespace { +using PrivateAggregationRequests = + std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>; + // Very short time used by some tests that want to wait until just before a // timer triggers. constexpr base::TimeDelta kTinyTime = base::Microseconds(1); @@ -166,13 +169,13 @@ absl::optional<uint32_t> expected_data_version = {}, const absl::optional<GURL>& expected_debug_loss_report_url = absl::nullopt, - const absl::optional<GURL>& expected_debug_win_report_url = - absl::nullopt) { + const absl::optional<GURL>& expected_debug_win_report_url = absl::nullopt, + PrivateAggregationRequests expected_pa_requests = {}) { RunScoreAdWithJavascriptExpectingResult( CreateScoreAdScript(raw_return_value), expected_score, expected_errors, std::move(expected_component_auction_modified_bid_params), expected_data_version, expected_debug_loss_report_url, - expected_debug_win_report_url); + expected_debug_win_report_url, std::move(expected_pa_requests)); } // Behaves just like RunScoreAdWithReturnValueExpectingResult(), but @@ -192,8 +195,8 @@ absl::optional<uint32_t> expected_data_version = {}, const absl::optional<GURL>& expected_debug_loss_report_url = absl::nullopt, - const absl::optional<GURL>& expected_debug_win_report_url = - absl::nullopt) { + const absl::optional<GURL>& expected_debug_win_report_url = absl::nullopt, + PrivateAggregationRequests expected_pa_requests = {}) { AddJavascriptResponse(&url_loader_factory_, decision_logic_url_, CreateScoreAdScript(raw_return_value)); auto seller_worklet = CreateWorklet(); @@ -203,7 +206,8 @@ seller_worklet.get(), expected_score, expected_errors, std::move(expected_component_auction_modified_bid_params), expected_data_version, expected_debug_loss_report_url, - expected_debug_win_report_url, run_loop.QuitClosure()); + expected_debug_win_report_url, std::move(expected_pa_requests), + run_loop.QuitClosure()); task_environment_.FastForwardBy(expected_duration - kTinyTime); EXPECT_FALSE(run_loop.AnyQuitCalled()); task_environment_.FastForwardBy(kTinyTime); @@ -223,8 +227,8 @@ absl::optional<uint32_t> expected_data_version = {}, const absl::optional<GURL>& expected_debug_loss_report_url = absl::nullopt, - const absl::optional<GURL>& expected_debug_win_report_url = - absl::nullopt) { + const absl::optional<GURL>& expected_debug_win_report_url = absl::nullopt, + PrivateAggregationRequests expected_pa_requests = {}) { SCOPED_TRACE(javascript); AddJavascriptResponse(&url_loader_factory_, decision_logic_url_, javascript); @@ -232,7 +236,7 @@ expected_score, expected_errors, std::move(expected_component_auction_modified_bid_params), expected_data_version, expected_debug_loss_report_url, - expected_debug_win_report_url); + expected_debug_win_report_url, std::move(expected_pa_requests)); } // Runs score_ad() script, checking result and invoking provided closure @@ -246,6 +250,7 @@ absl::optional<uint32_t> expected_data_version, const absl::optional<GURL>& expected_debug_loss_report_url, const absl::optional<GURL>& expected_debug_win_report_url, + PrivateAggregationRequests expected_pa_requests, base::OnceClosure done_closure) { seller_worklet->ScoreAd( ad_metadata_, bid_, auction_ad_config_non_shared_params_, @@ -261,6 +266,7 @@ absl::optional<uint32_t> expected_data_version, const absl::optional<GURL>& expected_debug_loss_report_url, const absl::optional<GURL>& expected_debug_win_report_url, + PrivateAggregationRequests expected_pa_requests, std::vector<std::string> expected_errors, base::OnceClosure done_closure, double score, mojom::ComponentAuctionModifiedBidParamsPtr @@ -268,6 +274,7 @@ uint32_t data_version, bool has_data_version, const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { absl::optional<uint32_t> maybe_data_version; if (has_data_version) @@ -291,14 +298,15 @@ EXPECT_EQ(expected_debug_loss_report_url, debug_loss_report_url); EXPECT_EQ(expected_debug_win_report_url, debug_win_report_url); EXPECT_EQ(expected_data_version, maybe_data_version); + EXPECT_EQ(expected_pa_requests, pa_requests); EXPECT_EQ(expected_errors, errors); std::move(done_closure).Run(); }, expected_score, std::move(expected_component_auction_modified_bid_params), expected_data_version, expected_debug_loss_report_url, - expected_debug_win_report_url, expected_errors, - std::move(done_closure))); + expected_debug_win_report_url, std::move(expected_pa_requests), + expected_errors, std::move(done_closure))); } void RunScoreAdOnWorkletExpectingCallbackNeverInvoked( @@ -317,6 +325,7 @@ bool has_scoring_signals_data_version, const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { ADD_FAILURE() << "This should not be invoked"; })); @@ -334,14 +343,15 @@ absl::optional<uint32_t> expected_data_version = absl::nullopt, const absl::optional<GURL>& expected_debug_loss_report_url = absl::nullopt, - const absl::optional<GURL>& expected_debug_win_report_url = - absl::nullopt) { + const absl::optional<GURL>& expected_debug_win_report_url = absl::nullopt, + PrivateAggregationRequests expected_pa_requests = {}) { base::RunLoop run_loop; RunScoreAdOnWorkletAsync( seller_worklet, expected_score, expected_errors, std::move(expected_component_auction_modified_bid_params), expected_data_version, expected_debug_loss_report_url, - expected_debug_win_report_url, run_loop.QuitClosure()); + expected_debug_win_report_url, std::move(expected_pa_requests), + run_loop.QuitClosure()); run_loop.Run(); } @@ -356,15 +366,15 @@ absl::optional<uint32_t> expected_data_version = absl::nullopt, const absl::optional<GURL>& expected_debug_loss_report_url = absl::nullopt, - const absl::optional<GURL>& expected_debug_win_report_url = - absl::nullopt) { + const absl::optional<GURL>& expected_debug_win_report_url = absl::nullopt, + PrivateAggregationRequests expected_pa_requests = {}) { auto seller_worklet = CreateWorklet(); ASSERT_TRUE(seller_worklet); RunScoreAdExpectingResultOnWorklet( seller_worklet.get(), expected_score, expected_errors, std::move(expected_component_auction_modified_bid_params), expected_data_version, expected_debug_loss_report_url, - expected_debug_win_report_url); + expected_debug_win_report_url, std::move(expected_pa_requests)); } // Configures `url_loader_factory_` to return a report_result() script created @@ -377,12 +387,14 @@ const absl::optional<GURL>& expected_report_url, const base::flat_map<std::string, GURL>& expected_ad_beacon_map = base::flat_map<std::string, GURL>(), + PrivateAggregationRequests expected_pa_requests = {}, const std::vector<std::string>& expected_errors = std::vector<std::string>()) { RunReportResultWithJavascriptExpectingResult( CreateReportToScript(raw_return_value, extra_code), expected_signals_for_winner, expected_report_url, - expected_ad_beacon_map, expected_errors); + expected_ad_beacon_map, std::move(expected_pa_requests), + expected_errors); } // Configures `url_loader_factory_` to return the provided script, and then @@ -394,6 +406,7 @@ const absl::optional<GURL>& expected_report_url, const base::flat_map<std::string, GURL>& expected_ad_beacon_map = base::flat_map<std::string, GURL>(), + PrivateAggregationRequests expected_pa_requests = {}, const std::vector<std::string>& expected_errors = std::vector<std::string>()) { SCOPED_TRACE(javascript); @@ -401,6 +414,7 @@ javascript); RunReportResultExpectingResult(expected_signals_for_winner, expected_report_url, expected_ad_beacon_map, + std::move(expected_pa_requests), expected_errors); } @@ -412,6 +426,7 @@ const absl::optional<std::string>& expected_signals_for_winner, const absl::optional<GURL>& expected_report_url, const base::flat_map<std::string, GURL>& expected_ad_beacon_map, + PrivateAggregationRequests expected_pa_requests, const std::vector<std::string>& expected_errors, base::OnceClosure done_closure) { seller_worklet->ReportResult( @@ -428,20 +443,24 @@ [](const absl::optional<std::string>& expected_signals_for_winner, const absl::optional<GURL>& expected_report_url, const base::flat_map<std::string, GURL>& expected_ad_beacon_map, + PrivateAggregationRequests expected_pa_requests, const std::vector<std::string>& expected_errors, base::OnceClosure done_closure, const absl::optional<std::string>& signals_for_winner, const absl::optional<GURL>& report_url, const base::flat_map<std::string, GURL>& ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ(expected_signals_for_winner, signals_for_winner); EXPECT_EQ(expected_report_url, report_url); EXPECT_EQ(expected_ad_beacon_map, ad_beacon_map); + EXPECT_EQ(expected_pa_requests, pa_requests); EXPECT_EQ(expected_errors, errors); std::move(done_closure).Run(); }, expected_signals_for_winner, expected_report_url, - expected_ad_beacon_map, expected_errors, std::move(done_closure))); + expected_ad_beacon_map, std::move(expected_pa_requests), + expected_errors, std::move(done_closure))); } void RunReportResultExpectingCallbackNeverInvoked( @@ -460,6 +479,7 @@ [](const absl::optional<std::string>& signals_for_winner, const absl::optional<GURL>& report_url, const base::flat_map<std::string, GURL>& ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { ADD_FAILURE() << "This should not be invoked"; })); @@ -471,6 +491,7 @@ const absl::optional<GURL>& expected_report_url, const base::flat_map<std::string, GURL>& expected_ad_beacon_map = base::flat_map<std::string, GURL>(), + PrivateAggregationRequests expected_pa_requests = {}, const std::vector<std::string>& expected_errors = std::vector<std::string>()) { auto seller_worklet = CreateWorklet(); @@ -479,7 +500,8 @@ base::RunLoop run_loop; RunReportResultExpectingResultAsync( seller_worklet.get(), expected_signals_for_winner, expected_report_url, - expected_ad_beacon_map, expected_errors, run_loop.QuitClosure()); + expected_ad_beacon_map, std::move(expected_pa_requests), + expected_errors, run_loop.QuitClosure()); run_loop.Run(); } @@ -1203,6 +1225,7 @@ /*expected_data_version=*/absl::nullopt, /*expected_debug_loss_report_url=*/absl::nullopt, /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, base::BindLambdaForTesting([&]() { ++num_completed_worklets; if (num_completed_worklets == kNumWorklets) @@ -1244,6 +1267,7 @@ /*expected_data_version=*/absl::nullopt, /*expected_debug_loss_report_url=*/absl::nullopt, /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, base::BindLambdaForTesting([&]() { ++num_completed_worklets; if (num_completed_worklets == kNumWorklets) @@ -1307,6 +1331,7 @@ /*expected_data_version=*/i, /*expected_debug_loss_report_url=*/absl::nullopt, /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, base::BindLambdaForTesting([&]() { ++num_completed_worklets; if (num_completed_worklets == kNumWorklets) @@ -1373,6 +1398,7 @@ /*expected_data_version=*/absl::nullopt, /*expected_debug_loss_report_url=*/absl::nullopt, /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, base::BindLambdaForTesting([&]() { ++num_completed_worklets; if (num_completed_worklets == kNumWorklets) @@ -1430,6 +1456,7 @@ /*expected_data_version=*/10, /*expected_debug_loss_report_url=*/absl::nullopt, /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, base::BindLambdaForTesting([&]() { ++num_completed_worklets; if (num_completed_worklets == kNumWorklets) @@ -1496,6 +1523,7 @@ /*expected_data_version=*/10, /*expected_debug_loss_report_url=*/absl::nullopt, /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, base::BindLambdaForTesting([&]() { ++num_completed_worklets; if (num_completed_worklets == kNumWorklets) @@ -1542,6 +1570,110 @@ run_loop.Run(); } +TEST_F(SellerWorkletTest, ScoreAdPrivateAggregationRequests) { + auction_worklet::mojom::PrivateAggregationRequestPtr kExpectedRequest1 = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/123, + /*value=*/45), + content::mojom::AggregationServiceMode::kDefault); + auction_worklet::mojom::PrivateAggregationRequestPtr kExpectedRequest2 = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/absl::MakeInt128(/*high=*/1, /*low=*/0), + /*value=*/1), + content::mojom::AggregationServiceMode::kDefault); + + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunScoreAdWithJavascriptExpectingResult( + CreateScoreAdScript( + "5", + "privateAggregation.sendHistogramReport({bucket: 123, value: 45})"), + 5, /*expected_errors=*/{}, + mojom::ComponentAuctionModifiedBidParamsPtr(), + /*expected_data_version=*/absl::nullopt, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + std::move(expected_pa_requests)); + } + + // BigInt bucket + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunScoreAdWithJavascriptExpectingResult( + CreateScoreAdScript("5", + "privateAggregation.sendHistogramReport(" + "{bucket: 123n, value: 45})"), + 5, /*expected_errors=*/{}, + mojom::ComponentAuctionModifiedBidParamsPtr(), + /*expected_data_version=*/absl::nullopt, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + std::move(expected_pa_requests)); + } + + // Large bucket + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest2.Clone()); + + RunScoreAdWithJavascriptExpectingResult( + CreateScoreAdScript("5", + "privateAggregation.sendHistogramReport(" + "{bucket: 18446744073709551616n, value: 1})"), + 5, /*expected_errors=*/{}, + mojom::ComponentAuctionModifiedBidParamsPtr(), + /*expected_data_version=*/absl::nullopt, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + std::move(expected_pa_requests)); + } + + // Multiple requests + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + expected_pa_requests.push_back(kExpectedRequest2.Clone()); + + RunScoreAdWithJavascriptExpectingResult( + CreateScoreAdScript("5", R"( + privateAggregation.sendHistogramReport({bucket: 123, value: 45}); + privateAggregation.sendHistogramReport({bucket: 18446744073709551616n, + value: 1}); + )"), + 5, /*expected_errors=*/{}, + mojom::ComponentAuctionModifiedBidParamsPtr(), + /*expected_data_version=*/absl::nullopt, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + std::move(expected_pa_requests)); + } + + // An unrelated exception after sendHistogramReport shouldn't block the report + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunScoreAdWithJavascriptExpectingResult( + CreateScoreAdScript("5", R"( + privateAggregation.sendHistogramReport({bucket: 123, value: 45}); + error; + )"), + 0, /*expected_errors=*/ + {"https://url.test/:6 Uncaught ReferenceError: error is not defined."}, + mojom::ComponentAuctionModifiedBidParamsPtr(), + /*expected_data_version=*/absl::nullopt, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + std::move(expected_pa_requests)); + } +} + // Test multiple ReportWin() calls on a single worklet, in parallel. Do this // twice, once before the worklet has loaded its Javascript, and once after, to // make sure both cases work. @@ -1568,6 +1700,7 @@ /*expected_report_url=*/ GURL("https://" + base::NumberToString(bid_)), /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, /*expected_errors=*/{}, base::BindLambdaForTesting([&run_loop, &num_report_result_calls]() { ++num_report_result_calls; @@ -1635,6 +1768,7 @@ /*expected_signals_for_winner=*/absl::nullopt, /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:10 Uncaught ReferenceError: " "shrimp is not defined."}); } @@ -1654,6 +1788,7 @@ /*expected_signals_for_winner=*/absl::nullopt, /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: " "sendReportTo must be passed a valid HTTPS url."}); RunReportResultCreatedScriptExpectingResult( @@ -1661,6 +1796,7 @@ /*expected_signals_for_winner=*/absl::nullopt, /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: " "sendReportTo must be passed a valid HTTPS url."}); @@ -1671,6 +1807,7 @@ /*expected_signals_for_winner=*/absl::nullopt, /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: " "sendReportTo may be called at most once."}); @@ -1689,6 +1826,7 @@ /*expected_signals_for_winner=*/absl::nullopt, /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: " "sendReportTo must be passed a valid HTTPS url."}); RunReportResultCreatedScriptExpectingResult( @@ -1696,6 +1834,7 @@ /*expected_signals_for_winner=*/absl::nullopt, /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: " "sendReportTo requires 1 string parameter."}); RunReportResultCreatedScriptExpectingResult( @@ -1703,6 +1842,7 @@ /*expected_signals_for_winner=*/absl::nullopt, /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: " "sendReportTo requires 1 string parameter."}); } @@ -1713,6 +1853,7 @@ /*expected_signals_for_winner=*/absl::nullopt, /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught ReferenceError: Date is not defined."}); } @@ -1945,6 +2086,7 @@ /*expected_signals_for_winner=*/{}, /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:13 Uncaught TypeError: registerAdBeacon may be " "called at most once."}); @@ -1978,6 +2120,7 @@ /*expected_signals_for_winner=*/{}, /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: registerAdBeacon requires 1 " "object parameter."}); @@ -1987,6 +2130,7 @@ /*expected_signals_for_winner=*/{}, /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: registerAdBeacon requires 1 " "object parameter."}); @@ -1996,6 +2140,7 @@ /*expected_signals_for_winner=*/{}, /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: registerAdBeacon requires 1 " "object parameter."}); @@ -2009,6 +2154,7 @@ /*expected_signals_for_winner=*/{}, /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: registerAdBeacon object " "attributes must be strings."}); @@ -2022,6 +2168,7 @@ /*expected_signals_for_winner=*/{}, /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: registerAdBeacon invalid " "reporting url for key 'view': 'gopher://view.example.com/'."}); @@ -2035,10 +2182,106 @@ /*expected_signals_for_winner=*/{}, /*expected_report_url =*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + /*expected_pa_requests=*/{}, {"https://url.test/:9 Uncaught TypeError: registerAdBeacon invalid " "reporting url for key 'view': 'http://view.example.com/'."}); } +TEST_F(SellerWorkletTest, ReportResultPrivateAggregationRequests) { + auction_worklet::mojom::PrivateAggregationRequestPtr kExpectedRequest1 = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/123, + /*value=*/45), + content::mojom::AggregationServiceMode::kDefault); + auction_worklet::mojom::PrivateAggregationRequestPtr kExpectedRequest2 = + auction_worklet::mojom::PrivateAggregationRequest::New( + content::mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/absl::MakeInt128(/*high=*/1, /*low=*/0), + /*value=*/1), + content::mojom::AggregationServiceMode::kDefault); + + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunReportResultCreatedScriptExpectingResult( + R"(5)", + R"(privateAggregation.sendHistogramReport({bucket: 123, value: 45});)", + /*expected_signals_for_winner=*/"5", + /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + std::move(expected_pa_requests), + /*expected_errors=*/{}); + } + + // BigInt bucket + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunReportResultCreatedScriptExpectingResult( + R"(5)", + R"(privateAggregation.sendHistogramReport({bucket: 123n, value: 45});)", + /*expected_signals_for_winner=*/"5", + /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + std::move(expected_pa_requests), + /*expected_errors=*/{}); + } + + // Large bucket + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest2.Clone()); + + RunReportResultCreatedScriptExpectingResult( + R"(5)", + R"(privateAggregation.sendHistogramReport( + {bucket: 18446744073709551616n, value: 1});)", + /*expected_signals_for_winner=*/"5", + /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + std::move(expected_pa_requests), + /*expected_errors=*/{}); + } + + // Multiple requests + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + expected_pa_requests.push_back(kExpectedRequest2.Clone()); + + RunReportResultCreatedScriptExpectingResult( + R"(5)", + R"( + privateAggregation.sendHistogramReport({bucket: 123, value: 45}); + privateAggregation.sendHistogramReport({bucket: 18446744073709551616n, + value: 1}); + )", + /*expected_signals_for_winner=*/"5", + /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + std::move(expected_pa_requests), + /*expected_errors=*/{}); + } + + // An unrelated exception after sendHistogramReport shouldn't block the report + { + PrivateAggregationRequests expected_pa_requests; + expected_pa_requests.push_back(kExpectedRequest1.Clone()); + + RunReportResultCreatedScriptExpectingResult( + R"(5)", + R"( + privateAggregation.sendHistogramReport({bucket: 123, value: 45}); + error; + )", + /*expected_signals_for_winner=*/absl::nullopt, + /*expected_report_url=*/absl::nullopt, /*expected_ad_beacon_map=*/{}, + std::move(expected_pa_requests), + /*expected_errors=*/ + {"https://url.test/:11 Uncaught ReferenceError: error is not " + "defined."}); + } +} + TEST_F(SellerWorkletTest, ReportResultBid) { bid_ = 5; RunReportResultCreatedScriptExpectingResult( @@ -2247,6 +2490,7 @@ bool has_scoring_signals_data_version, const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ(2, score); EXPECT_FALSE(has_scoring_signals_data_version); @@ -2273,6 +2517,7 @@ const absl::optional<std::string>& signals_for_winner, const absl::optional<GURL>& report_url, const base::flat_map<std::string, GURL>& ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { EXPECT_EQ("2", signals_for_winner); EXPECT_TRUE(errors.empty()); @@ -2304,6 +2549,7 @@ bool has_scoring_signals_data_version, const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { ADD_FAILURE() << "Callback should not be invoked since worklet deleted"; })); @@ -2334,6 +2580,7 @@ base::BindOnce([](const absl::optional<std::string>& signals_for_winner, const absl::optional<GURL>& report_url, const base::flat_map<std::string, GURL>& ad_beacon_map, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { ADD_FAILURE() << "Callback should not be invoked since worklet deleted"; })); @@ -2356,12 +2603,13 @@ // Queue a ScoreAd() call, which should not happen immediately since loading // is paused. base::RunLoop run_loop; - RunScoreAdOnWorkletAsync( - worklet.get(), /*expected_score=*/10, /*expected_errors=*/{}, - mojom::ComponentAuctionModifiedBidParamsPtr(), - /*expected_data_version=*/absl::nullopt, - /*expected_debug_loss_report_url=*/absl::nullopt, - /*expected_debug_win_report_url=*/absl::nullopt, run_loop.QuitClosure()); + RunScoreAdOnWorkletAsync(worklet.get(), /*expected_score=*/10, + /*expected_errors=*/{}, + mojom::ComponentAuctionModifiedBidParamsPtr(), + /*expected_data_version=*/absl::nullopt, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, run_loop.QuitClosure()); // Give it a chance to fetch. task_environment_.RunUntilIdle(); @@ -2442,7 +2690,8 @@ /*expected_errors=*/{}, mojom::ComponentAuctionModifiedBidParamsPtr(), /*expected_data_version=*/absl::nullopt, /*expected_debug_loss_report_url=*/absl::nullopt, - /*expected_debug_win_report_url=*/absl::nullopt, run_loop1.QuitClosure()); + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, run_loop1.QuitClosure()); decision_logic_url_ = kUrl2; SellerWorklet* worklet_impl2 = nullptr; @@ -2454,7 +2703,8 @@ /*expected_errors=*/{}, mojom::ComponentAuctionModifiedBidParamsPtr(), /*expected_data_version=*/absl::nullopt, /*expected_debug_loss_report_url=*/absl::nullopt, - /*expected_debug_win_report_url=*/absl::nullopt, run_loop2.QuitClosure()); + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, run_loop2.QuitClosure()); int id1 = worklet_impl1->context_group_id_for_testing(); int id2 = worklet_impl2->context_group_id_for_testing(); @@ -2572,7 +2822,8 @@ worklet1.get(), 100.5, {}, mojom::ComponentAuctionModifiedBidParamsPtr(), /*expected_data_version=*/absl::nullopt, /*expected_debug_loss_report_url=*/absl::nullopt, - /*expected_debug_win_report_url=*/absl::nullopt, run_loop1.QuitClosure()); + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, run_loop1.QuitClosure()); decision_logic_url_ = GURL(kUrl2); auto worklet2 = CreateWorklet(/*pause_for_debugger_on_start=*/true); @@ -2584,6 +2835,7 @@ /*expected_data_version=*/absl::nullopt, /*expected_debug_loss_report_url=*/absl::nullopt, /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, run_loop2.QuitClosure()); mojo::AssociatedRemote<blink::mojom::DevToolsAgent> agent1, agent2; @@ -2722,11 +2974,12 @@ decision_logic_url_ = GURL(kUrl); auto worklet = CreateWorklet(/*pause_for_debugger_on_start=*/true); base::RunLoop run_loop; - RunScoreAdOnWorkletAsync( - worklet.get(), 1.0, {}, mojom::ComponentAuctionModifiedBidParamsPtr(), - /*expected_data_version=*/absl::nullopt, - /*expected_debug_loss_report_url=*/absl::nullopt, - /*expected_debug_win_report_url=*/absl::nullopt, run_loop.QuitClosure()); + RunScoreAdOnWorkletAsync(worklet.get(), 1.0, {}, + mojom::ComponentAuctionModifiedBidParamsPtr(), + /*expected_data_version=*/absl::nullopt, + /*expected_debug_loss_report_url=*/absl::nullopt, + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, run_loop.QuitClosure()); mojo::AssociatedRemote<blink::mojom::DevToolsAgent> agent; worklet->ConnectDevToolsAgent(agent.BindNewEndpointAndPassReceiver()); @@ -2779,8 +3032,8 @@ base::RunLoop run_loop2; RunReportResultExpectingResultAsync( worklet.get(), "1", GURL("https://foo.test/"), - /*expected_ad_beacon_map=*/{}, /*expected_errors=*/{}, - run_loop2.QuitClosure()); + /*expected_ad_beacon_map=*/{}, /*expected_pa_requests=*/{}, + /*expected_errors=*/{}, run_loop2.QuitClosure()); TestDevToolsAgentClient::Event breakpoint_hit2 = debug.WaitForMethodNotification("Debugger.paused"); const std::string* breakpoint2 = @@ -2802,7 +3055,8 @@ worklet.get(), 1.0, {}, mojom::ComponentAuctionModifiedBidParamsPtr(), /*expected_data_version=*/absl::nullopt, /*expected_debug_loss_report_url=*/absl::nullopt, - /*expected_debug_win_report_url=*/absl::nullopt, run_loop3.QuitClosure()); + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, run_loop3.QuitClosure()); TestDevToolsAgentClient::Event breakpoint_hit3 = debug.WaitForMethodNotification("Debugger.paused"); @@ -2863,7 +3117,8 @@ worklet.get(), 1.0, {}, mojom::ComponentAuctionModifiedBidParamsPtr(), /*expected_data_version=*/absl::nullopt, /*expected_debug_loss_report_url=*/absl::nullopt, - /*expected_debug_win_report_url=*/absl::nullopt, base::BindOnce([]() { + /*expected_debug_win_report_url=*/absl::nullopt, + /*expected_pa_requests=*/{}, base::BindOnce([]() { ADD_FAILURE() << "scoreAd shouldn't actually get to finish."; })); @@ -3184,6 +3439,7 @@ bool has_scoring_signals_data_version, const absl::optional<GURL>& debug_loss_report_url, const absl::optional<GURL>& debug_win_report_url, + PrivateAggregationRequests pa_requests, const std::vector<std::string>& errors) { if (score == 1) { EXPECT_TRUE(debug_loss_report_url.has_value());
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index bde274f..560e0fb 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -150,6 +150,8 @@ "browser/shell_speech_recognition_manager_delegate.h", "browser/shell_web_contents_view_delegate.h", "browser/shell_web_contents_view_delegate_creator.h", + "common/main_frame_counter_test_impl.cc", + "common/main_frame_counter_test_impl.h", "common/power_monitor_test_impl.cc", "common/power_monitor_test_impl.h", "common/shell_content_client.cc", @@ -251,6 +253,7 @@ "//components/web_cache/renderer", "//content:content_resources", "//content:dev_ui_content_resources", + "//content/common:main_frame_counter", "//content/public/common", "//content/test:content_test_mojo_bindings", "//content/test:test_support", @@ -850,7 +853,10 @@ } mojom("content_browsertests_mojom") { - sources = [ "common/power_monitor_test.mojom" ] + sources = [ + "common/main_frame_counter_test.mojom", + "common/power_monitor_test.mojom", + ] public_deps = [ "//sandbox/policy/mojom" ] }
diff --git a/content/shell/common/main_frame_counter_test.mojom b/content/shell/common/main_frame_counter_test.mojom new file mode 100644 index 0000000..683ff22 --- /dev/null +++ b/content/shell/common/main_frame_counter_test.mojom
@@ -0,0 +1,13 @@ +// Copyright 2022 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 content.mojom; + +// This interface is only for the sake of browser test to query the number of +// main frames in a remote child process. +interface MainFrameCounterTest { + // Returns whether or not the renderer this is called on has a local main + // frame. + HasMainFrame() => (bool has_main_frame); +};
diff --git a/content/shell/common/main_frame_counter_test_impl.cc b/content/shell/common/main_frame_counter_test_impl.cc new file mode 100644 index 0000000..fb557f1 --- /dev/null +++ b/content/shell/common/main_frame_counter_test_impl.cc
@@ -0,0 +1,30 @@ +// Copyright 2022 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/shell/common/main_frame_counter_test_impl.h" +#include "base/no_destructor.h" +#include "content/common/main_frame_counter.h" +#include "mojo/public/cpp/bindings/receiver.h" + +namespace content { + +MainFrameCounterTestImpl* GetMainFrameCounterTestImpl() { + static base::NoDestructor<MainFrameCounterTestImpl> instance; + return instance.get(); +} + +MainFrameCounterTestImpl::MainFrameCounterTestImpl() = default; +MainFrameCounterTestImpl::~MainFrameCounterTestImpl() = default; + +// static +void MainFrameCounterTestImpl::Bind( + mojo::PendingReceiver<mojom::MainFrameCounterTest> receiver) { + GetMainFrameCounterTestImpl()->receiver_.Bind(std::move(receiver)); +} + +void MainFrameCounterTestImpl::HasMainFrame(HasMainFrameCallback callback) { + std::move(callback).Run(MainFrameCounter::has_main_frame()); +} + +}; // namespace content
diff --git a/content/shell/common/main_frame_counter_test_impl.h b/content/shell/common/main_frame_counter_test_impl.h new file mode 100644 index 0000000..0ab65b7 --- /dev/null +++ b/content/shell/common/main_frame_counter_test_impl.h
@@ -0,0 +1,27 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SHELL_COMMON_MAIN_FRAME_COUNTER_TEST_IMPL_H_ +#define CONTENT_SHELL_COMMON_MAIN_FRAME_COUNTER_TEST_IMPL_H_ + +#include "content/shell/common/main_frame_counter_test.mojom.h" +#include "mojo/public/cpp/bindings/receiver.h" + +namespace content { + +class MainFrameCounterTestImpl final : public mojom::MainFrameCounterTest { + public: + MainFrameCounterTestImpl(); + ~MainFrameCounterTestImpl() override; + static void Bind(mojo::PendingReceiver<mojom::MainFrameCounterTest> receiver); + + void HasMainFrame(HasMainFrameCallback) override; + + private: + mojo::Receiver<mojom::MainFrameCounterTest> receiver_{this}; +}; + +}; // namespace content + +#endif // CONTENT_SHELL_COMMON_MAIN_FRAME_COUNTER_TEST_IMPL_H_
diff --git a/content/shell/renderer/shell_content_renderer_client.cc b/content/shell/renderer/shell_content_renderer_client.cc index 1fe5a1c4..d7fe54a 100644 --- a/content/shell/renderer/shell_content_renderer_client.cc +++ b/content/shell/renderer/shell_content_renderer_client.cc
@@ -14,6 +14,7 @@ #include "components/cdm/renderer/external_clear_key_key_system_properties.h" #include "components/web_cache/renderer/web_cache_impl.h" #include "content/public/test/test_service.mojom.h" +#include "content/shell/common/main_frame_counter_test_impl.h" #include "content/shell/common/power_monitor_test_impl.h" #include "content/shell/common/shell_switches.h" #include "content/shell/renderer/shell_render_frame_observer.h" @@ -139,6 +140,9 @@ binders->Add<mojom::PowerMonitorTest>( base::BindRepeating(&PowerMonitorTestImpl::MakeSelfOwnedReceiver), base::ThreadTaskRunnerHandle::Get()); + binders->Add<mojom::MainFrameCounterTest>( + base::BindRepeating(&MainFrameCounterTestImpl::Bind), + base::ThreadTaskRunnerHandle::Get()); binders->Add<web_cache::mojom::WebCache>( base::BindRepeating(&web_cache::WebCacheImpl::BindReceiver, base::Unretained(web_cache_impl_.get())),
diff --git a/content/test/data/indexeddb/bug_1203335.js b/content/test/data/indexeddb/bug_1203335.js index f8e1330..3ceed70 100644 --- a/content/test/data/indexeddb/bug_1203335.js +++ b/content/test/data/indexeddb/bug_1203335.js
@@ -8,17 +8,18 @@ // transactions. function test() { - if (window.webkitStorageInfo) { + if (navigator.storage) { window.jsTestIsAsync = true; - navigator.webkitTemporaryStorage.queryUsageAndQuota( - initUsageCallback, unexpectedErrorCallback); + navigator.storage.estimate() + .then(initUsageCallback) + .catch(unexpectedErrorCallback); } else - debug('This test requires window.webkitStorageInfo.'); + debug('This test requires navigator.storage.'); } -function initUsageCallback(usage, quota) { - origReturnedUsage = returnedUsage = usage; - origReturnedQuota = returnedQuota = quota; +function initUsageCallback(result) { + origReturnedUsage = returnedUsage = result.usage; + origReturnedQuota = returnedQuota = result.quota; debug('original quota is ' + displaySize(origReturnedQuota)); debug('original usage is ' + displaySize(origReturnedUsage));
diff --git a/content/test/data/indexeddb/quota_test.js b/content/test/data/indexeddb/quota_test.js index afb2983..25ff82b 100644 --- a/content/test/data/indexeddb/quota_test.js +++ b/content/test/data/indexeddb/quota_test.js
@@ -3,18 +3,18 @@ // found in the LICENSE file. function test() { - if (window.webkitStorageInfo) { + if (navigator.storage) { window.jsTestIsAsync = true; - navigator.webkitTemporaryStorage.queryUsageAndQuota( - initUsageCallback, - unexpectedErrorCallback); + navigator.storage.estimate() + .then(initUsageCallback) + .catch(unexpectedErrorCallback); } else - debug("This test requires window.webkitStorageInfo."); + debug('This test requires navigator.storage.'); } -function initUsageCallback(usage, quota) { - origReturnedUsage = returnedUsage = usage; - origReturnedQuota = returnedQuota = quota; +function initUsageCallback(result) { + origReturnedUsage = returnedUsage = result.usage; + origReturnedQuota = returnedQuota = result.quota; debug("original quota is " + displaySize(origReturnedQuota)); debug("original usage is " + displaySize(origReturnedUsage));
diff --git a/content/test/gpu/gpu_tests/webgpu_cts_integration_test.py b/content/test/gpu/gpu_tests/webgpu_cts_integration_test.py index 92fd673..6bf9842 100644 --- a/content/test/gpu/gpu_tests/webgpu_cts_integration_test.py +++ b/content/test/gpu/gpu_tests/webgpu_cts_integration_test.py
@@ -11,7 +11,7 @@ import sys import tempfile import threading -from typing import Any, List +from typing import Any, Dict, List import unittest import websockets # pylint:disable=import-error @@ -42,12 +42,24 @@ HTML_FILENAME = os.path.join('webgpu-cts', 'test_page.html') JAVASCRIPT_DURATION = 'javascript_duration' +MESSAGE_TYPE_TEST_STARTED = 'TEST_STARTED' +MESSAGE_TYPE_TEST_HEARTBEAT = 'TEST_HEARTBEAT' +MESSAGE_TYPE_TEST_STATUS = 'TEST_STATUS' +MESSAGE_TYPE_TEST_LOG = 'TEST_LOG' MESSAGE_TYPE_TEST_FINISHED = 'TEST_FINISHED' # These are tests that, for whatever reason, don't like being run in parallel. SERIAL_TESTS = {} +class WebGpuTestResult(): + """Struct-like object for holding a single test result.""" + + def __init__(self): + self.status = None + self.log_pieces = [] + + async def StartWebsocketServer() -> None: async def HandleWebsocketConnection( websocket: ws_server.WebSocketServerProtocol) -> None: @@ -268,12 +280,14 @@ def RunActualGpuTest(self, test_path: str, args: ct.TestArgs) -> None: self._query, self._run_in_worker = args - timeout = self._GetTestTimeout() # Only a single instance is used to run tests despite a number of instances # (~2x the number of total tests) being initialized, so make sure to clear # this state so we don't accidentally keep it around from a previous test. if JAVASCRIPT_DURATION in self.additionalTags: del self.additionalTags[JAVASCRIPT_DURATION] + + timeout = self._GetTestTimeout() + try: self._NavigateIfNecessary(test_path) asyncio.run_coroutine_threadsafe( @@ -282,38 +296,10 @@ 'q': self._query, 'w': self._run_in_worker })), WebGpuCtsIntegrationTest.event_loop) - # Loop until we receive a message saying that the test is finished. This - # currently has no practical effect, but it is an intermediate step to - # supporting a heartbeat mechanism. See crbug.com/1340602. - while True: - future = asyncio.run_coroutine_threadsafe( - asyncio.wait_for(WebGpuCtsIntegrationTest.websocket.recv(), - timeout), WebGpuCtsIntegrationTest.event_loop) - response = future.result() - response = json.loads(response) - if response['type'] == MESSAGE_TYPE_TEST_FINISHED: - break + result = self.HandleMessageLoop(timeout) - status = response['s'] - logs_pieces = [response['l']] - is_final_payload = response['final'] - js_duration = response['js_duration_ms'] / 1000 - # Specify the precision to avoid scientific notation. Nanoseconds should - # be more precision than we need anyways. - self.additionalTags[JAVASCRIPT_DURATION] = '%.9fs' % js_duration - # Get multiple log pieces if necessary, e.g. if a monolithic log would - # have gone over the max payload size. - while not is_final_payload: - future = asyncio.run_coroutine_threadsafe( - asyncio.wait_for(WebGpuCtsIntegrationTest.websocket.recv(), - MULTI_PAYLOAD_TIMEOUT), - WebGpuCtsIntegrationTest.event_loop) - response = future.result() - response = json.loads(response) - logs_pieces.append(response['l']) - is_final_payload = response['final'] - - log_str = ''.join(logs_pieces) + log_str = ''.join(result.log_pieces) + status = result.status if status == 'skip': self.skipTest('WebGPU CTS JavaScript reported test skip with logs ' + log_str) @@ -329,6 +315,96 @@ finally: WebGpuCtsIntegrationTest.total_tests_run += 1 + def HandleMessageLoop(self, timeout: float) -> WebGpuTestResult: + """Helper function to handle the loop for the message protocol. + + See //docs/gpu/webgpu_cts_harness_message_protocol.md for more information + on the message format. + + TODO(crbug.com/1340602): Update this to be the total test timeout once the + heartbeat mechanism is implemented. + + Args: + timeout: A float denoting the number of seconds to the test is allowed + to wait between test messages before timing out. + + Returns: + A filled WebGpuTestResult instance. + """ + result = WebGpuTestResult() + message_state = { + MESSAGE_TYPE_TEST_STARTED: False, + MESSAGE_TYPE_TEST_STATUS: False, + MESSAGE_TYPE_TEST_LOG: False, + } + # Loop until we receive a message saying that the test is finished. This + # currently has no practical effect, but it is an intermediate step to + # supporting a heartbeat mechanism. See crbug.com/1340602. + while True: + future = asyncio.run_coroutine_threadsafe( + asyncio.wait_for(WebGpuCtsIntegrationTest.websocket.recv(), timeout), + WebGpuCtsIntegrationTest.event_loop) + response = future.result() + response = json.loads(response) + response_type = response['type'] + + if response == MESSAGE_TYPE_TEST_STARTED: + # If we ever want the adapter information from WebGPU, we would + # retrieve it from the message here. However, to avoid pylint + # complaining about unused variables, don't grab it until we actually + # need it. + VerifyMessageOrderTestStarted(message_state) + + elif response_type == MESSAGE_TYPE_TEST_HEARTBEAT: + VerifyMessageOrderTestHeartbeat(message_state) + continue + + elif response_type == MESSAGE_TYPE_TEST_STATUS: + VerifyMessageOrderTestStatus(message_state) + result.status = response['status'] + js_duration = response['js_duration_ms'] / 1000 + # Specify the precision to avoid scientific notation. Nanoseconds + # should be more precision than we need anyways. + self.additionalTags[JAVASCRIPT_DURATION] = '%.9fs' % js_duration + + elif response_type == MESSAGE_TYPE_TEST_LOG: + VerifyMessageOrderTestLog(message_state) + result.log_pieces.append(response['log']) + + elif response_type == MESSAGE_TYPE_TEST_FINISHED: + VerifyMessageOrderTestFinished(message_state) + # TODO(crbug.com/1340602): Remove log, etc. once the Dawn code has + # been updated to send multiple message types. + if 's' in response: + result.status = response['s'] + if 'l' in response: + result.log_pieces.append(response['l']) + if 'js_duration_ms' in response: + js_duration = response['js_duration_ms'] / 1000 + # Specify the precision to avoid scientific notation. Nanoseconds + # should be more precision than we need anyways. + self.additionalTags[JAVASCRIPT_DURATION] = '%.9fs' % js_duration + + if 'final' in response: + is_final_payload = response['final'] + # Get multiple log pieces if necessary, e.g. if a monolithic log + # would have gone over the max payload size. + while not is_final_payload: + future = asyncio.run_coroutine_threadsafe( + asyncio.wait_for(WebGpuCtsIntegrationTest.websocket.recv(), + MULTI_PAYLOAD_TIMEOUT), + WebGpuCtsIntegrationTest.event_loop) + response = future.result() + response = json.loads(response) + result.log_pieces.append(response['l']) + is_final_payload = response['final'] + break + + else: + raise WebGpuMessageProtocolError('Received unknown message type %s' % + response_type) + return result + @classmethod def CleanUpExistingWebsocket(cls) -> None: if cls.connection_stopper: @@ -404,6 +480,98 @@ return [EXPECTATIONS_FILE] +class WebGpuMessageProtocolError(RuntimeError): + pass + + +def VerifyMessageOrderTestStarted(message_state: Dict[str, bool]) -> None: + """Helper function to verify that messages are ordered correctly. + + Handles MESSAGE_TYPE_TEST_STARTED messages. + + Split out to reduce the number of branches within a single function. + + Args: + message_state: A map from message type to a boolean denoting whether a + message of that type has been received before. + """ + if message_state[MESSAGE_TYPE_TEST_STARTED]: + raise WebGpuMessageProtocolError( + 'Received multiple start messages for one test') + message_state[MESSAGE_TYPE_TEST_STARTED] = True + + +def VerifyMessageOrderTestHeartbeat(message_state: Dict[str, bool]) -> None: + """Helper function to verify that messages are ordered correctly. + + Handles MESSAGE_TYPE_TEST_HEARTBEAT messages. + + Split out to reduce the number of branches within a single function. + + Args: + message_state: A map from message type to a boolean denoting whether a + message of that type has been received before. + """ + if not message_state[MESSAGE_TYPE_TEST_STARTED]: + raise WebGpuMessageProtocolError('Received heartbeat before test start') + if message_state[MESSAGE_TYPE_TEST_STATUS]: + raise WebGpuMessageProtocolError( + 'Received heartbeat after test supposedly done') + + +def VerifyMessageOrderTestStatus(message_state: Dict[str, bool]) -> None: + """Helper function to verify that messages are ordered correctly. + + Handles MESSAGE_TYPE_TEST_STATUS messages. + + Split out to reduce the number of branches within a single function. + + Args: + message_state: A map from message type to a boolean denoting whether a + message of that type has been received before. + """ + if not message_state[MESSAGE_TYPE_TEST_STARTED]: + raise WebGpuMessageProtocolError( + 'Received test status message before test start') + if message_state[MESSAGE_TYPE_TEST_STATUS]: + raise WebGpuMessageProtocolError( + 'Received multiple status messages for one test') + message_state[MESSAGE_TYPE_TEST_STATUS] = True + + +def VerifyMessageOrderTestLog(message_state: Dict[str, bool]) -> None: + """Helper function to verify that messages are ordered correctly. + + Handles MESSAGE_TYPE_TEST_LOG messages. + + Split out to reduce the number of branches within a single function. + + Args: + message_state: A map from message type to a boolean denoting whether a + message of that type has been received before. + """ + if not message_state[MESSAGE_TYPE_TEST_STATUS]: + raise WebGpuMessageProtocolError( + 'Received log message before status message') + message_state[MESSAGE_TYPE_TEST_LOG] = True + + +def VerifyMessageOrderTestFinished(message_state: Dict[str, bool]) -> None: + """Helper function to verify that messages are ordered correctly. + + Handles MESSAGE_TYPE_TEST_FINISHED messages. + + Split out to reduce the number of branches within a single function. + + Args: + message_state: A map from message type to a boolean denoting whether a + message of that type has been received before. + """ + # TODO(crbug.com/1340602): Add message state verification once the Dawn code + # has been updated to send multiple message types. + del message_state # currently unused + + def TestNameFromInputs(query: str, worker: bool) -> str: return 'worker_%s' % query if worker else query
diff --git a/device/vr/android/arcore/arcore_gl.cc b/device/vr/android/arcore/arcore_gl.cc index 16336b67..2dd51af 100644 --- a/device/vr/android/arcore/arcore_gl.cc +++ b/device/vr/android/arcore/arcore_gl.cc
@@ -45,6 +45,7 @@ #include "ui/gl/gl_fence_egl.h" #include "ui/gl/gl_image_ahardwarebuffer.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace { @@ -444,10 +445,15 @@ // TODO(crbug.com/1170580): support ANGLE with cardboard? gl::init::DisableANGLE(); - if (gl::GetGLImplementation() == gl::kGLImplementationNone && - !gl::init::InitializeGLOneOff(/*system_device_id=*/0)) { - DLOG(ERROR) << "gl::init::InitializeGLOneOff failed"; - return false; + gl::GLDisplay* display = nullptr; + if (gl::GetGLImplementation() == gl::kGLImplementationNone) { + display = gl::init::InitializeGLOneOff(/*system_device_id=*/0); + if (!display) { + DLOG(ERROR) << "gl::init::InitializeGLOneOff failed"; + return false; + } + } else { + display = gl::GetDefaultDisplayEGL(); } DCHECK(gl::GetGLImplementation() != gl::kGLImplementationEGLANGLE); @@ -456,10 +462,10 @@ // surface for Offscreen usage. scoped_refptr<gl::GLSurface> surface; if (drawing_widget != gfx::kNullAcceleratedWidget) { - surface = gl::init::CreateViewGLSurface(drawing_widget); + surface = gl::init::CreateViewGLSurface(display, drawing_widget); } else { surface = gl::init::CreateOffscreenGLSurfaceWithFormat( - {0, 0}, gl::GLSurfaceFormat()); + display, {0, 0}, gl::GLSurfaceFormat()); } DVLOG(3) << "surface=" << surface.get(); if (!surface.get()) {
diff --git a/docs/gpu/webgpu_cts_harness_message_protocol.md b/docs/gpu/webgpu_cts_harness_message_protocol.md new file mode 100644 index 0000000..836f25f --- /dev/null +++ b/docs/gpu/webgpu_cts_harness_message_protocol.md
@@ -0,0 +1,136 @@ +# WebGPU CTS Harness Message Protocol + +The WebGPU conformance test suite harness makes use of a websocket connection to +pass information between the Python and JavaScript code. This document outlines +all valid message types, when they should be sent, etc. All messages are JSON +objects with at least a `type` field that differentiates message types from each +other. + +## TEST_STARTED + +### Description + +A message sent exactly once by the JavaScript code once it starts running the +requested test. In addition to serving as an ack, it also sends information +about how the test will be run. + +Sending more than one message of this type during a test is considered an error. + +### Fields + +* `type` - A string denoting the message type +* `adapter_info` - An optional object containing the same information as the + [GpuAdapterInfo] the test will be using + +[GpuAdapterInfo]: https://gpuweb.github.io/gpuweb/#gpu-adapterinfo + +### Example + +``` +{ + 'type': 'TEST_STARTED', + 'adapter_info': { + 'vendor': 'NVIDIA', + 'architecture': 'Turing', + 'device': '2184', + 'description': 'GTX 1660', + }, +} +``` + +## TEST_HEARTBEAT + +### Description + +A message sent periodically zero or more times by the JavaScript code to +prevent the Python test harness from timing out. + +Sending a message of this type before TEST_STARTED or after TEST_STATUS is +considered an error. + +### Fields + +* `type` - A string denoting the message type + +### Example + +``` +{ + 'type': 'TEST_HEARTBEAT', +} +``` + +## TEST_STATUS + +### Description + +A message sent exactly once when the actual test is completed. Contains +information about the status/result of the test. + +Sending more than one message of this type or sending before TEST_STARTED is +considered an error. + +### Fields + +* `type` - As string denoting the message type +* `status` - A string containing the status of the test, e.g. `skip` or `fail` +* `js_duration_ms` - An int containing the number of milliseconds the + JavaScript code took to run the test + +### Example + +``` +{ + 'type': 'TEST_STATUS', + 'status': 'fail', + 'js_duration_ms': 243, +} +``` + +## TEST_LOG + +### Description + +A message sent one or more times containing test logs. Multiple messages will be +sent if a single message would exceed the max payload size, in which case the +Python test harness will concatenate them together in the order received. + +Sending a message of this type before TEST_STATUS is considered an error. + +### Fields + +* `type` - A string denoting the message type +* `log` - A string containing log content output by the test + +### Example + +``` +{ + 'type': 'TEST_LOG', + 'log': 'Logging is fun', +} +``` + +## TEST_FINISHED + +### Description + +A message sent exactly once after all other messages have been sent. This +signals to the Python test harness that it should stop listening for any +additional messages and proceed with test cleanup. + +Sending a message of this type before TEST_LOG is considered an error. Sending +more than one message of this type is erroneous, but will not be caught until +the following test is run. + +### Fields + +* `type` - A string denoting the message type + +### Example + +``` +{ + 'type': 'TEST_FINISHED', +} +```
diff --git a/docs/speed/binary_size/fuchsia_binary_size_trybot.md b/docs/speed/binary_size/fuchsia_binary_size_trybot.md index 8703a36..184b509 100644 --- a/docs/speed/binary_size/fuchsia_binary_size_trybot.md +++ b/docs/speed/binary_size/fuchsia_binary_size_trybot.md
@@ -35,7 +35,8 @@ ### Binary Size Increase -- **What:** Checks that [compressed fuchsia archive] size increases by no more than 12kb. +- **What:** Checks that [compressed fuchsia archive] size increases by no more + than 12kb. - These packages are `cast_runner` and `web_engine`. - **Why:** Chrome-Fuchsia deploys on platforms with small footprints. As each release rolls, Fuchsia runs its own set of size checks that will reject a @@ -47,16 +48,23 @@ #### What to do if the Check Fails? -- Look at the provided `commit size analysis files` stdout to understand where the size is coming from. +- Look at the provided `commit size analysis files` stdout to understand where + the size is coming from. - The `Read diff results` stdout will also give a breakdown of growth by package, if any. + - If the compressed size grew (this is what we measure), but the + uncompressed size decreased, then **ignore** this failure. Add a + [footer](#skipping-the-check) to + the CL (see below) to document this (and ignore this failure). - See if any of the generic [optimization advice] is applicable. - If you are writing a new feature or including a new library you might want to - think about skipping the `web_engine`/`cast_runner` binaries and to restrict this new - feature/library to desktop platforms that might care less about binary size. + think about skipping the `web_engine`/`cast_runner` binaries and to restrict + this new feature/library to desktop platforms that might care less about + binary size. - This can be done by removing it with the `is_fuchsia` BUILD tag and `OS_FUCHSIA` macro. - - If this change belongs on a full-browser, but not `web_engine`/`cast_runner`, + - If this change belongs on a full-browser, but not + `web_engine`/`cast_runner`, you should also guard against the `ARCH_CPU_ARM64` tag, as this CPU-architecture is the only (current) set that requires size-checks. - See [the section below](#obvious-regressions) @@ -66,14 +74,18 @@ - If you think that there might not be a consensus that the code your adding is worth the added file size, then add why you think it is. -- Add a footer to the commit description along the lines of: +### Skipping the check +Add a **footer** to the commit description along the lines of: + - `Fuchsia-Binary-Size: Size increase is unavoidable (see above).` + - `Fuchsia-Binary-Size: Uncompressed size actually decreased.` - `Fuchsia-Binary-Size: Increase is temporary.` - - `Fuchsia-Binary-Size: See commit description.` <-- use this if longer than one line. + - `Fuchsia-Binary-Size: See commit description.` <-- use this if longer + than one line. ***note -**Note:** Make sure there are no blank lines between `Fuchsia-Binary-Size:` and other -footers. +**Note:** Make sure there are no blank lines between `Fuchsia-Binary-Size:` and +other footers. *** [optimization advice]: /docs/speed/binary_size/optimization_advice.md @@ -83,8 +95,8 @@ The size metric we care about the most is the compressed size. This is an **estimate** of how large the Chrome-Fuchsia packages will be when delivered on device (actual compression can vary between devices, so the computed numbers may -not be accurate). However, you may see the uncompressed and compressed size grow by -different amounts (and sometimes the compressed size is larger than the +not be accurate). However, you may see the uncompressed and compressed size +grow by different amounts (and sometimes the compressed size is larger than the uncompressed)! This is due to how sizes are calculated and how the compression is done. @@ -94,16 +106,21 @@ Compression is done via the `blobfs-compression` tool, exported from the Fuchsia SDK. This compresses the file into a package that is ready to be deployed to the Fuchsia device. With the current (default) compression-mode, -this compresses the package in page-sizes designed for the device and filesystem. -Since each page is at least 8K, **increments in the compressed size are always -multiples of 8K with the current compression mode**. So, if your change causes -the previous compression page to go over the limit, you may see an 8K increase -for an otherwise small change. +this compresses the package in page-sizes designed for the device and +filesystem. Since each page is at least 8K, **increments in the compressed size +are always multiples of 8K with the current compression mode**. So, if your +change causes the previous compression page to go over the limit, you may see +an 8K increase for an otherwise small change. Large changes will increase more than a page's work (to at least 16K), which is why we only monitor 12K+ changes (12K isn't possible due to the 8K page size) and not 8K+. +**You are responsible only for pre-compression size increases. If your change +did not cause a pre-compression size increase, but still failed the builder, +please ignore it using the `Fuchsia-Binary-Size:` +[footer](#skipping-the-check).** + ## Running a local binary-size check If you want to check your changes impact to binary size locally (instead of @@ -159,8 +176,8 @@ ``` The size breakdown by blob and package will be given, followed by a summary at -the end, for `chrome_fuchsia`, `web_engine`, and `cast_runner`. The number that is -deployed to the device is the `compressed` version. +the end, for `chrome_fuchsia`, `web_engine`, and `cast_runner`. The number that +is deployed to the device is the `compressed` version. ## How to reduce your binary-size for Fuchsia TODO(crbug.com/1296349): Fill this out. @@ -169,7 +186,8 @@ #### Many new blobs (shamelessly stolen from this -[doc](https://docs.google.com/document/d/1K3fOJJ3rsKA5WtvRCJtuLQSqn7MtOuVUzJA9cFXQYVs/edit#), but looking for any tips on how to improve this for Fuchsia specifically) +[doc](https://docs.google.com/document/d/1K3fOJJ3rsKA5WtvRCJtuLQSqn7MtOuVUzJA9cFXQYVs/edit#), +but looking for any tips on how to improve this for Fuchsia specifically) Look at blobs and see that there aren't a huge number of blobs added in. @@ -180,6 +198,56 @@ - Try searching BUILD files to see if the .so was included from somewhere in particular. +### Bloaty + +[Bloaty](https://github.com/google/bloaty) can be used +to determine the composition of the binary (and can be helpful for determining +the cause of the increase). + +0. (first time only) Install Bloaty using these +[instructions](https://github.com/google/bloaty#install). +1. Build two copies of the packages (see + [above](#running-a-local-binary_size-check)) - + with and without your changes in two separate output directories. +2. Generate Bloaty results. You can run Bloaty against the stripped binaries + (`<out dir>/web_engine_exe` and `<out dir>/cast_runner_exe`). However, if + you want more information, you will have to run it against the unstripped + binaries (located in `<out dir>/exe.unstripped`. You only need to run Bloaty + against the binary your change affected. + +```bash +$ bloaty -d compileunits,symbols $OUT_DIR/exe.unstripped/web_engine_exe \ + -n $ROW_LIMIT -s vm +``` + +`-n $ROW_LIMIT` determines the number of rows to show per level before +collapsing. Setting to `0` shows all rows. Default is 20. + +`-s vm` indicates to sort by Virtual Memory (VM) size increase. This is the +metric that grows somewhat closely to the binary-size bot's size metric. + +**NOTE**: that the sizes reported from Bloaty will not be exactly the same as +those reported by the [`binary_sizes` script](#run-the-size-script) since +Bloaty analyzes the uncompressed (and potentially unstripped) binary, but +the reported relative growth can point you in the right direction. The +`File Size` can vary a lot due to debug symbol information. The `VM Size` is +usually a good lead. + +**If Bloaty reports your change decreased the uncompressed size, use a +[footer](#skipping-the-check) to +ignore the check.** + +You can also directly generate a comparison with the following: + +```bash +$ bloaty -d compileunits,symbols \ + $OUT_DIR_WITH_CHANGE/exe.unstripped/web_engine_exe -n $ROW_LIMIT -s vm -- \ + $OUT_DIR_WITHOUT_CHANGE/exe.unstripped/web_engine_exe +``` + +You can find out more about sections of ELF binaries +[here](https://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/specialsections.html). + ## If All Else Fails - For help, email [chrome-fuchsia-team@google.com]. They're expert @@ -187,8 +255,9 @@ - Not all checks are perfect and sometimes you want to overrule the trybot (for example if you did your best and are unable to reduce binary size any further). -- Adding a “Fuchsia-Binary-Size: $ANY\_TEXT\_HERE” footer to your cl (next to “Bug:”) - will bypass the bot assertions. +- Adding a “Fuchsia-Binary-Size: $ANY\_TEXT\_HERE” + [footer](#skipping-the-check) to your cl (next to “Bug:”) will bypass + the bot assertions. - Most commits that trigger the warnings will also result in Telemetry alerts and be reviewed by a binary size sheriff. Failing to write an adequate justification may lead to the binary size sheriff filing a bug
diff --git a/extensions/browser/api/file_system/file_system_api.cc b/extensions/browser/api/file_system/file_system_api.cc index 032672a..ed5e8fb 100644 --- a/extensions/browser/api/file_system/file_system_api.cc +++ b/extensions/browser/api/file_system/file_system_api.cc
@@ -68,7 +68,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) #include "extensions/browser/api/file_handlers/non_native_file_system_delegate.h" -#endif +#endif // BUILDFLAG(IS_CHROMEOS_ASH) using storage::IsolatedContext; @@ -90,10 +90,10 @@ const char kRetainEntryIncognitoError[] = "Could not retain file entry in incognito mode"; -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) const char kNotSupportedOnNonKioskSessionError[] = "Operation only supported for kiosk apps running in a kiosk session."; -#endif +#endif // BUILDFLAG(IS_CHROMEOS) namespace extensions { @@ -1044,30 +1044,14 @@ return RespondNow(NoArguments()); } -#if !BUILDFLAG(IS_CHROMEOS_ASH) -FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() = +#if BUILDFLAG(IS_CHROMEOS) +/******** FileSystemRequestFileSystemFunction ********/ + +FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction() = default; -ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { - using file_system::RequestFileSystem::Params; - const std::unique_ptr<Params> params(Params::Create(args())); - EXTENSION_FUNCTION_VALIDATE(params); - - NOTIMPLEMENTED(); - return RespondNow(Error(kNotSupportedOnCurrentPlatformError)); -} - -FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() = default; - -ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() { - NOTIMPLEMENTED(); - return RespondNow(Error(kNotSupportedOnCurrentPlatformError)); -} -#else - -FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction() {} - -FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() {} +FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() = + default; ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { using file_system::RequestFileSystem::Params; @@ -1106,9 +1090,11 @@ Respond(Error(error)); } -FileSystemGetVolumeListFunction::FileSystemGetVolumeListFunction() {} +/******** FileSystemGetVolumeListFunction ********/ -FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() {} +FileSystemGetVolumeListFunction::FileSystemGetVolumeListFunction() = default; + +FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() = default; ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() { FileSystemDelegate* delegate = @@ -1136,6 +1122,29 @@ void FileSystemGetVolumeListFunction::OnError(const std::string& error) { Respond(Error(error)); } -#endif +#else // BUILDFLAG(IS_CHROMEOS) +/******** FileSystemRequestFileSystemFunction ********/ + +FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() = + default; + +ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { + using file_system::RequestFileSystem::Params; + const std::unique_ptr<Params> params(Params::Create(args())); + EXTENSION_FUNCTION_VALIDATE(params); + + NOTIMPLEMENTED(); + return RespondNow(Error(kNotSupportedOnCurrentPlatformError)); +} + +/******** FileSystemGetVolumeListFunction ********/ + +FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() = default; + +ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() { + NOTIMPLEMENTED(); + return RespondNow(Error(kNotSupportedOnCurrentPlatformError)); +} +#endif // BUILDFLAG(IS_CHROMEOS) } // namespace extensions
diff --git a/extensions/browser/api/file_system/file_system_api.h b/extensions/browser/api/file_system/file_system_api.h index 5a47260..23a6bb3a 100644 --- a/extensions/browser/api/file_system/file_system_api.h +++ b/extensions/browser/api/file_system/file_system_api.h
@@ -248,34 +248,7 @@ ResponseAction Run() override; }; -#if !BUILDFLAG(IS_CHROMEOS_ASH) -// Stub for non Chrome OS operating systems. -class FileSystemRequestFileSystemFunction : public ExtensionFunction { - public: - DECLARE_EXTENSION_FUNCTION("fileSystem.requestFileSystem", - FILESYSTEM_REQUESTFILESYSTEM) - - protected: - ~FileSystemRequestFileSystemFunction() override; - - // ExtensionFunction overrides. - ExtensionFunction::ResponseAction Run() override; -}; - -// Stub for non Chrome OS operating systems. -class FileSystemGetVolumeListFunction : public ExtensionFunction { - public: - DECLARE_EXTENSION_FUNCTION("fileSystem.getVolumeList", - FILESYSTEM_GETVOLUMELIST) - - protected: - ~FileSystemGetVolumeListFunction() override; - - // ExtensionFunction overrides. - ExtensionFunction::ResponseAction Run() override; -}; - -#else +#if BUILDFLAG(IS_CHROMEOS) // Requests a file system for the specified volume id. class FileSystemRequestFileSystemFunction : public ExtensionFunction { public: @@ -313,7 +286,33 @@ void OnGotVolumeList(const std::vector<api::file_system::Volume>& volumes); void OnError(const std::string& error); }; -#endif +#else // BUILDFLAG(IS_CHROMEOS) +// Stub for non Chrome OS operating systems. +class FileSystemRequestFileSystemFunction : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("fileSystem.requestFileSystem", + FILESYSTEM_REQUESTFILESYSTEM) + + protected: + ~FileSystemRequestFileSystemFunction() override; + + // ExtensionFunction overrides. + ExtensionFunction::ResponseAction Run() override; +}; + +// Stub for non Chrome OS operating systems. +class FileSystemGetVolumeListFunction : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("fileSystem.getVolumeList", + FILESYSTEM_GETVOLUMELIST) + + protected: + ~FileSystemGetVolumeListFunction() override; + + // ExtensionFunction overrides. + ExtensionFunction::ResponseAction Run() override; +}; +#endif // BUILDFLAG(IS_CHROMEOS) } // namespace extensions
diff --git a/extensions/browser/api/file_system/file_system_delegate.h b/extensions/browser/api/file_system/file_system_delegate.h index e56a18b..87d8b17 100644 --- a/extensions/browser/api/file_system/file_system_delegate.h +++ b/extensions/browser/api/file_system/file_system_delegate.h
@@ -10,6 +10,7 @@ #include <vector> #include "base/callback_forward.h" +#include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -18,10 +19,6 @@ class ExtensionFunction; -namespace base { -class FilePath; -} // namespace base - namespace content { class BrowserContext; class WebContents; @@ -77,7 +74,7 @@ // string ID is found. virtual int GetDescriptionIdForAcceptType(const std::string& accept_type) = 0; -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) // Checks whether the extension can be granted access. virtual bool IsGrantable(content::BrowserContext* browser_context, const Extension& extension) = 0; @@ -96,7 +93,7 @@ virtual void GetVolumeList(content::BrowserContext* browser_context, VolumeListCallback success_callback, ErrorCallback error_callback) = 0; -#endif +#endif // BUILDFLAG(IS_CHROMEOS) virtual SavedFilesServiceInterface* GetSavedFilesService( content::BrowserContext* browser_context) = 0;
diff --git a/extensions/browser/api/networking_private/networking_private_chromeos.cc b/extensions/browser/api/networking_private/networking_private_chromeos.cc index c07424a..148b796 100644 --- a/extensions/browser/api/networking_private/networking_private_chromeos.cc +++ b/extensions/browser/api/networking_private/networking_private_chromeos.cc
@@ -40,16 +40,16 @@ #include "third_party/cros_system_api/dbus/service_constants.h" using ::ash::NetworkCertificateHandler; +using ::ash::NetworkHandler; +using ::ash::NetworkStateHandler; using ::ash::NetworkTypePattern; -using chromeos::NetworkHandler; -using chromeos::NetworkStateHandler; using extensions::NetworkingPrivateDelegate; namespace private_api = extensions::api::networking_private; namespace { -chromeos::NetworkStateHandler* GetStateHandler() { +NetworkStateHandler* GetStateHandler() { return NetworkHandler::Get()->network_state_handler(); } @@ -680,7 +680,7 @@ void NetworkingPrivateChromeOS::GetEnabledNetworkTypes( EnabledNetworkTypesCallback callback) { - chromeos::NetworkStateHandler* state_handler = GetStateHandler(); + NetworkStateHandler* state_handler = GetStateHandler(); base::Value network_list(base::Value::Type::LIST);
diff --git a/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc b/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc index b6114f26..9de65c6 100644 --- a/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc +++ b/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc
@@ -135,8 +135,7 @@ void SetUpNetworkPolicy() { ash::ManagedNetworkConfigurationHandler* config_handler = - chromeos::NetworkHandler::Get() - ->managed_network_configuration_handler(); + ash::NetworkHandler::Get()->managed_network_configuration_handler(); const std::string user_policy_ssid = kManagedUserWifiSsid; std::unique_ptr<base::Value> user_policy_onc = @@ -283,7 +282,7 @@ base::Value GetNetworkProperties(const std::string& service_path) { base::RunLoop run_loop; absl::optional<base::Value> properties; - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_configuration_handler() ->GetShillProperties( service_path, @@ -325,7 +324,7 @@ bool GetUserSettingStringData(const std::string& guid, const std::string& key, std::string* value = nullptr) { - const ash::NetworkState* network = chromeos::NetworkHandler::Get() + const ash::NetworkState* network = ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(guid); @@ -381,7 +380,7 @@ EXPECT_EQ(ExtensionFunction::SUCCEEDED, *set_properties->response_type()); const ash::NetworkState* network = - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(kSharedWifiGuid); ASSERT_TRUE(network); @@ -398,7 +397,7 @@ EXPECT_EQ(ExtensionFunction::SUCCEEDED, *set_properties->response_type()); const ash::NetworkState* network = - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(kPrivateWifiGuid); ASSERT_TRUE(network); @@ -547,7 +546,7 @@ ASSERT_TRUE(result->is_string()); std::string guid = result->GetString(); - const ash::NetworkState* network = chromeos::NetworkHandler::Get() + const ash::NetworkState* network = ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(guid); ASSERT_TRUE(network); @@ -574,7 +573,7 @@ // Test the created config can be changed now. std::string guid = result->GetString(); - const ash::NetworkState* network = chromeos::NetworkHandler::Get() + const ash::NetworkState* network = ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(guid); ASSERT_TRUE(network); @@ -895,7 +894,7 @@ ASSERT_TRUE(result->is_string()); std::string guid = result->GetString(); - const ash::NetworkState* network = chromeos::NetworkHandler::Get() + const ash::NetworkState* network = ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(guid); @@ -934,7 +933,7 @@ // Test the created config can be changed now. const std::string guid = result->GetString(); - const ash::NetworkState* network = chromeos::NetworkHandler::Get() + const ash::NetworkState* network = ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(guid); ASSERT_TRUE(network); @@ -1212,7 +1211,7 @@ base::StringPrintf(R"(["%s"])", kManagedUserWifiGuid))); const ash::NetworkState* network = - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(kManagedUserWifiGuid); @@ -1233,7 +1232,7 @@ base::StringPrintf(R"(["%s"])", kManagedUserWifiGuid))); const ash::NetworkState* network = - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(kManagedUserWifiGuid); @@ -1245,7 +1244,7 @@ TEST_F(NetworkingPrivateApiTest, ForgetDevicePolicyNetworkWebUI) { const ash::NetworkState* network = - chromeos::NetworkHandler::Get() + ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(kManagedDeviceWifiGuid); ASSERT_TRUE(network);
diff --git a/extensions/browser/api/networking_private/networking_private_event_router_chromeos.cc b/extensions/browser/api/networking_private/networking_private_event_router_chromeos.cc index fa28f97..57e8182 100644 --- a/extensions/browser/api/networking_private/networking_private_event_router_chromeos.cc +++ b/extensions/browser/api/networking_private/networking_private_event_router_chromeos.cc
@@ -22,9 +22,9 @@ #include "third_party/cros_system_api/dbus/service_constants.h" using ::ash::DeviceState; +using ::ash::NetworkHandler; using ::ash::NetworkState; -using chromeos::NetworkHandler; -using chromeos::NetworkStateHandler; +using ::ash::NetworkStateHandler; namespace extensions {
diff --git a/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc b/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc index 4a0f7b9..2d60fe5 100644 --- a/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc +++ b/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc
@@ -63,6 +63,28 @@ return 0; } +#if BUILDFLAG(IS_CHROMEOS) +bool ShellFileSystemDelegate::IsGrantable( + content::BrowserContext* browser_context, + const Extension& extension) { + return false; +} + +void ShellFileSystemDelegate::RequestFileSystem( + content::BrowserContext* browser_context, + scoped_refptr<ExtensionFunction> requester, + const Extension& extension, + std::string volume_id, + bool writable, + FileSystemCallback success_callback, + ErrorCallback error_callback) {} + +void ShellFileSystemDelegate::GetVolumeList( + content::BrowserContext* browser_context, + VolumeListCallback success_callback, + ErrorCallback error_callback) {} +#endif // BUILDFLAG(IS_CHROMEOS) + SavedFilesServiceInterface* ShellFileSystemDelegate::GetSavedFilesService( content::BrowserContext* browser_context) { return apps::SavedFilesService::Get(browser_context);
diff --git a/extensions/shell/browser/api/file_system/shell_file_system_delegate.h b/extensions/shell/browser/api/file_system/shell_file_system_delegate.h index cc7d61d..a78e62f 100644 --- a/extensions/shell/browser/api/file_system/shell_file_system_delegate.h +++ b/extensions/shell/browser/api/file_system/shell_file_system_delegate.h
@@ -7,6 +7,8 @@ #include "extensions/browser/api/file_system/file_system_delegate.h" +#include "build/build_config.h" + namespace extensions { class ShellFileSystemDelegate : public FileSystemDelegate { @@ -36,6 +38,20 @@ base::OnceClosure on_accept, base::OnceClosure on_cancel) override; int GetDescriptionIdForAcceptType(const std::string& accept_type) override; +#if BUILDFLAG(IS_CHROMEOS) + bool IsGrantable(content::BrowserContext* browser_context, + const Extension& extension) override; + void RequestFileSystem(content::BrowserContext* browser_context, + scoped_refptr<ExtensionFunction> requester, + const Extension& extension, + std::string volume_id, + bool writable, + FileSystemCallback success_callback, + ErrorCallback error_callback) override; + void GetVolumeList(content::BrowserContext* browser_context, + VolumeListCallback success_callback, + ErrorCallback error_callback) override; +#endif // BUILDFLAG(IS_CHROMEOS) SavedFilesServiceInterface* GetSavedFilesService( content::BrowserContext* browser_context) override; };
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc index fa05bba9..b20c3fa 100644 --- a/extensions/shell/browser/shell_browser_main_parts.cc +++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -141,7 +141,7 @@ // Depends on CrosDisksClient. ash::disks::DiskMountManager::Initialize(); - chromeos::NetworkHandler::Initialize(); + ash::NetworkHandler::Initialize(); network_controller_ = std::make_unique<ShellNetworkController>( base::CommandLine::ForCurrentProcess()->GetSwitchValueNative( switches::kAppShellPreferredNetwork)); @@ -306,7 +306,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) network_controller_.reset(); - chromeos::NetworkHandler::Shutdown(); + ash::NetworkHandler::Shutdown(); ash::disks::DiskMountManager::Shutdown(); chromeos::PowerManagerClient::Shutdown(); chromeos::CrosDisksClient::Shutdown();
diff --git a/extensions/shell/browser/shell_network_controller_chromeos.cc b/extensions/shell/browser/shell_network_controller_chromeos.cc index 48c003a..b0aaf15 100644 --- a/extensions/shell/browser/shell_network_controller_chromeos.cc +++ b/extensions/shell/browser/shell_network_controller_chromeos.cc
@@ -42,8 +42,8 @@ // Returns true if shill is either connected or connecting to a network. bool IsConnectedOrConnecting() { - chromeos::NetworkStateHandler* state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler* state_handler = + ash::NetworkHandler::Get()->network_state_handler(); return state_handler->ConnectedNetworkByType( ash::NetworkTypePattern::Default()) || state_handler->ConnectingNetworkByType( @@ -57,8 +57,8 @@ : state_(STATE_IDLE), preferred_network_name_(preferred_network_name), preferred_network_is_active_(false) { - chromeos::NetworkStateHandler* state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler* state_handler = + ash::NetworkHandler::Get()->network_state_handler(); state_handler->AddObserver(this, FROM_HERE); state_handler->SetTechnologyEnabled( ash::NetworkTypePattern::Primitive(shill::kTypeWifi), true, @@ -69,7 +69,7 @@ } ShellNetworkController::~ShellNetworkController() { - chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( + ash::NetworkHandler::Get()->network_state_handler()->RemoveObserver( this, FROM_HERE); } @@ -105,8 +105,8 @@ } void ShellNetworkController::SetCellularAllowRoaming(bool allow_roaming) { - chromeos::NetworkHandler* handler = chromeos::NetworkHandler::Get(); - chromeos::NetworkStateHandler::NetworkStateList network_list; + ash::NetworkHandler* handler = ash::NetworkHandler::Get(); + ash::NetworkStateHandler::NetworkStateList network_list; base::DictionaryValue properties; properties.SetKey(shill::kCellularAllowRoamingProperty, @@ -123,8 +123,8 @@ } const ash::NetworkState* ShellNetworkController::GetActiveWiFiNetwork() { - chromeos::NetworkStateHandler* state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); + ash::NetworkStateHandler* state_handler = + ash::NetworkHandler::Get()->network_state_handler(); const ash::NetworkState* network = state_handler->FirstNetworkByType( ash::NetworkTypePattern::Primitive(shill::kTypeWifi)); return network && @@ -150,7 +150,7 @@ void ShellNetworkController::RequestScan() { VLOG(1) << "Requesting scan"; - chromeos::NetworkHandler::Get()->network_state_handler()->RequestScan( + ash::NetworkHandler::Get()->network_state_handler()->RequestScan( ash::NetworkTypePattern::Default()); } @@ -164,14 +164,13 @@ const ash::NetworkState* best_network = NULL; bool can_connect_to_preferred_network = false; - chromeos::NetworkHandler* handler = chromeos::NetworkHandler::Get(); - chromeos::NetworkStateHandler::NetworkStateList network_list; + ash::NetworkHandler* handler = ash::NetworkHandler::Get(); + ash::NetworkStateHandler::NetworkStateList network_list; handler->network_state_handler()->GetVisibleNetworkListByType( ash::NetworkTypePattern::WiFi(), &network_list); - for (chromeos::NetworkStateHandler::NetworkStateList::const_iterator it = + for (ash::NetworkStateHandler::NetworkStateList::const_iterator it = network_list.begin(); - it != network_list.end(); - ++it) { + it != network_list.end(); ++it) { const ash::NetworkState* network = *it; if (!network->connectable()) continue;
diff --git a/extensions/shell/browser/shell_network_controller_chromeos.h b/extensions/shell/browser/shell_network_controller_chromeos.h index b38ccd1..94c9c843 100644 --- a/extensions/shell/browser/shell_network_controller_chromeos.h +++ b/extensions/shell/browser/shell_network_controller_chromeos.h
@@ -65,7 +65,7 @@ void HandleConnectionSuccess(); void HandleConnectionError(const std::string& error_name); - // Current status of communication with the chromeos::NetworkStateHandler. + // Current status of communication with the ash::NetworkStateHandler. // This is tracked to avoid sending duplicate requests before the handler has // acknowledged the initial connection attempt. State state_;
diff --git a/fuchsia_web/common/test/run_all_integration_tests.cc b/fuchsia_web/common/test/run_all_integration_tests.cc index be4ad2b7..ca7f99e 100644 --- a/fuchsia_web/common/test/run_all_integration_tests.cc +++ b/fuchsia_web/common/test/run_all_integration_tests.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/system/sys_info.h" #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" @@ -21,5 +22,6 @@ return base::LaunchUnitTestsWithOptions( argc, argv, jobs, kDefaultTestBatchLimit, true /* use_job_objects */, + base::DoNothing(), base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite))); }
diff --git a/gin/gin_features.cc b/gin/gin_features.cc index 497ed28..9bfe5163 100644 --- a/gin/gin_features.cc +++ b/gin/gin_features.cc
@@ -131,4 +131,9 @@ const base::Feature kV8SlowHistogramsScriptAblation{ "V8SlowHistogramsScriptAblation", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kV8DelayMemoryReducer{"V8DelayMemoryReducer", + base::FEATURE_DISABLED_BY_DEFAULT}; +const base::FeatureParam<base::TimeDelta> kV8MemoryReducerStartDelay{ + &kV8DelayMemoryReducer, "delay", base::Seconds(8)}; + } // namespace features
diff --git a/gin/gin_features.h b/gin/gin_features.h index 1af22c2..a2a6fd8 100644 --- a/gin/gin_features.h +++ b/gin/gin_features.h
@@ -7,6 +7,7 @@ #include "base/feature_list.h" #include "base/metrics/field_trial_params.h" +#include "base/time/time.h" #include "gin/gin_export.h" namespace features { @@ -47,6 +48,9 @@ GIN_EXPORT extern const base::Feature kV8TurboFastApiCalls; GIN_EXPORT extern const base::Feature kV8Turboprop; GIN_EXPORT extern const base::Feature kV8UseMapSpace; +GIN_EXPORT extern const base::Feature kV8DelayMemoryReducer; +GIN_EXPORT extern const base::FeatureParam<base::TimeDelta> + kV8MemoryReducerStartDelay; } // namespace features
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc index ab2affb..cb3302bb 100644 --- a/gin/v8_initializer.cc +++ b/gin/v8_initializer.cc
@@ -260,6 +260,12 @@ SetV8FlagsIfOverridden(features::kV8OffThreadFinalization, "--finalize-streaming-on-background", "--no-finalize-streaming-on-background"); + if (base::FeatureList::IsEnabled(features::kV8DelayMemoryReducer)) { + SetV8FlagsFormatted( + "--gc-memory-reducer-start-delay-ms=%i", + static_cast<int>( + features::kV8MemoryReducerStartDelay.Get().InMilliseconds())); + } SetV8FlagsIfOverridden(features::kV8LazyFeedbackAllocation, "--lazy-feedback-allocation", "--no-lazy-feedback-allocation");
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 4148b86f..3e5cccc 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -2445,7 +2445,7 @@ &passthrough_discardable_manager_, &shared_image_manager_); surface_ = gl::init::CreateOffscreenGLSurface( - context_creation_attribs_.offscreen_framebuffer_size); + display_, context_creation_attribs_.offscreen_framebuffer_size); context_ = gl::init::CreateGLContext( nullptr, surface_.get(), GenerateGLContextAttribs(context_creation_attribs_, group_.get()));
diff --git a/gpu/command_buffer/service/gr_cache_controller_unittest.cc b/gpu/command_buffer/service/gr_cache_controller_unittest.cc index e8a9b4e..29f489e 100644 --- a/gpu/command_buffer/service/gr_cache_controller_unittest.cc +++ b/gpu/command_buffer/service/gr_cache_controller_unittest.cc
@@ -32,7 +32,7 @@ scoped_refptr<gl::GLShareGroup> share_group = new gl::GLShareGroup(); scoped_refptr<gl::GLSurface> surface = - gl::init::CreateOffscreenGLSurface(gfx::Size()); + gl::init::CreateOffscreenGLSurface(display_, gfx::Size()); scoped_refptr<gl::GLContext> context = gl::init::CreateGLContext( share_group.get(), surface.get(), gl::GLContextAttribs()); ASSERT_TRUE(context->MakeCurrent(surface.get()));
diff --git a/gpu/command_buffer/service/raster_decoder_unittest.cc b/gpu/command_buffer/service/raster_decoder_unittest.cc index 85f0699..dfefb1d1 100644 --- a/gpu/command_buffer/service/raster_decoder_unittest.cc +++ b/gpu/command_buffer/service/raster_decoder_unittest.cc
@@ -203,7 +203,7 @@ scoped_refptr<gl::GLShareGroup> share_group = new gl::GLShareGroup(); scoped_refptr<gl::GLSurface> surface = - gl::init::CreateOffscreenGLSurface(gfx::Size()); + gl::init::CreateOffscreenGLSurface(display_, gfx::Size()); scoped_refptr<gl::GLContext> context = gl::init::CreateGLContext( share_group.get(), surface.get(), gl::GLContextAttribs()); ASSERT_TRUE(context->MakeCurrent(surface.get()));
diff --git a/gpu/command_buffer/service/shared_image/ahardwarebuffer_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/ahardwarebuffer_image_backing_factory_unittest.cc index f6c529e9..642f076 100644 --- a/gpu/command_buffer/service/shared_image/ahardwarebuffer_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/ahardwarebuffer_image_backing_factory_unittest.cc
@@ -34,6 +34,7 @@ #include "ui/gl/gl_gl_api_implementation.h" #include "ui/gl/gl_image.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace gpu { @@ -46,8 +47,8 @@ // should not be run on android versions less that O. if (!base::AndroidHardwareBufferCompat::IsSupportAvailable()) return; - - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplayEGL(), + gfx::Size()); ASSERT_TRUE(surface_); context_ = gl::init::CreateGLContext(nullptr, surface_.get(), gl::GLContextAttribs());
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory_unittest.cc index b1e3e91..c6a1479 100644 --- a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory_unittest.cc
@@ -35,6 +35,7 @@ #include "ui/gl/gl_image_d3d.h" #include "ui/gl/gl_image_memory.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #if BUILDFLAG(USE_DAWN) @@ -135,8 +136,8 @@ void SetUp() override { if (!IsD3DSharedImageSupported()) return; - - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplayEGL(), + gfx::Size()); ASSERT_TRUE(surface_); context_ = gl::init::CreateGLContext(nullptr, surface_.get(), gl::GLContextAttribs());
diff --git a/gpu/command_buffer/service/shared_image/egl_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/egl_image_backing_factory_unittest.cc index b46518b..0bcf29d 100644 --- a/gpu/command_buffer/service/shared_image/egl_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/egl_image_backing_factory_unittest.cc
@@ -41,6 +41,7 @@ #include "ui/gl/gl_image_shared_memory.h" #include "ui/gl/gl_image_stub.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" using testing::AtLeast; @@ -53,7 +54,8 @@ scoped_refptr<gl::GLContext>& context, scoped_refptr<SharedContextState>& context_state, scoped_refptr<gles2::FeatureInfo>& feature_info) { - surface = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplayEGL(), + gfx::Size()); ASSERT_TRUE(surface); context = gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs());
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc index 706b863..50461aec 100644 --- a/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc
@@ -29,6 +29,7 @@ #include "ui/gl/buildflags.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #if BUILDFLAG(USE_DAWN) @@ -65,7 +66,8 @@ // Set up a GL context. We don't actually need it, but we can't make // a SharedContextState without one. - gl_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + gl_surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplayEGL(), + gfx::Size()); DCHECK(gl_surface_); gl_context_ = gl::init::CreateGLContext(nullptr, gl_surface_.get(), gl::GLContextAttribs());
diff --git a/gpu/command_buffer/service/shared_image/gl_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/gl_image_backing_factory_unittest.cc index 8ff5f049..5b0d4292 100644 --- a/gpu/command_buffer/service/shared_image/gl_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/gl_image_backing_factory_unittest.cc
@@ -41,6 +41,7 @@ #include "ui/gl/gl_image_shared_memory.h" #include "ui/gl/gl_image_stub.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #include "ui/gl/progress_reporter.h" @@ -54,7 +55,8 @@ scoped_refptr<gl::GLContext>& context, scoped_refptr<SharedContextState>& context_state, scoped_refptr<gles2::FeatureInfo>& feature_info) { - surface = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface = + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), gfx::Size()); ASSERT_TRUE(surface); context = gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs());
diff --git a/gpu/command_buffer/service/shared_image/gl_texture_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/gl_texture_image_backing_factory_unittest.cc index cb0af15..a8a3a70e 100644 --- a/gpu/command_buffer/service/shared_image/gl_texture_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/gl_texture_image_backing_factory_unittest.cc
@@ -37,6 +37,7 @@ #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/color_space.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #include "ui/gl/progress_reporter.h" @@ -50,7 +51,8 @@ scoped_refptr<gl::GLContext>& context, scoped_refptr<SharedContextState>& context_state, scoped_refptr<gles2::FeatureInfo>& feature_info) { - surface = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface = + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), gfx::Size()); ASSERT_TRUE(surface); context = gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs());
diff --git a/gpu/command_buffer/service/shared_image/iosurface_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/iosurface_image_backing_factory_unittest.cc index 681eba7..0e2a6d23 100644 --- a/gpu/command_buffer/service/shared_image/iosurface_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/iosurface_image_backing_factory_unittest.cc
@@ -29,6 +29,7 @@ #include "ui/gl/buildflags.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #if BUILDFLAG(USE_DAWN) @@ -43,7 +44,8 @@ class IOSurfaceImageBackingFactoryTest : public testing::Test { public: void SetUp() override { - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplayEGL(), + gfx::Size()); ASSERT_TRUE(surface_); context_ = gl::init::CreateGLContext(nullptr, surface_.get(), gl::GLContextAttribs());
diff --git a/gpu/command_buffer/service/shared_image/shared_image_factory_unittest.cc b/gpu/command_buffer/service/shared_image/shared_image_factory_unittest.cc index b4b725a0..1260e474 100644 --- a/gpu/command_buffer/service/shared_image/shared_image_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/shared_image_factory_unittest.cc
@@ -18,7 +18,9 @@ #include "ui/gfx/color_space.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" +#include "ui/gl/gl_display.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace gpu { @@ -27,7 +29,8 @@ class SharedImageFactoryTest : public testing::Test { public: void SetUp() override { - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), + gfx::Size()); ASSERT_TRUE(surface_); context_ = gl::init::CreateGLContext(nullptr, surface_.get(), gl::GLContextAttribs());
diff --git a/gpu/command_buffer/tests/decoder_perftest.cc b/gpu/command_buffer/tests/decoder_perftest.cc index 415188eb..1b297f6 100644 --- a/gpu/command_buffer/tests/decoder_perftest.cc +++ b/gpu/command_buffer/tests/decoder_perftest.cc
@@ -37,6 +37,7 @@ #include "ui/gl/gl_context_stub.h" #include "ui/gl/gl_share_group.h" #include "ui/gl/gl_surface_stub.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace gpu { @@ -171,7 +172,8 @@ gl::GLContextAttribs attribs; if (gpu_preferences_.use_passthrough_cmd_decoder) attribs.bind_generates_resource = bind_generates_resource; - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), + gfx::Size()); context_ = gl::init::CreateGLContext(share_group_.get(), surface_.get(), attribs); }
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc index 15f9ba37..d0e3fde 100644 --- a/gpu/command_buffer/tests/fuzzer_main.cc +++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -46,6 +46,7 @@ #include "ui/gl/gl_surface.h" #include "ui/gl/gl_surface_egl.h" #include "ui/gl/gl_surface_stub.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #include "ui/gl/test/gl_surface_test_support.h" @@ -341,11 +342,12 @@ CHECK(gl::init::InitializeStaticGLBindingsImplementation( gl::GLImplementationParts(gl::kGLImplementationEGLANGLE), false)); - CHECK(gl::init::InitializeGLOneOffPlatformImplementation( + display_ = gl::init::InitializeGLOneOffPlatformImplementation( /*fallback_to_software_gl=*/false, /*disable_gl_drawing=*/false, /*init_extensions=*/true, - /*system_device_id=*/0)); + /*system_device_id=*/0); + CHECK(display_); #elif defined(GPU_FUZZER_USE_STUB) gl::GLSurfaceTestSupport::InitializeOneOffWithStubBindings(); // Because the context depends on configuration bits, we want to recreate @@ -362,12 +364,19 @@ if (gpu_preferences_.use_passthrough_cmd_decoder) recreate_context_ = true; - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(display_, gfx::Size()); if (!recreate_context_) { InitContext(); } } + ~CommandBufferSetup() { + if (display_) { + gl::init::ShutdownGL(display_, false); + display_ = nullptr; + } + } + bool InitDecoder() { if (!context_) { InitContext(); @@ -636,6 +645,7 @@ std::unique_ptr<SharedImageFactory> shared_image_factory_; bool recreate_context_ = false; + gl::GLDisplay* display_ = nullptr; scoped_refptr<gl::GLSurface> surface_; scoped_refptr<gl::GLContext> context_; scoped_refptr<SharedContextState> context_state_;
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc index 4c803c70..9955d71 100644 --- a/gpu/command_buffer/tests/gl_manager.cc +++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -47,6 +47,7 @@ #include "ui/gl/gl_image_ref_counted_memory.h" #include "ui/gl/gl_share_group.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #if BUILDFLAG(IS_MAC) @@ -358,7 +359,8 @@ command_buffer_->set_handler(decoder_.get()); - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), gfx::Size()); ASSERT_TRUE(surface_.get() != nullptr) << "could not create offscreen surface"; @@ -427,7 +429,7 @@ new scoped_refptr<gl::GLShareGroup>(new gl::GLShareGroup); gfx::Size size(4, 4); base_surface_ = new scoped_refptr<gl::GLSurface>( - gl::init::CreateOffscreenGLSurface(size)); + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), size)); base_context_ = new scoped_refptr<gl::GLContext>(gl::init::CreateGLContext( base_share_group_->get(), base_surface_->get(), gl::GLContextAttribs()));
diff --git a/gpu/command_buffer/tests/gl_unittests_android.cc b/gpu/command_buffer/tests/gl_unittests_android.cc index cc6eccb7..6901fc8 100644 --- a/gpu/command_buffer/tests/gl_unittests_android.cc +++ b/gpu/command_buffer/tests/gl_unittests_android.cc
@@ -16,6 +16,7 @@ #include "ui/gfx/native_widget_types.h" #include "ui/gl/android/surface_texture.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace gpu { @@ -40,7 +41,7 @@ EXPECT_TRUE(window != nullptr); scoped_refptr<gl::GLSurface> gl_surface = - gl::init::CreateViewGLSurface(window); + gl::init::CreateViewGLSurface(gl::GetDefaultDisplayEGL(), window); EXPECT_TRUE(gl_surface.get() != nullptr); gl_.SetSurface(gl_surface.get());
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc index aebd98c..d5fb536e 100644 --- a/gpu/config/gpu_info_collector.cc +++ b/gpu/config/gpu_info_collector.cc
@@ -73,9 +73,9 @@ #define EGL_FEATURE_CONDITION_ANGLE 0x3468 #endif /* EGL_ANGLE_feature_control */ -scoped_refptr<gl::GLSurface> InitializeGLSurface() { +scoped_refptr<gl::GLSurface> InitializeGLSurface(gl::GLDisplay* display) { scoped_refptr<gl::GLSurface> surface( - gl::init::CreateOffscreenGLSurface(gfx::Size())); + gl::init::CreateOffscreenGLSurface(display, gfx::Size())); if (!surface.get()) { LOG(ERROR) << "gl::GLContext::CreateOffscreenGLSurface failed"; return nullptr; @@ -334,7 +334,7 @@ return CollectBasicGraphicsInfo(gpu_info); } -bool CollectGraphicsInfoGL(GPUInfo* gpu_info) { +bool CollectGraphicsInfoGL(GPUInfo* gpu_info, gl::GLDisplay* display) { TRACE_EVENT0("startup", "gpu_info_collector::CollectGraphicsInfoGL"); DCHECK_NE(gl::GetGLImplementation(), gl::kGLImplementationNone); @@ -343,7 +343,7 @@ gpu_info->passthrough_cmd_decoder = false; } - scoped_refptr<gl::GLSurface> surface(InitializeGLSurface()); + scoped_refptr<gl::GLSurface> surface(InitializeGLSurface(display)); if (!surface.get()) { LOG(ERROR) << "Could not create surface for info collection."; return false; @@ -386,11 +386,11 @@ base::UmaHistogramSparse("GPU.MaxMSAASampleCount", max_samples); #if BUILDFLAG(IS_ANDROID) - gl::GLDisplayEGL* display = gl::GLSurfaceEGL::GetGLDisplayEGL(); + gl::GLDisplayEGL* egl_display = display->GetAs<gl::GLDisplayEGL>(); gpu_info->can_support_threaded_texture_mailbox = - display->ext->b_EGL_KHR_fence_sync && - display->ext->b_EGL_KHR_image_base && - display->ext->b_EGL_KHR_gl_texture_2D_image && + egl_display->ext->b_EGL_KHR_fence_sync && + egl_display->ext->b_EGL_KHR_image_base && + egl_display->ext->b_EGL_KHR_gl_texture_2D_image && gfx::HasExtension(extension_set, "GL_OES_EGL_image"); #else gl::GLWindowSystemBindingInfo window_system_binding_info;
diff --git a/gpu/config/gpu_info_collector.h b/gpu/config/gpu_info_collector.h index a589192..a0152aa 100644 --- a/gpu/config/gpu_info_collector.h +++ b/gpu/config/gpu_info_collector.h
@@ -17,6 +17,10 @@ #include <d3dcommon.h> #endif // BUILDFLAG(IS_WIN) +namespace gl { +class GLDisplay; +} + namespace angle { struct SystemInfo; } @@ -70,7 +74,8 @@ #endif // BUILDFLAG(IS_WIN) // Create a GL context and collect GL strings and versions. -GPU_EXPORT bool CollectGraphicsInfoGL(GPUInfo* gpu_info); +GPU_EXPORT bool CollectGraphicsInfoGL(GPUInfo* gpu_info, + gl::GLDisplay* display); // If more than one GPUs are identified, and GL strings are available, // identify the active GPU based on GL strings.
diff --git a/gpu/config/gpu_info_collector_android.cc b/gpu/config/gpu_info_collector_android.cc index e529df6..20914857 100644 --- a/gpu/config/gpu_info_collector_android.cc +++ b/gpu/config/gpu_info_collector_android.cc
@@ -9,6 +9,8 @@ #include "base/android/build_info.h" #include "base/android/jni_android.h" #include "base/notreached.h" +#include "ui/gl/gl_display.h" +#include "ui/gl/gl_utils.h" namespace gpu { @@ -21,7 +23,7 @@ } // At this point GL bindings have been initialized already. - return CollectGraphicsInfoGL(gpu_info); + return CollectGraphicsInfoGL(gpu_info, gl::GetDefaultDisplayEGL()); } bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
diff --git a/gpu/config/gpu_info_collector_fuchsia.cc b/gpu/config/gpu_info_collector_fuchsia.cc index 1065114..9df5affd9 100644 --- a/gpu/config/gpu_info_collector_fuchsia.cc +++ b/gpu/config/gpu_info_collector_fuchsia.cc
@@ -6,6 +6,8 @@ #include "base/trace_event/trace_event.h" #include "third_party/angle/src/gpu_info_util/SystemInfo.h" +#include "ui/gl/gl_display.h" +#include "ui/gl/gl_utils.h" namespace gpu { @@ -14,7 +16,7 @@ TRACE_EVENT0("gpu", "gpu_info_collector::CollectGraphicsInfo"); - return CollectGraphicsInfoGL(gpu_info); + return CollectGraphicsInfoGL(gpu_info, gl::GetDefaultDisplay()); } bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
diff --git a/gpu/config/gpu_info_collector_linux.cc b/gpu/config/gpu_info_collector_linux.cc index faab718..a8aa560 100644 --- a/gpu/config/gpu_info_collector_linux.cc +++ b/gpu/config/gpu_info_collector_linux.cc
@@ -7,6 +7,8 @@ #include "build/chromecast_buildflags.h" #include "gpu/config/gpu_info_collector.h" #include "third_party/angle/src/gpu_info_util/SystemInfo.h" +#include "ui/gl/gl_display.h" +#include "ui/gl/gl_utils.h" namespace gpu { @@ -22,7 +24,7 @@ gpu_info->machine_model_name = "Chromecast"; #endif // BUILDFLAG(IS_CASTOS) - return CollectGraphicsInfoGL(gpu_info); + return CollectGraphicsInfoGL(gpu_info, gl::GetDefaultDisplay()); } bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
diff --git a/gpu/config/gpu_info_collector_mac.mm b/gpu/config/gpu_info_collector_mac.mm index 2fe78e2..57f8d8fc 100644 --- a/gpu/config/gpu_info_collector_mac.mm +++ b/gpu/config/gpu_info_collector_mac.mm
@@ -9,6 +9,8 @@ #include "base/trace_event/trace_event.h" #include "gpu/command_buffer/common/gpu_memory_buffer_support.h" #include "third_party/angle/src/gpu_info_util/SystemInfo.h" +#include "ui/gl/gl_display.h" +#include "ui/gl/gl_utils.h" #import <Metal/Metal.h> @@ -72,7 +74,7 @@ RecordReadWriteMetalTexturesSupportedHistogram(); - return CollectGraphicsInfoGL(gpu_info); + return CollectGraphicsInfoGL(gpu_info, gl::GetDefaultDisplayEGL()); } bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
diff --git a/gpu/config/gpu_info_collector_unittest.cc b/gpu/config/gpu_info_collector_unittest.cc index 760337e..92c3a8cc 100644 --- a/gpu/config/gpu_info_collector_unittest.cc +++ b/gpu/config/gpu_info_collector_unittest.cc
@@ -18,9 +18,11 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_context_stub.h" +#include "ui/gl/gl_display.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_mock.h" #include "ui/gl/gl_surface_stub.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" #include "ui/gl/test/gl_surface_test_support.h" @@ -216,7 +218,7 @@ // be fixed. TEST_P(GPUInfoCollectorTest, CollectGraphicsInfoGL) { GPUInfo gpu_info; - CollectGraphicsInfoGL(&gpu_info); + CollectGraphicsInfoGL(&gpu_info, gl::GetDefaultDisplay()); #if BUILDFLAG(IS_WIN) if (GetParam() == kMockedWindows) { EXPECT_EQ(test_values_.gpu.driver_vendor, gpu_info.gpu.driver_vendor);
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc index 5cb016e..2d247df 100644 --- a/gpu/config/gpu_info_collector_win.cc +++ b/gpu/config/gpu_info_collector_win.cc
@@ -37,7 +37,9 @@ #include "gpu/config/gpu_util.h" #include "ui/gl/direct_composition_support.h" #include "ui/gl/gl_angle_util_win.h" +#include "ui/gl/gl_display.h" #include "ui/gl/gl_surface_egl.h" +#include "ui/gl/gl_utils.h" namespace gpu { @@ -721,7 +723,7 @@ DCHECK(gpu_info); - if (!CollectGraphicsInfoGL(gpu_info)) + if (!CollectGraphicsInfoGL(gpu_info, gl::GetDefaultDisplayEGL())) return false; // ANGLE's renderer strings are of the form:
diff --git a/gpu/dawn_end2end_tests_main.cc b/gpu/dawn_end2end_tests_main.cc index 9df1925..c7721af 100644 --- a/gpu/dawn_end2end_tests_main.cc +++ b/gpu/dawn_end2end_tests_main.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/command_line.h" #include "base/task/single_thread_task_executor.h" #include "base/test/launcher/unit_test_launcher.h" @@ -34,9 +35,10 @@ base::TestSuite test_suite(argc, argv); int rt = base::LaunchUnitTestsWithOptions( argc, argv, - 1, // Run tests serially. - 0, // Disable batching. - true, // Use job objects. + 1, // Run tests serially. + 0, // Disable batching. + true, // Use job objects. + base::DoNothing(), // No special action on timeout. base::BindOnce(&RunHelper, base::Unretained(&test_suite))); return rt; }
diff --git a/gpu/gles2_conform_support/egl/display.cc b/gpu/gles2_conform_support/egl/display.cc index 6ff47fc..affff0a 100644 --- a/gpu/gles2_conform_support/egl/display.cc +++ b/gpu/gles2_conform_support/egl/display.cc
@@ -11,6 +11,8 @@ #include "gpu/gles2_conform_support/egl/context.h" #include "gpu/gles2_conform_support/egl/surface.h" #include "gpu/gles2_conform_support/egl/thread_state.h" +#include "ui/gl/gl_display.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace gles2_conform_support { @@ -20,8 +22,7 @@ : is_initialized_(false), next_create_window_surface_creates_pbuffer_(false), window_surface_pbuffer_width_(0), - window_surface_pbuffer_height_(0) { -} + window_surface_pbuffer_height_(0) {} Display::~Display() { surfaces_.clear(); @@ -183,7 +184,8 @@ EGLint height) { lock_.AssertAcquired(); scoped_refptr<gl::GLSurface> gl_surface; - gl_surface = gl::init::CreateOffscreenGLSurface(gfx::Size(width, height)); + gl_surface = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), + gfx::Size(width, height)); if (!gl_surface) return ts->ReturnError(EGL_BAD_ALLOC, nullptr); surfaces_.emplace_back(new Surface(gl_surface.get(), config)); @@ -223,7 +225,7 @@ #else gfx::AcceleratedWidget widget = static_cast<gfx::AcceleratedWidget>(win); #endif - gl_surface = gl::init::CreateViewGLSurface(widget); + gl_surface = gl::init::CreateViewGLSurface(gl::GetDefaultDisplay(), widget); if (!gl_surface) return ts->ReturnError(EGL_BAD_ALLOC, EGL_NO_SURFACE); surfaces_.emplace_back(new Surface(gl_surface.get(), config));
diff --git a/gpu/gles2_conform_support/egl/display.h b/gpu/gles2_conform_support/egl/display.h index 93602ea..322908d1 100644 --- a/gpu/gles2_conform_support/egl/display.h +++ b/gpu/gles2_conform_support/egl/display.h
@@ -15,8 +15,7 @@ #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" -namespace gles2_conform_support { -namespace egl { +namespace gles2_conform_support::egl { class Config; class Context; @@ -105,7 +104,6 @@ EGLint window_surface_pbuffer_height_; }; -} // namespace egl -} // namespace gles2_conform_support +} // namespace gles2_conform_support::egl #endif // GPU_GLES2_CONFORM_SUPPORT_EGL_DISPLAY_H_
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc index b74e7f2..e4d74b4 100644 --- a/gpu/ipc/in_process_command_buffer.cc +++ b/gpu/ipc/in_process_command_buffer.cc
@@ -64,6 +64,8 @@ #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_share_group.h" +#include "ui/gl/gl_surface_egl.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/gl_version_info.h" #include "ui/gl/init/create_gr_gl_interface.h" #include "ui/gl/init/gl_factory.h" @@ -286,7 +288,8 @@ } else { // TODO(crbug.com/1247756): Is creating an offscreen GL surface needed // still? - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), + gfx::Size()); if (!surface_.get()) { DestroyOnGpuThread(); LOG(ERROR) << "ContextResult::kFatalFailure: Failed to create surface.";
diff --git a/gpu/ipc/in_process_gpu_thread_holder.cc b/gpu/ipc/in_process_gpu_thread_holder.cc index 02167032..ab4e5f0 100644 --- a/gpu/ipc/in_process_gpu_thread_holder.cc +++ b/gpu/ipc/in_process_gpu_thread_holder.cc
@@ -17,6 +17,7 @@ #include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/config/gpu_info_collector.h" #include "gpu/config/gpu_util.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace gpu { @@ -78,7 +79,8 @@ gles2::PassthroughCommandDecoderSupported(); share_group_ = new gl::GLShareGroup(); - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), gfx::Size()); gl::GLContextAttribs attribs = gles2::GenerateGLContextAttribs( ContextCreationAttribs(), use_passthrough_cmd_decoder); context_ =
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.cc b/gpu/ipc/service/gles2_command_buffer_stub.cc index ac6e3f5..5c01966 100644 --- a/gpu/ipc/service/gles2_command_buffer_stub.cc +++ b/gpu/ipc/service/gles2_command_buffer_stub.cc
@@ -46,7 +46,9 @@ #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_egl.h" #include "ui/gl/gl_switches.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/gl_workarounds.h" #include "ui/gl/init/gl_factory.h" @@ -169,6 +171,26 @@ channel_->sync_point_manager()->CreateSyncPointClientState( CommandBufferNamespace::GPU_IO, command_buffer_id_, sequence_id_); + gl::GpuPreference gpu_preference = init_params.attribs.gpu_preference; + // If the user queries a low-power context, it's better to use whatever the + // default GPU used by Chrome is, which may be different than the low-power + // GPU determined by GLDisplayManager. + if (gpu_preference == gl::GpuPreference::kLowPower || + gpu_preference == gl::GpuPreference::kNone) { + gpu_preference = gl::GpuPreference::kDefault; + } + gl::GLDisplay* display = gl::GetDisplay(gpu_preference); + DCHECK(display); + + if (!display->IsInitialized()) { + gl::GLDisplay* initialized_display = + gl::init::InitializeGLOneOffPlatformImplementation( + /*fallback_to_software_gl=*/false, /*disable_gl_drawing=*/false, + /*init_extensions=*/true, + /*system_device_id=*/display->system_device_id()); + DCHECK_EQ(initialized_display, display); + } + if (offscreen) { // Do we want to create an offscreen rendering context suitable // for directly drawing to a separately supplied surface? In that @@ -196,8 +218,8 @@ if (!surface_format.IsCompatible(default_surface->GetFormat())) { DVLOG(1) << __FUNCTION__ << ": Hit the OwnOffscreenSurface path"; use_virtualized_gl_context_ = false; - surface_ = gl::init::CreateOffscreenGLSurfaceWithFormat(gfx::Size(), - surface_format); + surface_ = gl::init::CreateOffscreenGLSurfaceWithFormat( + display, gfx::Size(), surface_format); if (!surface_) { LOG(ERROR) << "ContextResult::kSurfaceFailure: Failed to create surface."; @@ -221,7 +243,8 @@ break; } surface_ = ImageTransportSurface::CreateNativeSurface( - weak_ptr_factory_.GetWeakPtr(), surface_handle_, surface_format); + display, weak_ptr_factory_.GetWeakPtr(), surface_handle_, + surface_format); if (!surface_ || !surface_->Initialize(surface_format)) { surface_ = nullptr; LOG(ERROR) << "ContextResult::kSurfaceFailure: Failed to create surface.";
diff --git a/gpu/ipc/service/gpu_channel_test_common.cc b/gpu/ipc/service/gpu_channel_test_common.cc index c6fc68c..c26e6e97 100644 --- a/gpu/ipc/service/gpu_channel_test_common.cc +++ b/gpu/ipc/service/gpu_channel_test_common.cc
@@ -102,7 +102,7 @@ sync_point_manager_.get(), shared_image_manager_.get(), nullptr, /* gpu_memory_buffer_factory */ std::move(feature_info), GpuProcessActivityFlags(), - gl::init::CreateOffscreenGLSurface(gfx::Size()), + gl::init::CreateOffscreenGLSurface(display_, gfx::Size()), nullptr /* image_decode_accelerator_worker */); }
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc index ad88e08..7636024 100644 --- a/gpu/ipc/service/gpu_init.cc +++ b/gpu/ipc/service/gpu_init.cc
@@ -246,7 +246,7 @@ // supported. gl::SetGpuPreferenceEGL(gl::GpuPreference::kDefault, system_device_id_default); - if (system_device_id_high_perf) { + if (system_device_id_high_perf && features::SupportsEGLDualGpuRendering()) { gl::SetGpuPreferenceEGL(gl::GpuPreference::kHighPerformance, system_device_id_high_perf); } @@ -664,7 +664,7 @@ return false; } default_offscreen_surface_ = - gl::init::CreateOffscreenGLSurface(gfx::Size()); + gl::init::CreateOffscreenGLSurface(gl_display, gfx::Size()); if (!default_offscreen_surface_) { VLOG(1) << "gl::init::CreateOffscreenGLSurface failed"; return false; @@ -784,8 +784,8 @@ command_line, gpu_feature_info_, gpu_preferences_.disable_software_rasterizer, false)); - InitializeGLThreadSafe(command_line, gpu_preferences_, &gpu_info_, - &gpu_feature_info_); + gl::GLDisplay* gl_display = InitializeGLThreadSafe( + command_line, gpu_preferences_, &gpu_info_, &gpu_feature_info_); if (command_line->HasSwitch(switches::kWebViewDrawFunctorUsesVulkan) && base::FeatureList::IsEnabled(features::kWebViewVulkan)) { @@ -795,7 +795,9 @@ } else { DisableInProcessGpuVulkan(&gpu_feature_info_, &gpu_preferences_); } - default_offscreen_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + + default_offscreen_surface_ = + gl::init::CreateOffscreenGLSurface(gl_display, gfx::Size()); UMA_HISTOGRAM_ENUMERATION("GPU.GLImplementation", gl::GetGLImplementation()); } @@ -899,7 +901,7 @@ VLOG(1) << "gl::init::InitializeExtensionSettingsOneOffPlatform failed"; } default_offscreen_surface_ = - gl::init::CreateOffscreenGLSurface(gfx::Size()); + gl::init::CreateOffscreenGLSurface(gl_display, gfx::Size()); if (!default_offscreen_surface_) { VLOG(1) << "gl::init::CreateOffscreenGLSurface failed"; }
diff --git a/gpu/ipc/service/image_transport_surface.h b/gpu/ipc/service/image_transport_surface.h index a978a061..17adff55 100644 --- a/gpu/ipc/service/image_transport_surface.h +++ b/gpu/ipc/service/image_transport_surface.h
@@ -28,6 +28,7 @@ // This will be implemented separately by each platform. On failure, a null // scoped_refptr should be returned. static scoped_refptr<gl::GLSurface> CreateNativeSurface( + gl::GLDisplay* display, base::WeakPtr<ImageTransportSurfaceDelegate> stub, SurfaceHandle surface_handle, gl::GLSurfaceFormat format);
diff --git a/gpu/ipc/service/image_transport_surface_android.cc b/gpu/ipc/service/image_transport_surface_android.cc index e49b821..a475b18 100644 --- a/gpu/ipc/service/image_transport_surface_android.cc +++ b/gpu/ipc/service/image_transport_surface_android.cc
@@ -19,6 +19,7 @@ // static scoped_refptr<gl::GLSurface> ImageTransportSurface::CreateNativeSurface( + gl::GLDisplay* display, base::WeakPtr<ImageTransportSurfaceDelegate> delegate, SurfaceHandle surface_handle, gl::GLSurfaceFormat format) { @@ -42,11 +43,11 @@ delegate->GetFeatureInfo()->feature_flags().android_surface_control && can_be_used_with_surface_control) { surface = new gl::GLSurfaceEGLSurfaceControl( - gl::GLSurfaceEGL::GetGLDisplayEGL(), window, + display->GetAs<gl::GLDisplayEGL>(), window, base::ThreadTaskRunnerHandle::Get()); } else { - surface = new gl::NativeViewGLSurfaceEGL( - gl::GLSurfaceEGL::GetGLDisplayEGL(), window, nullptr); + surface = new gl::NativeViewGLSurfaceEGL(display->GetAs<gl::GLDisplayEGL>(), + window, nullptr); } bool initialize_success = surface->Initialize(format);
diff --git a/gpu/ipc/service/image_transport_surface_fuchsia.cc b/gpu/ipc/service/image_transport_surface_fuchsia.cc index 8103537..9238bcb 100644 --- a/gpu/ipc/service/image_transport_surface_fuchsia.cc +++ b/gpu/ipc/service/image_transport_surface_fuchsia.cc
@@ -13,6 +13,7 @@ // static scoped_refptr<gl::GLSurface> ImageTransportSurface::CreateNativeSurface( + gl::GLDisplay* display, base::WeakPtr<ImageTransportSurfaceDelegate> delegate, SurfaceHandle surface_handle, gl::GLSurfaceFormat format) { @@ -22,7 +23,7 @@ } scoped_refptr<gl::GLSurface> surface = - gl::init::CreateViewGLSurface(surface_handle); + gl::init::CreateViewGLSurface(display, surface_handle); if (!surface) return surface;
diff --git a/gpu/ipc/service/image_transport_surface_linux.cc b/gpu/ipc/service/image_transport_surface_linux.cc index 05ce217a..29a93f3 100644 --- a/gpu/ipc/service/image_transport_surface_linux.cc +++ b/gpu/ipc/service/image_transport_surface_linux.cc
@@ -11,6 +11,7 @@ // static scoped_refptr<gl::GLSurface> ImageTransportSurface::CreateNativeSurface( + gl::GLDisplay* display, base::WeakPtr<ImageTransportSurfaceDelegate> delegate, SurfaceHandle surface_handle, gl::GLSurfaceFormat format) { @@ -18,10 +19,10 @@ scoped_refptr<gl::GLSurface> surface; bool override_vsync_for_multi_window_swap = false; #if defined(USE_OZONE) - surface = gl::init::CreateSurfacelessViewGLSurface(surface_handle); + surface = gl::init::CreateSurfacelessViewGLSurface(display, surface_handle); #endif if (!surface) { - surface = gl::init::CreateViewGLSurface(surface_handle); + surface = gl::init::CreateViewGLSurface(display, surface_handle); if (gl::GetGLImplementation() == gl::kGLImplementationDesktopGL || gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE) { override_vsync_for_multi_window_swap = true;
diff --git a/gpu/ipc/service/image_transport_surface_mac.mm b/gpu/ipc/service/image_transport_surface_mac.mm index 1071b3b..068eb98 100644 --- a/gpu/ipc/service/image_transport_surface_mac.mm +++ b/gpu/ipc/service/image_transport_surface_mac.mm
@@ -15,6 +15,7 @@ // static scoped_refptr<gl::GLSurface> ImageTransportSurface::CreateNativeSurface( + gl::GLDisplay* display, base::WeakPtr<ImageTransportSurfaceDelegate> delegate, SurfaceHandle surface_handle, gl::GLSurfaceFormat format) { @@ -30,7 +31,7 @@ case gl::kGLImplementationEGLANGLE: return base::WrapRefCounted<gl::GLSurface>( new ImageTransportSurfaceOverlayMacEGL( - gl::GLSurfaceEGL::GetGLDisplayEGL(), delegate)); + display->GetAs<gl::GLDisplayEGL>(), delegate)); #endif case gl::kGLImplementationMockGL: case gl::kGLImplementationStubGL:
diff --git a/gpu/ipc/service/image_transport_surface_win.cc b/gpu/ipc/service/image_transport_surface_win.cc index d8f9e42..f5f93c9a 100644 --- a/gpu/ipc/service/image_transport_surface_win.cc +++ b/gpu/ipc/service/image_transport_surface_win.cc
@@ -45,6 +45,7 @@ // static scoped_refptr<gl::GLSurface> ImageTransportSurface::CreateNativeSurface( + gl::GLDisplay* display, base::WeakPtr<ImageTransportSurfaceDelegate> delegate, SurfaceHandle surface_handle, gl::GLSurfaceFormat format) { @@ -57,7 +58,7 @@ auto settings = CreateDirectCompositionSurfaceSettings( delegate->GetFeatureInfo()->workarounds()); auto dc_surface = base::MakeRefCounted<gl::DirectCompositionSurfaceWin>( - gl::GLSurfaceEGL::GetGLDisplayEGL(), surface_handle, + display->GetAs<gl::GLDisplayEGL>(), surface_handle, std::move(vsync_callback), settings); if (!dc_surface->Initialize(gl::GLSurfaceFormat())) return nullptr; @@ -67,13 +68,13 @@ } else { surface = gl::InitializeGLSurface( base::MakeRefCounted<gl::NativeViewGLSurfaceEGL>( - gl::GLSurfaceEGL::GetGLDisplayEGL(), surface_handle, + display->GetAs<gl::GLDisplayEGL>(), surface_handle, std::make_unique<gl::VSyncProviderWin>(surface_handle))); if (!surface) return nullptr; } } else { - surface = gl::init::CreateViewGLSurface(surface_handle); + surface = gl::init::CreateViewGLSurface(display, surface_handle); if (!surface) return nullptr; }
diff --git a/gpu/perftests/texture_upload_perftest.cc b/gpu/perftests/texture_upload_perftest.cc index e472b1d..9fc9aff 100644 --- a/gpu/perftests/texture_upload_perftest.cc +++ b/gpu/perftests/texture_upload_perftest.cc
@@ -23,6 +23,7 @@ #include "ui/gl/gl_context.h" #include "ui/gl/gl_enums.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/gl_version_info.h" #include "ui/gl/gpu_timing.h" #include "ui/gl/init/gl_factory.h" @@ -179,7 +180,8 @@ // Overridden from testing::Test void SetUp() override { // Initialize an offscreen surface and a gl context. - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), + gfx::Size()); gl_context_ = gl::init::CreateGLContext(nullptr, // share_group surface_.get(), gl::GLContextAttribs());
diff --git a/gpu/swiftshader_tests_main.cc b/gpu/swiftshader_tests_main.cc index 3198197..8af170d9 100644 --- a/gpu/swiftshader_tests_main.cc +++ b/gpu/swiftshader_tests_main.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/command_line.h" #include "base/task/single_thread_task_executor.h" #include "base/test/launcher/unit_test_launcher.h" @@ -32,9 +33,10 @@ base::TestSuite test_suite(argc, argv); int rt = base::LaunchUnitTestsWithOptions( argc, argv, - 1, // Run tests serially. - 0, // Disable batching. - true, // Use job objects. + 1, // Run tests serially. + 0, // Disable batching. + true, // Use job objects. + base::DoNothing(), // No special action on test timeout. base::BindOnce(&RunHelper, base::Unretained(&test_suite))); return rt; }
diff --git a/infra/config/generated/builders/ci/win32-updater-builder-dbg/properties.json b/infra/config/generated/builders/ci/win32-updater-builder-dbg/properties.json index 78c43f5..ef2b07a 100644 --- a/infra/config/generated/builders/ci/win32-updater-builder-dbg/properties.json +++ b/infra/config/generated/builders/ci/win32-updater-builder-dbg/properties.json
@@ -1,4 +1,42 @@ { + "$build/chromium_tests_builder_config": { + "builder_config": { + "builder_db": { + "entries": [ + { + "builder_id": { + "bucket": "ci", + "builder": "win32-updater-builder-dbg", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.updater", + "execution_mode": "COMPILE_AND_TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "build_config": "Release", + "config": "chromium", + "target_bits": 64, + "target_platform": "win" + }, + "legacy_gclient_config": { + "config": "chromium" + } + } + } + ] + }, + "builder_ids": [ + { + "bucket": "ci", + "builder": "win32-updater-builder-dbg", + "project": "chromium" + } + ] + } + }, "$build/reclient": { "instance": "rbe-chromium-trusted", "jobs": 80,
diff --git a/infra/config/generated/builders/ci/win32-updater-builder-rel/properties.json b/infra/config/generated/builders/ci/win32-updater-builder-rel/properties.json index 78c43f5..328ea7f6 100644 --- a/infra/config/generated/builders/ci/win32-updater-builder-rel/properties.json +++ b/infra/config/generated/builders/ci/win32-updater-builder-rel/properties.json
@@ -1,4 +1,77 @@ { + "$build/chromium_tests_builder_config": { + "builder_config": { + "builder_db": { + "entries": [ + { + "builder_id": { + "bucket": "ci", + "builder": "win32-updater-builder-rel", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.updater", + "execution_mode": "COMPILE_AND_TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "build_config": "Release", + "config": "chromium", + "target_bits": 64, + "target_platform": "win" + }, + "legacy_gclient_config": { + "config": "chromium" + } + } + }, + { + "builder_id": { + "bucket": "ci", + "builder": "win7(32)-updater-tester-rel", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.updater", + "execution_mode": "TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "build_config": "Release", + "config": "chromium", + "target_bits": 64, + "target_platform": "win" + }, + "legacy_gclient_config": { + "config": "chromium" + }, + "parent": { + "bucket": "ci", + "builder": "win32-updater-builder-rel", + "project": "chromium" + } + } + } + ] + }, + "builder_ids": [ + { + "bucket": "ci", + "builder": "win32-updater-builder-rel", + "project": "chromium" + } + ], + "builder_ids_in_scope_for_testing": [ + { + "bucket": "ci", + "builder": "win7(32)-updater-tester-rel", + "project": "chromium" + } + ] + } + }, "$build/reclient": { "instance": "rbe-chromium-trusted", "jobs": 80,
diff --git "a/infra/config/generated/builders/ci/win7\05032\051-updater-tester-rel/properties.json" "b/infra/config/generated/builders/ci/win7\05032\051-updater-tester-rel/properties.json" index 0d6f98c..ab01470 100644 --- "a/infra/config/generated/builders/ci/win7\05032\051-updater-tester-rel/properties.json" +++ "b/infra/config/generated/builders/ci/win7\05032\051-updater-tester-rel/properties.json"
@@ -1,4 +1,70 @@ { + "$build/chromium_tests_builder_config": { + "builder_config": { + "builder_db": { + "entries": [ + { + "builder_id": { + "bucket": "ci", + "builder": "win32-updater-builder-rel", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.updater", + "execution_mode": "COMPILE_AND_TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "build_config": "Release", + "config": "chromium", + "target_bits": 64, + "target_platform": "win" + }, + "legacy_gclient_config": { + "config": "chromium" + } + } + }, + { + "builder_id": { + "bucket": "ci", + "builder": "win7(32)-updater-tester-rel", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.updater", + "execution_mode": "TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "build_config": "Release", + "config": "chromium", + "target_bits": 64, + "target_platform": "win" + }, + "legacy_gclient_config": { + "config": "chromium" + }, + "parent": { + "bucket": "ci", + "builder": "win32-updater-builder-rel", + "project": "chromium" + } + } + } + ] + }, + "builder_ids": [ + { + "bucket": "ci", + "builder": "win7(32)-updater-tester-rel", + "project": "chromium" + } + ] + } + }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [], "grouping_keys": [
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md index 1db1c55..f50fff7 100644 --- a/infra/config/generated/cq-builders.md +++ b/infra/config/generated/cq-builders.md
@@ -498,7 +498,7 @@ * Experiment percentage: 3.0 * [fuchsia-binary-size](https://ci.chromium.org/p/chromium/builders/try/fuchsia-binary-size) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""fuchsia-binary-size"")) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+""fuchsia-binary-size"")) - * Experiment percentage: 50.0 + * Experiment percentage: 75.0 * [linux-1mbu-compile-fyi-rel](https://ci.chromium.org/p/chromium/builders/try/linux-1mbu-compile-fyi-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""linux-1mbu-compile-fyi-rel"")) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+""linux-1mbu-compile-fyi-rel"")) * Experiment percentage: 5.0
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg index d49c8a9..f6c494d 100644 --- a/infra/config/generated/luci/commit-queue.cfg +++ b/infra/config/generated/luci/commit-queue.cfg
@@ -1871,7 +1871,7 @@ } builders { name: "chromium/try/fuchsia-binary-size" - experiment_percentage: 50 + experiment_percentage: 75 location_regexp: ".*" location_regexp_exclude: ".+/[+]/docs/.+" location_regexp_exclude: ".+/[+]/infra/config/.+"
diff --git a/infra/config/generated/luci/project.cfg b/infra/config/generated/luci/project.cfg index 4c731471..c23bdfa 100644 --- a/infra/config/generated/luci/project.cfg +++ b/infra/config/generated/luci/project.cfg
@@ -7,7 +7,7 @@ name: "chromium" access: "group:all" lucicfg { - version: "1.31.5" + version: "1.32.1" package_dir: "../.." config_dir: "generated/luci" entry_point: "main.star"
diff --git a/infra/config/lib/builders.star b/infra/config/lib/builders.star index 0c1bee7..cc387dc 100644 --- a/infra/config/lib/builders.star +++ b/infra/config/lib/builders.star
@@ -189,6 +189,8 @@ x14main = xcode_enum("14a5284g"), # A newer Xcode 14 version used on beta bots. x14betabots = xcode_enum("14a5284g"), + # Xcode14 beta 5 used on beta bots. + x14beta5bots = xcode_enum("14a5294e"), # in use by ios-webkit-tot x13wk = xcode_enum("13a1030dwk"), )
diff --git a/infra/config/subprojects/chromium/ci/chromium.updater.star b/infra/config/subprojects/chromium/ci/chromium.updater.star index b5e5a54a..4f2a01f 100644 --- a/infra/config/subprojects/chromium/ci/chromium.updater.star +++ b/infra/config/subprojects/chromium/ci/chromium.updater.star
@@ -409,6 +409,20 @@ ci.builder( name = "win32-updater-builder-dbg", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = [ + "mb", + ], + build_config = builder_config.build_config.RELEASE, + target_bits = 64, + target_platform = builder_config.target_platform.WIN, + ), + ), builderless = True, console_view_entry = consoles.console_view_entry( category = "debug|win (32)", @@ -451,6 +465,20 @@ ci.builder( name = "win32-updater-builder-rel", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = [ + "mb", + ], + build_config = builder_config.build_config.RELEASE, + target_bits = 64, + target_platform = builder_config.target_platform.WIN, + ), + ), builderless = True, console_view_entry = consoles.console_view_entry( category = "release|win (32)", @@ -488,6 +516,21 @@ ci.thin_tester( name = "win7(32)-updater-tester-rel", + builder_spec = builder_config.builder_spec( + execution_mode = builder_config.execution_mode.TEST, + gclient_config = builder_config.gclient_config( + config = "chromium", + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = [ + "mb", + ], + build_config = builder_config.build_config.RELEASE, + target_bits = 64, + target_platform = builder_config.target_platform.WIN, + ), + ), console_view_entry = consoles.console_view_entry( category = "release|win (32)", short_name = "7",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star index 18be405..f73d48f 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
@@ -61,7 +61,7 @@ }, }, tryjob = try_.job( - experiment_percentage = 50, + experiment_percentage = 75, ), )
diff --git a/ios/chrome/browser/crash_report/crash_helper.mm b/ios/chrome/browser/crash_report/crash_helper.mm index 1accf075..9ff4bd4 100644 --- a/ios/chrome/browser/crash_report/crash_helper.mm +++ b/ios/chrome/browser/crash_report/crash_helper.mm
@@ -80,43 +80,6 @@ crash_reporter::StartProcessingPendingReports(); } -// Callback for logging::SetLogMessageHandler -bool FatalMessageHandler(int severity, - const char* file, - int line, - size_t message_start, - const std::string& str) { - // Do not handle non-FATAL. - if (severity != logging::LOG_FATAL) - return false; - - // In case of OOM condition, this code could be reentered when - // constructing and storing the key. Using a static is not - // thread-safe, but if multiple threads are in the process of a - // fatal crash at the same time, this should work. - static bool guarded = false; - if (guarded) - return false; - - base::AutoReset<bool> guard(&guarded, true); - - // Only log last path component. This matches logging.cc. - if (file) { - const char* slash = strrchr(file, '/'); - if (slash) - file = slash + 1; - } - - NSString* fatal_value = [NSString - stringWithFormat:@"%s:%d: %s", file, line, str.c_str() + message_start]; - static crash_reporter::CrashKeyString<2550> key("LOG_FATAL"); - key.Set(base::SysNSStringToUTF8(fatal_value)); - - // Rather than including the code to force the crash here, allow the - // caller to do it. - return false; -} - // Called after Breakpad finishes uploading each report. void UploadResultHandler(NSString* report_id, NSError* error) { base::UmaHistogramSparse("CrashReport.BreakpadIOSUploadOutcome", error.code); @@ -153,7 +116,6 @@ // Notifying the PathService on the location of the crashes so that crashes // can be displayed to the user on the about:crashes page. Use the app group // so crashes can be shared by plugins. - logging::SetLogMessageHandler(&FatalMessageHandler); if (common::CanUseCrashpad()) { base::PathService::Override(ios::DIR_CRASH_DUMPS, common::CrashpadDumpLocation());
diff --git a/ios/chrome/browser/promos_manager/promos_manager_scene_agent.mm b/ios/chrome/browser/promos_manager/promos_manager_scene_agent.mm index 724e3ac5..d72b835 100644 --- a/ios/chrome/browser/promos_manager/promos_manager_scene_agent.mm +++ b/ios/chrome/browser/promos_manager/promos_manager_scene_agent.mm
@@ -31,4 +31,64 @@ [self.sceneState.appState addObserver:self]; } +#pragma mark - AppStateObserver + +- (void)appState:(AppState*)appState + didTransitionFromInitStage:(InitStage)previousInitStage { + // Monitor the app intialization stages to consider showing a promo at a point + // in the initialization of the app that allows it. + [self handlePromoDisplayIfUIAvailable]; +} + +#pragma mark - Private + +// Handle the display of a promo if the scene UI is available to display one. +- (void)handlePromoDisplayIfUIAvailable { + if (![self isUIAvailableForPromo]) + return; +} + +// Returns YES if a promo can be displayed. +- (BOOL)isUIAvailableForPromo { + // The following app & scene conditions need to be met to enable a promo's + // display (please note the Promos Manager may still decide *not* to display a + // promo, based on its own internal criteria): + + // (1) The app initialization is over (the stage InitStageFinal is reached). + if (self.sceneState.appState.initStage < InitStageFinal) + return NO; + + // (2) The scene is in the foreground. + if (self.sceneState.activationLevel < SceneActivationLevelForegroundActive) + return NO; + + // (3) There is no UI blocker. + if (self.sceneState.appState.currentUIBlocker) + return NO; + + // (4) The app isn't shutting down. + if (self.sceneState.appState.appIsTerminating) + return NO; + + // (5) There are no launch intents (external intents). + if (self.sceneState.startupHadExternalIntent) + return NO; + + // (6) The app isn't launching after a crash. + if (self.sceneState.appState.postCrashLaunch) + return NO; + + // Additional, sensible checks to add to minimize user annoyance: + + // (7) The user isn't currently signing in. + if (self.sceneState.signinInProgress) + return NO; + + // (8) The user isn't currently looking at a modal overlay. + if (self.sceneState.presentingModalOverlay) + return NO; + + return YES; +} + @end
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm index 657e381b..b6c296ae 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm
@@ -239,7 +239,16 @@ [self.formInputAccessoryViewController reset]; self.formInputViewController = nil; - [GetFirstResponder() reloadInputViews]; + if (@available(iOS 16, *)) { + @try { + [GetFirstResponder() reloadInputViews]; + } @catch (NSException* e) { + // TODO(crbug.com/1334530) iOS 16 beta 5 is still throwing an + // NSInternalInconsistencyException. + } + } else { + [GetFirstResponder() reloadInputViews]; + } } #pragma mark - Presenting Children
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/query_suggestion_view.mm b/ios/chrome/browser/ui/content_suggestions/cells/query_suggestion_view.mm index 4df2e415..617d951 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/query_suggestion_view.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/query_suggestion_view.mm
@@ -28,11 +28,20 @@ // Spacing between search ImageView and label. const CGFloat kQueryImageToLabelHorizontalSpacing = 9.5f; +// Touchdown alpha for `queryLabel` when the user presses on this view. +const CGFloat kTouchDownAlpha = 0.25f; + } // namespace @implementation QuerySuggestionConfig @end +@interface QuerySuggestionView () + +@property(nonatomic, strong) UILabel* queryLabel; + +@end + @implementation QuerySuggestionView - (instancetype)initWithConfiguration:(QuerySuggestionConfig*)config { @@ -44,26 +53,27 @@ [[UIImageView alloc] initWithImage:searchImage]; searchImageView.tintColor = [UIColor colorNamed:kGrey500Color]; searchImageView.translatesAutoresizingMaskIntoConstraints = NO; - UILabel* queryLabel = [[UILabel alloc] init]; - queryLabel.font = + self.queryLabel = [[UILabel alloc] init]; + self.queryLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]; - queryLabel.textColor = [UIColor colorNamed:kTextPrimaryColor]; - queryLabel.translatesAutoresizingMaskIntoConstraints = NO; - queryLabel.numberOfLines = 2; - queryLabel.adjustsFontForContentSizeCategory = YES; + self.queryLabel.textColor = [UIColor colorNamed:kTextPrimaryColor]; + self.queryLabel.translatesAutoresizingMaskIntoConstraints = NO; + self.queryLabel.numberOfLines = 2; + self.queryLabel.adjustsFontForContentSizeCategory = YES; + // self.userInteractionEnabled = YES; if (!config) { // If there is no config, then this is a placeholder tile. - queryLabel.backgroundColor = [UIColor colorNamed:kGrey100Color]; + self.queryLabel.backgroundColor = [UIColor colorNamed:kGrey100Color]; } else { _config = config; - queryLabel.text = config.query; + self.queryLabel.text = config.query; self.accessibilityLabel = config.query; self.isAccessibilityElement = YES; } [self addSubview:searchImageView]; - [self addSubview:queryLabel]; + [self addSubview:self.queryLabel]; [NSLayoutConstraint activateConstraints:@[ [searchImageView.widthAnchor @@ -74,26 +84,29 @@ constraintEqualToAnchor:self.centerYAnchor], [searchImageView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], - [queryLabel.leadingAnchor + [self.queryLabel.leadingAnchor constraintEqualToAnchor:searchImageView.trailingAnchor constant:kQueryImageToLabelHorizontalSpacing], - [queryLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], + [self.queryLabel.trailingAnchor + constraintEqualToAnchor:self.trailingAnchor], [self.heightAnchor constraintEqualToConstant:kViewHeightAnchor], [self.widthAnchor constraintEqualToConstant:kViewWidthAnchor] ]]; if (config) { // Let label take up all vertical space for two-line query text. [NSLayoutConstraint activateConstraints:@[ - [queryLabel.topAnchor constraintEqualToAnchor:self.topAnchor], - [queryLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor] + [self.queryLabel.topAnchor constraintEqualToAnchor:self.topAnchor], + [self.queryLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor] ]]; } else { // Vertically center and set thin height to visualize text placeholder. [NSLayoutConstraint activateConstraints:@[ - [queryLabel.centerYAnchor constraintEqualToAnchor:self.centerYAnchor], - [queryLabel.heightAnchor + [self.queryLabel.centerYAnchor + constraintEqualToAnchor:self.centerYAnchor], + [self.queryLabel.heightAnchor constraintEqualToConstant:kQueryLabelHeightAnchor], - [queryLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor] + [self.queryLabel.trailingAnchor + constraintEqualToAnchor:self.trailingAnchor] ]]; } } @@ -117,4 +130,26 @@ ]]; } +- (void)setHighlighted:(BOOL)highlighted { + if (highlighted) { + self.queryLabel.alpha = kTouchDownAlpha; + } else { + self.queryLabel.alpha = 1.0; + } +} + +#pragma mark - UIResponder + +- (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event { + [self setHighlighted:YES]; +} + +- (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event { + [self setHighlighted:NO]; +} + +- (void)touchesEnded:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event { + [self setHighlighted:NO]; +} + @end
diff --git a/ios/chrome/browser/ui/first_run/first_run_coordinator.mm b/ios/chrome/browser/ui/first_run/first_run_coordinator.mm index a19a5ac..59d12d8 100644 --- a/ios/chrome/browser/ui/first_run/first_run_coordinator.mm +++ b/ios/chrome/browser/ui/first_run/first_run_coordinator.mm
@@ -7,10 +7,11 @@ #import <UIKit/UIKit.h> #import "base/metrics/histogram_functions.h" -#include "base/notreached.h" -#include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/first_run/first_run_metrics.h" -#include "ios/chrome/browser/main/browser.h" +#import "base/notreached.h" +#import "base/time/time.h" +#import "ios/chrome/browser/browser_state/chrome_browser_state.h" +#import "ios/chrome/browser/first_run/first_run_metrics.h" +#import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.h" #import "ios/chrome/browser/ui/first_run/default_browser/default_browser_screen_coordinator.h" #import "ios/chrome/browser/ui/first_run/first_run_screen_delegate.h" @@ -31,6 +32,7 @@ @property(nonatomic, strong) ScreenProvider* screenProvider; @property(nonatomic, strong) ChromeCoordinator* childCoordinator; @property(nonatomic, strong) UINavigationController* navigationController; +@property(nonatomic, strong) NSDate* firstScreenStartTime; // YES if First Run was completed. @property(nonatomic, assign) BOOL completed; @@ -56,8 +58,10 @@ - (void)start { [self presentScreen:[self.screenProvider nextScreenType]]; + __weak FirstRunCoordinator* weakSelf = self; void (^completion)(void) = ^{ base::UmaHistogramEnumeration("FirstRun.Stage", first_run::kStart); + weakSelf.firstScreenStartTime = [NSDate now]; }; [self.navigationController setNavigationBarHidden:YES animated:NO]; [self.baseViewController presentViewController:self.navigationController @@ -89,6 +93,16 @@ - (void)willFinishPresenting { [self.childCoordinator stop]; self.childCoordinator = nil; + // Usually, finishing presenting the first FRE screen signifies that the user + // has accepted Terms of Services. Therefore, we can use the time it takes the + // first screen to be visible as the time it takes a user to accept Terms of + // Services. + if (self.firstScreenStartTime) { + base::TimeDelta delta = + base::Time::Now() - base::Time::FromNSDate(self.firstScreenStartTime); + base::UmaHistogramTimes("FirstRun.TermsOfServicesPromoDisplayTime", delta); + self.firstScreenStartTime = nil; + } [self presentScreen:[self.screenProvider nextScreenType]]; }
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index 89659c6..bd450cec 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -5cf1d75a2b03ebb9a06b6e76159d419718996ed0 \ No newline at end of file +d038ee2a702acdcb03af944fc3855f0baf0b4bfb \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 7f87d175..acb386e 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -17d93acd84fb63dbf55cb62d4e80eef7d183b5d5 \ No newline at end of file +2d882c96e7373339b3c443830dbf7afc14a27c02 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 2b5392f..a12422e 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -b34178ae86de8afead560cca5f6d7da70e8dc7bc \ No newline at end of file +274f2237441e67350cd3645cdc806700da82e2d3 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index dc56049..404e844 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -4b9b6b84813c4432bf2cf05e32cb1b596d90cabd \ No newline at end of file +f74b5a21eb76e450f12ac5389f32886b03adba71 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 index d63f24a..c5e6e03 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -4a44c24384ba8f05527e8f3e322d582ab849fe8f \ No newline at end of file +a05b2b224949b78985eb0e509af454e4891d91a7 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 index 23e5dbd7..3d595693 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -1070c31a24a9f8fbc310f6389b934bb63211943c \ No newline at end of file +59e61b8a329049031108726014d7ebb90f7ae053 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index 6d862aa..ec47853 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -ef4a30fc78f0cdc66b419e314dc4a46a14cd3b94 \ No newline at end of file +638aa4d3a18c64d0ce63fd2ad876eb6176d4abef \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index 26e0f04..4d8e5bf7 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -07ccf0b6f2c46446284a7992209ec454f795492b \ No newline at end of file +38a1312be66b2d75fe1d5e5f20914bc381318475 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index 06c4a59..caca5b34 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -308ecac6c58f15b3e9361e6df8496da6f15efd1a \ No newline at end of file +86e3bc4c89b56883a0f64c5cc8995202b1e949a9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index 06c7f53..4a532263 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -c7a35e0e1d93f97fee869c59a67440aad36be4b5 \ No newline at end of file +86aba0a111e6abd7981dd5fc24ba1be3a5ca9dfb \ No newline at end of file
diff --git a/media/gpu/chromeos/gl_image_processor_backend.cc b/media/gpu/chromeos/gl_image_processor_backend.cc index 9e8a6f0..bfc6816 100644 --- a/media/gpu/chromeos/gl_image_processor_backend.cc +++ b/media/gpu/chromeos/gl_image_processor_backend.cc
@@ -19,6 +19,7 @@ #include "ui/gl/gl_enums.h" #include "ui/gl/gl_image_native_pixmap.h" #include "ui/gl/gl_surface_egl.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/init/gl_factory.h" namespace media { @@ -213,7 +214,8 @@ // Create a driver-level GL context just for us. This is questionable because // work in this context will be competing with the context(s) used for // rasterization and compositing. However, it's a simple starting point. - gl_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + gl_surface_ = + gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(), gfx::Size()); if (!gl_surface_) { LOG(ERROR) << "Could not create the offscreen EGL surface"; return false;
diff --git a/media/gpu/v4l2/test/av1_decoder.cc b/media/gpu/v4l2/test/av1_decoder.cc index cb3a1063..2bef8ce 100644 --- a/media/gpu/v4l2/test/av1_decoder.cc +++ b/media/gpu/v4l2/test/av1_decoder.cc
@@ -116,172 +116,6 @@ v4l2_seq_params->max_frame_height_minus_1 = seq_header->max_frame_height - 1; } -// 5.9.2. Uncompressed header syntax -void FillFrameParams(struct v4l2_ctrl_av1_frame_header* v4l2_frame_params, - const libgav1::ObuFrameHeader& frm_header) { - conditionally_set_u32_flags(&v4l2_frame_params->flags, frm_header.show_frame, - V4L2_AV1_FRAME_HEADER_FLAG_SHOW_FRAME); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.showable_frame, - V4L2_AV1_FRAME_HEADER_FLAG_SHOWABLE_FRAME); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.error_resilient_mode, - V4L2_AV1_FRAME_HEADER_FLAG_ERROR_RESILIENT_MODE); - // libgav1 header has |enable_cdf_update| instead of |disable_cdf_update|. - conditionally_set_u32_flags(&v4l2_frame_params->flags, - !frm_header.enable_cdf_update, - V4L2_AV1_FRAME_HEADER_FLAG_DISABLE_CDF_UPDATE); - conditionally_set_u32_flags( - &v4l2_frame_params->flags, frm_header.allow_screen_content_tools, - V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_SCREEN_CONTENT_TOOLS); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.force_integer_mv, - V4L2_AV1_FRAME_HEADER_FLAG_FORCE_INTEGER_MV); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.allow_intrabc, - V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_INTRABC); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.use_superres, - V4L2_AV1_FRAME_HEADER_FLAG_USE_SUPERRES); - conditionally_set_u32_flags( - &v4l2_frame_params->flags, frm_header.allow_high_precision_mv, - V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_HIGH_PRECISION_MV); - conditionally_set_u32_flags( - &v4l2_frame_params->flags, frm_header.is_motion_mode_switchable, - V4L2_AV1_FRAME_HEADER_FLAG_IS_MOTION_MODE_SWITCHABLE); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.use_ref_frame_mvs, - V4L2_AV1_FRAME_HEADER_FLAG_USE_REF_FRAME_MVS); - // libgav1 header has |enable_frame_end_update_cdf| instead. - conditionally_set_u32_flags( - &v4l2_frame_params->flags, !frm_header.enable_frame_end_update_cdf, - V4L2_AV1_FRAME_HEADER_FLAG_DISABLE_FRAME_END_UPDATE_CDF); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.tile_info.uniform_spacing, - V4L2_AV1_FRAME_HEADER_FLAG_UNIFORM_TILE_SPACING); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.allow_warped_motion, - V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_WARPED_MOTION); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.reference_mode_select, - V4L2_AV1_FRAME_HEADER_FLAG_REFERENCE_SELECT); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.reduced_tx_set, - V4L2_AV1_FRAME_HEADER_FLAG_REDUCED_TX_SET); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.skip_mode_frame[0] > 0, - V4L2_AV1_FRAME_HEADER_FLAG_SKIP_MODE_ALLOWED); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.skip_mode_present, - V4L2_AV1_FRAME_HEADER_FLAG_SKIP_MODE_PRESENT); - conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.frame_size_override_flag, - V4L2_AV1_FRAME_HEADER_FLAG_FRAME_SIZE_OVERRIDE); - // libgav1 header doesn't have |buffer_removal_time_present_flag|. - conditionally_set_u32_flags( - &v4l2_frame_params->flags, frm_header.buffer_removal_time[0] > 0, - V4L2_AV1_FRAME_HEADER_FLAG_BUFFER_REMOVAL_TIME_PRESENT); - conditionally_set_u32_flags( - &v4l2_frame_params->flags, frm_header.frame_refs_short_signaling, - V4L2_AV1_FRAME_HEADER_FLAG_FRAME_REFS_SHORT_SIGNALING); - - switch (frm_header.frame_type) { - case libgav1::kFrameKey: - v4l2_frame_params->frame_type = V4L2_AV1_KEY_FRAME; - break; - case libgav1::kFrameInter: - v4l2_frame_params->frame_type = V4L2_AV1_INTER_FRAME; - break; - case libgav1::kFrameIntraOnly: - v4l2_frame_params->frame_type = V4L2_AV1_INTRA_ONLY_FRAME; - break; - case libgav1::kFrameSwitch: - v4l2_frame_params->frame_type = V4L2_AV1_SWITCH_FRAME; - break; - default: - NOTREACHED() << "Invalid frame type, " << frm_header.frame_type; - } - - v4l2_frame_params->order_hint = frm_header.order_hint; - v4l2_frame_params->superres_denom = frm_header.superres_scale_denominator; - v4l2_frame_params->upscaled_width = frm_header.upscaled_width; - - switch (frm_header.interpolation_filter) { - case libgav1::kInterpolationFilterEightTap: - v4l2_frame_params->interpolation_filter = - V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP; - break; - case libgav1::kInterpolationFilterEightTapSmooth: - v4l2_frame_params->interpolation_filter = - V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH; - break; - case libgav1::kInterpolationFilterEightTapSharp: - v4l2_frame_params->interpolation_filter = - V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP; - break; - case libgav1::kInterpolationFilterBilinear: - v4l2_frame_params->interpolation_filter = - V4L2_AV1_INTERPOLATION_FILTER_BILINEAR; - break; - case libgav1::kInterpolationFilterSwitchable: - v4l2_frame_params->interpolation_filter = - V4L2_AV1_INTERPOLATION_FILTER_SWITCHABLE; - break; - default: - NOTREACHED() << "Invalid interpolation filter, " - << frm_header.interpolation_filter; - } - - switch (frm_header.tx_mode) { - case libgav1::kTxModeOnly4x4: - v4l2_frame_params->tx_mode = V4L2_AV1_TX_MODE_ONLY_4X4; - break; - case libgav1::kTxModeLargest: - v4l2_frame_params->tx_mode = V4L2_AV1_TX_MODE_LARGEST; - break; - case libgav1::kTxModeSelect: - v4l2_frame_params->tx_mode = V4L2_AV1_TX_MODE_SELECT; - break; - default: - NOTREACHED() << "Invalid tx mode, " << frm_header.tx_mode; - } - - v4l2_frame_params->frame_width_minus_1 = frm_header.width - 1; - v4l2_frame_params->frame_height_minus_1 = frm_header.height - 1; - v4l2_frame_params->render_width_minus_1 = frm_header.render_width - 1; - v4l2_frame_params->render_height_minus_1 = frm_header.render_height - 1; - - v4l2_frame_params->current_frame_id = frm_header.current_frame_id; - v4l2_frame_params->primary_ref_frame = frm_header.primary_reference_frame; - SafeArrayMemcpy(v4l2_frame_params->buffer_removal_time, - frm_header.buffer_removal_time); - v4l2_frame_params->refresh_frame_flags = frm_header.refresh_frame_flags; - - static_assert(std::size(decltype(v4l2_frame_params->order_hints){}) == - libgav1::kNumReferenceFrameTypes, - "Invalid size of |order_hints| array"); - for (size_t i = 0; i < libgav1::kNumReferenceFrameTypes; i++) - v4l2_frame_params->order_hints[i] = - base::checked_cast<__u32>(frm_header.reference_order_hint[i]); - - v4l2_frame_params->last_frame_idx = - frm_header.reference_frame_index[libgav1::kReferenceFrameLast]; - v4l2_frame_params->gold_frame_idx = - frm_header.reference_frame_index[libgav1::kReferenceFrameGolden]; - - static_assert(std::size(decltype(v4l2_frame_params->ref_frame_idx){}) == - libgav1::kNumInterReferenceFrameTypes, - "Invalid size of |ref_frame_idx| array"); - for (size_t i = 0; i < libgav1::kNumInterReferenceFrameTypes; i++) - v4l2_frame_params->ref_frame_idx[i] = - base::checked_cast<__u64>(frm_header.reference_frame_index[i]); - - v4l2_frame_params->skip_mode_frame[0] = - base::checked_cast<__u8>(frm_header.skip_mode_frame[0]); - v4l2_frame_params->skip_mode_frame[1] = - base::checked_cast<__u8>(frm_header.skip_mode_frame[1]); -} - // Section 5.9.11. Loop filter params syntax. // Note that |update_ref_delta| and |update_mode_delta| flags in the spec // are not needed for V4L2 AV1 API. @@ -603,6 +437,200 @@ } } +// 5.9.2. Uncompressed header syntax +void FillFrameParams( + struct v4l2_ctrl_av1_frame_header* v4l2_frame_params, + const absl::optional<libgav1::ObuSequenceHeader>& seq_header, + const libgav1::ObuFrameHeader& frm_header) { + FillLoopFilterParams(&v4l2_frame_params->loop_filter, frm_header.loop_filter); + + FillLoopFilterDeltaParams(&v4l2_frame_params->loop_filter, + frm_header.delta_lf); + + FillQuantizationParams(&v4l2_frame_params->quantization, + frm_header.quantizer); + + FillQuantizerIndexDeltaParams(&v4l2_frame_params->quantization, seq_header, + frm_header); + + FillSegmentationParams(&v4l2_frame_params->segmentation, + frm_header.segmentation); + + const auto color_bitdepth = seq_header->color_config.bitdepth; + FillCdefParams(&v4l2_frame_params->cdef, frm_header.cdef, + base::strict_cast<int8_t>(color_bitdepth)); + + FillLoopRestorationParams(&v4l2_frame_params->loop_restoration, + frm_header.loop_restoration); + + FillTileInfo(&v4l2_frame_params->tile_info, frm_header.tile_info); + + FillGlobalMotionParams(&v4l2_frame_params->global_motion, + frm_header.global_motion); + + conditionally_set_u32_flags(&v4l2_frame_params->flags, frm_header.show_frame, + V4L2_AV1_FRAME_HEADER_FLAG_SHOW_FRAME); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.showable_frame, + V4L2_AV1_FRAME_HEADER_FLAG_SHOWABLE_FRAME); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.error_resilient_mode, + V4L2_AV1_FRAME_HEADER_FLAG_ERROR_RESILIENT_MODE); + // libgav1 header has |enable_cdf_update| instead of |disable_cdf_update|. + conditionally_set_u32_flags(&v4l2_frame_params->flags, + !frm_header.enable_cdf_update, + V4L2_AV1_FRAME_HEADER_FLAG_DISABLE_CDF_UPDATE); + conditionally_set_u32_flags( + &v4l2_frame_params->flags, frm_header.allow_screen_content_tools, + V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_SCREEN_CONTENT_TOOLS); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.force_integer_mv, + V4L2_AV1_FRAME_HEADER_FLAG_FORCE_INTEGER_MV); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.allow_intrabc, + V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_INTRABC); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.use_superres, + V4L2_AV1_FRAME_HEADER_FLAG_USE_SUPERRES); + conditionally_set_u32_flags( + &v4l2_frame_params->flags, frm_header.allow_high_precision_mv, + V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_HIGH_PRECISION_MV); + conditionally_set_u32_flags( + &v4l2_frame_params->flags, frm_header.is_motion_mode_switchable, + V4L2_AV1_FRAME_HEADER_FLAG_IS_MOTION_MODE_SWITCHABLE); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.use_ref_frame_mvs, + V4L2_AV1_FRAME_HEADER_FLAG_USE_REF_FRAME_MVS); + // libgav1 header has |enable_frame_end_update_cdf| instead. + conditionally_set_u32_flags( + &v4l2_frame_params->flags, !frm_header.enable_frame_end_update_cdf, + V4L2_AV1_FRAME_HEADER_FLAG_DISABLE_FRAME_END_UPDATE_CDF); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.tile_info.uniform_spacing, + V4L2_AV1_FRAME_HEADER_FLAG_UNIFORM_TILE_SPACING); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.allow_warped_motion, + V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_WARPED_MOTION); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.reference_mode_select, + V4L2_AV1_FRAME_HEADER_FLAG_REFERENCE_SELECT); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.reduced_tx_set, + V4L2_AV1_FRAME_HEADER_FLAG_REDUCED_TX_SET); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.skip_mode_frame[0] > 0, + V4L2_AV1_FRAME_HEADER_FLAG_SKIP_MODE_ALLOWED); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.skip_mode_present, + V4L2_AV1_FRAME_HEADER_FLAG_SKIP_MODE_PRESENT); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.frame_size_override_flag, + V4L2_AV1_FRAME_HEADER_FLAG_FRAME_SIZE_OVERRIDE); + // libgav1 header doesn't have |buffer_removal_time_present_flag|. + conditionally_set_u32_flags( + &v4l2_frame_params->flags, frm_header.buffer_removal_time[0] > 0, + V4L2_AV1_FRAME_HEADER_FLAG_BUFFER_REMOVAL_TIME_PRESENT); + conditionally_set_u32_flags( + &v4l2_frame_params->flags, frm_header.frame_refs_short_signaling, + V4L2_AV1_FRAME_HEADER_FLAG_FRAME_REFS_SHORT_SIGNALING); + + switch (frm_header.frame_type) { + case libgav1::kFrameKey: + v4l2_frame_params->frame_type = V4L2_AV1_KEY_FRAME; + break; + case libgav1::kFrameInter: + v4l2_frame_params->frame_type = V4L2_AV1_INTER_FRAME; + break; + case libgav1::kFrameIntraOnly: + v4l2_frame_params->frame_type = V4L2_AV1_INTRA_ONLY_FRAME; + break; + case libgav1::kFrameSwitch: + v4l2_frame_params->frame_type = V4L2_AV1_SWITCH_FRAME; + break; + default: + NOTREACHED() << "Invalid frame type, " << frm_header.frame_type; + } + + v4l2_frame_params->order_hint = frm_header.order_hint; + v4l2_frame_params->superres_denom = frm_header.superres_scale_denominator; + v4l2_frame_params->upscaled_width = frm_header.upscaled_width; + + switch (frm_header.interpolation_filter) { + case libgav1::kInterpolationFilterEightTap: + v4l2_frame_params->interpolation_filter = + V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP; + break; + case libgav1::kInterpolationFilterEightTapSmooth: + v4l2_frame_params->interpolation_filter = + V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH; + break; + case libgav1::kInterpolationFilterEightTapSharp: + v4l2_frame_params->interpolation_filter = + V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP; + break; + case libgav1::kInterpolationFilterBilinear: + v4l2_frame_params->interpolation_filter = + V4L2_AV1_INTERPOLATION_FILTER_BILINEAR; + break; + case libgav1::kInterpolationFilterSwitchable: + v4l2_frame_params->interpolation_filter = + V4L2_AV1_INTERPOLATION_FILTER_SWITCHABLE; + break; + default: + NOTREACHED() << "Invalid interpolation filter, " + << frm_header.interpolation_filter; + } + + switch (frm_header.tx_mode) { + case libgav1::kTxModeOnly4x4: + v4l2_frame_params->tx_mode = V4L2_AV1_TX_MODE_ONLY_4X4; + break; + case libgav1::kTxModeLargest: + v4l2_frame_params->tx_mode = V4L2_AV1_TX_MODE_LARGEST; + break; + case libgav1::kTxModeSelect: + v4l2_frame_params->tx_mode = V4L2_AV1_TX_MODE_SELECT; + break; + default: + NOTREACHED() << "Invalid tx mode, " << frm_header.tx_mode; + } + + v4l2_frame_params->frame_width_minus_1 = frm_header.width - 1; + v4l2_frame_params->frame_height_minus_1 = frm_header.height - 1; + v4l2_frame_params->render_width_minus_1 = frm_header.render_width - 1; + v4l2_frame_params->render_height_minus_1 = frm_header.render_height - 1; + + v4l2_frame_params->current_frame_id = frm_header.current_frame_id; + v4l2_frame_params->primary_ref_frame = frm_header.primary_reference_frame; + SafeArrayMemcpy(v4l2_frame_params->buffer_removal_time, + frm_header.buffer_removal_time); + v4l2_frame_params->refresh_frame_flags = frm_header.refresh_frame_flags; + + static_assert(std::size(decltype(v4l2_frame_params->order_hints){}) == + libgav1::kNumReferenceFrameTypes, + "Invalid size of |order_hints| array"); + for (size_t i = 0; i < libgav1::kNumReferenceFrameTypes; i++) + v4l2_frame_params->order_hints[i] = + base::checked_cast<__u32>(frm_header.reference_order_hint[i]); + + v4l2_frame_params->last_frame_idx = + frm_header.reference_frame_index[libgav1::kReferenceFrameLast]; + v4l2_frame_params->gold_frame_idx = + frm_header.reference_frame_index[libgav1::kReferenceFrameGolden]; + + static_assert(std::size(decltype(v4l2_frame_params->ref_frame_idx){}) == + libgav1::kNumInterReferenceFrameTypes, + "Invalid size of |ref_frame_idx| array"); + for (size_t i = 0; i < libgav1::kNumInterReferenceFrameTypes; i++) + v4l2_frame_params->ref_frame_idx[i] = + base::checked_cast<__u64>(frm_header.reference_frame_index[i]); + + v4l2_frame_params->skip_mode_frame[0] = + base::checked_cast<__u8>(frm_header.skip_mode_frame[0]); + v4l2_frame_params->skip_mode_frame[1] = + base::checked_cast<__u8>(frm_header.skip_mode_frame[1]); +} + // Section 5.11. Tile Group OBU syntax void FillTileGroupParams( v4l2_ctrl_av1_tile_group* tile_group_params, @@ -921,34 +949,8 @@ struct v4l2_ctrl_av1_frame_header v4l2_frame_params = {}; - FillLoopFilterParams(&v4l2_frame_params.loop_filter, - current_frame_header.loop_filter); - - FillLoopFilterDeltaParams(&v4l2_frame_params.loop_filter, - current_frame_header.delta_lf); - - FillQuantizationParams(&v4l2_frame_params.quantization, - current_frame_header.quantizer); - - FillQuantizerIndexDeltaParams(&v4l2_frame_params.quantization, - current_sequence_header_, current_frame_header); - - FillSegmentationParams(&v4l2_frame_params.segmentation, - current_frame_header.segmentation); - - const auto color_bitdepth = current_sequence_header_->color_config.bitdepth; - FillCdefParams(&v4l2_frame_params.cdef, current_frame_header.cdef, - base::strict_cast<int8_t>(color_bitdepth)); - - FillLoopRestorationParams(&v4l2_frame_params.loop_restoration, - current_frame_header.loop_restoration); - - FillTileInfo(&v4l2_frame_params.tile_info, current_frame_header.tile_info); - - FillGlobalMotionParams(&v4l2_frame_params.global_motion, - current_frame_header.global_motion); - - FillFrameParams(&v4l2_frame_params, current_frame_header); + FillFrameParams(&v4l2_frame_params, current_sequence_header_, + current_frame_header); // TODO(stevecho): V4L2_CID_STATELESS_AV1_FRAME_HEADER is trending to be // changed to V4L2_CID_STATELESS_AV1_FRAME
diff --git a/media/gpu/windows/d3d11_texture_wrapper_unittest.cc b/media/gpu/windows/d3d11_texture_wrapper_unittest.cc index 93c4b0b..4a7cfb1 100644 --- a/media/gpu/windows/d3d11_texture_wrapper_unittest.cc +++ b/media/gpu/windows/d3d11_texture_wrapper_unittest.cc
@@ -46,7 +46,7 @@ display_ = gl::GLSurfaceTestSupport::InitializeOneOffImplementation( gl::GLImplementationParts(gl::ANGLEImplementation::kD3D11), false); - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(display_, gfx::Size()); share_group_ = new gl::GLShareGroup(); context_ = gl::init::CreateGLContext(share_group_.get(), surface_.get(), gl::GLContextAttribs());
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc index abcdff84..485515a 100644 --- a/media/gpu/windows/d3d11_video_decoder.cc +++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -145,6 +145,9 @@ // from |impl_| will be cancelled by |weak_factory_| when we return. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // Log whatever usage we measured, if any. + LogPictureBufferUsage(); + impl_.Reset(); // Explicitly destroy the decoder, since it can reference picture buffers. @@ -544,6 +547,17 @@ return; } + // Periodically measure picture buffer usage. We could do this on every free, + // but it's not that important that we should run it so often. + if (picture_buffers_.size() > 0) { + if (!decode_count_until_picture_buffer_measurement_) { + MeasurePictureBufferUsage(); + decode_count_until_picture_buffer_measurement_ = picture_buffers_.size(); + } else { + decode_count_until_picture_buffer_measurement_--; + } + } + if (!current_buffer_) { if (input_buffer_queue_.empty()) { return; @@ -737,6 +751,10 @@ display_metadata = hdr_metadata_helper.GetDisplayMetadata(); } + // Since we are about to allocate new picture buffers, record whatever usage + // we had for the outgoing ones, if any. + LogPictureBufferUsage(); + // Drop any old pictures. for (auto& buffer : picture_buffers_) DCHECK(!buffer->in_picture_use()); @@ -936,6 +954,43 @@ input_buffer_queue_.clear(); } +void D3D11VideoDecoder::MeasurePictureBufferUsage() { + // Count the total number of buffers that are currently unused by either the + // client or the decoder. These are buffers that we didn't need to allocate. + int unused_buffers = 0; + for (const auto& buffer : picture_buffers_) { + if (!buffer->in_client_use() && !buffer->in_picture_use()) + unused_buffers++; + } + + if (!min_unused_buffers_ || unused_buffers < *min_unused_buffers_) { + min_unused_buffers_ = unused_buffers; + } +} + +void D3D11VideoDecoder::LogPictureBufferUsage() { + if (!min_unused_buffers_) + return; + + // Record these separately because (a) we could potentially fix the + // MultiTexture case pretty easily, and (b) we have no idea how often we're in + // one mode vs the other. This will let us know if there is enough usage of + // MultiTexture and also enough unused textures that it's worth fixing. Note + // that this assumes that we would lazily allocate buffers but not free them, + // and is a lower bound on savings. + if (use_single_video_decoder_texture_) { + UMA_HISTOGRAM_COUNTS_100( + "Media.D3D11VideoDecoder.UnusedPictureBufferCount.SingleTexture", + *min_unused_buffers_); + } else { + UMA_HISTOGRAM_COUNTS_100( + "Media.D3D11VideoDecoder.UnusedPictureBufferCount.MultiTexture", + *min_unused_buffers_); + } + + min_unused_buffers_.reset(); +} + // static bool D3D11VideoDecoder::GetD3D11FeatureLevel( ComD3D11Device dev,
diff --git a/media/gpu/windows/d3d11_video_decoder.h b/media/gpu/windows/d3d11_video_decoder.h index c838c9a..f774971 100644 --- a/media/gpu/windows/d3d11_video_decoder.h +++ b/media/gpu/windows/d3d11_video_decoder.h
@@ -150,6 +150,15 @@ // gpu main thread. void CreatePictureBuffers(); + // Measure the number of picture buffers that are currently unused, and see if + // it's smaller than the minimum we've seen since we've allocated them. + void MeasurePictureBufferUsage(); + + // Log the current measurement of picture buffer usage, as measured by + // `MeasurePictureBufferUsage()`, and clear the measurement. Do nothing, + // successfully, if no measurement has been made. + void LogPictureBufferUsage(); + // Create a D3D11VideoDecoder, if possible, based on the current config. D3D11Status::Or<ComD3D11VideoDecoder> CreateD3D11Decoder(); @@ -317,6 +326,17 @@ // this changes we need to recreate the decoder. VideoChromaSampling chroma_sampling_ = VideoChromaSampling::k420; + // If set, this is the minimum number of picture buffers that we've seen + // since the last time it was logged to UMA that are unused by both the + // client and the decoder. If unset, then no measurement has been made. + absl::optional<int> min_unused_buffers_; + + // Picture buffer usage is measured periodically after some number of decodes. + // This tracks how many until the next measurement. It's used strictly to + // rate limit the measurements, so we don't spent too much time counting + // unused picture buffers. + int decode_count_until_picture_buffer_measurement_ = 0; + base::WeakPtrFactory<D3D11VideoDecoder> weak_factory_{this}; };
diff --git a/net/data/ssl/root_stores/update_root_stores.py b/net/data/ssl/root_stores/update_root_stores.py index 8aca424..f9f58d9 100755 --- a/net/data/ssl/root_stores/update_root_stores.py +++ b/net/data/ssl/root_stores/update_root_stores.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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. @@ -22,7 +22,7 @@ ROOT_CERT_LIST_PATH = 'net/cert/root_cert_list_generated.h' ROOT_STORE_FILE_PATH = 'net/data/ssl/root_stores/root_stores.json' -LICENSE_AND_HEADER = """\ +LICENSE_AND_HEADER = b"""\ // 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. @@ -57,7 +57,7 @@ } kRootCerts[] = { """ -FOOTER = """\ +FOOTER = b"""\ }; @@ -93,8 +93,9 @@ cpp_str = ''.join('0x{:02X}, '.format(x) for x in bytearray.fromhex(spki)) log_id = int(data['id']) legacy = 'legacy' in data and data['legacy'] - header_file.write('{ { %s },\n%d, %s }, ' % - (cpp_str, log_id, "true" if legacy else "false")) + header_file.write( + ('{ { %s },\n%d, %s }, ' % + (cpp_str, log_id, "true" if legacy else "false")).encode('utf-8')) header_file.write(FOOTER)
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h index 93e944c..e13d8bb 100644 --- a/pdf/pdf_engine.h +++ b/pdf/pdf_engine.h
@@ -312,7 +312,7 @@ virtual void RotateCounterclockwise() = 0; virtual bool IsReadOnly() const = 0; virtual void SetReadOnly(bool enable) = 0; - virtual void SetTwoUpView(bool enable) = 0; + virtual void SetDocumentLayout(DocumentLayout::PageSpread page_spread) = 0; virtual void DisplayAnnotations(bool display) = 0; // Applies the document layout options proposed by a call to
diff --git a/pdf/pdf_view_plugin_base.cc b/pdf/pdf_view_plugin_base.cc index 5b5e106..dd4c5f5 100644 --- a/pdf/pdf_view_plugin_base.cc +++ b/pdf/pdf_view_plugin_base.cc
@@ -47,7 +47,6 @@ #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/common/input/web_mouse_event.h" #include "third_party/blink/public/common/input/web_touch_event.h" -#include "third_party/blink/public/web/web_print_preset_options.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkRefCnt.h" @@ -176,19 +175,6 @@ SendMessage(std::move(message)); } -void PdfViewPluginBase::Print() { - if (!engine()) - return; - - const bool can_print = - engine()->HasPermission(DocumentPermission::kPrintLowQuality) || - engine()->HasPermission(DocumentPermission::kPrintHighQuality); - if (!can_print) - return; - - InvokePrintDialog(); -} - void PdfViewPluginBase::DocumentLoadComplete() { DCHECK_EQ(DocumentLoadState::kLoading, document_load_state_); document_load_state_ = DocumentLoadState::kComplete; @@ -203,9 +189,6 @@ OnDocumentLoadComplete(); - if (accessibility_state_ == AccessibilityState::kPending) - LoadAccessibility(); - if (!full_frame()) return; @@ -329,12 +312,6 @@ SendMessage(std::move(message)); } -void PdfViewPluginBase::SendPrintPreviewLoadedNotification() { - base::Value::Dict message; - message.Set("type", "printPreviewLoaded"); - SendMessage(std::move(message)); -} - void PdfViewPluginBase::OnPaint(const std::vector<gfx::Rect>& paint_rects, std::vector<PaintReadyRect>& ready, std::vector<gfx::Rect>& pending) { @@ -342,22 +319,6 @@ DoPaint(paint_rects, ready, pending); } -void PdfViewPluginBase::EnableAccessibility() { - if (accessibility_state_ == AccessibilityState::kLoaded) - return; - - if (accessibility_state_ == AccessibilityState::kOff) - accessibility_state_ = AccessibilityState::kPending; - - if (document_load_state_ == DocumentLoadState::kComplete) - LoadAccessibility(); -} - -void PdfViewPluginBase::HandleAccessibilityAction( - const AccessibilityActionData& action_data) { - engine()->HandleAccessibilityAction(action_data); -} - int PdfViewPluginBase::GetContentRestrictions() const { int content_restrictions = kContentRestrictionCut | kContentRestrictionPaste; if (!engine()->HasPermission(DocumentPermission::kCopy)) @@ -397,47 +358,6 @@ PrepareAndSetAccessibilityViewportInfo(); } -blink::WebPrintPresetOptions PdfViewPluginBase::GetPrintPresetOptions() { - blink::WebPrintPresetOptions options; - options.is_scaling_disabled = !engine()->GetPrintScaling(); - options.copies = engine()->GetCopiesToPrint(); - options.duplex_mode = engine()->GetDuplexMode(); - options.uniform_page_size = engine()->GetUniformPageSizePoints(); - return options; -} - -int PdfViewPluginBase::PrintBegin(const blink::WebPrintParams& print_params) { - // The returned value is always equal to the number of pages in the PDF - // document irrespective of the printable area. - int32_t ret = engine()->GetNumberOfPages(); - if (!ret) - return 0; - - if (!engine()->HasPermission(DocumentPermission::kPrintLowQuality)) - return 0; - - print_params_ = print_params; - if (!engine()->HasPermission(DocumentPermission::kPrintHighQuality)) - print_params_->rasterize_pdf = true; - - engine()->PrintBegin(); - return ret; -} - -std::vector<uint8_t> PdfViewPluginBase::PrintPages( - const std::vector<int>& page_numbers) { - print_pages_called_ = true; - return engine()->PrintPages(page_numbers, print_params_.value()); -} - -void PdfViewPluginBase::PrintEnd() { - if (print_pages_called_) - UserMetricsRecordAction("PDF.PrintPage"); - print_pages_called_ = false; - print_params_.reset(); - engine()->PrintEnd(); -} - void PdfViewPluginBase::RecalculateAreas(double old_zoom, float old_device_scale) { if (zoom_ != old_zoom || device_scale() != old_device_scale) @@ -515,20 +435,6 @@ std::ceil(document_size_.height() * zoom() * device_scale())); } -void PdfViewPluginBase::SetCaretPosition(const gfx::PointF& position) { - engine()->SetCaretPosition(FrameToPdfCoordinates(position)); -} - -void PdfViewPluginBase::MoveRangeSelectionExtent(const gfx::PointF& extent) { - engine()->MoveRangeSelectionExtent(FrameToPdfCoordinates(extent)); -} - -void PdfViewPluginBase::SetSelectionBounds(const gfx::PointF& base, - const gfx::PointF& extent) { - engine()->SetSelectionBounds(FrameToPdfCoordinates(base), - FrameToPdfCoordinates(extent)); -} - void PdfViewPluginBase::PrepareAndSetAccessibilityPageInfo(int32_t page_index) { // Outdated calls are ignored. if (page_index != next_accessibility_page_index_)
diff --git a/pdf/pdf_view_plugin_base.h b/pdf/pdf_view_plugin_base.h index 15ae067..62f3314 100644 --- a/pdf/pdf_view_plugin_base.h +++ b/pdf/pdf_view_plugin_base.h
@@ -28,7 +28,6 @@ namespace blink { class WebInputEvent; -struct WebPrintPresetOptions; } // namespace blink namespace gfx { @@ -41,7 +40,6 @@ class PDFiumEngine; class PaintReadyRect; -struct AccessibilityActionData; struct AccessibilityCharInfo; struct AccessibilityDocInfo; struct AccessibilityPageInfo; @@ -91,7 +89,6 @@ const std::string& bcc, const std::string& subject, const std::string& body) override; - void Print() override; void DocumentLoadComplete() override; void DocumentLoadFailed() override; void DocumentLoadProgress(uint32_t available, uint32_t doc_size) override; @@ -105,12 +102,6 @@ std::vector<PaintReadyRect>& ready, std::vector<gfx::Rect>& pending) override; - // Enable accessibility for PDF plugin. - void EnableAccessibility(); - - // Handle invoked accessibility actions. - void HandleAccessibilityAction(const AccessibilityActionData& action_data); - // Gets the content restrictions based on the permissions which `engine_` has. int GetContentRestrictions() const; @@ -159,9 +150,6 @@ // -1 for loading error. void SendLoadingProgress(double percentage); - // Send a notification that the print preview has loaded. - void SendPrintPreviewLoadedNotification(); - // Schedules invalidation tasks after painting finishes. void InvalidateAfterPaintDone(); @@ -182,11 +170,6 @@ int GetDocumentPixelWidth() const; int GetDocumentPixelHeight() const; - // Common `pdf::mojom::PdfListener` implementations. - void SetCaretPosition(const gfx::PointF& position); - void MoveRangeSelectionExtent(const gfx::PointF& extent); - void SetSelectionBounds(const gfx::PointF& base, const gfx::PointF& extent); - // Sets the text input type for this plugin based on `in_focus`. virtual void SetFormTextFieldInFocus(bool in_focus) = 0; @@ -215,23 +198,11 @@ virtual void SetAccessibilityViewportInfo( AccessibilityViewportInfo viewport_info) = 0; - // Returns the print preset options for the document. - blink::WebPrintPresetOptions GetPrintPresetOptions(); - - // Begins a print session with the given `print_params`. A call to - // `PrintPages()` can only be made after after a successful call to - // `PrintBegin()`. Returns the number of pages required for the print output. - // A returned value of 0 indicates failure. - int PrintBegin(const blink::WebPrintParams& print_params); - // Prints the pages specified by `page_numbers` using the parameters passed to // `PrintBegin()` Returns a vector of bytes containing the printed output. An // empty returned value indicates failure. std::vector<uint8_t> PrintPages(const std::vector<int>& page_numbers); - // Ends the print session. Further calls to `PrintPages()` will fail. - void PrintEnd(); - // Disables browser commands because of restrictions on how the data is to be // used (i.e. can't copy/print). `content_restrictions` should have its bits // set by `chrome_pdf::ContentRestriction` enum values. @@ -241,10 +212,6 @@ virtual void DidStartLoading() = 0; virtual void DidStopLoading() = 0; - // Requests the plugin's render frame to set up a print dialog for the - // document. - virtual void InvokePrintDialog() = 0; - // Notifies the embedder of the top-left and bottom-right coordinates of the // current selection. virtual void NotifySelectionChanged(const gfx::PointF& left, @@ -299,6 +266,10 @@ return accessibility_state_; } + void set_accessibility_state(AccessibilityState state) { + accessibility_state_ = state; + } + static constexpr bool IsSaveDataSizeValid(size_t size) { return size > 0 && size <= kMaximumSavedFileSize; } @@ -368,12 +339,6 @@ // The next accessibility page index, used to track interprocess calls when // reconstructing the tree for new document layouts. int32_t next_accessibility_page_index_ = 0; - - // Assigned a value only between `PrintBegin()` and `PrintEnd()` calls. - absl::optional<blink::WebPrintParams> print_params_; - - // For identifying actual print operations to avoid double logging of UMA. - bool print_pages_called_; }; } // namespace chrome_pdf
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc index 35ab7794..edb53d5 100644 --- a/pdf/pdf_view_web_plugin.cc +++ b/pdf/pdf_view_web_plugin.cc
@@ -82,6 +82,7 @@ #include "third_party/blink/public/web/web_frame.h" #include "third_party/blink/public/web/web_plugin_container.h" #include "third_party/blink/public/web/web_plugin_params.h" +#include "third_party/blink/public/web/web_print_params.h" #include "third_party/blink/public/web/web_print_preset_options.h" #include "third_party/blink/public/web/web_view.h" #include "third_party/blink/public/web/web_widget.h" @@ -584,12 +585,29 @@ bool PdfViewWebPlugin::GetPrintPresetOptionsFromDocument( blink::WebPrintPresetOptions* print_preset_options) { - *print_preset_options = GetPrintPresetOptions(); + print_preset_options->is_scaling_disabled = !engine_->GetPrintScaling(); + print_preset_options->copies = engine_->GetCopiesToPrint(); + print_preset_options->duplex_mode = engine_->GetDuplexMode(); + print_preset_options->uniform_page_size = engine_->GetUniformPageSizePoints(); return true; } int PdfViewWebPlugin::PrintBegin(const blink::WebPrintParams& print_params) { - return PdfViewPluginBase::PrintBegin(print_params); + // The returned value is always equal to the number of pages in the PDF + // document irrespective of the printable area. + int32_t ret = engine_->GetNumberOfPages(); + if (!ret) + return 0; + + if (!engine_->HasPermission(DocumentPermission::kPrintLowQuality)) + return 0; + + print_params_ = print_params; + if (!engine_->HasPermission(DocumentPermission::kPrintHighQuality)) + print_params_->rasterize_pdf = true; + + engine_->PrintBegin(); + return ret; } void PdfViewWebPlugin::PrintPage(int page_number, cc::PaintCanvas* canvas) { @@ -618,9 +636,16 @@ if (pages_to_print_.empty()) return; - printing_metafile_->InitFromData(PrintPages(pages_to_print_)); + print_pages_called_ = true; + printing_metafile_->InitFromData( + engine_->PrintPages(pages_to_print_, print_params_.value())); - PdfViewPluginBase::PrintEnd(); + if (print_pages_called_) + UserMetricsRecordAction("PDF.PrintPage"); + print_pages_called_ = false; + print_params_.reset(); + engine_->PrintEnd(); + printing_metafile_ = nullptr; pages_to_print_.clear(); } @@ -878,6 +903,21 @@ base::BindOnce(std::move(callback), std::move(loader))); } +void PdfViewWebPlugin::Print() { + if (!engine_) + return; + + const bool can_print = + engine_->HasPermission(DocumentPermission::kPrintLowQuality) || + engine_->HasPermission(DocumentPermission::kPrintHighQuality); + if (!can_print) + return; + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&PdfViewWebPlugin::OnInvokePrintDialog, + weak_factory_.GetWeakPtr())); +} + void PdfViewWebPlugin::SubmitForm(const std::string& url, const void* data, int length) { @@ -977,16 +1017,17 @@ } void PdfViewWebPlugin::SetCaretPosition(const gfx::PointF& position) { - PdfViewPluginBase::SetCaretPosition(position); + engine_->SetCaretPosition(FrameToPdfCoordinates(position)); } void PdfViewWebPlugin::MoveRangeSelectionExtent(const gfx::PointF& extent) { - PdfViewPluginBase::MoveRangeSelectionExtent(extent); + engine_->MoveRangeSelectionExtent(FrameToPdfCoordinates(extent)); } void PdfViewWebPlugin::SetSelectionBounds(const gfx::PointF& base, const gfx::PointF& extent) { - PdfViewPluginBase::SetSelectionBounds(base, extent); + engine_->SetSelectionBounds(FrameToPdfCoordinates(base), + FrameToPdfCoordinates(extent)); } bool PdfViewWebPlugin::IsValid() const { @@ -1201,7 +1242,9 @@ void PdfViewWebPlugin::HandleSetTwoUpViewMessage( const base::Value::Dict& message) { - engine_->SetTwoUpView(message.FindBool("enableTwoUpView").value()); + engine_->SetDocumentLayout(message.FindBool("enableTwoUpView").value() + ? DocumentLayout::PageSpread::kTwoUpOdd + : DocumentLayout::PageSpread::kOneUp); } void PdfViewWebPlugin::HandleStopScrollingMessage( @@ -1418,12 +1461,19 @@ } void PdfViewWebPlugin::EnableAccessibility() { - PdfViewPluginBase::EnableAccessibility(); + if (accessibility_state() == AccessibilityState::kLoaded) + return; + + if (accessibility_state() == AccessibilityState::kOff) + set_accessibility_state(AccessibilityState::kPending); + + if (document_load_state() == DocumentLoadState::kComplete) + LoadAccessibility(); } void PdfViewWebPlugin::HandleAccessibilityAction( const AccessibilityActionData& action_data) { - PdfViewPluginBase::HandleAccessibilityAction(action_data); + engine_->HandleAccessibilityAction(action_data); } base::WeakPtr<PdfViewPluginBase> PdfViewWebPlugin::GetWeakPtr() { @@ -1453,6 +1503,9 @@ SendAttachments(); SendBookmarks(); SendMetadata(); + + if (accessibility_state() == AccessibilityState::kPending) + LoadAccessibility(); } void PdfViewWebPlugin::SendMessage(base::Value::Dict message) { @@ -1505,12 +1558,6 @@ did_call_start_loading_ = false; } -void PdfViewWebPlugin::InvokePrintDialog() { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&PdfViewWebPlugin::OnInvokePrintDialog, - weak_factory_.GetWeakPtr())); -} - void PdfViewWebPlugin::NotifySelectionChanged(const gfx::PointF& left, int left_height, const gfx::PointF& right, @@ -1906,6 +1953,12 @@ SendPrintPreviewLoadedNotification(); } +void PdfViewWebPlugin::SendPrintPreviewLoadedNotification() { + base::Value::Dict message; + message.Set("type", "printPreviewLoaded"); + SendMessage(std::move(message)); +} + void PdfViewWebPlugin::SendThumbnail(base::Value::Dict reply, Thumbnail thumbnail) { DCHECK_EQ(*reply.FindString("type"), "getThumbnailReply");
diff --git a/pdf/pdf_view_web_plugin.h b/pdf/pdf_view_web_plugin.h index e5099896..2cc4bbf 100644 --- a/pdf/pdf_view_web_plugin.h +++ b/pdf/pdf_view_web_plugin.h
@@ -36,6 +36,7 @@ #include "third_party/blink/public/web/web_plugin.h" #include "third_party/blink/public/web/web_plugin_container.h" #include "third_party/blink/public/web/web_plugin_params.h" +#include "third_party/blink/public/web/web_print_params.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" #include "ui/gfx/geometry/rect.h" @@ -48,6 +49,7 @@ class WebURL; class WebURLRequest; struct WebAssociatedURLLoaderOptions; +struct WebPrintPresetOptions; } // namespace blink namespace gfx { @@ -284,6 +286,7 @@ std::string Prompt(const std::string& question, const std::string& default_answer) override; std::string GetURL() override; + void Print() override; void SubmitForm(const std::string& url, const void* data, int length) override; @@ -363,7 +366,6 @@ void SetContentRestrictions(int content_restrictions) override; void DidStartLoading() override; void DidStopLoading() override; - void InvokePrintDialog() override; void NotifySelectionChanged(const gfx::PointF& left, int left_height, const gfx::PointF& right, @@ -490,6 +492,9 @@ // Continues loading the next preview page. void LoadNextPreviewPage(); + // Sends a notification that the print preview has loaded. + void SendPrintPreviewLoadedNotification(); + // Sends the thumbnail image data. void SendThumbnail(base::Value::Dict reply, Thumbnail thumbnail); @@ -638,6 +643,12 @@ // The indices of pages to print. std::vector<int> pages_to_print_; + // Assigned a value only between `PrintBegin()` and `PrintEnd()` calls. + absl::optional<blink::WebPrintParams> print_params_; + + // For identifying actual print operations to avoid double logging of UMA. + bool print_pages_called_; + // Whether the plugin is loaded in Print Preview. bool is_print_preview_ = false;
diff --git a/pdf/pdfium/findtext_unittest.cc b/pdf/pdfium/findtext_unittest.cc index 84e83614..242b1d58 100644 --- a/pdf/pdfium/findtext_unittest.cc +++ b/pdf/pdfium/findtext_unittest.cc
@@ -4,6 +4,7 @@ #include "base/check_op.h" #include "base/strings/utf_string_conversions.h" +#include "pdf/document_layout.h" #include "pdf/pdfium/pdfium_engine.h" #include "pdf/pdfium/pdfium_test_base.h" #include "pdf/test/test_client.h" @@ -223,7 +224,7 @@ EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(4, /*final_result=*/true)); } - engine->SetTwoUpView(true); + engine->SetDocumentLayout(DocumentLayout::PageSpread::kTwoUpOdd); { InSequence sequence;
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index b2ce295..ddb8d4a5 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -2153,10 +2153,8 @@ selection_.clear(); } -void PDFiumEngine::SetTwoUpView(bool enable) { - desired_layout_options_.set_page_spread( - enable ? DocumentLayout::PageSpread::kTwoUpOdd - : DocumentLayout::PageSpread::kOneUp); +void PDFiumEngine::SetDocumentLayout(DocumentLayout::PageSpread page_spread) { + desired_layout_options_.set_page_spread(page_spread); ProposeNextDocumentLayout(); }
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h index 61fd67a..c0f83d9 100644 --- a/pdf/pdfium/pdfium_engine.h +++ b/pdf/pdfium/pdfium_engine.h
@@ -114,7 +114,7 @@ void RotateCounterclockwise() override; bool IsReadOnly() const override; void SetReadOnly(bool enable) override; - void SetTwoUpView(bool enable) override; + void SetDocumentLayout(DocumentLayout::PageSpread page_spread) override; void DisplayAnnotations(bool display) override; gfx::Size ApplyDocumentLayout( const DocumentLayout::Options& options) override;
diff --git a/pdf/pdfium/pdfium_engine_unittest.cc b/pdf/pdfium/pdfium_engine_unittest.cc index c412480..9a9c4c6 100644 --- a/pdf/pdfium/pdfium_engine_unittest.cc +++ b/pdf/pdfium/pdfium_engine_unittest.cc
@@ -193,7 +193,7 @@ options.set_page_spread(DocumentLayout::PageSpread::kTwoUpOdd); EXPECT_CALL(client, ProposeDocumentLayout(LayoutWithOptions(options))) .WillOnce(Return()); - engine->SetTwoUpView(true); + engine->SetDocumentLayout(DocumentLayout::PageSpread::kTwoUpOdd); engine->ApplyDocumentLayout(options);
diff --git a/pdf/pdfium/pdfium_permissions.cc b/pdf/pdfium/pdfium_permissions.cc index 6f0f24d1..dc2d128a 100644 --- a/pdf/pdfium/pdfium_permissions.cc +++ b/pdf/pdfium/pdfium_permissions.cc
@@ -45,25 +45,25 @@ case DocumentPermission::kCopy: case DocumentPermission::kCopyAccessible: // Check the same copy bit for all copying permissions. - return HasPermissionBits(kPDFPermissionCopyMask); + return HasPermissionBits(kPDFPermissionBit05CopyMask); case DocumentPermission::kPrintLowQuality: case DocumentPermission::kPrintHighQuality: // Check the same printing bit for all printing permissions. - return HasPermissionBits(kPDFPermissionPrintMask); + return HasPermissionBits(kPDFPermissionBit03PrintMask); } } else { // Security handler revision 3+ have different rules for interpreting the // bits in `permission_bits_`. switch (permission) { case DocumentPermission::kCopy: - return HasPermissionBits(kPDFPermissionCopyMask); + return HasPermissionBits(kPDFPermissionBit05CopyMask); case DocumentPermission::kCopyAccessible: - return HasPermissionBits(kPDFPermissionCopyAccessibleMask); + return HasPermissionBits(kPDFPermissionBit10CopyAccessibleMask); case DocumentPermission::kPrintLowQuality: - return HasPermissionBits(kPDFPermissionPrintMask); + return HasPermissionBits(kPDFPermissionBit03PrintMask); case DocumentPermission::kPrintHighQuality: - return HasPermissionBits(kPDFPermissionPrintMask | - kPDFPermissionPrintHighQualityMask); + return HasPermissionBits(kPDFPermissionBit03PrintMask | + kPDFPermissionBit12PrintHighQualityMask); } } }
diff --git a/pdf/pdfium/pdfium_permissions.h b/pdf/pdfium/pdfium_permissions.h index c4c0ce7..8dc784b 100644 --- a/pdf/pdfium/pdfium_permissions.h +++ b/pdf/pdfium/pdfium_permissions.h
@@ -14,10 +14,10 @@ // See Table 3.20 in the PDF 1.7 spec for details on how to interpret permission // bits. Exposed for use in testing. -constexpr uint32_t kPDFPermissionPrintMask = 1 << 2; -constexpr uint32_t kPDFPermissionPrintHighQualityMask = 1 << 11; -constexpr uint32_t kPDFPermissionCopyMask = 1 << 4; -constexpr uint32_t kPDFPermissionCopyAccessibleMask = 1 << 9; +constexpr uint32_t kPDFPermissionBit03PrintMask = 1 << 2; +constexpr uint32_t kPDFPermissionBit05CopyMask = 1 << 4; +constexpr uint32_t kPDFPermissionBit10CopyAccessibleMask = 1 << 9; +constexpr uint32_t kPDFPermissionBit12PrintHighQualityMask = 1 << 11; // The permissions for a given FPDF_DOCUMENT. class PDFiumPermissions final {
diff --git a/pdf/pdfium/pdfium_permissions_unittest.cc b/pdf/pdfium/pdfium_permissions_unittest.cc index da61bc7..35fff42 100644 --- a/pdf/pdfium/pdfium_permissions_unittest.cc +++ b/pdf/pdfium/pdfium_permissions_unittest.cc
@@ -21,21 +21,24 @@ } // Sanity check the permission constants are correct. -static_assert(kPDFPermissionCopyAccessibleMask == 0x200, "Wrong permission"); -static_assert(kPDFPermissionCopyMask == 0x10, "Wrong permission"); -static_assert(kPDFPermissionPrintHighQualityMask == 0x800, "Wrong permission"); -static_assert(kPDFPermissionPrintMask == 0x4, "Wrong permission"); +static_assert(kPDFPermissionBit03PrintMask == 0x4, "Wrong permission"); +static_assert(kPDFPermissionBit05CopyMask == 0x10, "Wrong permission"); +static_assert(kPDFPermissionBit10CopyAccessibleMask == 0x200, + "Wrong permission"); +static_assert(kPDFPermissionBit12PrintHighQualityMask == 0x800, + "Wrong permission"); // Sanity check the permission generation functions above do the right thing. static_assert(GeneratePermissions2(0) == 0xffffffc0, "Wrong permission"); -static_assert(GeneratePermissions2(kPDFPermissionCopyMask | - kPDFPermissionPrintMask) == 0xffffffd4, +static_assert(GeneratePermissions2(kPDFPermissionBit03PrintMask | + kPDFPermissionBit05CopyMask) == 0xffffffd4, "Wrong permission"); static_assert(GeneratePermissions3(0) == 0xfffff0c0, "Wrong permission"); -static_assert(GeneratePermissions3(kPDFPermissionCopyAccessibleMask | - kPDFPermissionCopyMask | - kPDFPermissionPrintHighQualityMask | - kPDFPermissionPrintMask) == 0xfffffad4, +static_assert(GeneratePermissions3(kPDFPermissionBit03PrintMask | + kPDFPermissionBit05CopyMask | + kPDFPermissionBit10CopyAccessibleMask | + kPDFPermissionBit12PrintHighQualityMask) == + 0xfffffad4, "Wrong permission"); TEST(PDFiumPermissionTest, InvalidSecurityHandler) { @@ -62,16 +65,18 @@ obsolete_perms.HasPermission(DocumentPermission::kPrintHighQuality)); } -TEST(PDFiumPermissionTest, Revision2SecurityHandler) { +TEST(PDFiumPermissionTest, Revision2SecurityHandlerNone) { uint32_t permissions = GeneratePermissions2(0); auto no_perms = PDFiumPermissions::CreateForTesting(2, permissions); EXPECT_FALSE(no_perms.HasPermission(DocumentPermission::kCopy)); EXPECT_FALSE(no_perms.HasPermission(DocumentPermission::kCopyAccessible)); EXPECT_FALSE(no_perms.HasPermission(DocumentPermission::kPrintLowQuality)); EXPECT_FALSE(no_perms.HasPermission(DocumentPermission::kPrintHighQuality)); +} - permissions = - GeneratePermissions2(kPDFPermissionCopyMask | kPDFPermissionPrintMask); +TEST(PDFiumPermissionTest, Revision2SecurityHandlerAll) { + uint32_t permissions = GeneratePermissions2(kPDFPermissionBit03PrintMask | + kPDFPermissionBit05CopyMask); auto all_known_perms = PDFiumPermissions::CreateForTesting(2, permissions); EXPECT_TRUE(all_known_perms.HasPermission(DocumentPermission::kCopy)); EXPECT_TRUE( @@ -80,8 +85,10 @@ all_known_perms.HasPermission(DocumentPermission::kPrintLowQuality)); EXPECT_TRUE( all_known_perms.HasPermission(DocumentPermission::kPrintHighQuality)); +} - permissions = GeneratePermissions2(kPDFPermissionCopyMask); +TEST(PDFiumPermissionTest, Revision2SecurityHandlerCopyPrint) { + uint32_t permissions = GeneratePermissions2(kPDFPermissionBit05CopyMask); auto no_print_perms = PDFiumPermissions::CreateForTesting(2, permissions); EXPECT_TRUE(no_print_perms.HasPermission(DocumentPermission::kCopy)); EXPECT_TRUE( @@ -91,7 +98,7 @@ EXPECT_FALSE( no_print_perms.HasPermission(DocumentPermission::kPrintHighQuality)); - permissions = GeneratePermissions2(kPDFPermissionPrintMask); + permissions = GeneratePermissions2(kPDFPermissionBit03PrintMask); auto no_copy_perms = PDFiumPermissions::CreateForTesting(2, permissions); EXPECT_FALSE(no_copy_perms.HasPermission(DocumentPermission::kCopy)); EXPECT_FALSE( @@ -102,17 +109,20 @@ no_copy_perms.HasPermission(DocumentPermission::kPrintHighQuality)); } -TEST(PDFiumPermissionTest, Revision3SecurityHandler) { +TEST(PDFiumPermissionTest, Revision3SecurityHandlerNone) { uint32_t permissions = GeneratePermissions3(0); auto no_perms = PDFiumPermissions::CreateForTesting(3, permissions); EXPECT_FALSE(no_perms.HasPermission(DocumentPermission::kCopy)); EXPECT_FALSE(no_perms.HasPermission(DocumentPermission::kCopyAccessible)); EXPECT_FALSE(no_perms.HasPermission(DocumentPermission::kPrintLowQuality)); EXPECT_FALSE(no_perms.HasPermission(DocumentPermission::kPrintHighQuality)); +} - permissions = GeneratePermissions3( - kPDFPermissionCopyAccessibleMask | kPDFPermissionCopyMask | - kPDFPermissionPrintHighQualityMask | kPDFPermissionPrintMask); +TEST(PDFiumPermissionTest, Revision3SecurityHandlerAll) { + uint32_t permissions = GeneratePermissions3( + kPDFPermissionBit03PrintMask | kPDFPermissionBit05CopyMask | + kPDFPermissionBit10CopyAccessibleMask | + kPDFPermissionBit12PrintHighQualityMask); auto all_known_perms = PDFiumPermissions::CreateForTesting(3, permissions); EXPECT_TRUE(all_known_perms.HasPermission(DocumentPermission::kCopy)); EXPECT_TRUE( @@ -121,9 +131,11 @@ all_known_perms.HasPermission(DocumentPermission::kPrintLowQuality)); EXPECT_TRUE( all_known_perms.HasPermission(DocumentPermission::kPrintHighQuality)); +} - permissions = GeneratePermissions3(kPDFPermissionCopyAccessibleMask | - kPDFPermissionCopyMask); +TEST(PDFiumPermissionTest, Revision3SecurityHandlerCopyPrint) { + uint32_t permissions = GeneratePermissions3( + kPDFPermissionBit05CopyMask | kPDFPermissionBit10CopyAccessibleMask); auto copy_no_print_perms = PDFiumPermissions::CreateForTesting(3, permissions); EXPECT_TRUE(copy_no_print_perms.HasPermission(DocumentPermission::kCopy)); @@ -134,9 +146,9 @@ EXPECT_FALSE( copy_no_print_perms.HasPermission(DocumentPermission::kPrintHighQuality)); - permissions = - GeneratePermissions3(kPDFPermissionCopyAccessibleMask | - kPDFPermissionCopyMask | kPDFPermissionPrintMask); + permissions = GeneratePermissions3(kPDFPermissionBit03PrintMask | + kPDFPermissionBit05CopyMask | + kPDFPermissionBit10CopyAccessibleMask); auto copy_low_print_perms = PDFiumPermissions::CreateForTesting(3, permissions); EXPECT_TRUE(copy_low_print_perms.HasPermission(DocumentPermission::kCopy)); @@ -147,8 +159,8 @@ EXPECT_FALSE(copy_low_print_perms.HasPermission( DocumentPermission::kPrintHighQuality)); - permissions = GeneratePermissions3(kPDFPermissionPrintHighQualityMask | - kPDFPermissionPrintMask); + permissions = GeneratePermissions3(kPDFPermissionBit03PrintMask | + kPDFPermissionBit12PrintHighQualityMask); auto print_no_copy_perms = PDFiumPermissions::CreateForTesting(3, permissions); EXPECT_FALSE(print_no_copy_perms.HasPermission(DocumentPermission::kCopy)); @@ -159,9 +171,9 @@ EXPECT_TRUE( print_no_copy_perms.HasPermission(DocumentPermission::kPrintHighQuality)); - permissions = GeneratePermissions3(kPDFPermissionCopyAccessibleMask | - kPDFPermissionPrintHighQualityMask | - kPDFPermissionPrintMask); + permissions = GeneratePermissions3(kPDFPermissionBit03PrintMask | + kPDFPermissionBit10CopyAccessibleMask | + kPDFPermissionBit12PrintHighQualityMask); auto print_a11y_copy_perms = PDFiumPermissions::CreateForTesting(3, permissions); EXPECT_FALSE(print_a11y_copy_perms.HasPermission(DocumentPermission::kCopy));
diff --git a/remoting/base/result.h b/remoting/base/result.h index 6ca5e1c..6d1313c 100644 --- a/remoting/base/result.h +++ b/remoting/base/result.h
@@ -124,14 +124,16 @@ namespace remoting { +// TODO(joedow): Migrate instances of remoting::Result to base::expected. + // SuccessTag and ErrorTag are used for constructing a Result in the success // state or error state, respectively. class SuccessTag {}; class ErrorTag {}; -// absl::Monostate can be used for SuccessType or ErrorType to indicate that -// there is no data for that state. Thus, Result<SomeType, Monostate> is -// somewhat analogous to absl::optional<SomeType>, and Result<Monostate, -// Monostate> is effectively a (2-byte) boolean. Result<Monostate, ErrorType> +// absl::monostate can be used for SuccessType or ErrorType to indicate that +// there is no data for that state. Thus, Result<SomeType, monostate> is +// somewhat analogous to absl::optional<SomeType>, and Result<monostate, +// monostate> is effectively a (2-byte) boolean. Result<monostate, ErrorType> // can be useful for cases where an operation can fail, but there is no return // value in the success case.
diff --git a/remoting/codec/webrtc_video_encoder_av1.cc b/remoting/codec/webrtc_video_encoder_av1.cc index 83c4fbc..cc1bceb 100644 --- a/remoting/codec/webrtc_video_encoder_av1.cc +++ b/remoting/codec/webrtc_video_encoder_av1.cc
@@ -54,7 +54,13 @@ // Set the width, height, and thread count now that the frame size is known. config_.g_w = size.width(); config_.g_h = size.height(); - config_.g_threads = GetEncoderThreadCount(config_.g_w); + // Determine the number of threads to use for encoding by choosing the larger + // of the two dimensions. If we only checked the width, the performance for + // displays in portrait mode will be degraded due to a lower thread count. + // Since AV1 supports dividing the image into both rows and cols, we set the + // maximum number of threads here and then set the tile_row and tile_column + // values based on the frame dimensions later on. + config_.g_threads = GetEncoderThreadCount(std::max(config_.g_w, config_.g_h)); // Initialize an encoder instance. scoped_aom_codec codec(new aom_codec_ctx_t, DestroyAomCodecContext); @@ -79,13 +85,21 @@ DCHECK_EQ(error, AOM_CODEC_OK) << "Failed to set AV1E_SET_ROW_MT"; } - // The param for the tile column control is a log2 value so 0 is ok. - error = aom_codec_control(codec.get(), AV1E_SET_TILE_COLUMNS, - static_cast<int>(std::log2(config_.g_threads))); + // The param used to set the tile columns and tile rows is in log2 so 0 is ok. + int log2_threads = static_cast<int>(std::log2(config_.g_threads)); + // Split the cols/rows as evenly as possible, favoring columns for widescreen. + int log2_cols = (log2_threads + 1) / 2; + int log2_rows = log2_threads - log2_cols; + if (size.height() > size.width()) { + // Swap for portrait mode since we want more rows than columns. + std::swap(log2_cols, log2_rows); + } + + error = aom_codec_control(codec.get(), AV1E_SET_TILE_COLUMNS, log2_cols); DCHECK_EQ(error, AOM_CODEC_OK) << "Failed to set AV1E_SET_TILE_COLUMNS"; - // TODO(joedow): Experiment with AV1E_SET_TILE_ROWS. Note that the total - // number of COLUMNS and ROWS should add up to, at most, config_.g_threads. + error = aom_codec_control(codec.get(), AV1E_SET_TILE_ROWS, log2_rows); + DCHECK_EQ(error, AOM_CODEC_OK) << "Failed to set AV1E_SET_TILE_ROWS"; // These make realtime encoding faster. error =
diff --git a/remoting/codec/webrtc_video_encoder_vpx.cc b/remoting/codec/webrtc_video_encoder_vpx.cc index 65c42679..1c4be417 100644 --- a/remoting/codec/webrtc_video_encoder_vpx.cc +++ b/remoting/codec/webrtc_video_encoder_vpx.cc
@@ -66,6 +66,10 @@ config->g_w = size.width(); config->g_h = size.height(); config->g_pass = VPX_RC_ONE_PASS; + // TODO(joedow): Determine whether it is possible to support portrait mode. + // VP9 only supports breaking an image up into columns for parallel encoding, + // this means that a display in portrait mode cannot be broken up into as many + // columns as a display in landscape mode can so performance will be degraded. config->g_threads = WebrtcVideoEncoder::GetEncoderThreadCount(config->g_w); // Start emitting packets immediately.
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn index d371b41..0cfad5f4f 100644 --- a/remoting/host/BUILD.gn +++ b/remoting/host/BUILD.gn
@@ -96,7 +96,6 @@ "audio_volume_filter.h", "basic_desktop_environment.h", "chromoting_messages.h", - "chromoting_param_traits.h", "desktop_and_cursor_conditional_composer.h", "desktop_environment.h", "evaluate_capability.h", @@ -246,8 +245,6 @@ "chromoting_host_context.cc", "chromoting_host_context.h", "chromoting_messages.cc", - "chromoting_param_traits.cc", - "chromoting_param_traits_impl.h", "client_session.cc", "client_session.h", "client_session_events.h",
diff --git a/remoting/host/OWNERS b/remoting/host/OWNERS index d8a041f..2316a02 100644 --- a/remoting/host/OWNERS +++ b/remoting/host/OWNERS
@@ -4,8 +4,5 @@ per-file *_messages.cc=set noparent per-file *_messages.cc=file://ipc/SECURITY_OWNERS -per-file *_param_traits*.*=set noparent -per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS - per-file *event_reporter*=file://components/reporting/OWNERS
diff --git a/remoting/host/chromoting_messages.cc b/remoting/host/chromoting_messages.cc index 2367eb0..f4406af 100644 --- a/remoting/host/chromoting_messages.cc +++ b/remoting/host/chromoting_messages.cc
@@ -2,31 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/host/chromoting_param_traits_impl.h" - // Get basic type definitions. #define IPC_MESSAGE_IMPL #include "remoting/host/chromoting_messages.h" - -// Generate constructors. -#include "ipc/struct_constructor_macros.h" -#include "remoting/host/chromoting_messages.h" - -// Generate param traits write methods. -#include "ipc/param_traits_write_macros.h" -namespace IPC { -#include "remoting/host/chromoting_messages.h" -} // namespace IPC - -// Generate param traits read methods. -#include "ipc/param_traits_read_macros.h" -namespace IPC { -#include "remoting/host/chromoting_messages.h" -} // namespace IPC - -// Generate param traits log methods. -#include "ipc/param_traits_log_macros.h" -namespace IPC { -#include "remoting/host/chromoting_messages.h" -} // namespace IPC -
diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h index 205d36a..553b18e 100644 --- a/remoting/host/chromoting_messages.h +++ b/remoting/host/chromoting_messages.h
@@ -5,13 +5,7 @@ #ifndef REMOTING_HOST_CHROMOTING_MESSAGES_H_ #define REMOTING_HOST_CHROMOTING_MESSAGES_H_ -#include <stdint.h> - -#include "base/files/file_path.h" #include "ipc/ipc_message_start.h" -#include "ipc/ipc_platform_file.h" -#include "remoting/host/chromoting_param_traits.h" -#include "remoting/protocol/file_transfer_helpers.h" #endif // REMOTING_HOST_CHROMOTING_MESSAGES_H_ @@ -31,72 +25,3 @@ std::string /* function_name */, std::string /* file_name */, int /* line_number */) - -//----------------------------------------------------------------------------- -// Chromoting messages sent from the desktop to the network process. - -// Informs the network process of the result of a file operation on the file -// identified by |file_id|. If |result| is an error, the file ID is no longer -// valid. -IPC_MESSAGE_CONTROL( - ChromotingDesktopNetworkMsg_FileResult, - uint64_t /* file_id */, - remoting::protocol::FileTransferResult<absl::monostate> /* result */) - -// Carries the result of a read-file operation on the file identified by -// |file_id|. |result| is the filename and size of the selected file. If -// |result| is an error, the file ID is no longer valid. -IPC_MESSAGE_CONTROL(ChromotingDesktopNetworkMsg_FileInfoResult, - uint64_t /* file_id */, - remoting::protocol::FileTransferResult< - std::tuple<base::FilePath, uint64_t>> /* result */) - -// Carries the result of a file read-chunk operation on the file identified by -// |file_id|. |result| holds the read data. If |result| is an error, the file ID -// is no longer valid. -IPC_MESSAGE_CONTROL(ChromotingDesktopNetworkMsg_FileDataResult, - uint64_t /* file_id */, - remoting::protocol::FileTransferResult< - std::vector<std::uint8_t>> /* result */) - -//----------------------------------------------------------------------------- -// Chromoting messages sent from the network to the desktop process. - -// Requests that the desktop process create a new file for writing with the -// provided file name, which will be identified by |file_id|. The desktop -// process will respond with a FileResult message. -IPC_MESSAGE_CONTROL(ChromotingNetworkDesktopMsg_WriteFile, - uint64_t /* file_id */, - base::FilePath /* filename */) - -// Requests that the desktop process append the provided data chunk to the -// previously created file identified by |file_id|. The desktop process will -// respond with a FileResult message. -IPC_MESSAGE_CONTROL(ChromotingNetworkDesktopMsg_WriteFileChunk, - uint64_t /* file_id */, - std::vector<std::uint8_t> /* data */) - -// Prompt the user to select a file for reading, which will be identified by -// |file_id|. The desktop process will respond with a FileInfoResult message. -IPC_MESSAGE_CONTROL(ChromotingNetworkDesktopMsg_ReadFile, - uint64_t /* file_id */) - -// Requests that the desktop process read a data chunk from the file identified -// by |file_id|. The desktop process will respond with a FileDataResult message. -IPC_MESSAGE_CONTROL(ChromotingNetworkDesktopMsg_ReadFileChunk, - uint64_t /* file_id */, - uint64_t /* size */) - -// Requests that the desktop process close the file identified by |file_id|. -// If the file is being written, it will be finalized, and the desktop process -// will respond with a FileResult message. If the file is being read, there is -// no response message. -IPC_MESSAGE_CONTROL(ChromotingNetworkDesktopMsg_CloseFile, - uint64_t /* file_id */) - -// Requests that the desktop process cancel the file identified by |file_id|. -// If the file is being written, the partial file will be deleted. If the file -// is being read, it will be closed. In either case, there is no response -// message. -IPC_MESSAGE_CONTROL(ChromotingNetworkDesktopMsg_CancelFile, - uint64_t /* file_id */)
diff --git a/remoting/host/chromoting_param_traits.cc b/remoting/host/chromoting_param_traits.cc deleted file mode 100644 index f9ae7a7..0000000 --- a/remoting/host/chromoting_param_traits.cc +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2013 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/chromoting_param_traits.h" - -#include <stdint.h> -#include <sstream> - -#include "base/strings/stringprintf.h" -#include "ipc/ipc_message_protobuf_utils.h" -#include "ipc/ipc_message_utils.h" -#include "remoting/protocol/file_transfer_helpers.h" - -namespace IPC { - -// remoting::protocol::FileTransfer_Error - -// static -void IPC::ParamTraits<remoting::protocol::FileTransfer_Error>::Write( - base::Pickle* m, - const param_type& p) { - std::string serialized_file_transfer_error; - bool result = p.SerializeToString(&serialized_file_transfer_error); - DCHECK(result); - m->WriteString(serialized_file_transfer_error); -} - -// static -bool ParamTraits<remoting::protocol::FileTransfer_Error>::Read( - const base::Pickle* m, - base::PickleIterator* iter, - param_type* p) { - std::string serialized_file_transfer_error; - if (!iter->ReadString(&serialized_file_transfer_error)) - return false; - - return p->ParseFromString(serialized_file_transfer_error); -} - -// static -void ParamTraits<remoting::protocol::FileTransfer_Error>::Log( - const param_type& p, - std::string* l) { - std::ostringstream formatted; - formatted << p; - l->append( - base::StringPrintf("FileTransfer Error: %s", formatted.str().c_str())); -} - -} // namespace IPC
diff --git a/remoting/host/chromoting_param_traits.h b/remoting/host/chromoting_param_traits.h deleted file mode 100644 index 6ee451d2..0000000 --- a/remoting/host/chromoting_param_traits.h +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2013 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_CHROMOTING_PARAM_TRAITS_H_ -#define REMOTING_HOST_CHROMOTING_PARAM_TRAITS_H_ - -#include "ipc/ipc_message.h" -#include "ipc/ipc_param_traits.h" -#include "remoting/base/result.h" -#include "remoting/proto/file_transfer.pb.h" - -namespace IPC { - -template <> -struct ParamTraits<remoting::protocol::FileTransfer_Error> { - typedef remoting::protocol::FileTransfer_Error param_type; - static void Write(base::Pickle* m, const param_type& p); - static bool Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* p); - static void Log(const param_type& p, std::string* l); -}; - -template <typename SuccessType, typename ErrorType> -struct ParamTraits<remoting::Result<SuccessType, ErrorType>> { - typedef remoting::Result<SuccessType, ErrorType> param_type; - static void Write(base::Pickle* m, const param_type& p); - static bool Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* p); - static void Log(const param_type& p, std::string* l); -}; - -} // namespace IPC - -#endif // REMOTING_HOST_CHROMOTING_PARAM_TRAITS_H_
diff --git a/remoting/host/chromoting_param_traits_impl.h b/remoting/host/chromoting_param_traits_impl.h deleted file mode 100644 index 15c82ab..0000000 --- a/remoting/host/chromoting_param_traits_impl.h +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef REMOTING_HOST_CHROMOTING_PARAM_TRAITS_IMPL_H_ -#define REMOTING_HOST_CHROMOTING_PARAM_TRAITS_IMPL_H_ - -#include "remoting/host/chromoting_param_traits.h" - -#include "ipc/ipc_message_utils.h" - -template <typename SuccessType, typename ErrorType> -void IPC::ParamTraits<remoting::Result<SuccessType, ErrorType>>::Log( - const param_type& p, - std::string* l) { - if (p) { - l->append("success: "); - LogParam(p.success(), l); - } else { - l->append("error: "); - LogParam(p.error(), l); - } -} - -template <typename SuccessType, typename ErrorType> -bool IPC::ParamTraits<remoting::Result<SuccessType, ErrorType>>::Read( - const base::Pickle* m, - base::PickleIterator* iter, - param_type* p) { - bool is_success = false; - if (!ReadParam(m, iter, &is_success)) { - return false; - } - if (is_success) { - p->EmplaceSuccess(); - if (!ReadParam(m, iter, &p->success())) { - return false; - } - } else { - p->EmplaceError(); - if (!ReadParam(m, iter, &p->error())) { - return false; - } - } - return true; -} - -template <typename SuccessType, typename ErrorType> -void IPC::ParamTraits<remoting::Result<SuccessType, ErrorType>>::Write( - base::Pickle* m, - const param_type& p) { - WriteParam(m, p.is_success()); - if (p) { - WriteParam(m, p.success()); - } else { - WriteParam(m, p.error()); - } -} - -#endif // REMOTING_HOST_CHROMOTING_PARAM_TRAITS_IMPL_H_
diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc index ca8a029..d673173 100644 --- a/remoting/host/desktop_session_agent.cc +++ b/remoting/host/desktop_session_agent.cc
@@ -21,7 +21,6 @@ #include "build/build_config.h" #include "ipc/ipc_channel_proxy.h" #include "ipc/ipc_message.h" -#include "ipc/ipc_message_macros.h" #include "mojo/public/cpp/bindings/pending_associated_receiver.h" #include "remoting/base/auto_thread_task_runner.h" #include "remoting/base/constants.h" @@ -29,7 +28,6 @@ #include "remoting/host/audio_capturer.h" #include "remoting/host/base/screen_controls.h" #include "remoting/host/base/screen_resolution.h" -#include "remoting/host/chromoting_messages.h" #include "remoting/host/crash_process.h" #include "remoting/host/desktop_display_info_monitor.h" #include "remoting/host/desktop_environment.h" @@ -240,33 +238,8 @@ bool DesktopSessionAgent::OnMessageReceived(const IPC::Message& message) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); - CHECK(started_); - - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(DesktopSessionAgent, message) - IPC_MESSAGE_FORWARD(ChromotingNetworkDesktopMsg_ReadFile, - &*session_file_operations_handler_, - SessionFileOperationsHandler::ReadFile) - IPC_MESSAGE_FORWARD(ChromotingNetworkDesktopMsg_ReadFileChunk, - &*session_file_operations_handler_, - SessionFileOperationsHandler::ReadChunk) - IPC_MESSAGE_FORWARD(ChromotingNetworkDesktopMsg_WriteFile, - &*session_file_operations_handler_, - SessionFileOperationsHandler::WriteFile) - IPC_MESSAGE_FORWARD(ChromotingNetworkDesktopMsg_WriteFileChunk, - &*session_file_operations_handler_, - SessionFileOperationsHandler::WriteChunk) - IPC_MESSAGE_FORWARD(ChromotingNetworkDesktopMsg_CloseFile, - &*session_file_operations_handler_, - SessionFileOperationsHandler::Close) - IPC_MESSAGE_FORWARD(ChromotingNetworkDesktopMsg_CancelFile, - &*session_file_operations_handler_, - SessionFileOperationsHandler::Cancel) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - CHECK(handled) << "Received unexpected IPC type: " << message.type(); - return handled; + NOTREACHED() << "Received unexpected IPC type: " << message.type(); + return false; } void DesktopSessionAgent::OnChannelConnected(int32_t peer_pid) { @@ -462,7 +435,7 @@ // Set up the message handler for file transfers. session_file_operations_handler_.emplace( - this, desktop_environment_->CreateFileOperations()); + desktop_environment_->CreateFileOperations()); url_forwarder_configurator_ = desktop_environment_->CreateUrlForwarderConfigurator(); @@ -554,30 +527,6 @@ } } -void DesktopSessionAgent::OnResult(uint64_t file_id, - ResultHandler::Result result) { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - SendToNetwork(std::make_unique<ChromotingDesktopNetworkMsg_FileResult>( - file_id, std::move(result))); -} - -void DesktopSessionAgent::OnInfoResult(std::uint64_t file_id, - ResultHandler::InfoResult result) { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - SendToNetwork(std::make_unique<ChromotingDesktopNetworkMsg_FileInfoResult>( - file_id, std::move(result))); -} - -void DesktopSessionAgent::OnDataResult(std::uint64_t file_id, - ResultHandler::DataResult result) { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - SendToNetwork(std::make_unique<ChromotingDesktopNetworkMsg_FileDataResult>( - file_id, std::move(result))); -} - mojo::ScopedMessagePipeHandle DesktopSessionAgent::Initialize( const base::WeakPtr<Delegate>& delegate) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); @@ -773,19 +722,6 @@ screen_controls_->SetScreenResolution(resolution, absl::nullopt); } -void DesktopSessionAgent::SendToNetwork(std::unique_ptr<IPC::Message> message) { - if (!caller_task_runner_->BelongsToCurrentThread()) { - caller_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&DesktopSessionAgent::SendToNetwork, this, - std::move(message))); - return; - } - - if (network_channel_) { - network_channel_->Send(message.release()); - } -} - void DesktopSessionAgent::StartAudioCapturer() { DCHECK(audio_capture_task_runner_->BelongsToCurrentThread()); @@ -816,6 +752,22 @@ webauthn_state_change_notifier_->NotifyStateChange(); } +void DesktopSessionAgent::BeginFileRead(BeginFileReadCallback callback) { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + CHECK(started_); + + session_file_operations_handler_->BeginFileRead(std::move(callback)); +} + +void DesktopSessionAgent::BeginFileWrite(const base::FilePath& file_path, + BeginFileWriteCallback callback) { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + CHECK(started_); + + session_file_operations_handler_->BeginFileWrite(file_path, + std::move(callback)); +} + void DesktopSessionAgent::OnCheckUrlForwarderSetUpResult(bool is_set_up) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); if (!desktop_session_event_handler_) {
diff --git a/remoting/host/desktop_session_agent.h b/remoting/host/desktop_session_agent.h index b159db2b..7cfa429 100644 --- a/remoting/host/desktop_session_agent.h +++ b/remoting/host/desktop_session_agent.h
@@ -31,6 +31,7 @@ #include "remoting/host/mojom/remoting_mojom_traits.h" #include "remoting/proto/url_forwarder_control.pb.h" #include "remoting/protocol/clipboard_stub.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" @@ -73,7 +74,6 @@ public webrtc::DesktopCapturer::Callback, public webrtc::MouseCursorMonitor::Callback, public ClientSessionControl, - public IpcFileOperations::ResultHandler, public mojom::DesktopSessionAgent, public mojom::DesktopSessionControl { public: @@ -126,13 +126,6 @@ // Forwards an audio packet though the IPC channel to the network process. void ProcessAudioPacket(std::unique_ptr<AudioPacket> packet); - // IpcFileOperations::ResultHandler implementation. - void OnResult(std::uint64_t file_id, ResultHandler::Result result) override; - void OnInfoResult(std::uint64_t file_id, - ResultHandler::InfoResult result) override; - void OnDataResult(std::uint64_t file_id, - ResultHandler::DataResult result) override; - // mojom::DesktopSessionAgent implementation. void Start(const std::string& authenticated_jid, const ScreenResolution& resolution, @@ -152,6 +145,9 @@ void InjectTouchEvent(const protocol::TouchEvent& event) override; void SetUpUrlForwarder() override; void SignalWebAuthnExtension() override; + void BeginFileRead(BeginFileReadCallback callback) override; + void BeginFileWrite(const base::FilePath& file_path, + BeginFileWriteCallback callback) override; // Creates desktop integration components and a connected IPC channel to be // used to access them. The client end of the channel is returned. @@ -187,9 +183,6 @@ // Notifies the network process when a shared memory region is released. void OnSharedMemoryRegionReleased(int id); - // Sends a message to the network process. - void SendToNetwork(std::unique_ptr<IPC::Message> message); - // Posted to |audio_capture_task_runner_| to start the audio capturer. void StartAudioCapturer();
diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc index 64830da..934e340 100644 --- a/remoting/host/desktop_session_proxy.cc +++ b/remoting/host/desktop_session_proxy.cc
@@ -18,9 +18,7 @@ #include "base/task/single_thread_task_runner.h" #include "build/build_config.h" #include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_message_macros.h" #include "remoting/base/capabilities.h" -#include "remoting/host/chromoting_messages.h" #include "remoting/host/client_session.h" #include "remoting/host/client_session_control.h" #include "remoting/host/crash_process.h" @@ -33,6 +31,7 @@ #include "remoting/host/ipc_screen_controls.h" #include "remoting/host/ipc_url_forwarder_configurator.h" #include "remoting/host/ipc_video_frame_capturer.h" +#include "remoting/host/mojom/desktop_session.mojom.h" #include "remoting/host/remote_open_url/remote_open_url_util.h" #include "remoting/host/webauthn/remote_webauthn_delegated_state_change_notifier.h" #include "remoting/proto/audio.pb.h" @@ -237,22 +236,8 @@ bool DesktopSessionProxy::OnMessageReceived(const IPC::Message& message) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(DesktopSessionProxy, message) - IPC_MESSAGE_FORWARD(ChromotingDesktopNetworkMsg_FileResult, - &ipc_file_operations_factory_, - IpcFileOperations::ResultHandler::OnResult) - IPC_MESSAGE_FORWARD(ChromotingDesktopNetworkMsg_FileInfoResult, - &ipc_file_operations_factory_, - IpcFileOperations::ResultHandler::OnInfoResult) - IPC_MESSAGE_FORWARD(ChromotingDesktopNetworkMsg_FileDataResult, - &ipc_file_operations_factory_, - IpcFileOperations::ResultHandler::OnDataResult) - IPC_END_MESSAGE_MAP() - - CHECK(handled) << "Received unexpected IPC type: " << message.type(); - return handled; + NOTREACHED() << "Received unexpected IPC type: " << message.type(); + return false; } void DesktopSessionProxy::OnChannelConnected(int32_t peer_pid) { @@ -347,6 +332,9 @@ shared_buffers_.clear(); + // Notify interested folks that the IPC has been disconnected. + disconnect_handlers_.Notify(); + // Generate fake responses to keep the video capturer in sync. while (pending_capture_frame_requests_) { OnCaptureResult(mojom::CaptureResult::NewCaptureError( @@ -537,42 +525,46 @@ } } -void DesktopSessionProxy::ReadFile(std::uint64_t file_id) { +void DesktopSessionProxy::BeginFileRead( + IpcFileOperations::BeginFileReadCallback callback, + base::OnceClosure on_disconnect) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); + if (!desktop_session_control_) { + std::move(callback).Run( + mojom::BeginFileReadResult::NewError(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR))); + return; + } - SendToDesktop(new ChromotingNetworkDesktopMsg_ReadFile(file_id)); + auto disconnect_handler_subscription = + disconnect_handlers_.Add(std::move(on_disconnect)); + // Unretained is sound as DesktopSessionProxy owns |desktop_session_control_| + // and the callback won't be invoked after the remote is destroyed. + desktop_session_control_->BeginFileRead(base::BindOnce( + &DesktopSessionProxy::OnBeginFileReadResult, base::Unretained(this), + std::move(callback), std::move(disconnect_handler_subscription))); } -void DesktopSessionProxy::ReadChunk(std::uint64_t file_id, std::uint64_t size) { +void DesktopSessionProxy::BeginFileWrite( + const base::FilePath& file_path, + IpcFileOperations::BeginFileWriteCallback callback, + base::OnceClosure on_disconnect) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); + if (!desktop_session_control_) { + std::move(callback).Run( + mojom::BeginFileWriteResult::NewError(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR))); + return; + } - SendToDesktop(new ChromotingNetworkDesktopMsg_ReadFileChunk(file_id, size)); -} - -void DesktopSessionProxy::WriteFile(uint64_t file_id, - const base::FilePath& filename) { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - SendToDesktop(new ChromotingNetworkDesktopMsg_WriteFile(file_id, filename)); -} - -void DesktopSessionProxy::WriteChunk(uint64_t file_id, - std::vector<std::uint8_t> data) { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - SendToDesktop(new ChromotingNetworkDesktopMsg_WriteFileChunk(file_id, data)); -} - -void DesktopSessionProxy::Close(uint64_t file_id) { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - SendToDesktop(new ChromotingNetworkDesktopMsg_CloseFile(file_id)); -} - -void DesktopSessionProxy::Cancel(uint64_t file_id) { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - SendToDesktop(new ChromotingNetworkDesktopMsg_CancelFile(file_id)); + auto disconnect_handler_subscription = + disconnect_handlers_.Add(std::move(on_disconnect)); + // Unretained is sound as DesktopSessionProxy owns |desktop_session_control_| + // and the callback won't be invoked after the remote is destroyed. + desktop_session_control_->BeginFileWrite( + file_path, base::BindOnce(&DesktopSessionProxy::OnBeginFileWriteResult, + base::Unretained(this), std::move(callback), + std::move(disconnect_handler_subscription))); } void DesktopSessionProxy::IsUrlForwarderSetUp( @@ -755,6 +747,28 @@ std::move(frame)); } +void DesktopSessionProxy::OnBeginFileReadResult( + IpcFileOperations::BeginFileReadCallback callback, + base::CallbackListSubscription disconnect_handler_subscription, + mojom::BeginFileReadResultPtr result) { + // This handler is only needed until the pending_remote is returned from the + // DesktopSessionAgent as the IpcFileReader will then use the new channel and + // hook into its disconnect handler. + disconnect_handler_subscription = {}; + std::move(callback).Run(std::move(result)); +} + +void DesktopSessionProxy::OnBeginFileWriteResult( + IpcFileOperations::BeginFileWriteCallback callback, + base::CallbackListSubscription disconnect_handler_subscription, + mojom::BeginFileWriteResultPtr result) { + // This handler is only needed until the pending_remote is returned from the + // DesktopSessionAgent as the IpcFileWriter will then use the new channel and + // hook into its disconnect handler. + disconnect_handler_subscription = {}; + std::move(callback).Run(std::move(result)); +} + void DesktopSessionProxy::OnMouseCursorChanged( const webrtc::MouseCursor& mouse_cursor) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); @@ -792,16 +806,6 @@ } } -void DesktopSessionProxy::SendToDesktop(IPC::Message* message) { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - if (desktop_channel_) { - desktop_channel_->Send(message); - } else { - delete message; - } -} - // static void DesktopSessionProxyTraits::Destruct( const DesktopSessionProxy* desktop_session_proxy) {
diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h index ab3f4d3..306f0c7 100644 --- a/remoting/host/desktop_session_proxy.h +++ b/remoting/host/desktop_session_proxy.h
@@ -11,6 +11,7 @@ #include <vector> #include "base/callback.h" +#include "base/callback_list.h" #include "base/memory/read_only_shared_memory_region.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -173,14 +174,11 @@ void ExecuteAction(const protocol::ActionRequest& request); // IpcFileOperations::RequestHandler implementation. - void ReadFile(std::uint64_t file_id) override; - void ReadChunk(std::uint64_t file_id, std::uint64_t size) override; - void WriteFile(std::uint64_t file_id, - const base::FilePath& filename) override; - void WriteChunk(std::uint64_t file_id, - std::vector<std::uint8_t> data) override; - void Close(std::uint64_t file_id) override; - void Cancel(std::uint64_t file_id) override; + void BeginFileRead(IpcFileOperations::BeginFileReadCallback callback, + base::OnceClosure on_disconnect) override; + void BeginFileWrite(const base::FilePath& file_path, + IpcFileOperations::BeginFileWriteCallback callback, + base::OnceClosure on_disconnect) override; // mojom::DesktopSessionEventHandler implementation. void OnClipboardEvent(const protocol::ClipboardEvent& event) override; @@ -229,11 +227,19 @@ void OnCaptureResult(webrtc::DesktopCapturer::Result result, const SerializedDesktopFrame& serialized_frame); - void SignalWebAuthnExtension(); + // Handles the BeginFileReadResult returned from the DesktopSessionAgent. + void OnBeginFileReadResult( + IpcFileOperations::BeginFileReadCallback callback, + base::CallbackListSubscription disconnect_handler_subscription, + mojom::BeginFileReadResultPtr result); - // Sends a message to the desktop session agent. The message is silently - // deleted if the channel is broken. - void SendToDesktop(IPC::Message* message); + // Handles the BeginFileWriteResult returned from the DesktopSessionAgent. + void OnBeginFileWriteResult( + IpcFileOperations::BeginFileWriteCallback callback, + base::CallbackListSubscription disconnect_handler_subscription, + mojom::BeginFileWriteResultPtr result); + + void SignalWebAuthnExtension(); // Task runners: // - |audio_capturer_| is called back on |audio_capture_task_runner_|. @@ -298,6 +304,9 @@ // is called on IpcKeyboardLayoutMonitor. absl::optional<protocol::KeyboardLayout> keyboard_layout_; + // Used to notify registered handlers when the IPC channel is disconnected. + base::OnceClosureList disconnect_handlers_; + // |desktop_session_agent_| is only valid when |desktop_channel_| is // connected. mojo::AssociatedRemote<mojom::DesktopSessionAgent> desktop_session_agent_;
diff --git a/remoting/host/file_transfer/BUILD.gn b/remoting/host/file_transfer/BUILD.gn index b899af4..7f53fb8 100644 --- a/remoting/host/file_transfer/BUILD.gn +++ b/remoting/host/file_transfer/BUILD.gn
@@ -41,6 +41,7 @@ "//ipc:ipc", "//remoting/host:common", "//remoting/host/base", + "//remoting/host/mojom", "//remoting/host/win", ] } else { @@ -85,6 +86,7 @@ "//base", "//net:net", "//remoting/base:base", + "//remoting/host/mojom", "//remoting/protocol", "//ui/base:base", "//url:url", @@ -128,6 +130,7 @@ "//base/test:test_support", "//net:net", "//remoting/base:base", + "//remoting/host/mojom", "//remoting/protocol", "//remoting/protocol:test_support", "//testing/gtest",
diff --git a/remoting/host/file_transfer/file_chooser_main_win.cc b/remoting/host/file_transfer/file_chooser_main_win.cc index fe8c453..3427725 100644 --- a/remoting/host/file_transfer/file_chooser_main_win.cc +++ b/remoting/host/file_transfer/file_chooser_main_win.cc
@@ -13,17 +13,15 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "base/memory/scoped_refptr.h" -#include "base/pickle.h" #include "base/run_loop.h" #include "base/task/thread_pool/thread_pool_instance.h" #include "base/timer/timer.h" #include "base/win/scoped_co_mem.h" #include "base/win/scoped_com_initializer.h" -#include "ipc/ipc_message_utils.h" -#include "remoting/host/chromoting_param_traits.h" -#include "remoting/host/chromoting_param_traits_impl.h" +#include "mojo/public/cpp/bindings/message.h" #include "remoting/host/file_transfer/file_chooser.h" #include "remoting/host/file_transfer/file_chooser_common_win.h" +#include "remoting/host/mojom/desktop_session.mojom.h" #include "remoting/host/win/core_resource.h" #include "remoting/protocol/file_transfer_helpers.h" @@ -138,16 +136,15 @@ FileChooser::Result result = ShowFileChooser(); - base::Pickle pickle; - IPC::WriteParam(&pickle, result); + mojo::Message serialized_message = + mojom::FileChooserResult::SerializeAsMessage(&result); // Highly unlikely, but we want to know if it happens. - if (pickle.size() > kFileChooserPipeBufferSize) { - pickle = base::Pickle(); - IPC::WriteParam( - &pickle, - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); + if (serialized_message.data_num_bytes() > kFileChooserPipeBufferSize) { + FileChooser::Result error_result(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); + serialized_message = + mojom::FileChooserResult::SerializeAsMessage(&error_result); } HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); @@ -157,7 +154,8 @@ } DWORD bytes_written; - if (!WriteFile(stdout_handle, pickle.data(), pickle.size(), &bytes_written, + if (!WriteFile(stdout_handle, serialized_message.data(), + serialized_message.data_num_bytes(), &bytes_written, nullptr)) { PLOG(ERROR) << "Failed to write file chooser result"; } @@ -167,9 +165,10 @@ // in case. Check that all bytes were written successfully, and return an // error code if not to signal the parent that it shouldn't try to parse the // output. - if (bytes_written != pickle.size()) { + if (bytes_written != serialized_message.data_num_bytes()) { LOG(ERROR) << "Failed to write all bytes to pipe. (Buffer full?) Expected: " - << pickle.size() << " Actual: " << bytes_written; + << serialized_message.data_num_bytes() + << " Actual: " << bytes_written; return EXIT_FAILURE; }
diff --git a/remoting/host/file_transfer/file_chooser_win.cc b/remoting/host/file_transfer/file_chooser_win.cc index b1c2b131..578d7cf 100644 --- a/remoting/host/file_transfer/file_chooser_win.cc +++ b/remoting/host/file_transfer/file_chooser_win.cc
@@ -9,6 +9,7 @@ #include <cstdlib> #include <utility> +#include <vector> #include "base/bind.h" #include "base/command_line.h" @@ -18,12 +19,11 @@ #include "base/threading/sequenced_task_runner_handle.h" #include "base/win/object_watcher.h" #include "base/win/scoped_handle.h" -#include "ipc/ipc_message_utils.h" +#include "mojo/public/cpp/bindings/message.h" #include "remoting/host/base/host_exit_codes.h" #include "remoting/host/base/switches.h" -#include "remoting/host/chromoting_param_traits.h" -#include "remoting/host/chromoting_param_traits_impl.h" #include "remoting/host/file_transfer/file_chooser_common_win.h" +#include "remoting/host/mojom/desktop_session.mojom.h" namespace remoting { @@ -156,10 +156,10 @@ } process_.Close(); - char raw_response[kFileChooserPipeBufferSize]; + std::vector<uint8_t> response_bytes(kFileChooserPipeBufferSize); DWORD bytes_read; - if (!PeekNamedPipe(pipe_read_.Get(), raw_response, sizeof(raw_response), - &bytes_read, nullptr, nullptr)) { + if (!PeekNamedPipe(pipe_read_.Get(), response_bytes.data(), + response_bytes.size(), &bytes_read, nullptr, nullptr)) { PLOG(ERROR) << "Failed to read response from pipe"; std::move(callback_).Run(MakeFileTransferError( FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR, @@ -167,10 +167,13 @@ return; } + mojo::Message serialized_message( + base::span<uint8_t>(response_bytes.begin(), bytes_read), + base::span<mojo::ScopedHandle>()); + FileChooser::Result result; - base::Pickle pickle(raw_response, bytes_read); - base::PickleIterator iterator(pickle); - if (!IPC::ReadParam(&pickle, &iterator, &result)) { + if (!mojom::FileChooserResult::DeserializeFromMessage( + std::move(serialized_message), &result)) { LOG(ERROR) << "Failed to deserialize response."; std::move(callback_).Run(MakeFileTransferError( FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR));
diff --git a/remoting/host/file_transfer/file_operations.h b/remoting/host/file_transfer/file_operations.h index 6b9e94ec..d0fbacb 100644 --- a/remoting/host/file_transfer/file_operations.h +++ b/remoting/host/file_transfer/file_operations.h
@@ -86,7 +86,7 @@ // complete. virtual void Open(const base::FilePath& filename, Callback callback) = 0; - // Writes a chuck to the file. Chunks cannot be queued; the caller must + // Writes a chunk to the file. Chunks cannot be queued; the caller must // wait until callback is called before calling WriteChunk again or calling // Close. virtual void WriteChunk(std::vector<std::uint8_t> data,
diff --git a/remoting/host/file_transfer/file_transfer_message_handler.cc b/remoting/host/file_transfer/file_transfer_message_handler.cc index 96c3b89..a8a0279f 100644 --- a/remoting/host/file_transfer/file_transfer_message_handler.cc +++ b/remoting/host/file_transfer/file_transfer_message_handler.cc
@@ -169,6 +169,9 @@ void FileTransferMessageHandler::OnSuccess() { DCHECK_EQ(kEof, state_); SetState(kClosed); + + // Ensure any resources tied to the reader's lifetime are released. + file_reader_.reset(); } void FileTransferMessageHandler::OnError(protocol::FileTransfer_Error error) {
diff --git a/remoting/host/file_transfer/ipc_file_operations.cc b/remoting/host/file_transfer/ipc_file_operations.cc index 7fc55336..c2e7ab2 100644 --- a/remoting/host/file_transfer/ipc_file_operations.cc +++ b/remoting/host/file_transfer/ipc_file_operations.cc
@@ -5,19 +5,80 @@ #include "remoting/host/file_transfer/ipc_file_operations.h" #include <cstdint> +#include <memory> #include <utility> #include "base/bind.h" #include "base/files/file_path.h" #include "base/memory/ptr_util.h" #include "base/memory/weak_ptr.h" +#include "base/sequence_checker.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "remoting/host/mojom/desktop_session.mojom.h" #include "remoting/protocol/file_transfer_helpers.h" namespace remoting { +// This is an overview of how IpcFileOperations is integrated and used in the +// multi-process host architecture. Reasoning about the lifetime and ownership +// of the various pieces currently requires digging through the code so this +// comment block describes the relationships and pieces involved at a high-level +// to help those looking to understand the code. +// +// The IpcFileOperations and related classes are all used in the low-privilege +// network process. They handle network communication with the website client +// over a WebRTC data channel and proxy those requests using Mojo to the +// SessionFileOperationsHandler (and friends) which lives in the high-privilege +// desktop process and handles the actual file reading and writing. +// +// When a new file transfer data channel is opened by the client, the +// ClientSession instance on the host (running in the network process) will +// create a FileTransferMessageHandler (FTMH) instance to service it. As part of +// the FTMH creation, ClientSession will ask the IpcDesktopEnvironment to create +// a new IpcFileOperations instance. This instance will be provided with a +// WeakPtr<IpcFileOperations::RequestHandler> which is used to start a file read +// or write operation in the desktop process over an existing IPC channel owned +// by the DesktopSessionProxy. +// +// After the FTMH receives the initial message indicating the type of operation +// to perform, it creates an IpcFileReader or an IpcFileWriter instance. The +// IpcFile{Reader|Writer} begins an operation by calling the appropriate method +// on the IpcFileOperations::RequestHandler interface. This interface is +// implemented by the DesktopSessionProxy (DSP) which in turn calls the +// DesktopSessionAgent (DSA) via its mojom::DesktopSessionControl remote. The +// DSA passes the request to its SessionFileOperationsHandler instance which, if +// successful, will create a new IPC channel for the transfer and return a +// remote to the IpcFile{Reader|Writer} to allow it to proceed with the file +// operation. The receiver is owned by a MojoFileReader or MojoFileWriter +// instance whose lifetime is tied to the Mojo channel meaning the +// MojoFile{Reader|Writer} will be destroyed when the channel is disconnected. +// +// The lifetime of an FTMH instance is tied to the WebRTC file transfer data +// channel that it was created to service. Each data channel exists for one +// transfer request, so once the operation completes, or encounters an error, +// the IpcFileOperations instance and the IpcFile{Reader|Writer} it created will +// be destroyed (this will also trigger destruction of a MojoFile{Reader|Writer} +// in the desktop process). +// +// The lifetime of the DesktopSessionProxy is a bit harder to reason about as a +// number of classes and callbacks hold a scoped_refptr reference to it. At the +// very earliest, the DSP will be destroyed when the chromoting session is +// terminated. When this occurs, the scoped_refptr in ClientSession is released +// and the IpcDesktopEnvironment and IpcFileOperationsFactory are destroyed. +// +// Because of the objects involved, the two UaF concerns are: +// - Calling into |request_handler_| after the DSP has been destroyed. +// This is unlikely given that a DSP lasts for the entire session but it +// could occur if the timing was just right near the end of a session. +// Mitigation: |request_handler_| is wrapped in a WeakPtr and provided to each +// IpcFile{Reader|Writer} instance. +// - The DSP could invoke a disconnect_handler on the IpcFile{Reader|Writer} if +// the file transfer request was canceled just after the operation started. +// Mitigation: The disconnect_handler callback provided to the BeginFileRead +// BeginFileWrite method is bound with a WeakPtr. class IpcFileOperations::IpcReader : public FileOperations::Reader { public: - IpcReader(std::uint64_t file_id, base::WeakPtr<SharedState> shared_state); + explicit IpcReader(base::WeakPtr<RequestHandler> request_handler); IpcReader(const IpcReader&) = delete; IpcReader& operator=(const IpcReader&) = delete; @@ -31,20 +92,30 @@ std::uint64_t size() const override; State state() const override; - private: - void OnOpenResult(OpenCallback callback, ResultHandler::InfoResult result); - void OnReadResult(ReadCallback callback, ResultHandler::DataResult result); + void OnChannelDisconnected(); - State state_ = kCreated; - std::uint64_t file_id_; - base::FilePath filename_; - std::uint64_t size_ = 0; - base::WeakPtr<SharedState> shared_state_; + base::WeakPtr<IpcReader> GetWeakPtr() const; + + private: + void OnOpenResult(mojom::BeginFileReadResultPtr result); + void OnReadResult( + const protocol::FileTransferResult<std::vector<std::uint8_t>>& result); + + State state_ GUARDED_BY_CONTEXT(sequence_checker_) = kCreated; + base::FilePath filename_ GUARDED_BY_CONTEXT(sequence_checker_); + std::uint64_t size_ GUARDED_BY_CONTEXT(sequence_checker_) = 0; + OpenCallback pending_open_callback_ GUARDED_BY_CONTEXT(sequence_checker_); + ReadCallback pending_read_callback_ GUARDED_BY_CONTEXT(sequence_checker_); + base::WeakPtr<IpcFileOperations::RequestHandler> request_handler_; + mojo::AssociatedRemote<mojom::FileReader> remote_file_reader_ + GUARDED_BY_CONTEXT(sequence_checker_); + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<IpcReader> weak_ptr_factory_{this}; }; class IpcFileOperations::IpcWriter : public FileOperations::Writer { public: - IpcWriter(std::uint64_t file_id, base::WeakPtr<SharedState> shared_state); + explicit IpcWriter(base::WeakPtr<RequestHandler> request_handler); IpcWriter(const IpcWriter&) = delete; IpcWriter& operator=(const IpcWriter&) = delete; @@ -57,308 +128,309 @@ void Close(Callback callback) override; State state() const override; - private: - void OnOperationResult(Callback callback, ResultHandler::Result result); - void OnCloseResult(Callback callback, ResultHandler::Result result); + void OnChannelDisconnected(); - State state_ = kCreated; - std::uint64_t file_id_; - base::WeakPtr<SharedState> shared_state_; + base::WeakPtr<IpcWriter> GetWeakPtr() const; + + private: + void OnOpenResult(mojom::BeginFileWriteResultPtr result); + void OnOperationResult( + const absl::optional<::remoting::protocol::FileTransfer_Error>& error); + void OnCloseResult( + const absl::optional<::remoting::protocol::FileTransfer_Error>& error); + + State state_ GUARDED_BY_CONTEXT(sequence_checker_) = kCreated; + Callback pending_callback_ GUARDED_BY_CONTEXT(sequence_checker_); + base::WeakPtr<IpcFileOperations::RequestHandler> request_handler_; + mojo::AssociatedRemote<mojom::FileWriter> remote_file_writer_ + GUARDED_BY_CONTEXT(sequence_checker_); + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<IpcWriter> weak_ptr_factory_{this}; }; -IpcFileOperations::IpcFileOperations(base::WeakPtr<SharedState> shared_state) - : shared_state_(std::move(shared_state)) {} +IpcFileOperations::IpcFileOperations( + base::WeakPtr<RequestHandler> request_handler) + : request_handler_(std::move(request_handler)) {} IpcFileOperations::~IpcFileOperations() = default; std::unique_ptr<FileOperations::Reader> IpcFileOperations::CreateReader() { - return std::make_unique<IpcReader>(GetNextFileId(), shared_state_); + return std::make_unique<IpcReader>(request_handler_); } std::unique_ptr<FileOperations::Writer> IpcFileOperations::CreateWriter() { - return std::make_unique<IpcWriter>(GetNextFileId(), shared_state_); + return std::make_unique<IpcWriter>(request_handler_); } -std::uint64_t IpcFileOperations::GetNextFileId() { - // If shared_state_ is invalid, it means the connection is being torn down. - // Using a dummy id is okay in that case, as the IpcReader/IpcWriter won't - // actually do anything with an invalid shared_state_, and our call should be - // torn down soon, as well. - return shared_state_ ? shared_state_->next_file_id++ : 0; -} - -IpcFileOperations::SharedState::SharedState(RequestHandler* request_handler) - : request_handler(request_handler) {} - -void IpcFileOperations::SharedState::Abort(std::uint64_t file_id) { - request_handler->Cancel(file_id); - - protocol::FileTransfer_Error error = protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR); - - // Any given file_id is expected to have at most one callback at a time, so - // the order in which we search the maps is arbitrary. - - auto callback_iter = result_callbacks.find(file_id); - if (callback_iter != result_callbacks.end()) { - IpcFileOperations::ResultCallback callback = - std::move(callback_iter->second); - result_callbacks.erase(callback_iter); - std::move(callback).Run(error); - } - - auto info_callback_iter = info_result_callbacks.find(file_id); - if (info_callback_iter != info_result_callbacks.end()) { - IpcFileOperations::InfoResultCallback info_callback = - std::move(info_callback_iter->second); - info_result_callbacks.erase(info_callback_iter); - std::move(info_callback).Run(error); - } - - auto data_callback_iter = data_result_callbacks.find(file_id); - if (data_callback_iter != data_result_callbacks.end()) { - IpcFileOperations::DataResultCallback data_callback = - std::move(data_callback_iter->second); - data_result_callbacks.erase(data_callback_iter); - std::move(data_callback).Run(error); - } -} - -IpcFileOperations::SharedState::~SharedState() = default; - IpcFileOperationsFactory::IpcFileOperationsFactory( IpcFileOperations::RequestHandler* request_handler) - : shared_state_(request_handler) {} + : request_handler_weak_ptr_factory_(request_handler) {} IpcFileOperationsFactory::~IpcFileOperationsFactory() = default; std::unique_ptr<FileOperations> IpcFileOperationsFactory::CreateFileOperations() { return base::WrapUnique( - new IpcFileOperations(shared_state_.weak_ptr_factory.GetWeakPtr())); + new IpcFileOperations(request_handler_weak_ptr_factory_.GetWeakPtr())); } -void IpcFileOperationsFactory::OnResult(uint64_t file_id, Result result) { - auto callback_iter = shared_state_.result_callbacks.find(file_id); - if (callback_iter == shared_state_.result_callbacks.end()) { - shared_state_.Abort(file_id); - return; - } +IpcFileOperations::IpcReader::IpcReader( + base::WeakPtr<RequestHandler> request_handler) + : request_handler_(std::move(request_handler)) {} - IpcFileOperations::ResultCallback callback = std::move(callback_iter->second); - shared_state_.result_callbacks.erase(callback_iter); - std::move(callback).Run(std::move(result)); -} - -void IpcFileOperationsFactory::OnInfoResult(std::uint64_t file_id, - InfoResult result) { - auto callback_iter = shared_state_.info_result_callbacks.find(file_id); - if (callback_iter == shared_state_.info_result_callbacks.end()) { - shared_state_.Abort(file_id); - return; - } - - IpcFileOperations::InfoResultCallback callback = - std::move(callback_iter->second); - shared_state_.info_result_callbacks.erase(callback_iter); - std::move(callback).Run(std::move(result)); -} - -void IpcFileOperationsFactory::OnDataResult(std::uint64_t file_id, - DataResult result) { - auto callback_iter = shared_state_.data_result_callbacks.find(file_id); - if (callback_iter == shared_state_.data_result_callbacks.end()) { - shared_state_.Abort(file_id); - return; - } - - IpcFileOperations::DataResultCallback callback = - std::move(callback_iter->second); - shared_state_.data_result_callbacks.erase(callback_iter); - std::move(callback).Run(std::move(result)); -} - -IpcFileOperations::IpcReader::IpcReader(std::uint64_t file_id, - base::WeakPtr<SharedState> shared_state) - : file_id_(file_id), shared_state_(std::move(shared_state)) {} - -IpcFileOperations::IpcReader::~IpcReader() { - if (!shared_state_ || state_ == kCreated || state_ == kComplete || - state_ == kFailed) { - return; - } - - shared_state_->request_handler->Cancel(file_id_); - - // Destroy any pending callbacks. - auto info_callback_iter = shared_state_->info_result_callbacks.find(file_id_); - if (info_callback_iter != shared_state_->info_result_callbacks.end()) { - shared_state_->info_result_callbacks.erase(info_callback_iter); - } - - auto data_callback_iter = shared_state_->data_result_callbacks.find(file_id_); - if (data_callback_iter != shared_state_->data_result_callbacks.end()) { - shared_state_->data_result_callbacks.erase(data_callback_iter); - } -} +IpcFileOperations::IpcReader::~IpcReader() = default; void IpcFileOperations::IpcReader::Open(OpenCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(kCreated, state_); - if (!shared_state_) { + + if (!request_handler_) { + state_ = kFailed; + std::move(callback).Run(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); return; } state_ = kBusy; - // Unretained is sound because we destroy any pending callbacks in our - // destructor. - shared_state_->info_result_callbacks.emplace( - file_id_, base::BindOnce(&IpcReader::OnOpenResult, base::Unretained(this), - std::move(callback))); - shared_state_->request_handler->ReadFile(file_id_); + pending_open_callback_ = std::move(callback); + request_handler_->BeginFileRead( + base::BindOnce(&IpcReader::OnOpenResult, GetWeakPtr()), + base::BindOnce(&IpcReader::OnChannelDisconnected, GetWeakPtr())); } -void IpcFileOperations::IpcReader::ReadChunk( - std::size_t size, - FileOperations::Reader::ReadCallback callback) { - DCHECK_EQ(kReady, state_); - if (!shared_state_) { +void IpcFileOperations::IpcReader::ReadChunk(std::size_t size, + ReadCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (state_ != kReady || !remote_file_reader_.is_connected()) { + state_ = kFailed; + std::move(callback).Run(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); return; } state_ = kBusy; - // Unretained is sound because we destroy any pending callbacks in our - // destructor. - shared_state_->data_result_callbacks.emplace( - file_id_, base::BindOnce(&IpcReader::OnReadResult, base::Unretained(this), - std::move(callback))); - shared_state_->request_handler->ReadChunk(file_id_, size); + pending_read_callback_ = std::move(callback); + // Unretained is sound because the remote is owned by this instance and will + // be destroyed at the same time which will clear any callbacks. + remote_file_reader_->ReadChunk( + size, base::BindOnce(&IpcReader::OnReadResult, base::Unretained(this))); } const base::FilePath& IpcFileOperations::IpcReader::filename() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return filename_; } std::uint64_t IpcFileOperations::IpcReader::size() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return size_; } FileOperations::State IpcFileOperations::IpcReader::state() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return state_; } +void IpcFileOperations::IpcReader::OnChannelDisconnected() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + state_ = kFailed; + + if (pending_open_callback_) { + std::move(pending_open_callback_) + .Run(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); + } else if (pending_read_callback_) { + std::move(pending_read_callback_) + .Run(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); + } +} + +base::WeakPtr<IpcFileOperations::IpcReader> +IpcFileOperations::IpcReader::GetWeakPtr() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return weak_ptr_factory_.GetWeakPtr(); +} + void IpcFileOperations::IpcReader::OnOpenResult( - OpenCallback callback, - ResultHandler::InfoResult result) { - if (!result) { + mojom::BeginFileReadResultPtr result) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (result->is_error()) { state_ = kFailed; - std::move(callback).Run(result.error()); + std::move(pending_open_callback_).Run(result->get_error()); return; } state_ = kReady; - filename_ = std::move(std::get<0>(*result)); - size_ = std::move(std::get<1>(*result)); - std::move(callback).Run(kSuccessTag); + auto& success_ptr = result->get_success(); + filename_ = std::move(success_ptr->filename); + size_ = success_ptr->size; + + remote_file_reader_.Bind(std::move(success_ptr->file_reader)); + // base::Unretained is sound because this instance owns |remote_file_reader_| + // and the handler will not run after it is destroyed. + remote_file_reader_.set_disconnect_handler(base::BindOnce( + &IpcReader::OnChannelDisconnected, base::Unretained(this))); + + std::move(pending_open_callback_).Run(kSuccessTag); } void IpcFileOperations::IpcReader::OnReadResult( - ReadCallback callback, - ResultHandler::DataResult result) { + const protocol::FileTransferResult<std::vector<std::uint8_t>>& result) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (result) { state_ = result->size() == 0 ? kComplete : kReady; } else { state_ = kFailed; } - std::move(callback).Run(std::move(result)); -} -IpcFileOperations::IpcWriter::IpcWriter(std::uint64_t file_id, - base::WeakPtr<SharedState> shared_state) - : file_id_(file_id), shared_state_(std::move(shared_state)) {} - -IpcFileOperations::IpcWriter::~IpcWriter() { - if (!shared_state_ || state_ == kCreated || state_ == kComplete || - state_ == kFailed) { - return; + if (state_ != kReady) { + // Don't need the remote if we're done or an error occurred. + remote_file_reader_.reset(); } - shared_state_->request_handler->Cancel(file_id_); - - // Destroy any pending callbacks. - auto callback_iter = shared_state_->result_callbacks.find(file_id_); - if (callback_iter != shared_state_->result_callbacks.end()) { - shared_state_->result_callbacks.erase(callback_iter); - } + std::move(pending_read_callback_).Run(std::move(result)); } +IpcFileOperations::IpcWriter::IpcWriter( + base::WeakPtr<RequestHandler> request_handler) + : request_handler_(std::move(request_handler)) {} + +IpcFileOperations::IpcWriter::~IpcWriter() = default; + void IpcFileOperations::IpcWriter::Open(const base::FilePath& filename, Callback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(kCreated, state_); - if (!shared_state_) { + + if (!request_handler_) { + state_ = kFailed; + std::move(callback).Run(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); return; } state_ = kBusy; - shared_state_->result_callbacks.emplace( - file_id_, base::BindOnce(&IpcWriter::OnOperationResult, - base::Unretained(this), std::move(callback))); - shared_state_->request_handler->WriteFile(file_id_, filename); + pending_callback_ = std::move(callback); + request_handler_->BeginFileWrite( + filename, base::BindOnce(&IpcWriter::OnOpenResult, GetWeakPtr()), + base::BindOnce(&IpcWriter::OnChannelDisconnected, GetWeakPtr())); } void IpcFileOperations::IpcWriter::WriteChunk(std::vector<std::uint8_t> data, Callback callback) { - DCHECK_EQ(kReady, state_); - if (!shared_state_) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (state_ != kReady) { + state_ = kFailed; + std::move(callback).Run(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); return; } state_ = kBusy; - // Unretained is sound because IpcWriter will destroy any outstanding callback - // in its destructor. - shared_state_->result_callbacks.emplace( - file_id_, base::BindOnce(&IpcWriter::OnOperationResult, - base::Unretained(this), std::move(callback))); - shared_state_->request_handler->WriteChunk(file_id_, std::move(data)); + pending_callback_ = std::move(callback); + // Unretained is sound because the remote is owned by this instance and will + // be destroyed at the same time which will clear this callback. + remote_file_writer_->WriteChunk( + std::move(data), + base::BindOnce(&IpcWriter::OnOperationResult, base::Unretained(this))); } void IpcFileOperations::IpcWriter::Close(Callback callback) { - DCHECK_EQ(kReady, state_); - if (!shared_state_) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (state_ != kReady) { + state_ = kFailed; + std::move(callback).Run(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); return; } state_ = kBusy; - shared_state_->request_handler->Close(file_id_); - // Unretained is sound because IpcWriter will destroy any outstanding callback - // in its destructor. - shared_state_->result_callbacks.emplace( - file_id_, base::BindOnce(&IpcWriter::OnCloseResult, - base::Unretained(this), std::move(callback))); + pending_callback_ = std::move(callback); + // Unretained is sound because the remote is owned by this instance and will + // be destroyed at the same time which will clear this callback. + remote_file_writer_->CloseFile( + base::BindOnce(&IpcWriter::OnCloseResult, base::Unretained(this))); } FileOperations::State IpcFileOperations::IpcWriter::state() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return state_; } -void IpcFileOperations::IpcWriter::OnOperationResult( - Callback callback, - ResultHandler::Result result) { - if (result) { - state_ = kReady; - } else { - state_ = kFailed; +void IpcFileOperations::IpcWriter::OnChannelDisconnected() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + state_ = kFailed; + + if (pending_callback_) { + std::move(pending_callback_) + .Run(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); } - std::move(callback).Run(std::move(result)); } -void IpcFileOperations::IpcWriter::OnCloseResult(Callback callback, - ResultHandler::Result result) { - if (result) { - state_ = kComplete; - } else { +base::WeakPtr<IpcFileOperations::IpcWriter> +IpcFileOperations::IpcWriter::GetWeakPtr() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return weak_ptr_factory_.GetWeakPtr(); +} + +void IpcFileOperations::IpcWriter::OnOpenResult( + mojom::BeginFileWriteResultPtr result) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (result->is_error()) { state_ = kFailed; + std::move(pending_callback_).Run(result->get_error()); + return; } - std::move(callback).Run(std::move(result)); + + state_ = kReady; + auto& success_ptr = result->get_success(); + remote_file_writer_.Bind(std::move(success_ptr->file_writer)); + // base::Unretained is sound because this instance owns |remote_file_writer_| + // and the handler will not run after it is destroyed. + remote_file_writer_.set_disconnect_handler(base::BindOnce( + &IpcWriter::OnChannelDisconnected, base::Unretained(this))); + + std::move(pending_callback_).Run(kSuccessTag); +} + +void IpcFileOperations::IpcWriter::OnOperationResult( + const absl::optional<::remoting::protocol::FileTransfer_Error>& error) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (error) { + state_ = kFailed; + std::move(pending_callback_).Run(std::move(*error)); + remote_file_writer_.reset(); + return; + } + + state_ = kReady; + std::move(pending_callback_).Run({kSuccessTag}); +} + +void IpcFileOperations::IpcWriter::OnCloseResult( + const absl::optional<::remoting::protocol::FileTransfer_Error>& error) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // We're done with the remote regardless of the result. + remote_file_writer_.reset(); + + if (error) { + state_ = kFailed; + std::move(pending_callback_).Run(std::move(*error)); + } else { + state_ = kComplete; + std::move(pending_callback_).Run({kSuccessTag}); + } } } // namespace remoting
diff --git a/remoting/host/file_transfer/ipc_file_operations.h b/remoting/host/file_transfer/ipc_file_operations.h index 09d848c..5f2c4e4 100644 --- a/remoting/host/file_transfer/ipc_file_operations.h +++ b/remoting/host/file_transfer/ipc_file_operations.h
@@ -5,54 +5,37 @@ #ifndef REMOTING_HOST_FILE_TRANSFER_IPC_FILE_OPERATIONS_H_ #define REMOTING_HOST_FILE_TRANSFER_IPC_FILE_OPERATIONS_H_ -#include <cstdint> -#include <tuple> -#include <vector> +#include <memory> -#include "base/containers/flat_map.h" -#include "base/memory/raw_ptr.h" +#include "base/callback.h" +#include "base/files/file_path.h" #include "base/memory/weak_ptr.h" #include "remoting/host/file_transfer/file_operations.h" +#include "remoting/host/mojom/desktop_session.mojom.h" #include "remoting/protocol/file_transfer_helpers.h" namespace remoting { -// Implementation of FileOperations that translates the interface into easy-to- -// serialize requests that can be forwarded over an IPC channel. -// IpcFileOperationsRequestHandlerImpl can be used on the remote end to -// perform the requested operations. +// Implementation of FileOperations that forwards a file read or write request +// over a Mojo channel. class IpcFileOperations : public FileOperations { public: - // Handles requests generated by IpcFileOperations instances by either - // performing the requested operations directly or forwarding them to another - // process. + using BeginFileReadCallback = + mojom::DesktopSessionControl::BeginFileReadCallback; + using BeginFileWriteCallback = + mojom::DesktopSessionControl::BeginFileWriteCallback; + + // Handles requests from an IpcFileOperations instance by forwarding them to + // another process via Mojo IPC. class RequestHandler { public: virtual ~RequestHandler() = default; - virtual void ReadFile(std::uint64_t file_id) = 0; - virtual void ReadChunk(std::uint64_t file_id, std::uint64_t size) = 0; - virtual void WriteFile(std::uint64_t file_id, - const base::FilePath& filename) = 0; - virtual void WriteChunk(std::uint64_t file_id, - std::vector<std::uint8_t> data) = 0; - virtual void Close(std::uint64_t file_id) = 0; - virtual void Cancel(std::uint64_t file_id) = 0; - }; - - // Handles responses to file operations requests. - class ResultHandler { - public: - using Result = protocol::FileTransferResult<absl::monostate>; - using InfoResult = - protocol::FileTransferResult<std::tuple<base::FilePath, uint64_t>>; - using DataResult = - remoting::protocol::FileTransferResult<std::vector<std::uint8_t>>; - - virtual ~ResultHandler() = default; - virtual void OnResult(std::uint64_t file_id, Result result) = 0; - virtual void OnInfoResult(std::uint64_t file_id, InfoResult result) = 0; - virtual void OnDataResult(std::uint64_t file_id, DataResult result) = 0; + virtual void BeginFileRead(BeginFileReadCallback callback, + base::OnceClosure on_disconnect) = 0; + virtual void BeginFileWrite(const base::FilePath& file_path, + BeginFileWriteCallback callback, + base::OnceClosure on_disconnect) = 0; }; IpcFileOperations(const IpcFileOperations&) = delete; @@ -65,51 +48,12 @@ std::unique_ptr<Writer> CreateWriter() override; private: - using ResultCallback = base::OnceCallback<void(ResultHandler::Result)>; - using InfoResultCallback = - base::OnceCallback<void(ResultHandler::InfoResult)>; - using DataResultCallback = - base::OnceCallback<void(ResultHandler::DataResult)>; - class IpcReader; class IpcWriter; - struct SharedState { - public: - explicit SharedState(RequestHandler* request_handler); + explicit IpcFileOperations(base::WeakPtr<RequestHandler> request_handler); - SharedState(const SharedState&) = delete; - SharedState& operator=(const SharedState&) = delete; - - ~SharedState(); - - // Send a Cancel request for |file_id| and provide an error response to any - // pending response callbacks for it. Called in the event of an unexpected - // message from the Desktop process. - void Abort(std::uint64_t file_id); - - // File ID to use for the next file opened. - std::uint64_t next_file_id = 0; - - // Pending callbacks awaiting responses from the desktop process, keyed by - // the file_id of the waiting Reader or Writer. - base::flat_map<std::uint64_t, ResultCallback> result_callbacks; - base::flat_map<std::uint64_t, InfoResultCallback> info_result_callbacks; - base::flat_map<std::uint64_t, DataResultCallback> data_result_callbacks; - - // The associated RequestHandler. - raw_ptr<RequestHandler> request_handler; - - base::WeakPtrFactory<SharedState> weak_ptr_factory{this}; - }; - - explicit IpcFileOperations(base::WeakPtr<SharedState> shared_state); - - std::uint64_t GetNextFileId(); - - // Contains shared state used by all instances tied to a given - // RequestHandler. - base::WeakPtr<SharedState> shared_state_; + base::WeakPtr<RequestHandler> request_handler_; friend class IpcFileOperationsFactory; }; @@ -117,27 +61,22 @@ // Creates IpcFileOperations instances for a given RequestHandler. All // IpcFileOperations instances for the RequestHandler must be created through // the same IpcFileOperationsFactory. -class IpcFileOperationsFactory : public IpcFileOperations::ResultHandler { +class IpcFileOperationsFactory { public: - // |request_handler| must be valid for the entire lifetime of - // IpcFileOperationsFactory, and must only be used to construct a single - // IpcFileOperationsFactory to avoid file ID conflicts. - IpcFileOperationsFactory(IpcFileOperations::RequestHandler* request_handler); + // |request_handler| must outlive the IpcFileOperationsFactory instance. + explicit IpcFileOperationsFactory( + IpcFileOperations::RequestHandler* request_handler); IpcFileOperationsFactory(const IpcFileOperationsFactory&) = delete; IpcFileOperationsFactory& operator=(const IpcFileOperationsFactory&) = delete; - ~IpcFileOperationsFactory() override; + ~IpcFileOperationsFactory(); std::unique_ptr<FileOperations> CreateFileOperations(); - // ResultHandler implementation. - void OnResult(std::uint64_t file_id, Result result) override; - void OnInfoResult(std::uint64_t file_id, InfoResult result) override; - void OnDataResult(std::uint64_t file_id, DataResult result) override; - private: - IpcFileOperations::SharedState shared_state_; + base::WeakPtrFactory<IpcFileOperations::RequestHandler> + request_handler_weak_ptr_factory_; }; } // namespace remoting
diff --git a/remoting/host/file_transfer/ipc_file_operations_unittest.cc b/remoting/host/file_transfer/ipc_file_operations_unittest.cc index 4a3ec29..31df7db 100644 --- a/remoting/host/file_transfer/ipc_file_operations_unittest.cc +++ b/remoting/host/file_transfer/ipc_file_operations_unittest.cc
@@ -12,97 +12,249 @@ #include "base/bind.h" #include "base/callback_helpers.h" -#include "base/containers/queue.h" +#include "base/callback_list.h" #include "base/files/file_util.h" #include "base/path_service.h" +#include "base/test/bind.h" #include "base/test/scoped_path_override.h" #include "base/test/task_environment.h" #include "remoting/host/file_transfer/fake_file_chooser.h" #include "remoting/host/file_transfer/local_file_operations.h" #include "remoting/host/file_transfer/session_file_operations_handler.h" #include "remoting/host/file_transfer/test_byte_vector_utils.h" +#include "remoting/host/mojom/desktop_session.mojom.h" +#include "remoting/proto/file_transfer.pb.h" +#include "remoting/protocol/file_transfer_helpers.h" #include "testing/gtest/include/gtest/gtest.h" namespace remoting { +// Forward declare to allow for friending by the fake test classes. +class IpcFileOperationsTest; + namespace { -// BindOnce disallows binding lambdas with captures. This is reasonable in -// production code, as it requires one to either explicitly pass owned objects -// or pointers using Owned, Unretained, et cetera. This helps to avoid use after -// free bugs in async code. In test code, though, where the lambda is -// immediately invoked in the test method using, e.g., RunUntilIdle, the ability -// to capture can make the code much easier to read and write. -template <typename T> -auto BindLambda(T lambda) { - return base::BindOnce(&T::operator(), - base::Owned(new auto(std::move(lambda)))); -} - -class IpcTestBridge : public IpcFileOperations::RequestHandler, - public IpcFileOperations::ResultHandler, - public FileOperations { +// A simplified DesktopSessionProxy implementation for file transfer testing. +class FakeDesktopSessionProxy : public IpcFileOperations::RequestHandler { public: - explicit IpcTestBridge( - scoped_refptr<base::SequencedTaskRunner> ui_task_runner) - : ipc_file_operations_factory_(this), - session_file_operations_handler_( - this, - std::make_unique<LocalFileOperations>(std::move(ui_task_runner))), - file_operations_(ipc_file_operations_factory_.CreateFileOperations()) {} + FakeDesktopSessionProxy() = default; - IpcTestBridge(const IpcTestBridge&) = delete; - IpcTestBridge& operator=(const IpcTestBridge&) = delete; + FakeDesktopSessionProxy(const FakeDesktopSessionProxy&) = delete; + FakeDesktopSessionProxy& operator=(const FakeDesktopSessionProxy&) = delete; - ~IpcTestBridge() override = default; + ~FakeDesktopSessionProxy() override = default; // IpcFileOperations::RequestHandler implementation. - void ReadFile(std::uint64_t file_id) override { - session_file_operations_handler_.ReadFile(file_id); - } - void ReadChunk(std::uint64_t file_id, std::uint64_t size) override { - session_file_operations_handler_.ReadChunk(file_id, size); - } - void WriteFile(std::uint64_t file_id, - const base::FilePath& filename) override { - session_file_operations_handler_.WriteFile(file_id, filename); - } - void WriteChunk(std::uint64_t file_id, - std::vector<std::uint8_t> data) override { - session_file_operations_handler_.WriteChunk(file_id, std::move(data)); - } - void Close(std::uint64_t file_id) override { - session_file_operations_handler_.Close(file_id); - } - void Cancel(std::uint64_t file_id) override { - session_file_operations_handler_.Cancel(file_id); - } + void BeginFileRead(IpcFileOperations::BeginFileReadCallback callback, + base::OnceClosure on_disconnect) override; + void BeginFileWrite(const base::FilePath& file_path, + IpcFileOperations::BeginFileWriteCallback callback, + base::OnceClosure on_disconnect) override; - // ResultHandler implementation. - void OnResult(std::uint64_t file_id, Result result) override { - ipc_file_operations_factory_.OnResult(file_id, std::move(result)); - } - void OnInfoResult(std::uint64_t file_id, InfoResult result) override { - ipc_file_operations_factory_.OnInfoResult(file_id, std::move(result)); - } - void OnDataResult(std::uint64_t file_id, DataResult result) override { - ipc_file_operations_factory_.OnDataResult(file_id, std::move(result)); - } + // Binds the pending DesktopSessionControl remote to |remote_|. + void Bind(mojo::PendingAssociatedRemote<mojom::DesktopSessionControl> remote); - // FileOperations implementation. - std::unique_ptr<Reader> CreateReader() override { - return file_operations_->CreateReader(); - } - std::unique_ptr<Writer> CreateWriter() override { - return file_operations_->CreateWriter(); - } + // When set, this instance will return |error| on the next IPC request. + void SetErrorForNextRequest(protocol::FileTransfer_Error error); + + // Runs any registered disconnect handlers. + void TriggerDisconnectHandlers(); private: - IpcFileOperationsFactory ipc_file_operations_factory_; - SessionFileOperationsHandler session_file_operations_handler_; - std::unique_ptr<FileOperations> file_operations_; + // This member mirrors the handler in the real DesktopSessionProxy class. + base::OnceClosureList disconnect_handlers_; + + // Holds disconnect handler subscriptions until they are either triggered or + // destroyed along with this test instance. + std::vector<base::CallbackListSubscription> disconnect_subscriptions_; + + // If set, this will be returned on the next file transfer operation request. + absl::optional<protocol::FileTransfer_Error> request_error_; + + // Remote end of the DesktopSessionControl channel, the receiver is owned by + // a FakeDesktopSessionAgent instance. + mojo::AssociatedRemote<mojom::DesktopSessionControl> remote_; }; +void FakeDesktopSessionProxy::BeginFileRead( + IpcFileOperations::BeginFileReadCallback callback, + base::OnceClosure on_disconnect) { + if (request_error_) { + std::move(callback).Run( + mojom::BeginFileReadResult::NewError(std::move(*request_error_))); + return; + } + + disconnect_subscriptions_.emplace_back( + disconnect_handlers_.Add(std::move(on_disconnect))); + remote_->BeginFileRead(std::move(callback)); +} + +void FakeDesktopSessionProxy::BeginFileWrite( + const base::FilePath& file_path, + IpcFileOperations::BeginFileWriteCallback callback, + base::OnceClosure on_disconnect) { + if (request_error_) { + std::move(callback).Run( + mojom::BeginFileWriteResult::NewError(std::move(*request_error_))); + return; + } + disconnect_subscriptions_.emplace_back( + disconnect_handlers_.Add(std::move(on_disconnect))); + remote_->BeginFileWrite(file_path, std::move(callback)); +} + +void FakeDesktopSessionProxy::Bind( + mojo::PendingAssociatedRemote<mojom::DesktopSessionControl> remote) { + remote_.Bind(std::move(remote)); + remote_.set_disconnect_handler( + base::BindOnce(&FakeDesktopSessionProxy::TriggerDisconnectHandlers, + base::Unretained(this))); +} + +void FakeDesktopSessionProxy::SetErrorForNextRequest( + protocol::FileTransfer_Error error) { + request_error_ = std::move(error); +} + +void FakeDesktopSessionProxy::TriggerDisconnectHandlers() { + disconnect_handlers_.Notify(); +} + +// A simplified DesktopSessionAgent implementation for file transfer testing. +class FakeDesktopSessionAgent : public mojom::DesktopSessionControl { + public: + explicit FakeDesktopSessionAgent( + scoped_refptr<base::SequencedTaskRunner> ui_task_runner); + + FakeDesktopSessionAgent(const FakeDesktopSessionAgent&) = delete; + FakeDesktopSessionAgent& operator=(const FakeDesktopSessionAgent&) = delete; + + ~FakeDesktopSessionAgent() override = default; + + // mojom::DesktopSessionControl implementation. + void CaptureFrame() override; + void SelectSource(int id) override; + void SetScreenResolution(const ScreenResolution& resolution) override; + void LockWorkstation() override; + void InjectSendAttentionSequence() override; + void InjectClipboardEvent(const protocol::ClipboardEvent& event) override; + void InjectKeyEvent(const protocol::KeyEvent& event) override; + void InjectMouseEvent(const protocol::MouseEvent& event) override; + void InjectTextEvent(const protocol::TextEvent& event) override; + void InjectTouchEvent(const protocol::TouchEvent& event) override; + void SetUpUrlForwarder() override; + void SignalWebAuthnExtension() override; + void BeginFileRead(BeginFileReadCallback callback) override; + void BeginFileWrite(const base::FilePath& file_path, + BeginFileWriteCallback callback) override; + + // Binds the pending DesktopSessionControl receiver to |receiver_|. + void Bind( + mojo::PendingAssociatedReceiver<mojom::DesktopSessionControl> receiver); + + // When set, this instance will return |error| for its next IPC response. + void SetErrorForNextResponse(protocol::FileTransfer_Error error); + + // Disconnect |receiver_| after the next request is received. This is used to + // simulate an error while the FakeDesktopSessionProxy is waiting for a reply. + void DisconnectReceiverOnNextRequest(); + + private: + friend class ::remoting::IpcFileOperationsTest; + + // If true, the agent will disconnect |receiver_| on the next IPC request. + bool disconnect_on_next_request_ = false; + + // If set, |response_error_| will be returned in the next IPC response. + absl::optional<protocol::FileTransfer_Error> response_error_; + + // Handles file transfer requests over Mojo and manages receiver lifetimes. + SessionFileOperationsHandler session_file_operations_handler_; + + // Receiver end of the DesktopSessionControl channel, the remote is owned by a + // FakeDesktopSessionProxy instance. + mojo::AssociatedReceiver<mojom::DesktopSessionControl> receiver_{this}; +}; + +FakeDesktopSessionAgent::FakeDesktopSessionAgent( + scoped_refptr<base::SequencedTaskRunner> ui_task_runner) + : session_file_operations_handler_( + std::make_unique<LocalFileOperations>(std::move(ui_task_runner))) {} + +void FakeDesktopSessionAgent::CaptureFrame() {} + +void FakeDesktopSessionAgent::SelectSource(int id) {} + +void FakeDesktopSessionAgent::SetScreenResolution( + const ScreenResolution& resolution) {} + +void FakeDesktopSessionAgent::LockWorkstation() {} + +void FakeDesktopSessionAgent::InjectSendAttentionSequence() {} + +void FakeDesktopSessionAgent::InjectClipboardEvent( + const protocol::ClipboardEvent& event) {} + +void FakeDesktopSessionAgent::InjectKeyEvent(const protocol::KeyEvent& event) {} + +void FakeDesktopSessionAgent::InjectMouseEvent( + const protocol::MouseEvent& event) {} + +void FakeDesktopSessionAgent::InjectTextEvent( + const protocol::TextEvent& event) {} + +void FakeDesktopSessionAgent::InjectTouchEvent( + const protocol::TouchEvent& event) {} + +void FakeDesktopSessionAgent::SetUpUrlForwarder() {} + +void FakeDesktopSessionAgent::SignalWebAuthnExtension() {} + +void FakeDesktopSessionAgent::BeginFileRead(BeginFileReadCallback callback) { + if (disconnect_on_next_request_) { + disconnect_on_next_request_ = false; + receiver_.reset(); + return; + } + if (response_error_) { + std::move(callback).Run( + mojom::BeginFileReadResult::NewError(std::move(*response_error_))); + return; + } + session_file_operations_handler_.BeginFileRead(std::move(callback)); +} + +void FakeDesktopSessionAgent::BeginFileWrite(const base::FilePath& file_path, + BeginFileWriteCallback callback) { + if (disconnect_on_next_request_) { + disconnect_on_next_request_ = false; + receiver_.reset(); + return; + } + if (response_error_) { + std::move(callback).Run( + mojom::BeginFileWriteResult::NewError(std::move(*response_error_))); + return; + } + session_file_operations_handler_.BeginFileWrite(file_path, + std::move(callback)); +} + +void FakeDesktopSessionAgent::Bind( + mojo::PendingAssociatedReceiver<mojom::DesktopSessionControl> receiver) { + receiver_.Bind(std::move(receiver)); +} + +void FakeDesktopSessionAgent::SetErrorForNextResponse( + protocol::FileTransfer_Error error) { + response_error_ = std::move(error); +} + +void FakeDesktopSessionAgent::DisconnectReceiverOnNextRequest() { + disconnect_on_next_request_ = true; +} + } // namespace class IpcFileOperationsTest : public testing::Test { @@ -114,6 +266,8 @@ ~IpcFileOperationsTest() override; + void SetUp() override; + protected: const base::FilePath kTestFilename = base::FilePath::FromUTF8Unsafe("test-file.txt"); @@ -126,22 +280,57 @@ base::FilePath TestDir(); + size_t session_file_reader_count() const { + return fake_desktop_session_agent_.session_file_operations_handler_ + .file_readers_.size(); + } + + size_t session_file_writer_count() const { + return fake_desktop_session_agent_.session_file_operations_handler_ + .file_writers_.size(); + } + + // Destroys existing MojoFileReader and MojoFileWriter instances. This will + // also trigger any disconnect handlers set on the Mojo remote owned by the + // corresponding IpcFileReader / IpcFileWriter instances. + void clear_session_file_receivers() { + fake_desktop_session_agent_.session_file_operations_handler_.file_readers_ + .Clear(); + fake_desktop_session_agent_.session_file_operations_handler_.file_writers_ + .Clear(); + } + // Points DIR_USER_DESKTOP at a scoped temporary directory. - base::ScopedPathOverride scoped_path_override_; - base::test::TaskEnvironment task_environment_; - std::unique_ptr<FileOperations> file_operations_; + base::ScopedPathOverride scoped_path_override_{base::DIR_USER_DESKTOP}; + base::test::TaskEnvironment task_environment_{ + base::test::TaskEnvironment::MainThreadType::DEFAULT, + base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED}; + + FakeDesktopSessionProxy fake_desktop_session_proxy_; + FakeDesktopSessionAgent fake_desktop_session_agent_{ + task_environment_.GetMainThreadTaskRunner()}; + + IpcFileOperationsFactory ipc_file_operations_factory_{ + &fake_desktop_session_proxy_}; + + std::unique_ptr<FileOperations> file_operations_{ + ipc_file_operations_factory_.CreateFileOperations()}; }; -IpcFileOperationsTest::IpcFileOperationsTest() - : scoped_path_override_(base::DIR_USER_DESKTOP), - task_environment_( - base::test::TaskEnvironment::MainThreadType::DEFAULT, - base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED), - file_operations_(std::make_unique<IpcTestBridge>( - task_environment_.GetMainThreadTaskRunner())) {} +IpcFileOperationsTest::IpcFileOperationsTest() = default; IpcFileOperationsTest::~IpcFileOperationsTest() = default; +void IpcFileOperationsTest::SetUp() { + // Connect the fake proxy and agent using a pair of associated endpoints. The + // real classes would use a pre-existing IPC channel but we don't need this + // for our testing. + mojo::AssociatedRemote<mojom::DesktopSessionControl> remote; + fake_desktop_session_agent_.Bind( + remote.BindNewEndpointAndPassDedicatedReceiver()); + fake_desktop_session_proxy_.Bind(remote.Unbind()); +} + base::FilePath IpcFileOperationsTest::TestDir() { base::FilePath result; EXPECT_TRUE(base::PathService::Get(base::DIR_USER_DESKTOP, &result)); @@ -155,22 +344,23 @@ ASSERT_EQ(FileOperations::kCreated, writer->state()); absl::optional<FileOperations::Writer::Result> open_result; - writer->Open(kTestFilename, - BindLambda([&](FileOperations::Writer::Result result) { - open_result = std::move(result); - })); + writer->Open(kTestFilename, base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + open_result = std::move(result); + })); ASSERT_EQ(FileOperations::kBusy, writer->state()); task_environment_.RunUntilIdle(); ASSERT_EQ(FileOperations::kReady, writer->state()); ASSERT_TRUE(open_result); ASSERT_TRUE(*open_result); + ASSERT_EQ(session_file_writer_count(), size_t{1}); for (const auto& chunk : {kTestDataOne, kTestDataTwo, kTestDataThree}) { absl::optional<FileOperations::Writer::Result> write_result; - writer->WriteChunk(chunk, - BindLambda([&](FileOperations::Writer::Result result) { - write_result = std::move(result); - })); + writer->WriteChunk(chunk, base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + write_result = std::move(result); + })); ASSERT_EQ(FileOperations::kBusy, writer->state()); task_environment_.RunUntilIdle(); ASSERT_EQ(FileOperations::kReady, writer->state()); @@ -179,12 +369,15 @@ } absl::optional<FileOperations::Writer::Result> close_result; - writer->Close(BindLambda([&](FileOperations::Writer::Result result) { - close_result = std::move(result); - })); + writer->Close( + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + close_result = std::move(result); + })); ASSERT_EQ(FileOperations::kBusy, writer->state()); task_environment_.RunUntilIdle(); EXPECT_EQ(FileOperations::kComplete, writer->state()); + // Verify the MojoIpcWriter instance was released. + ASSERT_EQ(session_file_writer_count(), size_t{0}); std::string actual_file_data; ASSERT_TRUE(base::ReadFileToString(TestDir().Append(kTestFilename), @@ -194,32 +387,38 @@ } // Verifies that dropping early cancels the remote writer. -TEST_F(IpcFileOperationsTest, DroppingCancelsRemote) { +TEST_F(IpcFileOperationsTest, DroppingCancelsRemoteWriter) { std::unique_ptr<FileOperations::Writer> writer = file_operations_->CreateWriter(); absl::optional<FileOperations::Writer::Result> open_result; - writer->Open(kTestFilename, - BindLambda([&](FileOperations::Writer::Result result) { - open_result = std::move(result); - })); + writer->Open(kTestFilename, base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + open_result = std::move(result); + })); task_environment_.RunUntilIdle(); - ASSERT_TRUE(open_result && *open_result); + ASSERT_TRUE(open_result); + ASSERT_TRUE(*open_result); + ASSERT_EQ(session_file_writer_count(), size_t{1}); for (const auto& chunk : {kTestDataOne, kTestDataTwo, kTestDataThree}) { absl::optional<FileOperations::Writer::Result> write_result; - writer->WriteChunk(chunk, - BindLambda([&](FileOperations::Writer::Result result) { - write_result = std::move(result); - })); + writer->WriteChunk(chunk, base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + write_result = std::move(result); + })); task_environment_.RunUntilIdle(); - ASSERT_TRUE(write_result && *write_result); + ASSERT_TRUE(write_result); + ASSERT_TRUE(*write_result); } writer.reset(); task_environment_.RunUntilIdle(); EXPECT_TRUE(base::IsDirectoryEmpty(TestDir())); + + // Verify the MojoIpcWriter instance was released. + ASSERT_EQ(session_file_writer_count(), size_t{0}); } // Verifies that dropping works while an operation is pending. @@ -228,18 +427,21 @@ file_operations_->CreateWriter(); absl::optional<FileOperations::Writer::Result> open_result; - writer->Open(kTestFilename, - BindLambda([&](FileOperations::Writer::Result result) { - open_result = std::move(result); - })); + writer->Open(kTestFilename, base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + open_result = std::move(result); + })); task_environment_.RunUntilIdle(); - ASSERT_TRUE(open_result && *open_result); + ASSERT_TRUE(open_result); + ASSERT_TRUE(*open_result); + ASSERT_EQ(session_file_writer_count(), size_t{1}); absl::optional<FileOperations::Writer::Result> write_result; - writer->WriteChunk(kTestDataOne, - BindLambda([&](FileOperations::Writer::Result result) { - write_result = std::move(result); - })); + writer->WriteChunk( + kTestDataOne, + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + write_result = std::move(result); + })); EXPECT_EQ(FileOperations::kBusy, writer->state()); writer.reset(); @@ -247,6 +449,9 @@ EXPECT_FALSE(write_result); EXPECT_TRUE(base::IsDirectoryEmpty(TestDir())); + + // Verify the MojoIpcWriter instance was released. + ASSERT_EQ(session_file_writer_count(), size_t{0}); } // Verifies that a file can be successfully read in three chunks. @@ -265,22 +470,24 @@ FakeFileChooser::SetResult(path); absl::optional<FileOperations::Reader::OpenResult> open_result; - reader->Open(BindLambda([&](FileOperations::Reader::OpenResult result) { - open_result = std::move(result); - })); + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + open_result = std::move(result); + })); ASSERT_EQ(FileOperations::kBusy, reader->state()); task_environment_.RunUntilIdle(); EXPECT_EQ(FileOperations::kReady, reader->state()); ASSERT_TRUE(open_result); ASSERT_TRUE(*open_result); + ASSERT_EQ(session_file_reader_count(), size_t{1}); for (const auto& chunk : {kTestDataOne, kTestDataTwo, kTestDataThree}) { absl::optional<FileOperations::Reader::ReadResult> read_result; - reader->ReadChunk( - chunk.size(), - BindLambda([&](FileOperations::Reader::ReadResult result) { - read_result = std::move(result); - })); + reader->ReadChunk(chunk.size(), + base::BindLambdaForTesting( + [&](FileOperations::Reader::ReadResult result) { + read_result = std::move(result); + })); ASSERT_EQ(FileOperations::kBusy, reader->state()); task_environment_.RunUntilIdle(); ASSERT_EQ(FileOperations::kReady, reader->state()); @@ -288,6 +495,13 @@ ASSERT_TRUE(*read_result); EXPECT_EQ(chunk, **read_result); } + ASSERT_EQ(session_file_reader_count(), size_t{1}); + + reader.reset(); + task_environment_.RunUntilIdle(); + + // Verify the MojoIpcReader instance was released. + ASSERT_EQ(session_file_reader_count(), size_t{0}); } // Verifies proper EOF handling. @@ -306,35 +520,44 @@ FakeFileChooser::SetResult(path); absl::optional<FileOperations::Reader::OpenResult> open_result; - reader->Open(BindLambda([&](FileOperations::Reader::OpenResult result) { - open_result = std::move(result); - })); + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + open_result = std::move(result); + })); task_environment_.RunUntilIdle(); - ASSERT_TRUE(open_result && *open_result); + ASSERT_TRUE(open_result); + ASSERT_TRUE(*open_result); + ASSERT_EQ(session_file_reader_count(), size_t{1}); absl::optional<FileOperations::Reader::ReadResult> read_result; reader->ReadChunk( contents.size() + kOverreadAmount, // Attempt to read more than is in file. - BindLambda([&](FileOperations::Reader::ReadResult result) { - read_result = std::move(result); - })); + base::BindLambdaForTesting( + [&](FileOperations::Reader::ReadResult result) { + read_result = std::move(result); + })); task_environment_.RunUntilIdle(); ASSERT_EQ(FileOperations::kReady, reader->state()); ASSERT_TRUE(read_result); ASSERT_TRUE(*read_result); EXPECT_EQ(contents, **read_result); + ASSERT_EQ(session_file_reader_count(), size_t{1}); read_result.reset(); reader->ReadChunk(kOverreadAmount, - BindLambda([&](FileOperations::Reader::ReadResult result) { - read_result = std::move(result); - })); + base::BindLambdaForTesting( + [&](FileOperations::Reader::ReadResult result) { + read_result = std::move(result); + })); task_environment_.RunUntilIdle(); EXPECT_EQ(FileOperations::kComplete, reader->state()); ASSERT_TRUE(read_result); ASSERT_TRUE(*read_result); EXPECT_EQ(std::size_t{0}, (*read_result)->size()); + + // Verify the MojoIpcReader instance was released. + ASSERT_EQ(session_file_reader_count(), size_t{0}); } // Verifies proper handling of zero-size file @@ -348,39 +571,640 @@ FakeFileChooser::SetResult(path); absl::optional<FileOperations::Reader::OpenResult> open_result; - reader->Open(BindLambda([&](FileOperations::Reader::OpenResult result) { - open_result = std::move(result); - })); + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + open_result = std::move(result); + })); task_environment_.RunUntilIdle(); - ASSERT_TRUE(open_result && *open_result); + ASSERT_TRUE(open_result); + ASSERT_TRUE(*open_result); + ASSERT_EQ(session_file_reader_count(), size_t{1}); absl::optional<FileOperations::Reader::ReadResult> read_result; reader->ReadChunk(kChunkSize, - BindLambda([&](FileOperations::Reader::ReadResult result) { - read_result = std::move(result); - })); + base::BindLambdaForTesting( + [&](FileOperations::Reader::ReadResult result) { + read_result = std::move(result); + })); task_environment_.RunUntilIdle(); EXPECT_EQ(FileOperations::kComplete, reader->state()); ASSERT_TRUE(read_result); ASSERT_TRUE(*read_result); EXPECT_EQ(std::size_t{0}, (*read_result)->size()); + + // Verify the MojoIpcReader instance was released. + ASSERT_EQ(session_file_reader_count(), size_t{0}); } -// Verifies error is propagated. -TEST_F(IpcFileOperationsTest, ReaderPropagatesError) { +// Concurrent Read operations are handled and valid data is retuned. +TEST_F(IpcFileOperationsTest, ConcurrentReadOperationsSupported) { + base::FilePath base_path = TestDir().Append(kTestFilename); + std::vector<base::FilePath> paths{ + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(0)")), + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(1)")), + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(2)")), + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(3)")), + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(4)"))}; + + std::vector<std::uint8_t> contents = + ByteArrayFrom(kTestDataOne, kTestDataTwo, kTestDataThree); + for (const auto& path : paths) { + ASSERT_EQ( + static_cast<int>(contents.size()), + base::WriteFile(path, reinterpret_cast<const char*>(contents.data()), + contents.size())); + } + + std::vector<std::unique_ptr<FileOperations::Reader>> readers; + for (size_t i = 0; i < paths.size(); i++) { + readers.emplace_back(file_operations_->CreateReader()); + } + + int reader_count = static_cast<int>(readers.size()); + for (int i = 0; i < reader_count; i++) { + FakeFileChooser::SetResult(paths[i]); + absl::optional<FileOperations::Reader::OpenResult> open_result; + readers[i]->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + open_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + ASSERT_TRUE(open_result); + ASSERT_TRUE(*open_result); + ASSERT_EQ(session_file_reader_count(), static_cast<size_t>(i + 1)); + } + ASSERT_EQ(session_file_reader_count(), readers.size()); + + for (int i = 0; i < reader_count; i++) { + for (const auto& chunk : {kTestDataOne, kTestDataTwo, kTestDataThree}) { + absl::optional<FileOperations::Reader::ReadResult> read_result; + readers[i]->ReadChunk(chunk.size(), + base::BindLambdaForTesting( + [&](FileOperations::Reader::ReadResult result) { + read_result = std::move(result); + })); + ASSERT_EQ(FileOperations::kBusy, readers[i]->state()); + task_environment_.RunUntilIdle(); + ASSERT_EQ(FileOperations::kReady, readers[i]->state()); + ASSERT_TRUE(read_result); + ASSERT_TRUE(*read_result); + EXPECT_EQ(chunk, **read_result); + } + } + ASSERT_EQ(session_file_reader_count(), readers.size()); + + for (int i = reader_count - 1; i >= 0; i--) { + absl::optional<FileOperations::Reader::ReadResult> read_result; + // Simulate EOF by reading 1 additional byte. + readers[i]->ReadChunk(1, + base::BindLambdaForTesting( + [&](FileOperations::Reader::ReadResult result) { + read_result = std::move(result); + })); + ASSERT_EQ(FileOperations::kBusy, readers[i]->state()); + task_environment_.RunUntilIdle(); + ASSERT_EQ(FileOperations::kComplete, readers[i]->state()); + ASSERT_TRUE(read_result); + // Verify each MojoIpcReader instance is released as it completes and that + // other instances are retained. + ASSERT_EQ(session_file_reader_count(), static_cast<size_t>(i)); + } + ASSERT_EQ(session_file_reader_count(), size_t{0}); +} + +// Concurrent Write operations handled. +TEST_F(IpcFileOperationsTest, ConcurrentWriteOperationsSupported) { + base::FilePath base_path = TestDir().Append(kTestFilename); + std::vector<base::FilePath> paths{ + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(0)")), + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(1)")), + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(2)")), + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(3)")), + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(4)"))}; + + std::vector<std::uint8_t> contents = + ByteArrayFrom(kTestDataOne, kTestDataTwo, kTestDataThree); + + std::vector<std::unique_ptr<FileOperations::Writer>> writers; + for (size_t i = 0; i < paths.size(); i++) { + writers.emplace_back(file_operations_->CreateWriter()); + } + + int writer_count = static_cast<int>(writers.size()); + for (int i = 0; i < writer_count; i++) { + absl::optional<FileOperations::Writer::Result> open_result; + writers[i]->Open(paths[i], base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + open_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + ASSERT_TRUE(open_result); + ASSERT_TRUE(*open_result); + ASSERT_EQ(session_file_writer_count(), static_cast<size_t>(i + 1)); + } + ASSERT_EQ(session_file_writer_count(), writers.size()); + + for (const auto& chunk : {kTestDataOne, kTestDataTwo, kTestDataThree}) { + for (int i = 0; i < writer_count; i++) { + absl::optional<FileOperations::Writer::Result> write_result; + writers[i]->WriteChunk(chunk, + base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + write_result = std::move(result); + })); + EXPECT_EQ(writers[i]->state(), FileOperations::kBusy); + task_environment_.RunUntilIdle(); + EXPECT_EQ(writers[i]->state(), FileOperations::kReady); + ASSERT_TRUE(write_result); + ASSERT_FALSE(write_result->is_error()); + ASSERT_TRUE(*write_result); + } + } + ASSERT_EQ(session_file_writer_count(), writers.size()); + + for (int i = writer_count - 1; i >= 0; i--) { + absl::optional<FileOperations::Writer::Result> close_result; + writers[i]->Close( + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + close_result = std::move(result); + })); + ASSERT_EQ(writers[i]->state(), FileOperations::kBusy); + task_environment_.RunUntilIdle(); + EXPECT_EQ(writers[i]->state(), FileOperations::kComplete); + ASSERT_TRUE(close_result); + ASSERT_FALSE(close_result->is_error()); + ASSERT_TRUE(*close_result); + // Verify each MojoIpcWriter instance is released as it completes and that + // any other instances are still retained. + ASSERT_EQ(session_file_writer_count(), static_cast<size_t>(i)); + } + ASSERT_EQ(session_file_writer_count(), size_t{0}); + ASSERT_FALSE(base::IsDirectoryEmpty(TestDir())); +} + +// Concurrent Read and Write operations handled. +TEST_F(IpcFileOperationsTest, ConcurrentReadAndWriteOperationsSupported) { + std::vector<std::uint8_t> contents = + ByteArrayFrom(kTestDataOne, kTestDataTwo, kTestDataThree); + base::FilePath base_path = TestDir().Append(kTestFilename); + + std::unique_ptr<FileOperations::Reader> reader = + file_operations_->CreateReader(); + std::unique_ptr<FileOperations::Writer> writer = + file_operations_->CreateWriter(); + + // Write to the read path first so that the writer can select a 'unique' file + // which doesn't conflict with this |read_path|. + base::FilePath read_path( + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(read)"))); + ASSERT_EQ( + static_cast<int>(contents.size()), + base::WriteFile(read_path, reinterpret_cast<const char*>(contents.data()), + contents.size())); + + // Pending open file operations. + absl::optional<FileOperations::Writer::Result> open_for_write_result; + writer->Open( + base_path.InsertBeforeExtension(FILE_PATH_LITERAL("(write)")), + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + open_for_write_result = std::move(result); + })); + FakeFileChooser::SetResult(read_path); + absl::optional<FileOperations::Reader::OpenResult> open_for_read_result; + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + open_for_read_result = std::move(result); + })); + EXPECT_EQ(writer->state(), FileOperations::kBusy); + EXPECT_EQ(reader->state(), FileOperations::kBusy); + // Complete the operations. + task_environment_.RunUntilIdle(); + // Validate results. + EXPECT_EQ(writer->state(), FileOperations::kReady); + EXPECT_EQ(reader->state(), FileOperations::kReady); + ASSERT_TRUE(open_for_write_result); + ASSERT_TRUE(open_for_read_result); + ASSERT_TRUE(*open_for_write_result); + ASSERT_TRUE(*open_for_read_result); + ASSERT_EQ(session_file_writer_count(), size_t{1}); + ASSERT_EQ(session_file_reader_count(), size_t{1}); + + // Pending write operation. + absl::optional<FileOperations::Writer::Result> write_result; + writer->WriteChunk(contents, base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + write_result = std::move(result); + })); + // Pending read operation. + absl::optional<FileOperations::Reader::ReadResult> read_result; + reader->ReadChunk(contents.size(), + base::BindLambdaForTesting( + [&](FileOperations::Reader::ReadResult result) { + read_result = std::move(result); + })); + EXPECT_EQ(writer->state(), FileOperations::kBusy); + EXPECT_EQ(reader->state(), FileOperations::kBusy); + // Complete the pending operations. + task_environment_.RunUntilIdle(); + // Validate the results. + EXPECT_EQ(writer->state(), FileOperations::kReady); + EXPECT_EQ(reader->state(), FileOperations::kReady); + ASSERT_TRUE(write_result); + ASSERT_TRUE(read_result); + ASSERT_TRUE(*write_result); + ASSERT_TRUE(*read_result); + ASSERT_EQ(session_file_writer_count(), size_t{1}); + ASSERT_EQ(session_file_reader_count(), size_t{1}); + + // Close the writer. + absl::optional<FileOperations::Writer::Result> close_result; + writer->Close( + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + close_result = std::move(result); + })); + ASSERT_EQ(writer->state(), FileOperations::kBusy); + task_environment_.RunUntilIdle(); + EXPECT_EQ(writer->state(), FileOperations::kComplete); + ASSERT_TRUE(close_result); + ASSERT_TRUE(*close_result); + ASSERT_EQ(session_file_writer_count(), size_t{0}); + ASSERT_EQ(session_file_reader_count(), size_t{1}); + + // Close the reader by reading 1 additional byte to simulate EOF. + reader->ReadChunk(1, base::BindLambdaForTesting( + [&](FileOperations::Reader::ReadResult result) { + read_result = std::move(result); + })); + ASSERT_EQ(reader->state(), FileOperations::kBusy); + task_environment_.RunUntilIdle(); + ASSERT_EQ(reader->state(), FileOperations::kComplete); + ASSERT_TRUE(read_result); + ASSERT_EQ(session_file_writer_count(), size_t{0}); + ASSERT_EQ(session_file_reader_count(), size_t{0}); + + ASSERT_FALSE(base::IsDirectoryEmpty(TestDir())); + + // Reset the handlers, then trigger a 'disconnect' to verify it is a no-op. + reader.reset(); + writer.reset(); + fake_desktop_session_proxy_.TriggerDisconnectHandlers(); +} + +// Verify a file chooser error is propagated. +TEST_F(IpcFileOperationsTest, ReaderPropagatesErrorFromFileChooser) { std::unique_ptr<FileOperations::Reader> reader = file_operations_->CreateReader(); // Currently non-existent file. FakeFileChooser::SetResult(TestDir().Append(kTestFilename)); absl::optional<FileOperations::Reader::OpenResult> open_result; - reader->Open(BindLambda([&](FileOperations::Reader::OpenResult result) { - open_result = std::move(result); - })); + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + open_result = std::move(result); + })); task_environment_.RunUntilIdle(); EXPECT_EQ(FileOperations::kFailed, reader->state()); ASSERT_TRUE(open_result); ASSERT_FALSE(*open_result); + // Verify the MojoIpcReader instance was not retained. + ASSERT_EQ(session_file_reader_count(), size_t{0}); +} + +// Verify IpcFileReader handles an error returned from the request handler. +TEST_F(IpcFileOperationsTest, ErrorReturnedByFileReadRequestHandler) { + std::unique_ptr<FileOperations::Reader> reader = + file_operations_->CreateReader(); + fake_desktop_session_proxy_.SetErrorForNextRequest( + protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); + absl::optional<FileOperations::Reader::OpenResult> open_result; + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + open_result = std::move(result); + })); + ASSERT_TRUE(open_result->is_error()); + ASSERT_EQ(reader->state(), FileOperations::kFailed); + // Verify the MojoIpcReader instance was not created. + ASSERT_EQ(session_file_reader_count(), size_t{0}); +} + +// Verify IpcFileWriter handles an error returned from the request handler. +TEST_F(IpcFileOperationsTest, ErrorReturnedByFileWriteRequestHandler) { + std::unique_ptr<FileOperations::Writer> writer = + file_operations_->CreateWriter(); + fake_desktop_session_proxy_.SetErrorForNextRequest( + protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); + absl::optional<FileOperations::Writer::Result> open_result; + writer->Open( + TestDir().Append(kTestFilename), + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + open_result = std::move(result); + })); + ASSERT_TRUE(open_result->is_error()); + ASSERT_EQ(writer->state(), FileOperations::kFailed); + // Verify the MojoIpcWriter instance was not created. + ASSERT_EQ(session_file_writer_count(), size_t{0}); + ASSERT_TRUE(base::IsDirectoryEmpty(TestDir())); +} + +// Verify IpcFileReader handles an error returned from the mojo receiver. +TEST_F(IpcFileOperationsTest, ErrorReturnedByMojoReceiverForFileRead) { + std::unique_ptr<FileOperations::Reader> reader = + file_operations_->CreateReader(); + fake_desktop_session_agent_.SetErrorForNextResponse( + protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); + absl::optional<FileOperations::Reader::OpenResult> open_result; + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + open_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + ASSERT_TRUE(open_result->is_error()); + ASSERT_EQ(reader->state(), FileOperations::kFailed); + // Verify a MojoIpcReader instance was not created. + ASSERT_EQ(session_file_reader_count(), size_t{0}); +} + +// Verify IpcFileWriter handles an error returned from the mojo receiver. +TEST_F(IpcFileOperationsTest, ErrorReturnedByMojoReceiverForFileWrite) { + std::unique_ptr<FileOperations::Writer> writer = + file_operations_->CreateWriter(); + fake_desktop_session_agent_.SetErrorForNextResponse( + protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); + absl::optional<FileOperations::Writer::Result> open_result; + writer->Open( + TestDir().Append(kTestFilename), + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + open_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + ASSERT_TRUE(open_result->is_error()); + ASSERT_EQ(writer->state(), FileOperations::kFailed); + // Verify the MojoIpcWriter instance was not retained. + ASSERT_EQ(session_file_writer_count(), size_t{0}); + ASSERT_TRUE(base::IsDirectoryEmpty(TestDir())); +} + +TEST_F(IpcFileOperationsTest, ReaderNotifiedOfIpcChannelDisconnect) { + std::unique_ptr<FileOperations::Reader> reader = + file_operations_->CreateReader(); + // This will trigger the DesktopSessionControl remote disconnect handler. + fake_desktop_session_agent_.DisconnectReceiverOnNextRequest(); + absl::optional<FileOperations::Reader::OpenResult> open_result; + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + open_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + // Verify a MojoIpcReader instance was not created. + ASSERT_EQ(session_file_reader_count(), size_t{0}); + ASSERT_EQ(reader->state(), FileOperations::kFailed); + ASSERT_TRUE(open_result); + ASSERT_TRUE(open_result->is_error()); +} + +TEST_F(IpcFileOperationsTest, WriterNotifiedOfIpcChannelDisconnect) { + std::unique_ptr<FileOperations::Writer> writer = + file_operations_->CreateWriter(); + // This will trigger the DesktopSessionControl remote disconnect handler. + fake_desktop_session_agent_.DisconnectReceiverOnNextRequest(); + absl::optional<FileOperations::Writer::Result> open_result; + writer->Open( + TestDir().Append(kTestFilename), + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + open_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + // Verify a MojoIpcWriter instance was not created. + ASSERT_EQ(session_file_writer_count(), size_t{0}); + ASSERT_EQ(writer->state(), FileOperations::kFailed); + ASSERT_TRUE(open_result); + ASSERT_TRUE(open_result->is_error()); + ASSERT_TRUE(base::IsDirectoryEmpty(TestDir())); +} + +TEST_F(IpcFileOperationsTest, ErrorWhenReadChunkCalledBeforeOpen) { + constexpr std::size_t kChunkSize = 5; + std::unique_ptr<FileOperations::Reader> reader = + file_operations_->CreateReader(); + absl::optional<FileOperations::Reader::ReadResult> read_result; + reader->ReadChunk(kChunkSize, + base::BindLambdaForTesting( + [&](FileOperations::Reader::ReadResult result) { + read_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + EXPECT_EQ(FileOperations::kFailed, reader->state()); + ASSERT_TRUE(read_result); + ASSERT_TRUE(read_result->is_error()); + ASSERT_FALSE(*read_result); + // Verify a MojoIpcReader instance was not created. + ASSERT_EQ(session_file_reader_count(), size_t{0}); +} + +TEST_F(IpcFileOperationsTest, ErrorWhenWriteChunkCalledBeforeOpen) { + std::unique_ptr<FileOperations::Writer> writer = + file_operations_->CreateWriter(); + absl::optional<FileOperations::Writer::Result> write_result; + writer->WriteChunk( + std::vector<uint8_t>{16, 16, 16, 16, 16}, + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + write_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + EXPECT_EQ(FileOperations::kFailed, writer->state()); + ASSERT_TRUE(write_result); + ASSERT_TRUE(write_result->is_error()); + ASSERT_FALSE(*write_result); + // Verify a MojoIpcWriter instance was not created. + ASSERT_EQ(session_file_writer_count(), size_t{0}); +} + +TEST_F(IpcFileOperationsTest, ErrorWhenCloseCalledBeforeOpen) { + std::unique_ptr<FileOperations::Writer> writer = + file_operations_->CreateWriter(); + absl::optional<FileOperations::Writer::Result> close_result; + writer->Close( + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + close_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + EXPECT_EQ(FileOperations::kFailed, writer->state()); + ASSERT_TRUE(close_result); + ASSERT_TRUE(close_result->is_error()); + ASSERT_FALSE(*close_result); + // Verify a MojoIpcWriter instance was not created. + ASSERT_EQ(session_file_writer_count(), size_t{0}); +} + +TEST_F(IpcFileOperationsTest, ErrorWhenReadChunkCalledAfterReceiverDisconnect) { + constexpr std::size_t kChunkSize = 5; + base::FilePath path = TestDir().Append(kTestFilename); + ASSERT_EQ(0, base::WriteFile(path, "", 0)); + + std::unique_ptr<FileOperations::Reader> reader = + file_operations_->CreateReader(); + + FakeFileChooser::SetResult(path); + absl::optional<FileOperations::Reader::OpenResult> open_result; + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + open_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + ASSERT_TRUE(open_result); + ASSERT_TRUE(*open_result); + ASSERT_EQ(session_file_reader_count(), size_t{1}); + + clear_session_file_receivers(); + // Verify the MojoIpcReader instance was released. + ASSERT_EQ(session_file_reader_count(), size_t{0}); + task_environment_.RunUntilIdle(); + + absl::optional<FileOperations::Reader::ReadResult> read_result; + reader->ReadChunk(kChunkSize, + base::BindLambdaForTesting( + [&](FileOperations::Reader::ReadResult result) { + read_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + EXPECT_EQ(FileOperations::kFailed, reader->state()); + ASSERT_TRUE(read_result); + ASSERT_TRUE(read_result->is_error()); + ASSERT_FALSE(*read_result); +} + +TEST_F(IpcFileOperationsTest, + ErrorWhenWriteChunkCalledAfterReceiverDisconnect) { + std::unique_ptr<FileOperations::Writer> writer = + file_operations_->CreateWriter(); + + absl::optional<FileOperations::Writer::Result> open_result; + writer->Open(kTestFilename, base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + open_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + ASSERT_EQ(FileOperations::kReady, writer->state()); + ASSERT_EQ(session_file_writer_count(), size_t{1}); + + clear_session_file_receivers(); + // Verify the MojoIpcWriter instance was released. + ASSERT_EQ(session_file_writer_count(), size_t{0}); + task_environment_.RunUntilIdle(); + + absl::optional<FileOperations::Writer::Result> write_result; + writer->WriteChunk( + std::vector<uint8_t>{16, 16, 16, 16, 16}, + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + write_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + EXPECT_EQ(FileOperations::kFailed, writer->state()); + ASSERT_TRUE(write_result); + ASSERT_TRUE(write_result->is_error()); + ASSERT_FALSE(*write_result); + ASSERT_TRUE(base::IsDirectoryEmpty(TestDir())); +} + +TEST_F(IpcFileOperationsTest, ErrorWhenCloseCalledAfterReceiverDisconnect) { + std::unique_ptr<FileOperations::Writer> writer = + file_operations_->CreateWriter(); + + absl::optional<FileOperations::Writer::Result> open_result; + writer->Open(kTestFilename, base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + open_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + ASSERT_EQ(FileOperations::kReady, writer->state()); + ASSERT_EQ(session_file_writer_count(), size_t{1}); + + clear_session_file_receivers(); + // Verify the MojoIpcWriter instance was released. + ASSERT_EQ(session_file_writer_count(), size_t{0}); + task_environment_.RunUntilIdle(); + + absl::optional<FileOperations::Writer::Result> close_result; + writer->Close( + base::BindLambdaForTesting([&](FileOperations::Writer::Result result) { + close_result = std::move(result); + })); + task_environment_.RunUntilIdle(); + EXPECT_EQ(FileOperations::kFailed, writer->state()); + ASSERT_TRUE(close_result); + ASSERT_TRUE(close_result->is_error()); + ASSERT_FALSE(*close_result); + ASSERT_TRUE(base::IsDirectoryEmpty(TestDir())); +} + +TEST_F(IpcFileOperationsTest, + ErrorWhenUsingExistingFileOperationsAfterFactoryDestroyed) { + std::unique_ptr<IpcFileOperationsFactory> ipc_file_operations_factory = + std::make_unique<IpcFileOperationsFactory>(&fake_desktop_session_proxy_); + std::unique_ptr<FileOperations> file_operations = + ipc_file_operations_factory->CreateFileOperations(); + + std::unique_ptr<FileOperations::Writer> writer = + file_operations->CreateWriter(); + std::unique_ptr<FileOperations::Reader> reader = + file_operations->CreateReader(); + + ipc_file_operations_factory.reset(); + + absl::optional<FileOperations::Writer::Result> writer_open_result; + writer->Open(kTestFilename, base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + writer_open_result = std::move(result); + })); + // We expect this to immediately fail. + ASSERT_EQ(writer->state(), FileOperations::kFailed); + ASSERT_TRUE(writer_open_result->is_error()); + + absl::optional<FileOperations::Reader::OpenResult> reader_open_result; + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + reader_open_result = std::move(result); + })); + // We expect this to immediately fail. + ASSERT_EQ(reader->state(), FileOperations::kFailed); + ASSERT_TRUE(reader_open_result->is_error()); +} + +TEST_F(IpcFileOperationsTest, + ErrorWhenUsingNewFileOperationsAfterFactoryDestroyed) { + std::unique_ptr<IpcFileOperationsFactory> ipc_file_operations_factory = + std::make_unique<IpcFileOperationsFactory>(&fake_desktop_session_proxy_); + std::unique_ptr<FileOperations> file_operations = + ipc_file_operations_factory->CreateFileOperations(); + + ipc_file_operations_factory.reset(); + + std::unique_ptr<FileOperations::Writer> writer = + file_operations->CreateWriter(); + std::unique_ptr<FileOperations::Reader> reader = + file_operations->CreateReader(); + + absl::optional<FileOperations::Writer::Result> writer_open_result; + writer->Open(kTestFilename, base::BindLambdaForTesting( + [&](FileOperations::Writer::Result result) { + writer_open_result = std::move(result); + })); + // We expect this to immediately fail. + ASSERT_EQ(writer->state(), FileOperations::kFailed); + ASSERT_TRUE(writer_open_result->is_error()); + + absl::optional<FileOperations::Reader::OpenResult> reader_open_result; + reader->Open(base::BindLambdaForTesting( + [&](FileOperations::Reader::OpenResult result) { + reader_open_result = std::move(result); + })); + // We expect this to immediately fail. + ASSERT_EQ(reader->state(), FileOperations::kFailed); + ASSERT_TRUE(reader_open_result->is_error()); } } // namespace remoting
diff --git a/remoting/host/file_transfer/session_file_operations_handler.cc b/remoting/host/file_transfer/session_file_operations_handler.cc index 6c450f4..62653b99 100644 --- a/remoting/host/file_transfer/session_file_operations_handler.cc +++ b/remoting/host/file_transfer/session_file_operations_handler.cc
@@ -4,172 +4,224 @@ #include "remoting/host/file_transfer/session_file_operations_handler.h" +#include <memory> + #include "base/bind.h" #include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "remoting/host/mojom/desktop_session.mojom.h" #include "remoting/protocol/file_transfer_helpers.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace remoting { -SessionFileOperationsHandler::SessionFileOperationsHandler( - IpcFileOperations::ResultHandler* result_handler, - std::unique_ptr<FileOperations> file_operations) - : result_handler_(result_handler), - file_operations_(std::move(file_operations)) {} +namespace { -void SessionFileOperationsHandler::ReadFile(std::uint64_t file_id) { - auto location = readers_.emplace(file_id, file_operations_->CreateReader()); - if (!location.second) { - // Strange, we've already received a ReadFile message for this ID. Cancel - // it and send an error to be safe. - readers_.erase(location.first); - result_handler_->OnInfoResult( - file_id, - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); - return; - } - // Unretained is sound because no Reader callbacks will be invoked after the - // Writer is destroyed. - location.first->second->Open( - base::BindOnce(&SessionFileOperationsHandler::OnReaderOpenResult, - base::Unretained(this), file_id)); +using BeginFileReadCallback = + SessionFileOperationsHandler::BeginFileReadCallback; +using BeginFileWriteCallback = + SessionFileOperationsHandler::BeginFileWriteCallback; + +using Reader = FileOperations::Reader; +using Writer = FileOperations::Writer; + +class MojoFileReader : public mojom::FileReader { + public: + explicit MojoFileReader(std::unique_ptr<Reader> file_reader); + + MojoFileReader(const MojoFileReader&) = delete; + MojoFileReader& operator=(const MojoFileReader&) = delete; + + ~MojoFileReader() override = default; + + base::WeakPtr<MojoFileReader> GetWeakPtr(); + + // Requests |file_reader_| to open an existing file for reading. + void Open(Reader::OpenCallback callback); + // Receives the result from Open() and returns it over the mojo channel. + void OnFileOpened(BeginFileReadCallback callback, + mojo::PendingAssociatedRemote<mojom::FileReader> remote, + Reader::OpenResult result); + + // mojom::FileReader implementation. + void ReadChunk(uint64_t bytes_to_read, ReadChunkCallback callback) override; + + const base::FilePath& filename() const { return file_reader_->filename(); } + + uint64_t size() const { return file_reader_->size(); } + + private: + const std::unique_ptr<Reader> file_reader_; + base::WeakPtrFactory<MojoFileReader> weak_ptr_factory{this}; +}; + +class MojoFileWriter : public mojom::FileWriter { + public: + explicit MojoFileWriter(std::unique_ptr<Writer> file_writer); + + MojoFileWriter(const MojoFileWriter&) = delete; + MojoFileWriter& operator=(const MojoFileWriter&) = delete; + + ~MojoFileWriter() override = default; + + // Requests |file_writer_| to open a new file for writing. + void Open(const base::FilePath& filename, Writer::Callback callback); + // Receives the result from Open() and returns it over the mojo channel. + void OnFileOpened(BeginFileWriteCallback callback, + mojo::PendingAssociatedRemote<mojom::FileWriter> remote, + Writer::Result result); + + // mojom::FileWriter implementation. + void WriteChunk(const std::vector<std::uint8_t>& data, + WriteChunkCallback callback) override; + void CloseFile(CloseFileCallback callback) override; + + base::WeakPtr<MojoFileWriter> GetWeakPtr(); + + private: + const std::unique_ptr<Writer> file_writer_; + base::WeakPtrFactory<MojoFileWriter> weak_ptr_factory{this}; +}; + +MojoFileReader::MojoFileReader(std::unique_ptr<Reader> file_reader) + : file_reader_(std::move(file_reader)) {} + +base::WeakPtr<MojoFileReader> MojoFileReader::GetWeakPtr() { + return weak_ptr_factory.GetWeakPtr(); } -void SessionFileOperationsHandler::ReadChunk(std::uint64_t file_id, - std::uint64_t size) { - auto reader_iter = readers_.find(file_id); - if (reader_iter == readers_.end()) { - result_handler_->OnDataResult( - file_id, - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); - return; - } - reader_iter->second->ReadChunk( - size, base::BindOnce(&SessionFileOperationsHandler::OnReaderReadResult, - base::Unretained(this), file_id)); +void MojoFileReader::Open(Reader::OpenCallback callback) { + file_reader_->Open(std::move(callback)); } -void SessionFileOperationsHandler::WriteFile(uint64_t file_id, - const base::FilePath& filename) { - auto location = writers_.emplace(file_id, file_operations_->CreateWriter()); - if (!location.second) { - // Strange, we've already received a WriteFile message for this ID. Cancel - // it and send an error to be safe. - writers_.erase(location.first); - result_handler_->OnResult( - file_id, - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); +void MojoFileReader::OnFileOpened( + BeginFileReadCallback callback, + mojo::PendingAssociatedRemote<mojom::FileReader> remote, + Reader::OpenResult result) { + if (result.is_error()) { + std::move(callback).Run( + mojom::BeginFileReadResult::NewError(result.error())); + // This will asynchronously trigger the destruction of this object. + remote.reset(); return; } - // Unretained is sound because no Writer callbacks will be invoked after the - // Writer is destroyed. - location.first->second->Open( - filename, - base::BindOnce(&SessionFileOperationsHandler::OnWriterOperationResult, - base::Unretained(this), file_id)); + + std::move(callback).Run(mojom::BeginFileReadResult::NewSuccess( + mojom::BeginFileReadSuccess::New(std::move(remote), filename(), size()))); } -void SessionFileOperationsHandler::WriteChunk(uint64_t file_id, - std::vector<std::uint8_t> data) { - auto writer_iter = writers_.find(file_id); - if (writer_iter == writers_.end()) { - result_handler_->OnResult( - file_id, - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); +// The Mojo-generated ReadChunkCallback has a const& param whereas the +// FileReader::ReadCallback does not so this function wraps the Mojo callback +// so it is compatible with the FileReader interface. +void ReadChunkCallbackWrapper( + mojom::FileReader::ReadChunkCallback callback, + protocol::FileTransferResult<std::vector<std::uint8_t>> result) { + std::move(callback).Run(result); +} + +void MojoFileReader::ReadChunk(uint64_t bytes_to_read, + ReadChunkCallback callback) { + file_reader_->ReadChunk( + bytes_to_read, + base::BindOnce(&ReadChunkCallbackWrapper, std::move(callback))); +} + +MojoFileWriter::MojoFileWriter(std::unique_ptr<Writer> file_writer) + : file_writer_(std::move(file_writer)) {} + +void MojoFileWriter::Open(const base::FilePath& filename, + Writer::Callback callback) { + file_writer_->Open(filename, std::move(callback)); +} + +void MojoFileWriter::OnFileOpened( + BeginFileWriteCallback callback, + mojo::PendingAssociatedRemote<mojom::FileWriter> remote, + Writer::Result result) { + if (result.is_error()) { + std::move(callback).Run( + mojom::BeginFileWriteResult::NewError(result.error())); + // This will asynchronously trigger the destruction of this object. + remote.reset(); return; } - writer_iter->second->WriteChunk( + + std::move(callback).Run(mojom::BeginFileWriteResult::NewSuccess( + mojom::BeginFileWriteSuccess::New(std::move(remote)))); +} + +base::WeakPtr<MojoFileWriter> MojoFileWriter::GetWeakPtr() { + return weak_ptr_factory.GetWeakPtr(); +} + +// Wraps a Mojo-generated callback to provide compatibility with the FileWriter +// methods which expect a Writer::Callback. +template <class T> +void FileWriterCallbackWrapper(T callback, remoting::Writer::Result result) { + absl::optional<protocol::FileTransfer_Error> error; + if (result.is_error()) { + error = std::move(result.error()); + } + std::move(callback).Run(std::move(error)); +} + +void MojoFileWriter::WriteChunk(const std::vector<std::uint8_t>& data, + WriteChunkCallback callback) { + file_writer_->WriteChunk( std::move(data), - base::BindOnce(&SessionFileOperationsHandler::OnWriterOperationResult, - base::Unretained(this), file_id)); + base::BindOnce(&FileWriterCallbackWrapper<WriteChunkCallback>, + std::move(callback))); } -void SessionFileOperationsHandler::Close(uint64_t file_id) { - auto reader_iter = readers_.find(file_id); - if (reader_iter != readers_.end()) { - readers_.erase(reader_iter); - return; - } - - auto writer_iter = writers_.find(file_id); - if (writer_iter != writers_.end()) { - writer_iter->second->Close( - base::BindOnce(&SessionFileOperationsHandler::OnWriterCloseResult, - base::Unretained(this), file_id)); - return; - } - - // |file_id| is not a known reader or writer. Send an error in case the - // network process is waiting for a response. - result_handler_->OnResult( - file_id, - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)); +void MojoFileWriter::CloseFile(CloseFileCallback callback) { + file_writer_->Close(base::BindOnce( + &FileWriterCallbackWrapper<CloseFileCallback>, std::move(callback))); } -void SessionFileOperationsHandler::Cancel(uint64_t file_id) { - // It's possible for a cancel request and an error response (from a previous - // request) to pass each other in the message pipe, so the lack of a reader or - // writer matching |file_id| is not necessarily an error. Since a cancel - // request doesn't expect a response, it's fine to do nothing in that case. +} // namespace - auto reader_iter = readers_.find(file_id); - if (reader_iter != readers_.end()) { - readers_.erase(reader_iter); - } - - auto writer_iter = writers_.find(file_id); - if (writer_iter != writers_.end()) { - writers_.erase(writer_iter); - } -} - -void SessionFileOperationsHandler::OnReaderOpenResult( - std::uint64_t file_id, - FileOperations::Reader::OpenResult result) { - if (!result) { - readers_.erase(file_id); - result_handler_->OnInfoResult(file_id, std::move(result.error())); - return; - } - - auto reader_iter = readers_.find(file_id); - // Should never get a callback if the reader has been destroyed. - DCHECK(reader_iter != readers_.end()); - result_handler_->OnInfoResult(file_id, - {kSuccessTag, reader_iter->second->filename(), - reader_iter->second->size()}); -} - -void SessionFileOperationsHandler::OnReaderReadResult( - std::uint64_t file_id, - FileOperations::Reader::ReadResult result) { - if (!result || result->size() == 0) { - readers_.erase(file_id); - } - - result_handler_->OnDataResult(file_id, std::move(result)); -} - -void SessionFileOperationsHandler::OnWriterOperationResult( - uint64_t file_id, - FileOperations::Writer::Result result) { - if (!result) { - writers_.erase(file_id); - } - result_handler_->OnResult(file_id, std::move(result)); -} - -void SessionFileOperationsHandler::OnWriterCloseResult( - uint64_t file_id, - FileOperations::Writer::Result result) { - writers_.erase(file_id); - result_handler_->OnResult(file_id, std::move(result)); -} +SessionFileOperationsHandler::SessionFileOperationsHandler( + std::unique_ptr<FileOperations> file_operations) + : file_operations_(std::move(file_operations)) {} SessionFileOperationsHandler::~SessionFileOperationsHandler() = default; +void SessionFileOperationsHandler::BeginFileRead( + BeginFileReadCallback callback) { + mojo::AssociatedRemote<mojom::FileReader> remote; + auto mojo_file_reader = + std::make_unique<MojoFileReader>(file_operations_->CreateReader()); + MojoFileReader* ptr = mojo_file_reader.get(); + + // |file_readers_| now manages the lifetime of |mojo_file_reader| and will + // destroy the instance when |remote| is reset. + file_readers_.Add(std::move(mojo_file_reader), + remote.BindNewEndpointAndPassReceiver()); + + // We Unbind() |remote| so we can return it to the other end of the IPC + // channel, this will not cause |mojo_file_reader| to be destroyed. + ptr->Open(base::BindOnce(&MojoFileReader::OnFileOpened, ptr->GetWeakPtr(), + std::move(callback), remote.Unbind())); +} + +void SessionFileOperationsHandler::BeginFileWrite( + const base::FilePath& file_path, + BeginFileWriteCallback callback) { + mojo::AssociatedRemote<mojom::FileWriter> remote; + auto mojo_file_writer = + std::make_unique<MojoFileWriter>(file_operations_->CreateWriter()); + MojoFileWriter* ptr = mojo_file_writer.get(); + + // |file_writers_| now manages the lifetime of |mojo_file_writer| and will + // destroy the instance when |remote| is reset. + file_writers_.Add(std::move(mojo_file_writer), + remote.BindNewEndpointAndPassReceiver()); + + // We Unbind() |remote| so we can return it to the other end of the IPC + // channel, this will not cause |mojo_file_writer| to be destroyed. + ptr->Open(file_path, + base::BindOnce(&MojoFileWriter::OnFileOpened, ptr->GetWeakPtr(), + std::move(callback), remote.Unbind())); +} + } // namespace remoting
diff --git a/remoting/host/file_transfer/session_file_operations_handler.h b/remoting/host/file_transfer/session_file_operations_handler.h index ae4f0f5..243c488 100644 --- a/remoting/host/file_transfer/session_file_operations_handler.h +++ b/remoting/host/file_transfer/session_file_operations_handler.h
@@ -5,53 +5,46 @@ #ifndef REMOTING_HOST_FILE_TRANSFER_SESSION_FILE_OPERATIONS_HANDLER_H_ #define REMOTING_HOST_FILE_TRANSFER_SESSION_FILE_OPERATIONS_HANDLER_H_ -#include <cstdint> #include <memory> -#include <vector> -#include "base/containers/flat_map.h" -#include "base/memory/weak_ptr.h" -#include "remoting/host/file_transfer/ipc_file_operations.h" +#include "base/files/file_path.h" +#include "mojo/public/cpp/bindings/unique_associated_receiver_set.h" +#include "remoting/host/file_transfer/file_operations.h" +#include "remoting/host/mojom/desktop_session.mojom.h" namespace remoting { -// An implementation of IpcFileOperations::RequestHandler that forwards all -// operations to another FileOperations implementation. -class SessionFileOperationsHandler : public IpcFileOperations::RequestHandler { +// A Mojo-aware FileOperations wrapper which handles requests to begin file read +// and write operations. This class can handle concurrent requests as it creates +// a new handler for each one and ensures and resource are released when the +// new Mojo channel is closed. +class SessionFileOperationsHandler { public: - // |result_handler| must be valid for the entire lifetime of - // SessionFileOperationsHandler. explicit SessionFileOperationsHandler( - IpcFileOperations::ResultHandler* result_handler, std::unique_ptr<FileOperations> file_operations); - ~SessionFileOperationsHandler() override; - // IpcFileOperations::RequestHandler implementation - void ReadFile(std::uint64_t file_id) override; - void ReadChunk(std::uint64_t file_id, std::uint64_t size) override; - void WriteFile(std::uint64_t file_id, - const base::FilePath& filename) override; - void WriteChunk(std::uint64_t file_id, - std::vector<std::uint8_t> data) override; - void Close(std::uint64_t file_id) override; - void Cancel(std::uint64_t file_id) override; + SessionFileOperationsHandler(const SessionFileOperationsHandler&) = delete; + SessionFileOperationsHandler& operator=(const SessionFileOperationsHandler&) = + delete; + + ~SessionFileOperationsHandler(); + + using BeginFileReadCallback = + base::OnceCallback<void(mojom::BeginFileReadResultPtr)>; + void BeginFileRead(BeginFileReadCallback callback); + + using BeginFileWriteCallback = + base::OnceCallback<void(mojom::BeginFileWriteResultPtr)>; + void BeginFileWrite(const base::FilePath& file_path, + BeginFileWriteCallback callback); private: - void OnReaderOpenResult(std::uint64_t file_id, - FileOperations::Reader::OpenResult result); - void OnReaderReadResult(std::uint64_t file_id, - FileOperations::Reader::ReadResult result); - void OnWriterOperationResult(std::uint64_t file_id, - FileOperations::Writer::Result result); - void OnWriterCloseResult(std::uint64_t file_id, - FileOperations::Writer::Result result); + friend class IpcFileOperationsTest; - IpcFileOperations::ResultHandler* result_handler_; - std::unique_ptr<FileOperations> file_operations_; - base::flat_map<std::uint64_t, std::unique_ptr<FileOperations::Writer>> - writers_; - base::flat_map<std::uint64_t, std::unique_ptr<FileOperations::Reader>> - readers_; + const std::unique_ptr<FileOperations> file_operations_; + + mojo::UniqueAssociatedReceiverSet<mojom::FileReader> file_readers_; + mojo::UniqueAssociatedReceiverSet<mojom::FileWriter> file_writers_; }; } // namespace remoting
diff --git a/remoting/host/mojom/BUILD.gn b/remoting/host/mojom/BUILD.gn index 292676e..7827b50 100644 --- a/remoting/host/mojom/BUILD.gn +++ b/remoting/host/mojom/BUILD.gn
@@ -79,6 +79,18 @@ cpp = "::webrtc::DesktopVector" }, { + mojom = "remoting.mojom.FileChooserResult" + cpp = "::remoting::Result<base::FilePath, ::remoting::protocol::FileTransfer_Error>" + }, + { + mojom = "remoting.mojom.FileTransferError" + cpp = "::remoting::protocol::FileTransfer_Error" + }, + { + mojom = "remoting.mojom.FileTransferError.Type" + cpp = "::remoting::protocol::FileTransfer_Error_Type" + }, + { mojom = "remoting.mojom.KeyboardLayout" cpp = "::remoting::protocol::KeyboardLayout" }, @@ -115,6 +127,10 @@ cpp = "::remoting::protocol::ErrorCode" }, { + mojom = "remoting.mojom.ReadChunkResult" + cpp = "::remoting::protocol::FileTransferResult<std::vector<uint8_t>>" + }, + { mojom = "remoting.mojom.ScreenResolution" cpp = "::remoting::ScreenResolution" }, @@ -159,6 +175,7 @@ "//mojo/public/cpp/bindings:protobuf_support", "//remoting/host/base", "//remoting/proto", + "//remoting/protocol", "//remoting/protocol:errors", "//remoting/protocol:transport", "//services/network/public/cpp:ip_address_mojom_support",
diff --git a/remoting/host/mojom/desktop_session.mojom b/remoting/host/mojom/desktop_session.mojom index 47c6fb36..95faec8 100644 --- a/remoting/host/mojom/desktop_session.mojom +++ b/remoting/host/mojom/desktop_session.mojom
@@ -5,6 +5,7 @@ module remoting.mojom; import "mojo/public/mojom/base/byte_string.mojom"; +import "mojo/public/mojom/base/file_path.mojom"; import "mojo/public/mojom/base/shared_memory.mojom"; import "remoting/host/mojom/keyboard_layout.mojom"; import "remoting/host/mojom/webrtc_types.mojom"; @@ -297,6 +298,101 @@ desktop_session_control); }; +// Enables writing to a file, this is used when the client website uploads a +// a file to the host machine. The remote is provided in the return value of a +// successful mojom::DesktopSessionControl::BeginFileWrite() call. +// The remote for this interface is owned in the low-privilege network process +// and the receiver is bound in the high-privilege desktop integration process. +interface FileWriter { + // Writes |data| to the file opened in the BeginFileWrite call. Returns + // |error| if the data could not be written. + WriteChunk(array<uint8> data) => (FileTransferError? error); + + // Closes the file opened in the BeginFileWrite call and moves it from the + // temporary location to the desktop of the logged-in user. Returns |error| if + // a problem occurs during this process. + CloseFile() => (FileTransferError? error); +}; + +// Returned by FileReader::ReadChunk(). |data| is populated if the read request +// succeeded, otherwise |error| will indicate why the request failed. +union ReadChunkResult { + array<uint8> data; + FileTransferError error; +}; + +// Allows reading from a file, this is used when the client website downloads +// a file from the host machine. The remote is provided after a successful call +// to mojom::DesktopSessionControl::BeginFileRead(). +// The remote for this interface is owned in the low-privilege network process +// and the receiver is bound in the high-privilege desktop integration process. +interface FileReader { + // Reads |bytes_to_read| from the file opened in the BeginFileRead call. + // |result| contains the file data if successful, otherwise an error. + ReadChunk(uint64 bytes_to_read) => (ReadChunkResult result); +}; + +// Used by the remoting::FileChooser class which prompts the user to select a +// file to download to the client machine using a file picker dialog. +// |filepath| is populated if the user selected a file from the dialog, +// otherwise |error| indicates why the operation failed. +// This message is serialized in a child process which is running in the current +// user context, sent over STDIO as a stream of bytes, then deserialized in the +// parent process which is the high-privilege desktop integration process. +[EnableIf=is_win] +union FileChooserResult { + mojo_base.mojom.FilePath filepath; + FileTransferError error; +}; + +// Error information for file transfer operations. +// This enum mirrors the remoting::protocol::FileTransfer_Error message. +struct FileTransferError { + // The set of errors which may occur while transferring files. + // This enum mirrors the remoting::protocol::FileTransfer_Error_Type enum. + enum Type { + kUnknown = 0, + kCanceled = 1, + kUnexpectedError = 2, + kProtocolError = 3, + kPermissionDenied = 4, + kOutOfDiskSpace = 5, + kIoError = 6, + kNotLoggedIn = 7, + }; + Type type; + Int32? api_error_code; + string function; + string source_file; + uint32 line_number; +}; + +// Returned when the user has selected a file to begin transferring. This struct +// contains the metadata for the file and the remote used to read from the file. +struct BeginFileReadSuccess { + pending_associated_remote<FileReader> file_reader; + mojo_base.mojom.FilePath filename; + uint64 size; +}; + +// |success| is populated if BeginFileRead() succeeded, otherwise |error|. +union BeginFileReadResult { + BeginFileReadSuccess success; + FileTransferError error; +}; + +// Returned when a new file has been written and the client can begin +// transferring data. This struct contains the remote used to write to the file. +struct BeginFileWriteSuccess { + pending_associated_remote<FileWriter> file_writer; +}; + +// |success| is populated if BeginFileRead() succeeded, otherwise |error|. +union BeginFileWriteResult { + BeginFileWriteSuccess success; + FileTransferError error; +}; + // Allows the network process to inject input events and control A/V capture in // the desktop session. // The remote for this interface is owned in the low-privilege network process @@ -341,6 +437,15 @@ // change, so the extension can determine whether it should attach to or // detach to the WebAuthn proxy API. SignalWebAuthnExtension(); + + // Opens a file chooser dialog so the user can choose a file to transfer to + // the client machine. This action is requested when the remote user chooses + // to download a file. + BeginFileRead() => (BeginFileReadResult result); + + // Opens a new file for writing when the remote user chooses to upload a file. + BeginFileWrite(mojo_base.mojom.FilePath file_path) + => (BeginFileWriteResult result); }; // |frame| is set and contains valid frame data when a frame is captured
diff --git a/remoting/host/mojom/remoting_mojom_traits.cc b/remoting/host/mojom/remoting_mojom_traits.cc index b3408522..9e5f3dc 100644 --- a/remoting/host/mojom/remoting_mojom_traits.cc +++ b/remoting/host/mojom/remoting_mojom_traits.cc
@@ -139,6 +139,102 @@ return true; } +#if BUILDFLAG(IS_WIN) +// static +bool mojo::UnionTraits< + remoting::mojom::FileChooserResultDataView, + ::remoting::Result<base::FilePath, + ::remoting::protocol::FileTransfer_Error>>:: + Read(remoting::mojom::FileChooserResultDataView data_view, + ::remoting::Result<base::FilePath, + ::remoting::protocol::FileTransfer_Error>* + out_result) { + switch (data_view.tag()) { + case remoting::mojom::FileChooserResultDataView::Tag::kFilepath: { + base::FilePath filepath; + if (!data_view.ReadFilepath(&filepath)) { + return false; + } + out_result->EmplaceSuccess(std::move(filepath)); + return true; + } + case remoting::mojom::FileChooserResultDataView::Tag::kError: { + ::remoting::protocol::FileTransfer_Error error; + if (!data_view.ReadError(&error)) { + return false; + } + out_result->EmplaceError(std::move(error)); + return true; + } + } +} +#endif // BUILDFLAG(IS_WIN) + +// static +bool mojo::UnionTraits< + remoting::mojom::ReadChunkResultDataView, + ::remoting::Result<std::vector<uint8_t>, + ::remoting::protocol::FileTransfer_Error>>:: + Read(remoting::mojom::ReadChunkResultDataView data_view, + ::remoting::Result<std::vector<uint8_t>, + ::remoting::protocol::FileTransfer_Error>* + out_result) { + switch (data_view.tag()) { + case remoting::mojom::ReadChunkResultDataView::Tag::kData: { + std::vector<uint8_t> data; + if (!data_view.ReadData(&data)) { + return false; + } + out_result->EmplaceSuccess(std::move(data)); + return true; + } + case remoting::mojom::ReadChunkResultDataView::Tag::kError: { + ::remoting::protocol::FileTransfer_Error error; + if (!data_view.ReadError(&error)) { + return false; + } + out_result->EmplaceError(std::move(error)); + return true; + } + } +} + +// static +bool mojo::StructTraits<remoting::mojom::FileTransferErrorDataView, + ::remoting::protocol::FileTransfer_Error>:: + Read(remoting::mojom::FileTransferErrorDataView data_view, + ::remoting::protocol::FileTransfer_Error* out_error) { + ::remoting::protocol::FileTransfer_Error_Type type; + if (!data_view.ReadType(&type)) { + return false; + } + out_error->set_type(type); + + absl::optional<int32_t> api_error_code; + if (!data_view.ReadApiErrorCode(&api_error_code)) { + return false; + } + if (api_error_code) { + out_error->set_api_error_code(*api_error_code); + } + + std::string function; + if (!data_view.ReadFunction(&function)) { + return false; + } + out_error->set_function(std::move(function)); + + std::string source_file; + if (!data_view.ReadSourceFile(&source_file)) { + return false; + } + out_error->set_source_file(std::move(source_file)); + + out_error->set_line_number(data_view.line_number()); + + return true; +} + // static bool mojo::StructTraits<remoting::mojom::KeyboardLayoutDataView, ::remoting::protocol::KeyboardLayout>:: @@ -192,7 +288,7 @@ return false; } if (caps_lock_state.has_value()) { - out_event->set_caps_lock_state(caps_lock_state.value()); + out_event->set_caps_lock_state(*caps_lock_state); } absl::optional<bool> num_lock_state; @@ -200,7 +296,7 @@ return false; } if (num_lock_state.has_value()) { - out_event->set_num_lock_state(num_lock_state.value()); + out_event->set_num_lock_state(*num_lock_state); } return true; @@ -258,7 +354,7 @@ return false; } if (x.has_value()) { - out_event->set_x(x.value()); + out_event->set_x(*x); } absl::optional<int32_t> y; @@ -266,7 +362,7 @@ return false; } if (y.has_value()) { - out_event->set_y(y.value()); + out_event->set_y(*y); } if (data_view.button() != remoting::mojom::MouseButton::kUndefined) { @@ -282,7 +378,7 @@ return false; } if (button_down.has_value()) { - out_event->set_button_down(button_down.value()); + out_event->set_button_down(*button_down); } absl::optional<float> wheel_delta_x; @@ -290,7 +386,7 @@ return false; } if (wheel_delta_x.has_value()) { - out_event->set_wheel_delta_x(wheel_delta_x.value()); + out_event->set_wheel_delta_x(*wheel_delta_x); } absl::optional<float> wheel_delta_y; @@ -298,7 +394,7 @@ return false; } if (wheel_delta_y.has_value()) { - out_event->set_wheel_delta_y(wheel_delta_y.value()); + out_event->set_wheel_delta_y(*wheel_delta_y); } absl::optional<float> wheel_ticks_x; @@ -306,7 +402,7 @@ return false; } if (wheel_ticks_x.has_value()) { - out_event->set_wheel_ticks_x(wheel_ticks_x.value()); + out_event->set_wheel_ticks_x(*wheel_ticks_x); } absl::optional<float> wheel_ticks_y; @@ -314,7 +410,7 @@ return false; } if (wheel_ticks_y.has_value()) { - out_event->set_wheel_ticks_y(wheel_ticks_y.value()); + out_event->set_wheel_ticks_y(*wheel_ticks_y); } absl::optional<int32_t> delta_x; @@ -322,7 +418,7 @@ return false; } if (delta_x.has_value()) { - out_event->set_delta_x(delta_x.value()); + out_event->set_delta_x(*delta_x); } absl::optional<int32_t> delta_y; @@ -330,7 +426,7 @@ return false; } if (delta_y.has_value()) { - out_event->set_delta_y(delta_y.value()); + out_event->set_delta_y(*delta_y); } return true;
diff --git a/remoting/host/mojom/remoting_mojom_traits.h b/remoting/host/mojom/remoting_mojom_traits.h index 39bbf9a99..4e5fea4 100644 --- a/remoting/host/mojom/remoting_mojom_traits.h +++ b/remoting/host/mojom/remoting_mojom_traits.h
@@ -10,14 +10,17 @@ #include <string> #include "base/containers/span.h" +#include "base/files/file_path.h" #include "base/numerics/safe_conversions.h" #include "build/build_config.h" #include "mojo/public/cpp/base/byte_string_mojom_traits.h" +#include "mojo/public/cpp/base/file_path_mojom_traits.h" #include "mojo/public/cpp/bindings/array_traits.h" #include "mojo/public/cpp/bindings/array_traits_protobuf.h" #include "mojo/public/cpp/bindings/enum_traits.h" #include "mojo/public/cpp/bindings/map_traits_protobuf.h" #include "mojo/public/cpp/bindings/struct_traits.h" +#include "remoting/base/result.h" #include "remoting/host/base/desktop_environment_options.h" #include "remoting/host/base/screen_resolution.h" #include "remoting/host/mojom/desktop_session.mojom-shared.h" @@ -27,6 +30,8 @@ #include "remoting/proto/audio.pb.h" #include "remoting/proto/control.pb.h" #include "remoting/proto/event.pb.h" +#include "remoting/proto/file_transfer.pb.h" +#include "remoting/protocol/file_transfer_helpers.h" #include "remoting/protocol/transport.h" #include "services/network/public/cpp/ip_endpoint_mojom_traits.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -562,6 +567,184 @@ }; template <> +class mojo::UnionTraits< + remoting::mojom::ReadChunkResultDataView, + ::remoting::Result<std::vector<uint8_t>, + ::remoting::protocol::FileTransfer_Error>> { + public: + static remoting::mojom::ReadChunkResultDataView::Tag GetTag( + const ::remoting::Result<std::vector<uint8_t>, + ::remoting::protocol::FileTransfer_Error>& + result) { + if (result.is_success()) + return remoting::mojom::ReadChunkResultDataView::Tag::kData; + else if (result.is_error()) + return remoting::mojom::ReadChunkResultDataView::Tag::kError; + + NOTREACHED(); + return remoting::mojom::ReadChunkResultDataView::Tag::kError; + } + + static const std::vector<uint8_t>& data( + const ::remoting::Result<std::vector<uint8_t>, + ::remoting::protocol::FileTransfer_Error>& + result) { + return result.success(); + } + + static const ::remoting::protocol::FileTransfer_Error& error( + const ::remoting::Result<std::vector<uint8_t>, + ::remoting::protocol::FileTransfer_Error>& + result) { + return result.error(); + } + + static bool Read( + remoting::mojom::ReadChunkResultDataView data_view, + ::remoting::Result<std::vector<uint8_t>, + ::remoting::protocol::FileTransfer_Error>* out_result); +}; + +template <> +class mojo::StructTraits<remoting::mojom::FileTransferErrorDataView, + ::remoting::protocol::FileTransfer_Error> { + public: + static ::remoting::protocol::FileTransfer_Error_Type type( + const ::remoting::protocol::FileTransfer_Error& error) { + return error.type(); + } + + static absl::optional<int32_t> api_error_code( + const ::remoting::protocol::FileTransfer_Error& error) { + if (error.has_api_error_code()) { + return error.api_error_code(); + } + return absl::nullopt; + } + + static const std::string& function( + const ::remoting::protocol::FileTransfer_Error& error) { + return error.function(); + } + + static const std::string& source_file( + const ::remoting::protocol::FileTransfer_Error& error) { + return error.source_file(); + } + + static uint32_t line_number( + const ::remoting::protocol::FileTransfer_Error& error) { + return error.line_number(); + } + + static bool Read(remoting::mojom::FileTransferErrorDataView data_view, + ::remoting::protocol::FileTransfer_Error* out_error); +}; + +template <> +struct EnumTraits<remoting::mojom::FileTransferError_Type, + ::remoting::protocol::FileTransfer_Error_Type> { + static remoting::mojom::FileTransferError_Type ToMojom( + ::remoting::protocol::FileTransfer_Error_Type input) { + switch (input) { + case ::remoting::protocol::FileTransfer_Error::UNSPECIFIED: + return remoting::mojom::FileTransferError_Type::kUnknown; + case ::remoting::protocol::FileTransfer_Error::CANCELED: + return remoting::mojom::FileTransferError_Type::kCanceled; + case ::remoting::protocol::FileTransfer_Error::UNEXPECTED_ERROR: + return remoting::mojom::FileTransferError_Type::kUnexpectedError; + case ::remoting::protocol::FileTransfer_Error::PROTOCOL_ERROR: + return remoting::mojom::FileTransferError_Type::kProtocolError; + case ::remoting::protocol::FileTransfer_Error::PERMISSION_DENIED: + return remoting::mojom::FileTransferError_Type::kPermissionDenied; + case ::remoting::protocol::FileTransfer_Error::OUT_OF_DISK_SPACE: + return remoting::mojom::FileTransferError_Type::kOutOfDiskSpace; + case ::remoting::protocol::FileTransfer_Error::IO_ERROR: + return remoting::mojom::FileTransferError_Type::kIoError; + case ::remoting::protocol::FileTransfer_Error::NOT_LOGGED_IN: + return remoting::mojom::FileTransferError_Type::kNotLoggedIn; + } + + NOTREACHED(); + return remoting::mojom::FileTransferError_Type::kUnknown; + } + + static bool FromMojom(remoting::mojom::FileTransferError_Type input, + ::remoting::protocol::FileTransfer_Error_Type* out) { + switch (input) { + case remoting::mojom::FileTransferError_Type::kUnknown: + *out = ::remoting::protocol::FileTransfer_Error::UNSPECIFIED; + return true; + case remoting::mojom::FileTransferError_Type::kCanceled: + *out = ::remoting::protocol::FileTransfer_Error::CANCELED; + return true; + case remoting::mojom::FileTransferError_Type::kUnexpectedError: + *out = ::remoting::protocol::FileTransfer_Error::UNEXPECTED_ERROR; + return true; + case remoting::mojom::FileTransferError_Type::kProtocolError: + *out = ::remoting::protocol::FileTransfer_Error::PROTOCOL_ERROR; + return true; + case remoting::mojom::FileTransferError_Type::kPermissionDenied: + *out = ::remoting::protocol::FileTransfer_Error::PERMISSION_DENIED; + return true; + case remoting::mojom::FileTransferError_Type::kOutOfDiskSpace: + *out = ::remoting::protocol::FileTransfer_Error::OUT_OF_DISK_SPACE; + return true; + case remoting::mojom::FileTransferError_Type::kIoError: + *out = ::remoting::protocol::FileTransfer_Error::IO_ERROR; + return true; + case remoting::mojom::FileTransferError_Type::kNotLoggedIn: + *out = ::remoting::protocol::FileTransfer_Error::NOT_LOGGED_IN; + return true; + } + + NOTREACHED(); + return false; + } +}; + +#if BUILDFLAG(IS_WIN) +template <> +class mojo::UnionTraits< + remoting::mojom::FileChooserResultDataView, + ::remoting::Result<base::FilePath, + ::remoting::protocol::FileTransfer_Error>> { + public: + static remoting::mojom::FileChooserResultDataView::Tag GetTag( + const ::remoting::Result<base::FilePath, + ::remoting::protocol::FileTransfer_Error>& + result) { + if (result.is_success()) + return remoting::mojom::FileChooserResultDataView::Tag::kFilepath; + else if (result.is_error()) + return remoting::mojom::FileChooserResultDataView::Tag::kError; + + NOTREACHED(); + return remoting::mojom::FileChooserResultDataView::Tag::kError; + } + + static const base::FilePath& filepath( + const ::remoting::Result<base::FilePath, + ::remoting::protocol::FileTransfer_Error>& + result) { + return result.success(); + } + + static const ::remoting::protocol::FileTransfer_Error& error( + const ::remoting::Result<base::FilePath, + ::remoting::protocol::FileTransfer_Error>& + result) { + return result.error(); + } + + static bool Read( + remoting::mojom::FileChooserResultDataView data_view, + ::remoting::Result<base::FilePath, + ::remoting::protocol::FileTransfer_Error>* out_result); +}; +#endif // BUILDFLAG(IS_WIN) + +template <> class mojo::StructTraits<remoting::mojom::KeyboardLayoutDataView, ::remoting::protocol::KeyboardLayout> { public:
diff --git a/services/device/geolocation/geolocation_service_unittest.cc b/services/device/geolocation/geolocation_service_unittest.cc index 8f04503f..8364a0a 100644 --- a/services/device/geolocation/geolocation_service_unittest.cc +++ b/services/device/geolocation/geolocation_service_unittest.cc
@@ -52,7 +52,7 @@ void SetUp() override { #if BUILDFLAG(IS_CHROMEOS_ASH) chromeos::shill_clients::InitializeFakes(); - chromeos::NetworkHandler::Initialize(); + ash::NetworkHandler::Initialize(); #endif network_change_notifier_ = net::NetworkChangeNotifier::CreateMockIfNeeded(); // We need to initialize the above *before* the base fixture instantiates @@ -73,7 +73,7 @@ DeviceServiceTestBase::TearDown(); #if BUILDFLAG(IS_CHROMEOS_ASH) - chromeos::NetworkHandler::Shutdown(); + ash::NetworkHandler::Shutdown(); chromeos::shill_clients::Shutdown(); #endif
diff --git a/services/device/geolocation/wifi_data_provider_chromeos.cc b/services/device/geolocation/wifi_data_provider_chromeos.cc index bd6473d..f17a3566 100644 --- a/services/device/geolocation/wifi_data_provider_chromeos.cc +++ b/services/device/geolocation/wifi_data_provider_chromeos.cc
@@ -15,7 +15,7 @@ #include "chromeos/ash/components/network/network_handler.h" #include "services/device/geolocation/wifi_data_provider_handle.h" -using chromeos::NetworkHandler; +using ::ash::NetworkHandler; namespace device {
diff --git a/services/media_session/public/mojom/media_session.mojom b/services/media_session/public/mojom/media_session.mojom index b376d2a..8abe36b 100644 --- a/services/media_session/public/mojom/media_session.mojom +++ b/services/media_session/public/mojom/media_session.mojom
@@ -9,7 +9,7 @@ import "ui/gfx/geometry/mojom/geometry.mojom"; import "url/mojom/url.mojom"; -// Next MinVersion: 14 +// Next MinVersion: 15 [Stable, Extensible] enum MediaPlaybackState { @@ -193,6 +193,9 @@ // Tracks whether the media player is muted. [MinVersion=12] bool muted; + + // Tracks whether the associated WebContents has a presentation. + [MinVersion=14] bool has_presentation; }; // Contains debugging information about a MediaSession. This will be displayed
diff --git a/storage/browser/quota/README.md b/storage/browser/quota/README.md index c94d182a..7997cdf5 100644 --- a/storage/browser/quota/README.md +++ b/storage/browser/quota/README.md
@@ -51,7 +51,7 @@ last-modified-time, and last-accessed-time for each origin (used to implement LRU eviction on storage pressure, and Clear Site Data with a time filter), and quota granted via the deprecated API -webkitStorageInfo.requestQuota(PERSISTENT,...). +navigator.webkitPersistentStorage.requestQuota(1000, ...). ### QuotaTemporaryStorageEvictor Handles eviction and records stats about eviction rounds.
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 54295fe..84c22e00 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -80680,7 +80680,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -80712,7 +80712,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -80734,7 +80734,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -80766,7 +80766,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -80788,7 +80788,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -80820,7 +80820,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -80842,7 +80842,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -80874,7 +80874,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -80896,7 +80896,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -80928,7 +80928,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -80950,7 +80950,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -80982,7 +80982,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81004,7 +81004,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81036,7 +81036,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81058,7 +81058,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81090,7 +81090,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81112,7 +81112,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81144,7 +81144,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81166,7 +81166,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81198,7 +81198,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81220,7 +81220,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81252,7 +81252,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81274,7 +81274,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81306,7 +81306,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81328,7 +81328,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81360,7 +81360,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81382,7 +81382,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81414,7 +81414,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81436,7 +81436,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81468,7 +81468,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81490,7 +81490,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81522,7 +81522,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81544,7 +81544,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81576,7 +81576,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81598,7 +81598,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81630,7 +81630,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81652,7 +81652,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81684,7 +81684,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81706,7 +81706,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81738,7 +81738,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81760,7 +81760,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81792,7 +81792,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81814,7 +81814,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81846,7 +81846,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81868,7 +81868,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81900,7 +81900,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81922,7 +81922,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -81954,7 +81954,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -81976,7 +81976,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -82008,7 +82008,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82030,7 +82030,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -82062,7 +82062,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82084,7 +82084,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -82116,7 +82116,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82138,7 +82138,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -82170,7 +82170,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82192,7 +82192,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -82224,7 +82224,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82246,7 +82246,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -82278,7 +82278,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82300,7 +82300,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82333,7 +82333,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82355,7 +82355,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82388,7 +82388,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82410,7 +82410,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82443,7 +82443,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82465,7 +82465,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82498,7 +82498,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82520,7 +82520,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82553,7 +82553,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82575,7 +82575,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82608,7 +82608,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82630,7 +82630,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82663,7 +82663,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82685,7 +82685,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82718,7 +82718,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82740,7 +82740,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82773,7 +82773,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82795,7 +82795,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82828,7 +82828,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82851,7 +82851,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82884,7 +82884,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82907,7 +82907,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82940,7 +82940,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -82963,7 +82963,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -82996,7 +82996,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83019,7 +83019,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83052,7 +83052,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83075,7 +83075,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83108,7 +83108,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83131,7 +83131,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83164,7 +83164,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83187,7 +83187,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83220,7 +83220,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83243,7 +83243,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83276,7 +83276,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83299,7 +83299,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83332,7 +83332,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83355,7 +83355,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83388,7 +83388,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83411,7 +83411,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83444,7 +83444,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83467,7 +83467,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83500,7 +83500,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83523,7 +83523,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83556,7 +83556,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83579,7 +83579,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83612,7 +83612,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83635,7 +83635,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83668,7 +83668,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83691,7 +83691,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83724,7 +83724,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83747,7 +83747,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83780,7 +83780,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83803,7 +83803,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83836,7 +83836,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83859,7 +83859,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83892,7 +83892,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83915,7 +83915,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -83948,7 +83948,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -83971,7 +83971,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84004,7 +84004,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84027,7 +84027,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84060,7 +84060,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84083,7 +84083,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84116,7 +84116,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84139,7 +84139,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84172,7 +84172,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84195,7 +84195,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84228,7 +84228,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84251,7 +84251,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84284,7 +84284,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84307,7 +84307,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84340,7 +84340,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84362,7 +84362,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84395,7 +84395,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84417,7 +84417,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84450,7 +84450,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84472,7 +84472,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84505,7 +84505,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84527,7 +84527,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84560,7 +84560,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84582,7 +84582,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84615,7 +84615,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84637,7 +84637,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84670,7 +84670,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84692,7 +84692,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84725,7 +84725,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84747,7 +84747,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84780,7 +84780,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84802,7 +84802,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84835,7 +84835,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84858,7 +84858,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84891,7 +84891,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84914,7 +84914,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -84947,7 +84947,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -84970,7 +84970,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85003,7 +85003,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85026,7 +85026,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85059,7 +85059,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85082,7 +85082,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85115,7 +85115,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85138,7 +85138,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85171,7 +85171,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85194,7 +85194,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85227,7 +85227,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85250,7 +85250,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85283,7 +85283,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85306,7 +85306,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -85338,7 +85338,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85360,7 +85360,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -85392,7 +85392,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85414,7 +85414,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -85446,7 +85446,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85468,7 +85468,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -85500,7 +85500,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85522,7 +85522,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85555,7 +85555,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85577,7 +85577,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85610,7 +85610,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85632,7 +85632,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85665,7 +85665,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85687,7 +85687,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85720,7 +85720,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85742,7 +85742,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85775,7 +85775,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85797,7 +85797,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85830,7 +85830,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85852,7 +85852,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85885,7 +85885,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85907,7 +85907,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85940,7 +85940,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -85962,7 +85962,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -85995,7 +85995,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86017,7 +86017,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -86049,7 +86049,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86071,7 +86071,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -86103,7 +86103,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86125,7 +86125,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -86157,7 +86157,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86179,7 +86179,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -86212,7 +86212,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86234,7 +86234,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -86267,7 +86267,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86289,7 +86289,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -86322,7 +86322,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86344,7 +86344,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -86376,7 +86376,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86399,7 +86399,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -86431,7 +86431,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86454,7 +86454,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -86486,7 +86486,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86509,7 +86509,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -86541,7 +86541,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86563,7 +86563,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -86595,7 +86595,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86617,7 +86617,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -86649,7 +86649,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86671,7 +86671,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -86704,7 +86704,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86726,7 +86726,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -86759,7 +86759,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86781,7 +86781,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -86814,7 +86814,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86836,7 +86836,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -86869,7 +86869,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86891,7 +86891,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -86924,7 +86924,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -86946,7 +86946,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -86979,7 +86979,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87001,7 +87001,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87034,7 +87034,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87056,7 +87056,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87089,7 +87089,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87111,7 +87111,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87144,7 +87144,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87166,7 +87166,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -87198,7 +87198,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87220,7 +87220,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -87252,7 +87252,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87274,7 +87274,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -87306,7 +87306,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87328,7 +87328,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -87360,7 +87360,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87382,7 +87382,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -87414,7 +87414,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87436,7 +87436,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -87468,7 +87468,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87490,7 +87490,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -87522,7 +87522,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87544,7 +87544,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87577,7 +87577,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87599,7 +87599,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87632,7 +87632,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87654,7 +87654,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87687,7 +87687,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87709,7 +87709,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87742,7 +87742,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87764,7 +87764,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87797,7 +87797,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87819,7 +87819,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87852,7 +87852,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87874,7 +87874,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87907,7 +87907,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87929,7 +87929,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -87962,7 +87962,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -87984,7 +87984,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest", @@ -88017,7 +88017,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88039,7 +88039,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88071,7 +88071,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88093,7 +88093,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88125,7 +88125,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88147,7 +88147,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88179,7 +88179,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88201,7 +88201,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88233,7 +88233,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88255,7 +88255,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88287,7 +88287,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88309,7 +88309,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88341,7 +88341,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88363,7 +88363,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88395,7 +88395,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88417,7 +88417,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88449,7 +88449,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88471,7 +88471,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88503,7 +88503,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88525,7 +88525,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88557,7 +88557,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88579,7 +88579,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88611,7 +88611,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88633,7 +88633,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88665,7 +88665,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88687,7 +88687,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88719,7 +88719,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88741,7 +88741,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88773,7 +88773,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88795,7 +88795,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88827,7 +88827,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88849,7 +88849,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88881,7 +88881,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88903,7 +88903,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88935,7 +88935,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -88957,7 +88957,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -88989,7 +88989,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89011,7 +89011,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89043,7 +89043,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89065,7 +89065,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89097,7 +89097,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89119,7 +89119,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89151,7 +89151,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89173,7 +89173,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89205,7 +89205,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89227,7 +89227,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89259,7 +89259,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89281,7 +89281,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89313,7 +89313,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89335,7 +89335,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89367,7 +89367,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89389,7 +89389,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89421,7 +89421,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89443,7 +89443,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89475,7 +89475,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89497,7 +89497,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89529,7 +89529,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89551,7 +89551,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89583,7 +89583,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89605,7 +89605,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89637,7 +89637,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89659,7 +89659,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89691,7 +89691,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, { @@ -89713,7 +89713,7 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "14a5284g", + "14a5294e", "--readline-timeout", "600", "--xctest" @@ -89745,7 +89745,7 @@ ], "named_caches": [ { - "name": "xcode_ios_14a5284g", + "name": "xcode_ios_14a5294e", "path": "Xcode.app" }, {
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index d99d8265..cc04210 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -1382,6 +1382,23 @@ ], }, }, + # Xcode 14 beta 5. + 'xcode_14_beta_5': { + '$mixin_append': { + 'args': [ + '--xcode-build-version', + '14a5294e' + ], + }, + 'swarming': { + 'named_caches': [ + { + 'name': 'xcode_ios_14a5294e', + 'path': 'Xcode.app', + }, + ], + }, + }, # Xcode 14 on iOS main. 'xcode_14_main': { '$mixin_append': {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index cc58025..d55ad97 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -3454,7 +3454,7 @@ 'mac_beta_x64', 'mac_toolchain', 'out_dir_arg', - 'xcode_14_beta', + 'xcode_14_beta_5', # crbug/1343123: temporarily increasing readline timeout due to slow simulator start up time. 'xcode_14_readline_timeout', 'xctest',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 928f288..309599e 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -3429,6 +3429,21 @@ ] } ], + "DeprecateAssistantStylusFeatures": [ + { + "platforms": [ + "chromeos" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "DeprecateAssistantStylusFeatures" + ] + } + ] + } + ], "DeprioritizeTimersUntilDOMContentLoadedExperiment": [ { "platforms": [ @@ -5123,6 +5138,16 @@ "name": "Enabled", "enable_features": [ "CalendarExperienceKit" + ], + "disable_features": [ + "EnableExpKitCalendarTextClassifier" + ] + }, + { + "name": "EnabledWithTextClassifier", + "enable_features": [ + "CalendarExperienceKit", + "EnableExpKitCalendarTextClassifier" ] } ] @@ -5916,21 +5941,6 @@ ] } ], - "LocationBarModelOptimizations": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "LocationBarModelOptimizations" - ] - } - ] - } - ], "MacAllowBackgroundingProcesses": [ { "platforms": [ @@ -6828,21 +6838,6 @@ ] } ], - "PartialCustomTabs": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "CCTResizableAllowResizeByUserGesture" - ] - } - ] - } - ], "PartialCustomTabs3rdPartyPolicy": [ { "platforms": [
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn index d10f539..7439e172e 100644 --- a/third_party/blink/public/common/BUILD.gn +++ b/third_party/blink/public/common/BUILD.gn
@@ -255,6 +255,7 @@ "permissions_policy/policy_value.h", "renderer_preferences/renderer_preferences.h", "responsiveness_metrics/user_interaction_latency.h", + "scheduler/task_attribution_id.h", "scheduler/web_scheduler_tracked_feature.h", "scheme_registry.h", "security/address_space_feature.h",
diff --git a/third_party/blink/public/common/scheduler/task_attribution_id.h b/third_party/blink/public/common/scheduler/task_attribution_id.h new file mode 100644 index 0000000..f50e7ac --- /dev/null +++ b/third_party/blink/public/common/scheduler/task_attribution_id.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 THIRD_PARTY_BLINK_PUBLIC_COMMON_SCHEDULER_TASK_ATTRIBUTION_ID_H_ +#define THIRD_PARTY_BLINK_PUBLIC_COMMON_SCHEDULER_TASK_ATTRIBUTION_ID_H_ + +#include <cstdint> +#include "base/types/strong_alias.h" + +namespace blink::scheduler { + +using TaskAttributionIdType = uint32_t; + +// TaskAttributionId represents the ID of a task scope, encompassing a task and +// its continuations. It enables comparison and incrementation operations on it, +// while abstracting the underlying value from callers. +class TaskAttributionId { + public: + explicit TaskAttributionId(TaskAttributionIdType value) : value_(value) {} + TaskAttributionId(const TaskAttributionId&) = default; + TaskAttributionId& operator=(const TaskAttributionId&) = default; + TaskAttributionIdType value() const { return value_; } + + bool operator==(const TaskAttributionId& id) const { + return id.value_ == value_; + } + bool operator!=(const TaskAttributionId& id) const { + return id.value_ != value_; + } + bool operator<(const TaskAttributionId& id) const { + return value_ < id.value_; + } + TaskAttributionId NextId() const { return TaskAttributionId(value_ + 1); } + + private: + TaskAttributionIdType value_; +}; + +} // namespace blink::scheduler + +#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_SCHEDULER_TASK_ATTRIBUTION_ID_H_
diff --git a/third_party/blink/public/web/web_plugin.h b/third_party/blink/public/web/web_plugin.h index 9773e8d..72dd64ef 100644 --- a/third_party/blink/public/web/web_plugin.h +++ b/third_party/blink/public/web/web_plugin.h
@@ -149,13 +149,17 @@ return false; } - // Sets up printing with the specified printParams. Returns the number of - // pages to be printed at these settings. + // Begins a print session with the given `print_params`. A call to + // `PrintPage()` can only be made after after a successful call to + // `PrintBegin()`. Returns the number of pages required for the print output. + // A returned value of 0 indicates failure. virtual int PrintBegin(const WebPrintParams& print_params) { return 0; } + // Prints the page specified by `page_number`, using the parameters passed to + // `PrintBegin()`, into `canvas`. virtual void PrintPage(int page_number, cc::PaintCanvas* canvas) {} - // Ends the print operation. + // Ends the print session. Further calls to `PrintPages()` will fail. virtual void PrintEnd() {} virtual bool HasSelection() const { return false; }
diff --git a/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc b/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc index 151a2d5..3a0bbcb 100644 --- a/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc +++ b/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc
@@ -106,11 +106,11 @@ // have also elided creating a new scope entirely. 2) If there is no // current running task, set the parent to absl::nullopt, making the // current callback a root task. - absl::optional<scheduler::TaskId> parent_id = + absl::optional<scheduler::TaskAttributionId> parent_id = callback_->GetParentTaskId(); if (!parent_id) { - parent_id = - tracker->RunningTaskId(callback_->CallbackRelevantScriptState()); + parent_id = tracker->RunningTaskAttributionId( + callback_->CallbackRelevantScriptState()); } task_attribution_scope_ = tracker->CreateTaskScope( callback_->CallbackRelevantScriptState(), parent_id);
diff --git a/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc b/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc index 3188fe6..23b7d12 100644 --- a/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc +++ b/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc
@@ -64,7 +64,8 @@ arguments_ = arguments; auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker(); if (tracker && script_state->World().IsMainWorld()) { - function_->SetParentTaskId(tracker->RunningTaskId(script_state)); + function_->SetParentTaskId( + tracker->RunningTaskAttributionId(script_state)); } } else { UseCounter::Count(target, WebFeature::kScheduledActionIgnored); @@ -84,7 +85,7 @@ code_ = handler; auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker(); if (tracker && script_state->World().IsMainWorld()) { - code_parent_task_id_ = tracker->RunningTaskId(script_state); + code_parent_task_id_ = tracker->RunningTaskAttributionId(script_state); } } else { UseCounter::Count(target, WebFeature::kScheduledActionIgnored);
diff --git a/third_party/blink/renderer/bindings/core/v8/scheduled_action.h b/third_party/blink/renderer/bindings/core/v8/scheduled_action.h index fc5df33d..cb73ef3d 100644 --- a/third_party/blink/renderer/bindings/core/v8/scheduled_action.h +++ b/third_party/blink/renderer/bindings/core/v8/scheduled_action.h
@@ -32,10 +32,10 @@ #define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCHEDULED_ACTION_H_ #include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/renderer/platform/bindings/name_client.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" -#include "third_party/blink/renderer/platform/scheduler/public/task_id.h" #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "v8/include/v8.h" @@ -78,7 +78,7 @@ Member<V8Function> function_; HeapVector<ScriptValue> arguments_; String code_; - absl::optional<scheduler::TaskId> code_parent_task_id_; + absl::optional<scheduler::TaskAttributionId> code_parent_task_id_; }; } // namespace blink
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni index 0cef5d1..9a9b7a41 100644 --- a/third_party/blink/renderer/bindings/generated_in_modules.gni +++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -895,8 +895,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_save_file_picker_options.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_scheduler_post_task_options.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_scheduler_post_task_options.h", - "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_id.cc", - "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_id.h", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_attribution_id.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_attribution_id.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_secure_payment_confirmation_request.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_secure_payment_confirmation_request.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sensor_error_event_init.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni index 0f06adc..bf50224 100644 --- a/third_party/blink/renderer/bindings/idl_in_modules.gni +++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -653,7 +653,7 @@ "//third_party/blink/renderer/modules/scheduler/scheduler.idl", "//third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl", "//third_party/blink/renderer/modules/scheduler/scheduler_post_task_options.idl", - "//third_party/blink/renderer/modules/scheduler/script_wrappable_task_id.idl", + "//third_party/blink/renderer/modules/scheduler/script_wrappable_task_attribution_id.idl", "//third_party/blink/renderer/modules/scheduler/task_controller.idl", "//third_party/blink/renderer/modules/scheduler/task_controller_init.idl", "//third_party/blink/renderer/modules/scheduler/task_priority_change_event.idl",
diff --git a/third_party/blink/renderer/core/editing/substring_util.mm b/third_party/blink/renderer/core/editing/substring_util.mm index bb3815d..6dc25f21 100644 --- a/third_party/blink/renderer/core/editing/substring_util.mm +++ b/third_party/blink/renderer/core/editing/substring_util.mm
@@ -86,7 +86,8 @@ const Node& container = it.CurrentContainer(); const LayoutObject* layout_object = container.GetLayoutObject(); - DCHECK(layout_object); + if (!layout_object) + continue; // There are two ways that the size of text can be affected by the user. One // is the page scale factor, which is what the user changes by pinching on
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index 77b574c3..cae474b 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -1821,7 +1821,7 @@ ScriptState* script_state = callback->CallbackRelevantScriptState(); auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker(); if (tracker && script_state->World().IsMainWorld()) { - callback->SetParentTaskId(tracker->RunningTaskId(script_state)); + callback->SetParentTaskId(tracker->RunningTaskAttributionId(script_state)); } Microtask::EnqueueMicrotask( WTF::Bind(&V8VoidFunction::InvokeAndReportException,
diff --git a/third_party/blink/renderer/core/html/build.gni b/third_party/blink/renderer/core/html/build.gni index c18d792..abf6554d 100644 --- a/third_party/blink/renderer/core/html/build.gni +++ b/third_party/blink/renderer/core/html/build.gni
@@ -614,8 +614,6 @@ "parser/html_token.h", "parser/html_tokenizer.cc", "parser/html_tokenizer.h", - "parser/html_tokenizer_metrics_reporter.cc", - "parser/html_tokenizer_metrics_reporter.h", "parser/html_tree_builder.cc", "parser/html_tree_builder.h", "parser/html_view_source_parser.cc", @@ -722,7 +720,6 @@ "parser/background_html_scanner_test.cc", "parser/html_resource_preloader_test.cc", "parser/html_srcset_parser_test.cc", - "parser/html_tokenizer_metrics_reporter_test.cc", "parser/html_tree_builder_test.cc", "parser/html_tokenizer_test.cc", "parser/html_view_source_parser_test.cc",
diff --git a/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc b/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc index b0a0120..ffd1759 100644 --- a/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc +++ b/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
@@ -337,18 +337,12 @@ if (!input || input->IsDisabledFormControl() || !event) return; - auto* thumb = To<SliderThumbElement>( - GetTreeScope().getElementById(shadow_element_names::kIdSliderThumb)); - - // TODO: Also do this for touchcancel? if (event->type() == event_type_names::kTouchend) { - if (!touch_moved_ && thumb) - thumb->SetPositionFromPoint(start_point_); + // TODO: Also do this for touchcancel? input->DispatchFormControlChangeEvent(); event->SetDefaultHandled(); sliding_direction_ = Direction::kNoMove; touch_started_ = false; - touch_moved_ = false; return; } @@ -359,6 +353,8 @@ } TouchList* touches = event->targetTouches(); + auto* thumb = To<SliderThumbElement>( + GetTreeScope().getElementById(shadow_element_names::kIdSliderThumb)); if (!thumb || !touches) return; @@ -367,9 +363,8 @@ start_point_ = touches->item(0)->AbsoluteLocation(); sliding_direction_ = Direction::kNoMove; touch_started_ = true; - touch_moved_ = false; + thumb->SetPositionFromPoint(touches->item(0)->AbsoluteLocation()); } else if (touch_started_) { - touch_moved_ = true; LayoutPoint current_point = touches->item(0)->AbsoluteLocation(); if (sliding_direction_ == Direction::kNoMove) { // Still needs to update the direction.
diff --git a/third_party/blink/renderer/core/html/forms/slider_thumb_element.h b/third_party/blink/renderer/core/html/forms/slider_thumb_element.h index 437ff3f..15f1cec 100644 --- a/third_party/blink/renderer/core/html/forms/slider_thumb_element.h +++ b/third_party/blink/renderer/core/html/forms/slider_thumb_element.h
@@ -111,7 +111,6 @@ bool has_touch_event_handler_ = false; bool touch_started_ = false; - bool touch_moved_ = false; Direction sliding_direction_ = Direction::kNoMove; LayoutPoint start_point_; };
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/third_party/blink/renderer/core/html/parser/html_document_parser.cc index 14600a8..a02061e 100644 --- a/third_party/blink/renderer/core/html/parser/html_document_parser.cc +++ b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -537,12 +537,6 @@ document.UkmSourceID(), document.UkmRecorder()); } - if (GetDocument()->IsInOutermostMainFrame() && - !task_runner_state_->IsSynchronous()) { - tokenizer_metrics_reporter_ = - std::make_unique<HTMLTokenizerMetricsReporter>(tokenizer_.get()); - } - // Don't create preloader for parsing clipboard content. if (content_policy == kDisallowScriptingAndPluginContent) return; @@ -592,8 +586,6 @@ insertion_preload_scanner_.reset(); background_script_scanner_.Reset(); background_scanner_.Reset(); - // `tokenizer_metrics_reporter_` has a reference to `tokenizer_`. - tokenizer_metrics_reporter_.reset(); // Oilpan: It is important to clear token_ to deallocate backing memory of // HTMLToken::data_ and let the allocator reuse the memory for // HTMLToken::data_ of a next HTMLDocumentParser. We need to clear @@ -842,9 +834,6 @@ RUNTIME_CALL_TIMER_SCOPE( V8PerIsolateData::MainThreadIsolate(), RuntimeCallStats::CounterId::kHTMLTokenizerNextToken); - if (tokenizer_metrics_reporter_) - tokenizer_metrics_reporter_->WillProcessNextToken(input_.Current()); - if (!tokenizer_->NextToken(input_.Current(), Token())) break; budget--; @@ -969,11 +958,6 @@ // parser. Token().Clear(); - if (tokenizer_metrics_reporter_) { - tokenizer_metrics_reporter_->WillConstructTreeFromToken(atomic_token, - input_.Current()); - } - tree_builder_->ConstructTree(&atomic_token); CheckIfBlockingStylesheetAdded(); } @@ -995,9 +979,6 @@ TRACE_EVENT2("blink", "HTMLDocumentParser::insert", "source_length", source.length(), "parser", (void*)this); - if (tokenizer_metrics_reporter_ && !source.IsEmpty()) - tokenizer_metrics_reporter_->OnDocumentWrite(input_.Current()); - SegmentedString excluded_line_number_source(source); excluded_line_number_source.SetExcludeLineNumbers(); input_.InsertAtCurrentInsertionPoint(excluded_line_number_source); @@ -1072,8 +1053,6 @@ } } - if (tokenizer_metrics_reporter_) - tokenizer_metrics_reporter_->WillAppend(input_source); input_.AppendToEnd(source); task_runner_state_->MarkSeenFirstByte();
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.h b/third_party/blink/renderer/core/html/parser/html_document_parser.h index 9d3cc6e8..a9f7900 100644 --- a/third_party/blink/renderer/core/html/parser/html_document_parser.h +++ b/third_party/blink/renderer/core/html/parser/html_document_parser.h
@@ -41,7 +41,6 @@ #include "third_party/blink/renderer/core/html/parser/html_preload_scanner.h" #include "third_party/blink/renderer/core/html/parser/html_token.h" #include "third_party/blink/renderer/core/html/parser/html_tokenizer.h" -#include "third_party/blink/renderer/core/html/parser/html_tokenizer_metrics_reporter.h" #include "third_party/blink/renderer/core/html/parser/parser_synchronization_policy.h" #include "third_party/blink/renderer/core/html/parser/preload_request.h" #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h" @@ -112,16 +111,6 @@ HTMLTokenizer* Tokenizer() const { return tokenizer_.get(); } - void SetTokenizerState(const AtomicHTMLToken& token, - HTMLTokenizer::State state) { - DCHECK(tokenizer_); - if (tokenizer_metrics_reporter_) { - tokenizer_metrics_reporter_->WillChangeTokenizerState(input_.Current(), - token, state); - } - tokenizer_->SetState(state); - } - TextPosition GetTextPosition() const final; OrdinalNumber LineNumber() const final; @@ -230,7 +219,6 @@ Member<HTMLParserReentryPermit> reentry_permit_ = MakeGarbageCollected<HTMLParserReentryPermit>(); - std::unique_ptr<HTMLTokenizerMetricsReporter> tokenizer_metrics_reporter_; std::unique_ptr<HTMLToken> token_; std::unique_ptr<HTMLTokenizer> tokenizer_; Member<HTMLParserScriptRunner> script_runner_;
diff --git a/third_party/blink/renderer/core/html/parser/html_tokenizer_metrics_reporter.cc b/third_party/blink/renderer/core/html/parser/html_tokenizer_metrics_reporter.cc deleted file mode 100644 index e54b7e49..0000000 --- a/third_party/blink/renderer/core/html/parser/html_tokenizer_metrics_reporter.cc +++ /dev/null
@@ -1,200 +0,0 @@ -// Copyright 2022 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/html/parser/html_tokenizer_metrics_reporter.h" - -#include "base/metrics/histogram_functions.h" -#include "base/task/sequenced_task_runner.h" -#include "third_party/blink/renderer/core/html/parser/atomic_html_token.h" -#include "third_party/blink/renderer/core/html/parser/html_token.h" -#include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h" -#include "third_party/blink/renderer/platform/text/segmented_string.h" - -namespace blink { -namespace { - -const LChar kCData[] = "<![CDATA["; -// Don't include the \0 in the count. -constexpr wtf_size_t kCDataLength = - static_cast<wtf_size_t>(std::size(kCData) - 1); - -} // namespace - -// static -base::RepeatingClosure* - HTMLTokenizerMetricsReporter::metrics_logged_callback_for_test_ = nullptr; - -HTMLTokenizerMetricsReporter::BackgroundReporter::~BackgroundReporter() { - // Only log if something was actually parsed. - if (input_length_encountered_ == 0) - return; - - const int bitmask = - (document_write_encountered_ ? 1 : 0) | - (speculative_state_mismatch_ ? 2 : 0) | - (index_of_null_char_ != std::numeric_limits<unsigned>::max() ? 4 : 0) | - (index_of_cdata_section_ != std::numeric_limits<unsigned>::max() ? 8 : 0); - base::UmaHistogramExactLinear("Blink.Tokenizer.MainDocument.ATypicalStates", - bitmask, 16); - if (bitmask != 0) { - const unsigned min_position = std::min( - std::min(write_or_state_mismatch_position_, index_of_null_char_), - index_of_cdata_section_); - base::UmaHistogramCounts10M( - "Blink.Tokenizer.MainDocument.LocationOfFirstATypicalState", - min_position); - } - if (metrics_logged_callback_for_test_) - metrics_logged_callback_for_test_->Run(); -} - -void HTMLTokenizerMetricsReporter::BackgroundReporter::WillAppend( - const String& content) { - UpdateIndexOfNullChar(content); - UpdateIndexOfCDATA(content); - input_length_encountered_ += content.length(); -} - -void HTMLTokenizerMetricsReporter::BackgroundReporter::DocumentWriteEncountered( - int position) { - DCHECK(!document_write_encountered_); - document_write_encountered_ = true; - write_or_state_mismatch_position_ = std::min( - write_or_state_mismatch_position_, static_cast<unsigned>(position)); -} - -void HTMLTokenizerMetricsReporter::BackgroundReporter::SpeculativeStateMismatch( - int position) { - DCHECK(!speculative_state_mismatch_); - speculative_state_mismatch_ = true; - write_or_state_mismatch_position_ = std::min( - write_or_state_mismatch_position_, static_cast<unsigned>(position)); -} - -void HTMLTokenizerMetricsReporter::BackgroundReporter::UpdateIndexOfNullChar( - const String& string) { - if (index_of_null_char_ != std::numeric_limits<unsigned>::max()) - return; - - index_of_null_char_ = string.find(static_cast<UChar>('\0')); - if (index_of_null_char_ != kNotFound) - index_of_null_char_ += input_length_encountered_; - else - index_of_null_char_ = std::numeric_limits<unsigned>::max(); -} - -bool HTMLTokenizerMetricsReporter::BackgroundReporter:: - MatchPossibleCDataSection(const String& string, - wtf_size_t start_string_index) { - DCHECK_GT(num_matching_cdata_chars_, 0u); - DCHECK_LT(start_string_index, kNotFound); - const wtf_size_t string_length = string.length(); - wtf_size_t i = 0; - // Iterate through `string` while it matches `kCData`. i starts at 0, but is - // relative to `start_string_index`. `num_matching_cdata_chars_` is the - // position into `kCData` to start the match from (portion of previous string - // that matched). - while (i + num_matching_cdata_chars_ < kCDataLength && - (i + start_string_index) < string_length && - string[i + start_string_index] == - kCData[i + num_matching_cdata_chars_]) { - ++i; - } - if (i + num_matching_cdata_chars_ == kCDataLength) { - // Matched all cdata. - index_of_cdata_section_ = - input_length_encountered_ + i + start_string_index - kCDataLength; - return true; - } - if ((i + start_string_index) == string_length) { - // This branch is hit in the case of matching all available data, but - // more is required for a full match. - num_matching_cdata_chars_ += i; - return true; - } - return false; -} - -void HTMLTokenizerMetricsReporter::BackgroundReporter::UpdateIndexOfCDATA( - const String& string) { - if (index_of_cdata_section_ != std::numeric_limits<unsigned>::max()) - return; - - if (num_matching_cdata_chars_ != 0) { - if (MatchPossibleCDataSection(string, 0)) - return; - num_matching_cdata_chars_ = 0; - } - - for (wtf_size_t next_possible_index = 0; next_possible_index != kNotFound; - next_possible_index = string.find(kCData[0], next_possible_index)) { - num_matching_cdata_chars_ = 1; - if (MatchPossibleCDataSection(string, next_possible_index + 1)) - return; - ++next_possible_index; - } - num_matching_cdata_chars_ = 0; -} - -HTMLTokenizerMetricsReporter::HTMLTokenizerMetricsReporter( - const HTMLTokenizer* tokenizer) - : tokenizer_(tokenizer), - background_reporter_(worker_pool::CreateSequencedTaskRunner( - {base::TaskPriority::BEST_EFFORT})) {} - -void HTMLTokenizerMetricsReporter::WillConstructTreeFromToken( - const AtomicHTMLToken& token, - const SegmentedString& input) { - if (speculative_state_mismatch_) - return; - - if (token.GetType() == HTMLToken::kStartTag) { - last_token_was_start_ = true; - tokenizer_state_for_start_ = - tokenizer_->SpeculativeStateForTag(token.GetName()); - } -} - -void HTMLTokenizerMetricsReporter::WillChangeTokenizerState( - const SegmentedString& input, - const AtomicHTMLToken& token, - HTMLTokenizer::State state) { - if (speculative_state_mismatch_) - return; - - if (token.GetType() != HTMLToken::kStartTag && - state != tokenizer_->GetState()) { - RecordSpeculativeStateMismatch(input.NumberOfCharactersConsumed()); - } -} - -void HTMLTokenizerMetricsReporter::OnDocumentWrite( - const SegmentedString& input) { - if (document_write_encountered_) - return; - document_write_encountered_ = true; - // At the time this is called `input` should have a next segment string with - // the data before the write. See InsertionPointRecord. - const int length = - input.NextSegmentedString() - ? input.NextSegmentedString()->NumberOfCharactersConsumed() - : input.NumberOfCharactersConsumed(); - background_reporter_.AsyncCall(&BackgroundReporter::DocumentWriteEncountered) - .WithArgs(length); -} - -void HTMLTokenizerMetricsReporter::WillAppend(const String& content) { - background_reporter_.AsyncCall(&BackgroundReporter::WillAppend) - .WithArgs(content); -} - -void HTMLTokenizerMetricsReporter::RecordSpeculativeStateMismatch( - int position) { - DCHECK(!speculative_state_mismatch_); - speculative_state_mismatch_ = true; - background_reporter_.AsyncCall(&BackgroundReporter::SpeculativeStateMismatch) - .WithArgs(position); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/html/parser/html_tokenizer_metrics_reporter.h b/third_party/blink/renderer/core/html/parser/html_tokenizer_metrics_reporter.h deleted file mode 100644 index 4206dd6..0000000 --- a/third_party/blink/renderer/core/html/parser/html_tokenizer_metrics_reporter.h +++ /dev/null
@@ -1,143 +0,0 @@ -// Copyright 2022 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 THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_HTML_TOKENIZER_METRICS_REPORTER_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_HTML_TOKENIZER_METRICS_REPORTER_H_ - -#include <limits> - -#include "base/callback.h" -#include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/core/html/parser/html_tokenizer.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/sequence_bound.h" -#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" - -namespace blink { - -class AtomicHTMLToken; -class SegmentedString; - -// HTMLTokenizerMetricsReporter is used to track how often a handful of -// non-typical cases occur when tokenizing. It specifically tracks the -// following: -// . document.write(). -// . A null character. -// . CDATA section. -// . How often SpeculativeStateForTag() doesn't match the actual state. -// This code is called on the critical path, so detection of a null character -// and CDATA are done in the background. Logging is done once in the destructor -// (in the background). -// -// TODO(crbug.com/1345267): remove this class once data has been collected. -class CORE_EXPORT HTMLTokenizerMetricsReporter { - USING_FAST_MALLOC(HTMLTokenizerMetricsReporter); - - public: - explicit HTMLTokenizerMetricsReporter(const HTMLTokenizer* tokenizer); - - // Called prior to HTMLTokenizer::NextToken(). - void WillProcessNextToken(const SegmentedString& input) { - if (speculative_state_mismatch_) - return; - - if (last_token_was_start_) { - last_token_was_start_ = false; - if (tokenizer_state_for_start_.has_value() && - tokenizer_state_for_start_ != tokenizer_->GetState()) { - RecordSpeculativeStateMismatch(input.NumberOfCharactersConsumed()); - } - } - } - - // Called after a token has been created by the tokenizer but before - // ConstructTree(). - void WillConstructTreeFromToken(const AtomicHTMLToken& token, - const SegmentedString& input); - - // Called when the state of the tokenizer is going to be explicitly set. - void WillChangeTokenizerState(const SegmentedString& input, - const AtomicHTMLToken& token, - HTMLTokenizer::State state); - - // Called when document.write() occurs. - void OnDocumentWrite(const SegmentedString& input); - - // Called when data is available to be tokenized. - void WillAppend(const String& content); - - // BackgroundReporter does the actual metric recording, as well as any - // non-trivial processing. The public methods of HTMLTokenizerMetricsReporter - // call through to this object so that it can log the metrics in the - // destructor. - // - // NOTE: public for tests, treat as private. - class CORE_EXPORT BackgroundReporter { - USING_FAST_MALLOC(BackgroundReporter); - - public: - ~BackgroundReporter(); - - void WillAppend(const String& content); - void DocumentWriteEncountered(int position); - void SpeculativeStateMismatch(int position); - - unsigned index_of_null_char() const { return index_of_null_char_; } - - unsigned index_of_cdata_section() const { return index_of_cdata_section_; } - - private: - void UpdateIndexOfNullChar(const String& string); - // Attempts to match a possible cdata secition. `string` is the string to - // search in, starting at `start_string_index`. Returns true on success, - // or the section matches but the end of input is reached (partial match). - bool MatchPossibleCDataSection(const String& string, - wtf_size_t start_string_index); - void UpdateIndexOfCDATA(const String& string); - - bool document_write_encountered_ = false; - bool speculative_state_mismatch_ = false; - unsigned write_or_state_mismatch_position_ = - std::numeric_limits<unsigned>::max(); - - // Amount of data encountered to date (sum of length of strings supplied - // to WillAppend()). - unsigned input_length_encountered_ = 0; - - unsigned index_of_null_char_ = std::numeric_limits<unsigned>::max(); - - // Following is used to match a CDATA section: - unsigned index_of_cdata_section_ = std::numeric_limits<unsigned>::max(); - unsigned num_matching_cdata_chars_ = 0; - }; - - // Run when metrics have been logged. Provided for tests. This callback is - // run on a background thread. - static base::RepeatingClosure* metrics_logged_callback_for_test_; - - private: - void RecordSpeculativeStateMismatch(int position); - - const HTMLTokenizer* tokenizer_; - - // True if the last token was a start. - bool last_token_was_start_ = false; - - // If the last token was a start tag, this is the corresponding speculative - // state (which may not be set). - absl::optional<HTMLTokenizer::State> tokenizer_state_for_start_; - - // Whether document.write() was encountered. - bool document_write_encountered_ = false; - - // Whether the Tokenizer state from the builder does not match the - // speculative state. - bool speculative_state_mismatch_ = false; - - WTF::SequenceBound<BackgroundReporter> background_reporter_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_HTML_TOKENIZER_METRICS_REPORTER_H_
diff --git a/third_party/blink/renderer/core/html/parser/html_tokenizer_metrics_reporter_test.cc b/third_party/blink/renderer/core/html/parser/html_tokenizer_metrics_reporter_test.cc deleted file mode 100644 index e0fb1dc..0000000 --- a/third_party/blink/renderer/core/html/parser/html_tokenizer_metrics_reporter_test.cc +++ /dev/null
@@ -1,112 +0,0 @@ -// Copyright 2022 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/html/parser/html_tokenizer_metrics_reporter.h" - -#include "base/bind.h" -#include "base/run_loop.h" -#include "base/test/metrics/histogram_tester.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/renderer/core/html/html_document.h" -#include "third_party/blink/renderer/core/html/parser/html_document_parser.h" -#include "third_party/blink/renderer/core/testing/sim/sim_request.h" -#include "third_party/blink/renderer/core/testing/sim/sim_test.h" - -namespace blink { - -TEST(HTMLTokenizerMetricsReporterTest, FindNullChar) { - HTMLTokenizerMetricsReporter::BackgroundReporter reporter; - reporter.WillAppend(String("123\0", 4u)); - EXPECT_EQ(3u, reporter.index_of_null_char()); -} - -TEST(HTMLTokenizerMetricsReporterTest, FindNullCharSecondChunk) { - HTMLTokenizerMetricsReporter::BackgroundReporter reporter; - reporter.WillAppend("abc"); - reporter.WillAppend(String("d\0f", 3u)); - EXPECT_EQ(4u, reporter.index_of_null_char()); -} - -TEST(HTMLTokenizerMetricsReporterTest, SimpleCData) { - HTMLTokenizerMetricsReporter::BackgroundReporter reporter; - reporter.WillAppend("abcdef<<![CDATA["); - EXPECT_EQ(7u, reporter.index_of_cdata_section()); -} - -TEST(HTMLTokenizerMetricsReporterTest, SplitCData) { - HTMLTokenizerMetricsReporter::BackgroundReporter reporter; - reporter.WillAppend("abc<!["); - reporter.WillAppend("CD"); - reporter.WillAppend("ATA["); - EXPECT_EQ(3u, reporter.index_of_cdata_section()); -} - -TEST(HTMLTokenizerMetricsReporterTest, IncompleteCData) { - HTMLTokenizerMetricsReporter::BackgroundReporter reporter; - reporter.WillAppend("abcdef<<![CDATA"); - EXPECT_EQ(std::numeric_limits<unsigned>::max(), - reporter.index_of_cdata_section()); -} - -TEST(HTMLTokenizerMetricsReporterTest, SplitWithPartialThenFull) { - HTMLTokenizerMetricsReporter::BackgroundReporter reporter; - reporter.WillAppend("abc<!["); - reporter.WillAppend("<![CDATA["); - EXPECT_EQ(6u, reporter.index_of_cdata_section()); -} - -class HTMLTokenizerMetricsReporterSimTest : public SimTest { - public: - void LoadPageWithContentForReporter(const String& string) { - // To ensure metrics reporter is created. - Document::SetForceSynchronousParsingForTesting(false); - base::RunLoop run_loop; - auto quit_closure = run_loop.QuitClosure(); - HTMLTokenizerMetricsReporter::metrics_logged_callback_for_test_ = - &quit_closure; - - String source("https://example.com/p1"); - SimRequest main_resource(source, "text/html"); - LoadURL(source); - main_resource.Complete(string); - - // Because SetForceSynchronousParsingForTesting(false) was called, - // tokenizing doesn't happen immediately. Use this to ensure it runs. - base::RunLoop().RunUntilIdle(); - - String source2("https://example.com/p2"); - SimRequest resource2(source2, "text/html"); - Document::SetForceSynchronousParsingForTesting(true); - LoadURL(source2); - resource2.Complete("empty"); - - run_loop.Run(); - HTMLTokenizerMetricsReporter::metrics_logged_callback_for_test_ = nullptr; - } -}; - -TEST_F(HTMLTokenizerMetricsReporterSimTest, UnexpectedState) { - base::HistogramTester tester; - LoadPageWithContentForReporter("<svg><style></style></svg>"); - // Bucket 2 means a state mismatch. - tester.ExpectUniqueSample("Blink.Tokenizer.MainDocument.ATypicalStates", 2, - 1); -} - -TEST_F(HTMLTokenizerMetricsReporterSimTest, DocumentWrite) { - base::HistogramTester tester; - LoadPageWithContentForReporter("<script>document.write('test');</script>"); - // Bucket 1 is for document.write(). - tester.ExpectUniqueSample("Blink.Tokenizer.MainDocument.ATypicalStates", 1, - 1); -} - -TEST_F(HTMLTokenizerMetricsReporterSimTest, EmbeddedNull) { - base::HistogramTester tester; - LoadPageWithContentForReporter(String("<div>t\0ext", 10u)); - tester.ExpectUniqueSample("Blink.Tokenizer.MainDocument.ATypicalStates", 4, - 1); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc index 887deab..1561b3d 100644 --- a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc +++ b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
@@ -677,7 +677,7 @@ case TagParsingGroup::kPlaintextTag: ProcessFakePEndTagIfPInButtonScope(); tree_.InsertHTMLElement(token); - parser_->SetTokenizerState(*token, HTMLTokenizer::kPLAINTEXTState); + parser_->Tokenizer()->SetState(HTMLTokenizer::kPLAINTEXTState); break; case TagParsingGroup::kATag: { Element* active_a_tag = @@ -751,7 +751,7 @@ case TagParsingGroup::kTextareaTag: tree_.InsertHTMLElement(token); should_skip_leading_newline_ = true; - parser_->SetTokenizerState(*token, HTMLTokenizer::kRCDATAState); + parser_->Tokenizer()->SetState(HTMLTokenizer::kRCDATAState); original_insertion_mode_ = insertion_mode_; frameset_ok_ = false; SetInsertionMode(kTextMode); @@ -2165,7 +2165,7 @@ // We must set the tokenizer's state to DataState explicitly if the // tokenizer didn't have a chance to. - parser_->SetTokenizerState(*token, HTMLTokenizer::kDataState); + parser_->Tokenizer()->SetState(HTMLTokenizer::kDataState); return; } tree_.OpenElements()->Pop(); @@ -2698,7 +2698,7 @@ void HTMLTreeBuilder::ProcessGenericRCDATAStartTag(AtomicHTMLToken* token) { DCHECK_EQ(token->GetType(), HTMLToken::kStartTag); tree_.InsertHTMLElement(token); - parser_->SetTokenizerState(*token, HTMLTokenizer::kRCDATAState); + parser_->Tokenizer()->SetState(HTMLTokenizer::kRCDATAState); original_insertion_mode_ = insertion_mode_; SetInsertionMode(kTextMode); } @@ -2706,7 +2706,7 @@ void HTMLTreeBuilder::ProcessGenericRawTextStartTag(AtomicHTMLToken* token) { DCHECK_EQ(token->GetType(), HTMLToken::kStartTag); tree_.InsertHTMLElement(token); - parser_->SetTokenizerState(*token, HTMLTokenizer::kRAWTEXTState); + parser_->Tokenizer()->SetState(HTMLTokenizer::kRAWTEXTState); original_insertion_mode_ = insertion_mode_; SetInsertionMode(kTextMode); } @@ -2714,7 +2714,7 @@ void HTMLTreeBuilder::ProcessScriptStartTag(AtomicHTMLToken* token) { DCHECK_EQ(token->GetType(), HTMLToken::kStartTag); tree_.InsertScriptElement(token); - parser_->SetTokenizerState(*token, HTMLTokenizer::kScriptDataState); + parser_->Tokenizer()->SetState(HTMLTokenizer::kScriptDataState); original_insertion_mode_ = insertion_mode_; TextPosition position = parser_->GetTextPosition();
diff --git a/third_party/blink/renderer/core/input/touch_event_manager_test.cc b/third_party/blink/renderer/core/input/touch_event_manager_test.cc index aa83914..5266a0a 100644 --- a/third_party/blink/renderer/core/input/touch_event_manager_test.cc +++ b/third_party/blink/renderer/core/input/touch_event_manager_test.cc
@@ -98,11 +98,6 @@ Vector<WebPointerEvent>(), Vector<WebPointerEvent>()); GetEventHandler().DispatchBufferedTouchEvents(); - GetEventHandler().HandlePointerEvent( - CreateTouchPointerEvent(WebInputEvent::Type::kPointerUp), - Vector<WebPointerEvent>(), Vector<WebPointerEvent>()); - GetEventHandler().DispatchBufferedTouchEvents(); - auto* input = To<HTMLInputElement>(GetDocument().getElementById("slideElement")); // Allow off by 1 error because it may result in different value in some
diff --git a/third_party/blink/renderer/core/paint/cull_rect_updater_test.cc b/third_party/blink/renderer/core/paint/cull_rect_updater_test.cc index 004b760..a20c3ee6 100644 --- a/third_party/blink/renderer/core/paint/cull_rect_updater_test.cc +++ b/third_party/blink/renderer/core/paint/cull_rect_updater_test.cc
@@ -11,12 +11,16 @@ namespace blink { -class CullRectUpdaterTest : public PaintControllerPaintTestBase { +class CullRectUpdaterTest : public PaintControllerPaintTest { protected: CullRect GetCullRect(const char* id) { return GetLayoutObjectByElementId(id)->FirstFragment().GetCullRect(); } + CullRect GetCullRect(const PaintLayer& layer) { + return layer.GetLayoutObject().FirstFragment().GetCullRect(); + } + CullRect GetContentsCullRect(const char* id) { return GetLayoutObjectByElementId(id) ->FirstFragment() @@ -24,14 +28,355 @@ } }; -// TODO(wangxianzhu): Move other cull rect tests from PaintLayerPainterTest -// into this file. +INSTANTIATE_PAINT_TEST_SUITE_P(CullRectUpdaterTest); -CullRect GetCullRect(const PaintLayer& layer) { - return layer.GetLayoutObject().FirstFragment().GetCullRect(); +TEST_P(CullRectUpdaterTest, SimpleCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' + style='width: 200px; height: 200px; position: relative'> + </div> + )HTML"); + + EXPECT_EQ(gfx::Rect(0, 0, 800, 600), GetCullRect("target").Rect()); } -TEST_F(CullRectUpdaterTest, FixedPositionUnderClipPath) { +TEST_P(CullRectUpdaterTest, TallLayerCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' + style='width: 200px; height: 10000px; position: relative'> + </div> + )HTML"); + + // Viewport rect (0, 0, 800, 600) expanded by 4000 for scrolling then clipped + // by the contents rect. + EXPECT_EQ(gfx::Rect(0, 0, 800, 4600), GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, WideLayerCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' + style='width: 10000px; height: 200px; position: relative'> + </div> + )HTML"); + + // Same as TallLayerCullRect. + EXPECT_EQ(gfx::Rect(0, 0, 4800, 600), GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, VerticalRightLeftWritingModeDocument) { + SetBodyInnerHTML(R"HTML( + <style> + html { writing-mode: vertical-rl; } + body { margin: 0; } + </style> + <div id='target' style='width: 10000px; height: 200px; position: relative'> + </div> + )HTML"); + + GetDocument().View()->LayoutViewport()->SetScrollOffset( + ScrollOffset(-5000, 0), mojom::blink::ScrollType::kProgrammatic); + UpdateAllLifecyclePhasesForTest(); + + // A scroll by -5000px is equivalent to a scroll by (10000 - 5000 - 800)px = + // 4200px in non-RTL mode. Expanding the resulting rect by 4000px in each + // direction and clipping by the contents rect yields this result. + EXPECT_EQ(gfx::Rect(200, 0, 8800, 600), GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, ScaledCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' + style='width: 200px; height: 300px; will-change: transform; + transform: scaleX(3) scaleY(0.5)'> + </div> + )HTML"); + + // The expansion is 4000 / max(scaleX, scaleY). + // TODO(wangxianzhu): The above comment is not right. We should probably + // adjust LocalPixelDistanceToExpand() to make the comment true. + EXPECT_EQ(gfx::Rect(-7936, -8166, 16267, 17200), + GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, ScaledCullRectUnderCompositedScroller) { + SetBodyInnerHTML(R"HTML( + <div style='width: 200px; height: 300px; overflow: scroll; background: blue; + transform: scaleX(3) scaleY(0.5)'> + <div id='target' style='height: 400px; position: relative'></div> + <div style='width: 10000px; height: 10000px'></div> + </div> + )HTML"); + + // The expansion is 4000 / max(scaleX, scaleY). + // TODO(wangxianzhu): The above comment is not right. We should probably + // adjust LocalPixelDistanceToExpand() to make the comment true. + EXPECT_EQ(gfx::Rect(0, 0, 8200, 8300), GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, ScaledAndRotatedCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' + style='width: 200px; height: 300px; will-change: transform; + transform: scaleX(3) scaleY(0.5) rotateZ(45deg)'> + </div> + )HTML"); + + // The expansion 6599 is 4000 * max_dimension(1x1 rect projected from screen + // to local). + // TODO(wangxianzhu): The above comment is not right. We should probably + // adjust LocalPixelDistanceToExpand() to make the comment true. + EXPECT_EQ(gfx::Rect(-6748, -6836, 14236, 14236), + GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, ScaledAndRotatedCullRectUnderCompositedScroller) { + SetBodyInnerHTML(R"HTML( + <div style='width: 200px; height: 300px; overflow: scroll; background: blue; + transform: scaleX(3) scaleY(0.5) rotateZ(45deg)'> + <div id='target' style='height: 400px; position: relative; + will-change: transform'></div> + <div style='width: 10000px; height: 10000px'></div> + </div> + )HTML"); + + // The expansion 6599 is 4000 * max_dimension(1x1 rect projected from screen + // to local). + // TODO(wangxianzhu): The above comment is not right. We should probably + // adjust LocalPixelDistanceToExpand() to make the comment true. + EXPECT_EQ(gfx::Rect(0, 0, 6799, 6899), GetCullRect("target").Rect()); + EXPECT_EQ(gfx::Rect(0, 0, 6799, 6899), GetContentsCullRect("target").Rect()); +} + +// This is a testcase for https://crbug.com/1227907 where repeated cull rect +// updates are expensive on the motionmark microbenchmark. +TEST_P(CullRectUpdaterTest, OptimizeNonCompositedTransformUpdate) { + SetBodyInnerHTML(R"HTML( + <style> + #target { + width: 50px; + height: 50px; + background: green; + transform: translate(-8px, -8px); + } + </style> + <div id='target'></div> + )HTML"); + + // The cull rect should be correctly calculated on first paint. + EXPECT_EQ(gfx::Rect(0, 0, 800, 600), GetCullRect("target").Rect()); + + // On subsequent paints, fall back to an infinite cull rect. + GetDocument().getElementById("target")->setAttribute( + html_names::kStyleAttr, "transform: rotate(10deg);"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_TRUE(GetCullRect("target").IsInfinite()); +} + +TEST_P(CullRectUpdaterTest, 3DRotated90DegreesCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' + style='width: 200px; height: 300px; will-change: transform; + transform: rotateY(90deg)'> + </div> + )HTML"); + + EXPECT_TRUE(GetCullRect("target").Rect().Contains(gfx::Rect(0, 0, 200, 300))); +} + +TEST_P(CullRectUpdaterTest, 3DRotatedNear90DegreesCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' + style='width: 200px; height: 300px; will-change: transform; + transform: rotateY(89.9999deg)'> + </div> + )HTML"); + + EXPECT_TRUE(GetCullRect("target").Rect().Contains(gfx::Rect(0, 0, 200, 300))); +} + +TEST_P(CullRectUpdaterTest, PerspectiveCullRect) { + SetBodyInnerHTML(R"HTML( + <div id=target style='transform: perspective(1000px) rotateX(-100deg);'> + <div style='width: 2000px; height: 3000px></div> + </div> + )HTML"); + + EXPECT_TRUE( + GetCullRect("target").Rect().Contains(gfx::Rect(0, 0, 2000, 3000))); +} + +TEST_P(CullRectUpdaterTest, 3D45DegRotatedTallCullRect) { + SetBodyInnerHTML(R"HTML( + <style>body { margin: 0 }</style> + <div id='target' + style='width: 200px; height: 10000px; transform: rotateY(45deg)'> + </div> + )HTML"); + + EXPECT_TRUE( + GetCullRect("target").Rect().Contains(gfx::Rect(0, 0, 200, 10000))); +} + +TEST_P(CullRectUpdaterTest, FixedPositionInNonScrollableViewCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' style='width: 1000px; height: 2000px; + position: fixed; top: 100px; left: 200px;'> + </div> + )HTML"); + + // The cull rect is inflated when scrolling, because fixed elements don't + // participate in overscroll. + EXPECT_EQ(gfx::Rect(-200, -100, 800, 600), GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, FixedPositionInScrollableViewCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' style='width: 1000px; height: 2000px; + position: fixed; top: 100px; left: 200px;'> + </div> + <div style='height: 3000px'></div> + )HTML"); + + EXPECT_EQ(gfx::Rect(-200, -100, 800, 600), GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, LayerOffscreenNearCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' + style='width: 200px; height: 300px; will-change: transform; + position: absolute; top: 3000px; left: 0px;'> + </div> + )HTML"); + + auto cull_rect = GetCullRect("target").Rect(); + EXPECT_TRUE(cull_rect.Contains(gfx::Rect(0, 0, 200, 300))); +} + +TEST_P(CullRectUpdaterTest, LayerOffscreenFarCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' + style='width: 200px; height: 300px; will-change: transform; + position: absolute; top: 9000px'> + </div> + )HTML"); + + // The layer is too far away from the viewport. + EXPECT_FALSE( + GetCullRect("target").Rect().Intersects(gfx::Rect(0, 0, 200, 300))); +} + +TEST_P(CullRectUpdaterTest, ScrollingLayerCullRect) { + SetBodyInnerHTML(R"HTML( + <style> + div::-webkit-scrollbar { width: 5px; } + </style> + <div style='width: 200px; height: 200px; overflow: scroll; + background: blue'> + <div id='target' + style='width: 100px; height: 10000px; position: relative'> + </div> + </div> + )HTML"); + + // In screen space, the scroller is (8, 8, 195, 193) (because of overflow clip + // of 'target', scrollbar and root margin). + // Applying the viewport clip of the root has no effect because + // the clip is already small. Mapping it down into the graphics layer + // space yields (0, 0, 195, 193). This is then expanded by 4000px and clipped + // by the contents rect. + EXPECT_EQ(gfx::Rect(0, 0, 195, 4193), GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, NonCompositedScrollingLayerCullRect) { + GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(false); + SetBodyInnerHTML(R"HTML( + <style> + div::-webkit-scrollbar { width: 5px; } + </style> + <div style='width: 200px; height: 200px; overflow: scroll'> + <div id='target' + style='width: 100px; height: 10000px; position: relative'> + </div> + </div> + )HTML"); + + // See ScrollingLayerCullRect for the calculation. + EXPECT_EQ(gfx::Rect(0, 0, 195, 193), GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, ClippedBigLayer) { + SetBodyInnerHTML(R"HTML( + <div style='width: 1px; height: 1px; overflow: hidden'> + <div id='target' + style='width: 10000px; height: 10000px; position: relative'> + </div> + </div> + )HTML"); + + EXPECT_EQ(gfx::Rect(8, 8, 1, 1), GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, TallScrolledLayerCullRect) { + SetBodyInnerHTML(R"HTML( + <div id='target' style='width: 200px; height: 12000px; position: relative'> + </div> + )HTML"); + + // Viewport rect (0, 0, 800, 600) expanded by 4000 for scrolling then clipped + // by the contents rect. + EXPECT_EQ(gfx::Rect(0, 0, 800, 4600), GetCullRect("target").Rect()); + + GetDocument().View()->LayoutViewport()->SetScrollOffset( + ScrollOffset(0, 4000), mojom::blink::ScrollType::kProgrammatic); + UpdateAllLifecyclePhasesForTest(); + EXPECT_EQ(gfx::Rect(0, 0, 800, 8600), GetCullRect("target").Rect()); + + GetDocument().View()->LayoutViewport()->SetScrollOffset( + ScrollOffset(0, 4500), mojom::blink::ScrollType::kProgrammatic); + UpdateAllLifecyclePhasesForTest(); + // Used the previous cull rect because the scroll amount is small. + EXPECT_EQ(gfx::Rect(0, 0, 800, 8600), GetCullRect("target").Rect()); + + GetDocument().View()->LayoutViewport()->SetScrollOffset( + ScrollOffset(0, 4600), mojom::blink::ScrollType::kProgrammatic); + UpdateAllLifecyclePhasesForTest(); + // Used new cull rect. + EXPECT_EQ(gfx::Rect(0, 600, 800, 8600), GetCullRect("target").Rect()); +} + +TEST_P(CullRectUpdaterTest, WholeDocumentCullRect) { + GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); + GetDocument().GetSettings()->SetMainFrameClipsContent(false); + SetBodyInnerHTML(R"HTML( + <style> + div { background: blue; } + ::-webkit-scrollbar { display: none; } + </style> + <div id='relative' + style='width: 200px; height: 10000px; position: relative'> + </div> + <div id='fixed' style='width: 200px; height: 200px; position: fixed'> + </div> + <div id='scroll' style='width: 200px; height: 200px; overflow: scroll'> + <div id='below-scroll' style='height: 5000px; position: relative'></div> + <div style='height: 200px'>Should not paint</div> + </div> + <div id='normal' style='width: 200px; height: 200px'></div> + )HTML"); + + // Viewport clipping is disabled. + EXPECT_TRUE(GetCullRect(*GetLayoutView().Layer()).IsInfinite()); + EXPECT_TRUE(GetCullRect("relative").IsInfinite()); + EXPECT_TRUE(GetCullRect("fixed").IsInfinite()); + EXPECT_TRUE(GetCullRect("scroll").IsInfinite()); + + // Cull rect is normal for contents below scroll other than the viewport. + EXPECT_EQ(gfx::Rect(0, 0, 200, 4200), GetCullRect("below-scroll").Rect()); + + EXPECT_EQ(7u, ContentDisplayItems().size()); +} + +TEST_P(CullRectUpdaterTest, FixedPositionUnderClipPath) { GetDocument().View()->Resize(800, 600); SetBodyInnerHTML(R"HTML( <div style="height: 100vh"></div> @@ -52,7 +397,7 @@ EXPECT_EQ(gfx::Rect(0, 0, 800, 1000), GetCullRect("fixed").Rect()); } -TEST_F(CullRectUpdaterTest, FixedPositionUnderClipPathWillChangeTransform) { +TEST_P(CullRectUpdaterTest, FixedPositionUnderClipPathWillChangeTransform) { GetDocument().View()->Resize(800, 600); SetBodyInnerHTML(R"HTML( <div style="height: 100vh"></div> @@ -73,7 +418,7 @@ EXPECT_EQ(gfx::Rect(-4000, -4000, 8800, 10000), GetCullRect("fixed").Rect()); } -TEST_F(CullRectUpdaterTest, AbsolutePositionUnderNonContainingStackingContext) { +TEST_P(CullRectUpdaterTest, AbsolutePositionUnderNonContainingStackingContext) { GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(false); SetBodyInnerHTML(R"HTML( <div id="scroller" style="width: 200px; height: 200px; overflow: auto; @@ -96,7 +441,7 @@ GetCullRect("absolute").Rect()); } -TEST_F(CullRectUpdaterTest, StackedChildOfNonStackingContextScroller) { +TEST_P(CullRectUpdaterTest, StackedChildOfNonStackingContextScroller) { SetBodyInnerHTML(R"HTML( <div id="scroller" style="width: 200px; height: 200px; overflow: auto; background: white"> @@ -137,7 +482,7 @@ EXPECT_EQ(gfx::Rect(0, 2800, 200, 4200), GetCullRect("child").Rect()); } -TEST_F(CullRectUpdaterTest, ContentsCullRectCoveringWholeContentsRect) { +TEST_P(CullRectUpdaterTest, ContentsCullRectCoveringWholeContentsRect) { GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); SetBodyInnerHTML(R"HTML( <div id="scroller" style="width: 400px; height: 400px; overflow: scroll"> @@ -166,7 +511,7 @@ EXPECT_EQ(gfx::Rect(-4000, -8100, 8600, 8120), GetCullRect("child").Rect()); } -TEST_F(CullRectUpdaterTest, SVGForeignObject) { +TEST_P(CullRectUpdaterTest, SVGForeignObject) { GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(false); SetBodyInnerHTML(R"HTML( <div id="scroller" style="width: 100px; height: 100px; overflow: scroll"> @@ -202,7 +547,7 @@ EXPECT_FALSE(svg->DescendantNeedsCullRectUpdate()); } -TEST_F(CullRectUpdaterTest, LayerUnderSVGHiddenContainer) { +TEST_P(CullRectUpdaterTest, LayerUnderSVGHiddenContainer) { SetBodyInnerHTML(R"HTML( <div id="div" style="display: contents"> <svg id="svg1"></svg> @@ -221,7 +566,7 @@ EXPECT_TRUE(GetCullRect("svg1").Rect().IsEmpty()); } -TEST_F(CullRectUpdaterTest, PerspectiveDescendants) { +TEST_P(CullRectUpdaterTest, PerspectiveDescendants) { SetBodyInnerHTML(R"HTML( <div style="perspective: 1000px"> <div style="height: 300px; transform-style: preserve-3d; contain: strict"> @@ -315,7 +660,9 @@ )HTML"; }; -TEST_F(CullRectUpdateOnPaintPropertyChangeTest, Opacity) { +INSTANTIATE_PAINT_TEST_SUITE_P(CullRectUpdateOnPaintPropertyChangeTest); + +TEST_P(CullRectUpdateOnPaintPropertyChangeTest, Opacity) { TestTargetChange("opacity: 0.2", "opacity: 0.8", false, false, false); TestTargetChange("opacity: 0.5", "", true, false, true); TestTargetChange("", "opacity: 0.5", true, false, true); @@ -325,7 +672,7 @@ false, false, false); } -TEST_F(CullRectUpdateOnPaintPropertyChangeTest, NonPixelMovingFilter) { +TEST_P(CullRectUpdateOnPaintPropertyChangeTest, NonPixelMovingFilter) { TestTargetChange("filter: invert(5%)", "filter: invert(8%)", false, false, false); TestTargetChange("filter: invert(5%)", "", true, false, true); @@ -337,7 +684,7 @@ false); } -TEST_F(CullRectUpdateOnPaintPropertyChangeTest, PixelMovingFilter) { +TEST_P(CullRectUpdateOnPaintPropertyChangeTest, PixelMovingFilter) { TestTargetChange("filter: blur(5px)", "filter: blur(8px)", false, false, false); TestTargetChange("filter: blur(5px)", "", true, true, true); @@ -349,7 +696,7 @@ false); } -TEST_F(CullRectUpdateOnPaintPropertyChangeTest, Transform) { +TEST_P(CullRectUpdateOnPaintPropertyChangeTest, Transform) { TestTargetChange("transform: translateX(10px)", "transform: translateX(20px)", false, true, false); TestTargetChange("transform: translateX(10px)", "", true, true, true); @@ -361,7 +708,7 @@ true, false); } -TEST_F(CullRectUpdateOnPaintPropertyChangeTest, AnimatingTransform) { +TEST_P(CullRectUpdateOnPaintPropertyChangeTest, AnimatingTransform) { html_ = html_ + R"HTML( <style> @keyframes test { @@ -377,13 +724,13 @@ TestTargetChange("", "transform: translateX(10px)", false, false, false); } -TEST_F(CullRectUpdateOnPaintPropertyChangeTest, ScrollContentsSizeChange) { +TEST_P(CullRectUpdateOnPaintPropertyChangeTest, ScrollContentsSizeChange) { TestChildChange("", "width: 3000px", true, true, true); TestChildChange("", "height: 3000px", true, true, true); TestChildChange("", "width: 50px; height: 50px", true, true, true); } -TEST_F(CullRectUpdateOnPaintPropertyChangeTest, SmallContentsScroll) { +TEST_P(CullRectUpdateOnPaintPropertyChangeTest, SmallContentsScroll) { // TODO(wangxianzhu): Optimize for scrollers with small contents. TestTargetScroll(ScrollOffset(), ScrollOffset(100, 200), false, true, false); TestTargetScroll(ScrollOffset(100, 200), ScrollOffset(1000, 1000), false, @@ -392,7 +739,7 @@ false); } -TEST_F(CullRectUpdateOnPaintPropertyChangeTest, LargeContentsScroll) { +TEST_P(CullRectUpdateOnPaintPropertyChangeTest, LargeContentsScroll) { html_ = html_ + "<style>#child { width: 10000px; height: 10000px; }</style>"; // TODO(wangxianzhu): Optimize for small scroll delta. TestTargetScroll(ScrollOffset(), ScrollOffset(100, 200), false, true, false);
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc b/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc index 2f4329ae..d9064a1 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
@@ -749,379 +749,6 @@ EXPECT_TRUE(html_layer.NeedsPaintPhaseDescendantOutlines()); } -TEST_P(PaintLayerPainterTest, SimpleCullRect) { - SetBodyInnerHTML(R"HTML( - <div id='target' - style='width: 200px; height: 200px; position: relative'> - </div> - )HTML"); - - EXPECT_EQ(gfx::Rect(0, 0, 800, 600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, TallLayerCullRect) { - SetBodyInnerHTML(R"HTML( - <div id='target' - style='width: 200px; height: 10000px; position: relative'> - </div> - )HTML"); - - // Viewport rect (0, 0, 800, 600) expanded by 4000 for scrolling then clipped - // by the contents rect. - EXPECT_EQ(gfx::Rect(0, 0, 800, 4600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, WideLayerCullRect) { - SetBodyInnerHTML(R"HTML( - <div id='target' - style='width: 10000px; height: 200px; position: relative'> - </div> - )HTML"); - - // Same as TallLayerCullRect. - EXPECT_EQ(gfx::Rect(0, 0, 4800, 600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, TallScrolledLayerCullRect) { - SetBodyInnerHTML(R"HTML( - <div id='target' style='width: 200px; height: 12000px; position: relative'> - </div> - )HTML"); - - // Viewport rect (0, 0, 800, 600) expanded by 4000 for scrolling then clipped - // by the contents rect. - EXPECT_EQ(gfx::Rect(0, 0, 800, 4600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); - - GetDocument().View()->LayoutViewport()->SetScrollOffset( - ScrollOffset(0, 4000), mojom::blink::ScrollType::kProgrammatic); - UpdateAllLifecyclePhasesForTest(); - EXPECT_EQ(gfx::Rect(0, 0, 800, 8600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); - - GetDocument().View()->LayoutViewport()->SetScrollOffset( - ScrollOffset(0, 4500), mojom::blink::ScrollType::kProgrammatic); - UpdateAllLifecyclePhasesForTest(); - // Used the previous cull rect because the scroll amount is small. - EXPECT_EQ(gfx::Rect(0, 0, 800, 8600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); - - GetDocument().View()->LayoutViewport()->SetScrollOffset( - ScrollOffset(0, 4600), mojom::blink::ScrollType::kProgrammatic); - UpdateAllLifecyclePhasesForTest(); - // Used new cull rect. - EXPECT_EQ(gfx::Rect(0, 600, 800, 8600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, WholeDocumentCullRect) { - GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); - GetDocument().GetSettings()->SetMainFrameClipsContent(false); - SetBodyInnerHTML(R"HTML( - <style> - div { background: blue; } - ::-webkit-scrollbar { display: none; } - </style> - <div id='relative' - style='width: 200px; height: 10000px; position: relative'> - </div> - <div id='fixed' style='width: 200px; height: 200px; position: fixed'> - </div> - <div id='scroll' style='width: 200px; height: 200px; overflow: scroll'> - <div id='below-scroll' style='height: 5000px; position: relative'></div> - <div style='height: 200px'>Should not paint</div> - </div> - <div id='normal' style='width: 200px; height: 200px'></div> - )HTML"); - - // Viewport clipping is disabled. - EXPECT_TRUE(GetCullRect(*GetLayoutView().Layer()).IsInfinite()); - EXPECT_TRUE(GetCullRect(*GetPaintLayerByElementId("relative")).IsInfinite()); - EXPECT_TRUE(GetCullRect(*GetPaintLayerByElementId("fixed")).IsInfinite()); - EXPECT_TRUE(GetCullRect(*GetPaintLayerByElementId("scroll")).IsInfinite()); - - // Cull rect is normal for contents below scroll other than the viewport. - EXPECT_EQ(gfx::Rect(0, 0, 200, 4200), - GetCullRect(*GetPaintLayerByElementId("below-scroll")).Rect()); - - EXPECT_THAT( - ContentDisplayItems(), - UnorderedElementsAre( - VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM, - IsSameId(GetDisplayItemClientFromElementId("relative")->Id(), - kBackgroundType), - IsSameId(GetDisplayItemClientFromElementId("normal")->Id(), - kBackgroundType), - IsSameId(GetDisplayItemClientFromElementId("scroll")->Id(), - kBackgroundType), - IsSameId(GetLayoutBoxByElementId("scroll") - ->GetScrollableArea() - ->GetScrollingBackgroundDisplayItemClient() - .Id(), - kBackgroundType), - IsSameId(GetDisplayItemClientFromElementId("below-scroll")->Id(), - kBackgroundType), - IsSameId(GetDisplayItemClientFromElementId("fixed")->Id(), - kBackgroundType))); -} - -TEST_P(PaintLayerPainterTest, VerticalRightLeftWritingModeDocument) { - SetBodyInnerHTML(R"HTML( - <style> - html { writing-mode: vertical-rl; } - body { margin: 0; } - </style> - <div id='target' style='width: 10000px; height: 200px; position: relative'> - </div> - )HTML"); - - GetDocument().View()->LayoutViewport()->SetScrollOffset( - ScrollOffset(-5000, 0), mojom::blink::ScrollType::kProgrammatic); - UpdateAllLifecyclePhasesForTest(); - - // A scroll by -5000px is equivalent to a scroll by (10000 - 5000 - 800)px = - // 4200px in non-RTL mode. Expanding the resulting rect by 4000px in each - // direction and clipping by the contents rect yields this result. - EXPECT_EQ(gfx::Rect(200, 0, 8800, 600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -// TODO(wangxianzhu): These tests should correspond to the tests in -// CompositedLayerMapping testing interest rects. However, for now because in -// CompositeAfterPaint we expand cull rect for composited scrollers only, so -// the tests are modified to use composited scrolling. Will change these back to -// their original version when we support expansion for all composited layers. -// Will be done in CullRectUpdate. -TEST_P(PaintLayerPainterTest, ScaledCullRect) { - GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); - SetBodyInnerHTML(R"HTML( - <div style='width: 200px; height: 300px; overflow: scroll; - transform: scaleX(3) scaleY(0.5)'> - <div id='target' style='height: 400px; position: relative'></div> - <div style='width: 10000px; height: 10000px'></div> - </div> - )HTML"); - - // The expansion is 4000 / max(scaleX, scaleY). - EXPECT_EQ(gfx::Rect(0, 0, 8200, 8300), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, ScaledAndRotatedCullRect) { - GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); - SetBodyInnerHTML(R"HTML( - <div style='width: 200px; height: 300px; overflow: scroll; - transform: scaleX(3) scaleY(0.5) rotateZ(45deg)'> - <div id='target' style='height: 400px; position: relative; - will-change: transform'></div> - <div style='width: 10000px; height: 10000px'></div> - </div> - )HTML"); - - // The expansion 6599 is 4000 * max_dimension(1x1 rect projected from screen - // to local). - EXPECT_EQ(gfx::Rect(0, 0, 6799, 6899), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -// This is a testcase for https://crbug.com/1227907 where repeated cull rect -// updates are expensive on the motionmark microbenchmark. -TEST_P(PaintLayerPainterTest, OptimizeNonCompositedTransformUpdate) { - SetBodyInnerHTML(R"HTML( - <style> - #target { - width: 50px; - height: 50px; - background: green; - transform: translate(-8px, -8px); - } - </style> - <div id='target'></div> - )HTML"); - - // The cull rect should be correctly calculated on first paint. - EXPECT_EQ(gfx::Rect(0, 0, 800, 600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); - - // On subsequent paints, fall back to an infinite cull rect. - GetDocument().getElementById("target")->setAttribute( - html_names::kStyleAttr, "transform: rotate(10deg);"); - UpdateAllLifecyclePhasesForTest(); - EXPECT_EQ(CullRect::Infinite().Rect(), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, 3DRotated90DegreesCullRect) { - GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); - SetBodyInnerHTML(R"HTML( - <div style='width: 200px; height: 300px; overflow: scroll; - transform: rotateY(90deg)'> - <div id='target' style='height: 400px; position: relative'></div> - <div style='width: 10000px; height: 10000px'></div> - </div> - )HTML"); - - // It's rotated 90 degrees about the X axis, which means its visual content - // rect is empty, we fall back to the 4000px cull rect padding amount. - EXPECT_EQ(gfx::Rect(0, 0, 4200, 4300), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, 3DRotatedNear90DegreesCullRect) { - GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); - SetBodyInnerHTML(R"HTML( - <div style='width: 200px; height: 300px; overflow: scroll; - transform: rotateY(89.9999deg)'> - <div id='target' style='height: 400px; position: relative'></div> - <div style='width: 10000px; height: 10000px'></div> - </div> - )HTML"); - - // Because the layer is rotated to almost 90 degrees, floating-point error - // leads to a reverse-projected rect that is much much larger than the - // original layer size in certain dimensions. In such cases, we often fall - // back to the 4000px cull rect padding amount. - EXPECT_EQ(gfx::Rect(0, 0, 4200, 4300), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, PerspectiveCullRect) { - SetBodyInnerHTML(R"HTML( - <div id=target style='transform: perspective(1000px) rotateX(-100deg);'> - <div style='width: 2000px; height: 3000px></div> - </div> - )HTML"); - - EXPECT_TRUE(GetCullRect(*GetPaintLayerByElementId("target")) - .Rect() - .Contains(gfx::Rect(0, 0, 2000, 3000))); -} - -TEST_P(PaintLayerPainterTest, 3D45DegRotatedTallCullRect) { - SetBodyInnerHTML(R"HTML( - <div id='target' - style='width: 200px; height: 10000px; transform: rotateY(45deg)'> - </div> - )HTML"); - - // See CompositedLayerMappingTest.3D45DegRotatedTallInterestRect (which with - // be combined with this one) for why the cull rect covers the whole layer. - EXPECT_TRUE(GetCullRect(*GetPaintLayerByElementId("target")) - .Rect() - .Contains(gfx::Rect(0, 0, 200, 10000))); -} - -TEST_P(PaintLayerPainterTest, FixedPositionInNonScrollableViewCullRect) { - SetBodyInnerHTML(R"HTML( - <div id='target' style='width: 1000px; height: 2000px; - position: fixed; top: 100px; left: 200px;'> - </div> - )HTML"); - - // The cull rect is inflated when scrolling, because fixed elements don't - // participate in overscroll. - EXPECT_EQ(gfx::Rect(-200, -100, 800, 600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, FixedPositionInScrollableViewCullRect) { - SetBodyInnerHTML(R"HTML( - <div id='target' style='width: 1000px; height: 2000px; - position: fixed; top: 100px; left: 200px;'> - </div> - <div style='height: 3000px'></div> - )HTML"); - - EXPECT_EQ(gfx::Rect(-200, -100, 800, 600), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, LayerOffscreenNearCullRect) { - GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); - SetBodyInnerHTML(R"HTML( - <div style='width: 200px; height: 300px; overflow: scroll; - position: absolute; top: 3000px; left: 0px;'> - <div id='target' style='height: 500px; position: relative'></div> - <div style='width: 10000px; height: 10000px'></div> - </div> - )HTML"); - - EXPECT_EQ(gfx::Rect(0, 0, 4200, 4300), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, LayerOffscreenFarCullRect) { - GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); - SetBodyInnerHTML(R"HTML( - <div style='width: 200px; height: 300px; overflow: scroll; - position: absolute; top: 9000px'> - <div id='target' style='height: 500px; position: relative'></div> - <div style='width: 10000px; height: 10000px'></div> - </div> - )HTML"); - - // The layer is too far away from the viewport. - EXPECT_EQ(gfx::Rect(), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, ScrollingLayerCullRect) { - GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); - SetBodyInnerHTML(R"HTML( - <style> - div::-webkit-scrollbar { width: 5px; } - </style> - <div style='width: 200px; height: 200px; overflow: scroll'> - <div id='target' - style='width: 100px; height: 10000px; position: relative'> - </div> - </div> - )HTML"); - - // In screen space, the scroller is (8, 8, 195, 193) (because of overflow clip - // of 'target', scrollbar and root margin). - // Applying the viewport clip of the root has no effect because - // the clip is already small. Mapping it down into the graphics layer - // space yields (0, 0, 195, 193). This is then expanded by 4000px and clipped - // by the contents rect. - EXPECT_EQ(gfx::Rect(0, 0, 195, 4193), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, NonCompositedScrollingLayerCullRect) { - GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(false); - SetBodyInnerHTML(R"HTML( - <style> - div::-webkit-scrollbar { width: 5px; } - </style> - <div style='width: 200px; height: 200px; overflow: scroll'> - <div id='target' - style='width: 100px; height: 10000px; position: relative'> - </div> - </div> - )HTML"); - - // See ScrollingLayerCullRect for the calculation. - EXPECT_EQ(gfx::Rect(0, 0, 195, 193), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - -TEST_P(PaintLayerPainterTest, ClippedBigLayer) { - SetBodyInnerHTML(R"HTML( - <div style='width: 1px; height: 1px; overflow: hidden'> - <div id='target' - style='width: 10000px; height: 10000px; position: relative'> - </div> - </div> - )HTML"); - - EXPECT_EQ(gfx::Rect(8, 8, 1, 1), - GetCullRect(*GetPaintLayerByElementId("target")).Rect()); -} - class PaintLayerPainterPaintedOutputInvisibleTest : public PaintLayerPainterTest { protected:
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc index 25e01f6..c76285f4 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -2814,10 +2814,8 @@ box_model_object.OffsetForInFlowPosition(); break; case EPosition::kAbsolute: { -#if DCHECK_IS_ON() DCHECK_EQ(full_context_.container_for_absolute_position, box_model_object.Container()); -#endif SwitchToOOFContext(context_.absolute_position); // Absolutely positioned content in an inline should be positioned
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc index 8e276bd..615f47d2 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc +++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
@@ -167,7 +167,7 @@ } void SoftNavigationHeuristics::OnCreateTaskScope( - const scheduler::TaskId& task_id) { + const scheduler::TaskAttributionId& task_id) { // We're inside a click event handler, so need to add this task to the set of // potential soft navigation root tasks. potential_soft_navigation_task_ids_.insert(task_id.value());
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h index 34df3b0..331baa7 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h +++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
@@ -6,10 +6,10 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_SOFT_NAVIGATION_HEURISTICS_H_ #include "base/containers/enum_set.h" +#include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h" -#include "third_party/blink/renderer/platform/scheduler/public/task_id.h" #include "third_party/blink/renderer/platform/supplementable.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" @@ -41,7 +41,7 @@ uint32_t SoftNavigationCount() { return soft_navigation_count_; } // TaskAttributionTracker::Observer's implementation. - void OnCreateTaskScope(const scheduler::TaskId&) override; + void OnCreateTaskScope(const scheduler::TaskAttributionId&) override; private: void CheckSoftNavigation(ScriptState*); @@ -56,7 +56,8 @@ bool SetFlagIfDescendantAndCheck(ScriptState*, FlagType); void ResetHeuristic(); - WTF::HashSet<scheduler::TaskIdType> potential_soft_navigation_task_ids_; + WTF::HashSet<scheduler::TaskAttributionIdType> + potential_soft_navigation_task_ids_; FlagTypeSet flag_set_; uint32_t soft_navigation_count_ = 0; };
diff --git a/third_party/blink/renderer/modules/scheduler/BUILD.gn b/third_party/blink/renderer/modules/scheduler/BUILD.gn index c7908c41..185ab16 100644 --- a/third_party/blink/renderer/modules/scheduler/BUILD.gn +++ b/third_party/blink/renderer/modules/scheduler/BUILD.gn
@@ -14,7 +14,7 @@ "dom_task_controller.h", "dom_task_signal.cc", "dom_task_signal.h", - "script_wrappable_task_id.h", + "script_wrappable_task_attribution_id.h", "task_attribution_tracker_impl.cc", "task_attribution_tracker_impl.h", "task_priority_change_event.cc",
diff --git a/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc b/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc index 5fc5703..a7da6ca 100644 --- a/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc +++ b/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc
@@ -80,7 +80,8 @@ auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker(); if (tracker && script_state->World().IsMainWorld()) { - callback_function->SetParentTaskId(tracker->RunningTaskId(script_state)); + callback_function->SetParentTaskId( + tracker->RunningTaskAttributionId(script_state)); } // Always honor the priority and the task signal if given. DOMTaskQueue* task_queue; @@ -111,20 +112,23 @@ return resolver->Promise(); } -scheduler::TaskIdType DOMScheduler::taskId(ScriptState* script_state) { +scheduler::TaskAttributionIdType DOMScheduler::taskId( + ScriptState* script_state) { ThreadScheduler* scheduler = ThreadScheduler::Current(); DCHECK(scheduler); DCHECK(scheduler->GetTaskAttributionTracker()); - absl::optional<scheduler::TaskId> task_id = - scheduler->GetTaskAttributionTracker()->RunningTaskId(script_state); + absl::optional<scheduler::TaskAttributionId> task_id = + scheduler->GetTaskAttributionTracker()->RunningTaskAttributionId( + script_state); // task_id cannot be unset here, as a task has presumably already ran in order // for this API call to be called. DCHECK(task_id); return task_id.value().value(); } -AtomicString DOMScheduler::isAncestor(ScriptState* script_state, - scheduler::TaskIdType parentId) { +AtomicString DOMScheduler::isAncestor( + ScriptState* script_state, + scheduler::TaskAttributionIdType parentId) { scheduler::TaskAttributionTracker::AncestorStatus status = scheduler::TaskAttributionTracker::AncestorStatus::kNotAncestor; ThreadScheduler* scheduler = ThreadScheduler::Current(); @@ -132,7 +136,8 @@ scheduler::TaskAttributionTracker* tracker = scheduler->GetTaskAttributionTracker(); DCHECK(tracker); - status = tracker->IsAncestor(script_state, scheduler::TaskId(parentId)); + status = + tracker->IsAncestor(script_state, scheduler::TaskAttributionId(parentId)); switch (status) { case scheduler::TaskAttributionTracker::AncestorStatus::kAncestor: return "ancestor";
diff --git a/third_party/blink/renderer/modules/scheduler/dom_scheduler.h b/third_party/blink/renderer/modules/scheduler/dom_scheduler.h index 49d5b4b..6c0320e 100644 --- a/third_party/blink/renderer/modules/scheduler/dom_scheduler.h +++ b/third_party/blink/renderer/modules/scheduler/dom_scheduler.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_DOM_SCHEDULER_H_ #include "base/memory/scoped_refptr.h" +#include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" @@ -14,7 +15,6 @@ #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" -#include "third_party/blink/renderer/platform/scheduler/public/task_id.h" #include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_priority.h" #include "third_party/blink/renderer/platform/supplementable.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" @@ -75,8 +75,9 @@ SchedulerPostTaskOptions*, ExceptionState&); - scheduler::TaskIdType taskId(ScriptState*); - AtomicString isAncestor(ScriptState*, scheduler::TaskIdType parent_id); + scheduler::TaskAttributionIdType taskId(ScriptState*); + AtomicString isAncestor(ScriptState*, + scheduler::TaskAttributionIdType parent_id); void ContextDestroyed() override;
diff --git a/third_party/blink/renderer/modules/scheduler/script_wrappable_task_attribution_id.h b/third_party/blink/renderer/modules/scheduler/script_wrappable_task_attribution_id.h new file mode 100644 index 0000000..ec22391c --- /dev/null +++ b/third_party/blink/renderer/modules/scheduler/script_wrappable_task_attribution_id.h
@@ -0,0 +1,27 @@ +// Copyright 2022 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 THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_SCRIPT_WRAPPABLE_TASK_ATTRIBUTION_ID_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_SCRIPT_WRAPPABLE_TASK_ATTRIBUTION_ID_H_ + +#include "third_party/blink/public/common/scheduler/task_attribution_id.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/bindings/v8_set_return_value.h" + +namespace blink { + +class ScriptWrappableTaskAttributionId final + : public ScriptWrappable, + public scheduler::TaskAttributionId { + DEFINE_WRAPPERTYPEINFO(); + + public: + explicit ScriptWrappableTaskAttributionId( + const scheduler::TaskAttributionId& id) + : TaskAttributionId(id) {} +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_SCRIPT_WRAPPABLE_TASK_ATTRIBUTION_ID_H_
diff --git a/third_party/blink/renderer/modules/scheduler/script_wrappable_task_id.idl b/third_party/blink/renderer/modules/scheduler/script_wrappable_task_attribution_id.idl similarity index 89% rename from third_party/blink/renderer/modules/scheduler/script_wrappable_task_id.idl rename to third_party/blink/renderer/modules/scheduler/script_wrappable_task_attribution_id.idl index f3b5a4f..1f58130 100644 --- a/third_party/blink/renderer/modules/scheduler/script_wrappable_task_id.idl +++ b/third_party/blink/renderer/modules/scheduler/script_wrappable_task_attribution_id.idl
@@ -5,6 +5,6 @@ // This interface of not really web-exposed, and only used to generate a // ScriptWrappable object, that would pass along the TaskId to V8 and back, as // continuation embedder data. -interface ScriptWrappableTaskId { +interface ScriptWrappableTaskAttributionId { readonly attribute long value; }; \ No newline at end of file
diff --git a/third_party/blink/renderer/modules/scheduler/script_wrappable_task_id.h b/third_party/blink/renderer/modules/scheduler/script_wrappable_task_id.h deleted file mode 100644 index d75776c..0000000 --- a/third_party/blink/renderer/modules/scheduler/script_wrappable_task_id.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2022 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 THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_SCRIPT_WRAPPABLE_TASK_ID_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_SCRIPT_WRAPPABLE_TASK_ID_H_ - -#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" -#include "third_party/blink/renderer/platform/bindings/v8_set_return_value.h" -#include "third_party/blink/renderer/platform/scheduler/public/task_id.h" - -namespace blink { - -class ScriptWrappableTaskId final : public ScriptWrappable, - public scheduler::TaskId { - DEFINE_WRAPPERTYPEINFO(); - - public: - explicit ScriptWrappableTaskId(const scheduler::TaskId& id) : TaskId(id) {} -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_SCRIPT_WRAPPABLE_TASK_ID_H_
diff --git a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc index 36aca86..dbac95b 100644 --- a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc +++ b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc
@@ -9,8 +9,8 @@ #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h" -#include "third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_id.h" -#include "third_party/blink/renderer/modules/scheduler/script_wrappable_task_id.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_attribution_id.h" +#include "third_party/blink/renderer/modules/scheduler/script_wrappable_task_attribution_id.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h" #include "third_party/blink/renderer/platform/bindings/to_v8.h" @@ -21,7 +21,7 @@ namespace { -static unsigned Hash(TaskId id) { +static unsigned Hash(TaskAttributionId id) { return id.value() % TaskAttributionTrackerImpl::kVectorSize; } @@ -30,25 +30,29 @@ TaskAttributionTrackerImpl::TaskAttributionTrackerImpl() : next_task_id_(0), v8_adapter_(std::make_unique<V8Adapter>()) {} -absl::optional<TaskId> TaskAttributionTrackerImpl::RunningTaskId( +absl::optional<TaskAttributionId> +TaskAttributionTrackerImpl::RunningTaskAttributionId( ScriptState* script_state) const { DCHECK(v8_adapter_); - absl::optional<TaskId> task_id = v8_adapter_->GetValue(script_state); + absl::optional<TaskAttributionId> task_id = + v8_adapter_->GetValue(script_state); // V8 embedder state may have no value in the case of a JSPromise that wasn't // yet resolved. return task_id ? task_id : running_task_id_; } -void TaskAttributionTrackerImpl::InsertTaskIdPair( - TaskId task_id, - absl::optional<TaskId> parent_task_id) { +void TaskAttributionTrackerImpl::InsertTaskAttributionIdPair( + TaskAttributionId task_id, + absl::optional<TaskAttributionId> parent_task_id) { unsigned task_id_hash = Hash(task_id); - task_container_[task_id_hash] = TaskIdPair(parent_task_id, task_id); + task_container_[task_id_hash] = + TaskAttributionIdPair(parent_task_id, task_id); } -TaskAttributionTrackerImpl::TaskIdPair& -TaskAttributionTrackerImpl::GetTaskIdPairFromTaskContainer(TaskId id) { +TaskAttributionTrackerImpl::TaskAttributionIdPair& +TaskAttributionTrackerImpl::GetTaskAttributionIdPairFromTaskContainer( + TaskAttributionId id) { unsigned slot = Hash(id); DCHECK_LT(slot, task_container_.size()); return (task_container_[slot]); @@ -60,12 +64,13 @@ F is_ancestor) { DCHECK(script_state); if (!script_state->World().IsMainWorld()) { - // As RunningTaskId will not return a TaskId for non-main-world tasks, - // there's no point in testing their ancestry. + // As RunningTaskAttributionId will not return a TaskAttributionId for + // non-main-world tasks, there's no point in testing their ancestry. return AncestorStatus::kNotAncestor; } - absl::optional<TaskId> current_task_id = RunningTaskId(script_state); + absl::optional<TaskAttributionId> current_task_id = + RunningTaskAttributionId(script_state); if (!current_task_id) { // TODO(yoav): This should not happen, but does. See crbug.com/1326872. return AncestorStatus::kNotAncestor; @@ -80,13 +85,13 @@ // finds a parent, which current task ID doesn't match the one its child // pointed at, indicating that the parent's slot in the array was overwritten. // In that case, it's returning the kUnknown value. - const TaskIdPair& current_pair = - GetTaskIdPairFromTaskContainer(current_task_id.value()); - absl::optional<TaskId> parent_id = current_pair.parent; + const TaskAttributionIdPair& current_pair = + GetTaskAttributionIdPairFromTaskContainer(current_task_id.value()); + absl::optional<TaskAttributionId> parent_id = current_pair.parent; DCHECK(current_pair.current); while (parent_id) { - const TaskIdPair& parent_pair = - GetTaskIdPairFromTaskContainer(parent_id.value()); + const TaskAttributionIdPair& parent_pair = + GetTaskAttributionIdPairFromTaskContainer(parent_id.value()); if (parent_pair.current && parent_pair.current != parent_id) { // Found a parent slot, but its ID doesn't match what we thought it would // be. That means we circled around the circular array, and we can no @@ -105,34 +110,35 @@ TaskAttributionTracker::AncestorStatus TaskAttributionTrackerImpl::IsAncestor( ScriptState* script_state, - TaskId ancestor_id) { - return IsAncestorInternal(script_state, [&](const TaskId& task_id) { - return task_id == ancestor_id; - }); + TaskAttributionId ancestor_id) { + return IsAncestorInternal( + script_state, + [&](const TaskAttributionId& task_id) { return task_id == ancestor_id; }); } TaskAttributionTracker::AncestorStatus TaskAttributionTrackerImpl::HasAncestorInSet( ScriptState* script_state, - const WTF::HashSet<scheduler::TaskIdType>& set) { - return IsAncestorInternal(script_state, [&](const TaskId& task_id) { - return set.Contains(task_id.value()); - }); + const WTF::HashSet<scheduler::TaskAttributionIdType>& set) { + return IsAncestorInternal(script_state, + [&](const TaskAttributionId& task_id) { + return set.Contains(task_id.value()); + }); } std::unique_ptr<TaskAttributionTracker::TaskScope> TaskAttributionTrackerImpl::CreateTaskScope( ScriptState* script_state, - absl::optional<TaskId> parent_task_id) { - absl::optional<TaskId> previous_task_id = running_task_id_; + absl::optional<TaskAttributionId> parent_task_id) { + absl::optional<TaskAttributionId> previous_task_id = running_task_id_; DCHECK(v8_adapter_); - absl::optional<TaskId> previous_v8_task_id = + absl::optional<TaskAttributionId> previous_v8_task_id = v8_adapter_->GetValue(script_state); - next_task_id_ = next_task_id_.NextTaskId(); + next_task_id_ = next_task_id_.NextId(); running_task_id_ = next_task_id_; - InsertTaskIdPair(next_task_id_, parent_task_id); + InsertTaskAttributionIdPair(next_task_id_, parent_task_id); if (observer_) { observer_->OnCreateTaskScope(next_task_id_); } @@ -145,14 +151,14 @@ void TaskAttributionTrackerImpl::TaskScopeCompleted( const TaskScopeImpl& task_scope) { DCHECK(running_task_id_ == task_scope.GetTaskId()); - running_task_id_ = task_scope.PreviousTaskId(); + running_task_id_ = task_scope.PreviousTaskAttributionId(); SaveTaskIdStateInV8(task_scope.GetScriptState(), - task_scope.PreviousV8TaskId()); + task_scope.PreviousV8TaskAttributionId()); } void TaskAttributionTrackerImpl::SaveTaskIdStateInV8( ScriptState* script_state, - absl::optional<TaskId> task_id) { + absl::optional<TaskAttributionId> task_id) { DCHECK(v8_adapter_); v8_adapter_->SetValue(script_state, task_id); } @@ -162,9 +168,9 @@ TaskAttributionTrackerImpl::TaskScopeImpl::TaskScopeImpl( ScriptState* script_state, TaskAttributionTrackerImpl* task_tracker, - TaskId scope_task_id, - absl::optional<TaskId> previous_task_id, - absl::optional<TaskId> previous_v8_task_id) + TaskAttributionId scope_task_id, + absl::optional<TaskAttributionId> previous_task_id, + absl::optional<TaskAttributionId> previous_v8_task_id) : task_tracker_(task_tracker), scope_task_id_(scope_task_id), previous_task_id_(previous_task_id), @@ -177,8 +183,8 @@ // V8Adapter's implementation ////////////////////////////////////// -absl::optional<TaskId> TaskAttributionTrackerImpl::V8Adapter::GetValue( - ScriptState* script_state) { +absl::optional<TaskAttributionId> +TaskAttributionTrackerImpl::V8Adapter::GetValue(ScriptState* script_state) { DCHECK(script_state); if (!script_state->ContextIsValid()) { return absl::nullopt; @@ -197,18 +203,18 @@ if (isolate->IsExecutionTerminating()) { return absl::nullopt; } - // If not empty, the value must be a ScriptWrappableTaskId. + // If not empty, the value must be a ScriptWrappableTaskAttributionId. NonThrowableExceptionState exception_state; - ScriptWrappableTaskId* script_wrappable_task_id = - NativeValueTraits<ScriptWrappableTaskId>::NativeValue(isolate, v8_value, - exception_state); + ScriptWrappableTaskAttributionId* script_wrappable_task_id = + NativeValueTraits<ScriptWrappableTaskAttributionId>::NativeValue( + isolate, v8_value, exception_state); DCHECK(script_wrappable_task_id); return *script_wrappable_task_id; } void TaskAttributionTrackerImpl::V8Adapter::SetValue( ScriptState* script_state, - absl::optional<TaskId> task_id) { + absl::optional<TaskAttributionId> task_id) { DCHECK(script_state); if (!script_state->ContextIsValid()) { return; @@ -224,11 +230,11 @@ DCHECK(!context.IsEmpty()); if (task_id) { - ScriptWrappableTaskId* script_wrappable_task_id = - MakeGarbageCollected<ScriptWrappableTaskId>(task_id.value()); + ScriptWrappableTaskAttributionId* script_wrappable_task_id = + MakeGarbageCollected<ScriptWrappableTaskAttributionId>(task_id.value()); context->SetContinuationPreservedEmbedderData( - ToV8Traits<ScriptWrappableTaskId>::ToV8(script_state, - script_wrappable_task_id) + ToV8Traits<ScriptWrappableTaskAttributionId>::ToV8( + script_state, script_wrappable_task_id) .ToLocalChecked()); } else { context->SetContinuationPreservedEmbedderData(v8::Local<v8::Value>());
diff --git a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h index b4091f3a..de7f597 100644 --- a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h +++ b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h
@@ -5,10 +5,10 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_TASK_ATTRIBUTION_TRACKER_IMPL_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_TASK_ATTRIBUTION_TRACKER_IMPL_H_ +#include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h" -#include "third_party/blink/renderer/platform/scheduler/public/task_id.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -30,16 +30,17 @@ public: TaskAttributionTrackerImpl(); - absl::optional<TaskId> RunningTaskId(ScriptState*) const override; + absl::optional<TaskAttributionId> RunningTaskAttributionId( + ScriptState*) const override; - AncestorStatus IsAncestor(ScriptState*, TaskId parent_id) override; + AncestorStatus IsAncestor(ScriptState*, TaskAttributionId parent_id) override; AncestorStatus HasAncestorInSet( ScriptState*, - const WTF::HashSet<scheduler::TaskIdType>&) override; + const WTF::HashSet<scheduler::TaskAttributionIdType>&) override; std::unique_ptr<TaskScope> CreateTaskScope( ScriptState* script_state, - absl::optional<TaskId> parent_task_id) override; + absl::optional<TaskAttributionId> parent_task_id) override; // The vector size limits the amount of tasks we keep track of. Setting this // value too small can result in calls to `IsAncestor` returning an `Unknown` @@ -47,9 +48,11 @@ // increase this value (at the expense of memory dedicated to task tracking). static constexpr size_t kVectorSize = 1024; - void SetRunningTaskId(absl::optional<TaskId> id) { running_task_id_ = id; } + void SetRunningTaskAttributionId(absl::optional<TaskAttributionId> id) { + running_task_id_ = id; + } - void TaskScopeCompleted(ScriptState*, TaskId); + void TaskScopeCompleted(ScriptState*, TaskAttributionId); void RegisterObserver(TaskAttributionTracker::Observer* observer) override { DCHECK(!observer_ || observer == observer_); @@ -59,15 +62,15 @@ void UnregisterObserver() override { observer_.Clear(); } private: - struct TaskIdPair { - TaskIdPair() = default; - TaskIdPair(absl::optional<TaskId> parent_id, - absl::optional<TaskId> current_id) + struct TaskAttributionIdPair { + TaskAttributionIdPair() = default; + TaskAttributionIdPair(absl::optional<TaskAttributionId> parent_id, + absl::optional<TaskAttributionId> current_id) : parent(parent_id), current(current_id) {} explicit operator bool() const { return parent.has_value(); } - absl::optional<TaskId> parent; - absl::optional<TaskId> current; + absl::optional<TaskAttributionId> parent; + absl::optional<TaskAttributionId> current; }; template <typename F> @@ -77,61 +80,67 @@ public: TaskScopeImpl(ScriptState*, TaskAttributionTrackerImpl*, - TaskId scope_task_id, - absl::optional<TaskId> previous_task_id, - absl::optional<TaskId> previous_v8_task_id); + TaskAttributionId scope_task_id, + absl::optional<TaskAttributionId> previous_task_id, + absl::optional<TaskAttributionId> previous_v8_task_id); ~TaskScopeImpl() override; TaskScopeImpl(const TaskScopeImpl&) = delete; TaskScopeImpl& operator=(const TaskScopeImpl&) = delete; - TaskId GetTaskId() const { return scope_task_id_; } - absl::optional<TaskId> PreviousTaskId() const { return previous_task_id_; } - absl::optional<TaskId> PreviousV8TaskId() const { + TaskAttributionId GetTaskId() const { return scope_task_id_; } + absl::optional<TaskAttributionId> PreviousTaskAttributionId() const { + return previous_task_id_; + } + absl::optional<TaskAttributionId> PreviousV8TaskAttributionId() const { return previous_v8_task_id_; } ScriptState* GetScriptState() const { return script_state_; } private: TaskAttributionTrackerImpl* task_tracker_; - TaskId scope_task_id_; - absl::optional<TaskId> previous_task_id_; - absl::optional<TaskId> previous_v8_task_id_; + TaskAttributionId scope_task_id_; + absl::optional<TaskAttributionId> previous_task_id_; + absl::optional<TaskAttributionId> previous_v8_task_id_; Persistent<ScriptState> script_state_; }; class MODULES_EXPORT V8Adapter { public: - virtual absl::optional<TaskId> GetValue(ScriptState*); - virtual void SetValue(ScriptState*, absl::optional<TaskId>); + virtual absl::optional<TaskAttributionId> GetValue(ScriptState*); + virtual void SetValue(ScriptState*, absl::optional<TaskAttributionId>); virtual ~V8Adapter() = default; }; void TaskScopeCompleted(const TaskScopeImpl&); - TaskIdPair& GetTaskIdPairFromTaskContainer(TaskId); - void InsertTaskIdPair(TaskId task_id, absl::optional<TaskId> parent_task_id); - void SaveTaskIdStateInV8(ScriptState*, absl::optional<TaskId>); + TaskAttributionIdPair& GetTaskAttributionIdPairFromTaskContainer( + TaskAttributionId); + void InsertTaskAttributionIdPair( + TaskAttributionId task_id, + absl::optional<TaskAttributionId> parent_task_id); + void SaveTaskIdStateInV8(ScriptState*, absl::optional<TaskAttributionId>); void SetV8AdapterForTesting(std::unique_ptr<V8Adapter> adapter) { v8_adapter_.swap(adapter); } - TaskId next_task_id_; - absl::optional<TaskId> running_task_id_; + TaskAttributionId next_task_id_; + absl::optional<TaskAttributionId> running_task_id_; std::unique_ptr<V8Adapter> v8_adapter_; - // The task container is a vector of optional TaskIdPairs where its indexes - // are TaskId hashes, and its values are the TaskId of the parent task for the - // TaskId that is resulted in the index. We're using this vector as a circular - // array, where in order to find if task A is an ancestor of task B, we look - // up the value at B's taskId hash position, get its parent, and repeat that - // process until we either find A in the ancestor chain, get no parent task - // (indicating that a task has no parent, so wasn't initiated by another JS - // task), or reach a parent that doesn't have the current ID its child though - // it should have, which indicates that the parent was overwritten by a newer - // task, indicating that we went "full circle". - WTF::Vector<TaskIdPair> task_container_ = - WTF::Vector<TaskIdPair>(kVectorSize); + // The task container is a vector of optional TaskAttributionIdPairs where its + // indexes are TaskAttributionId hashes, and its values are the TaskId of the + // parent task for the TaskAttributionId that is resulted in the index. We're + // using this vector as a circular array, where in order to find if task A is + // an ancestor of task B, we look up the value at B's taskAttributionId hash + // position, get its parent, and repeat that process until we either find A in + // the ancestor chain, get no parent task (indicating that a task has no + // parent, so wasn't initiated by another JS task), or reach a parent that + // doesn't have the current ID its child though it should have, which + // indicates that the parent was overwritten by a newer task, indicating that + // we went "full circle". + WTF::Vector<TaskAttributionIdPair> task_container_ = + WTF::Vector<TaskAttributionIdPair>(kVectorSize); WeakPersistent<TaskAttributionTracker::Observer> observer_; };
diff --git a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl_test.cc b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl_test.cc index f6d0dcf..b92164a 100644 --- a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl_test.cc +++ b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl_test.cc
@@ -7,9 +7,9 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" -#include "third_party/blink/renderer/platform/scheduler/public/task_id.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink::scheduler { @@ -21,44 +21,45 @@ public: class MockV8Adapter : public TaskAttributionTrackerImpl::V8Adapter { public: - absl::optional<TaskId> GetValue(ScriptState*) override { return value_; } - void SetValue(ScriptState*, absl::optional<TaskId> task_id) override { - value_ = task_id; + absl::optional<TaskAttributionId> GetValue(ScriptState*) override { + return value_; + } + void SetValue(ScriptState*, absl::optional<TaskAttributionId> id) override { + value_ = id; } private: - absl::optional<TaskId> value_; + absl::optional<TaskAttributionId> value_; }; void PostTasks(TaskAttributionTrackerImpl& tracker, unsigned task_number, unsigned number_to_assert, - TaskIdType parent_to_assert, + TaskAttributionIdType parent_to_assert, bool complete, - TaskId* task_id = nullptr) { - TaskId previous_task_id = TaskId(parent_to_assert); + TaskAttributionId* id = nullptr) { + TaskAttributionId previous_id = TaskAttributionId(parent_to_assert); ScriptState* script_state = ToScriptStateForMainWorld(&GetFrame()); for (unsigned i = 0; i < task_number; ++i) { - task_stack_.push_back( - tracker.CreateTaskScope(script_state, previous_task_id)); - absl::optional<TaskId> running_task_id = - tracker.RunningTaskId(script_state); + task_stack_.push_back(tracker.CreateTaskScope(script_state, previous_id)); + absl::optional<TaskAttributionId> running_id = + tracker.RunningTaskAttributionId(script_state); if (i < number_to_assert) { // Make sure that the parent task is an ancestor. - TaskId parent_task(parent_to_assert); + TaskAttributionId parent_task(parent_to_assert); TaskAttributionTracker::AncestorStatus is_ancestor = tracker.IsAncestor(script_state, parent_task); ASSERT_TRUE(is_ancestor == TaskAttributionTracker::AncestorStatus::kAncestor); if (!complete) { - ASSERT_TRUE(tracker.IsAncestor(script_state, previous_task_id) == + ASSERT_TRUE(tracker.IsAncestor(script_state, previous_id) == TaskAttributionTracker::AncestorStatus::kAncestor); } } - if (task_id) { - *task_id = running_task_id.value(); + if (id) { + *id = running_id.value(); } - previous_task_id = running_task_id.value(); + previous_id = running_id.value(); if (complete) { task_stack_.pop_back(); } @@ -73,30 +74,31 @@ MockV8ForTracker(tracker); // Post tasks for half the queue. unsigned half_queue = TaskAttributionTrackerImpl::kVectorSize / 2; - TaskId task_id(0); + TaskAttributionId id(0); ScriptState* script_state = ToScriptStateForMainWorld(&GetFrame()); PostTasks(tracker, half_queue, /*number_to_assert=*/0, /*parent_to_assert=*/0, - /*complete=*/true, &task_id); + /*complete=*/true, &id); // Verify that the ID of the last task that ran is what we expect it to be. - ASSERT_EQ(half_queue, task_id.value()); + ASSERT_EQ(half_queue, id.value()); // Start the parent task, but don't complete it. task_stack_.push_back(tracker.CreateTaskScope( - script_state, tracker.RunningTaskId(script_state))); + script_state, tracker.RunningTaskAttributionId(script_state))); // Get its ID. - TaskId parent_task_id = tracker.RunningTaskId(script_state).value(); + TaskAttributionId parent_id = + tracker.RunningTaskAttributionId(script_state).value(); // Post |overflow_length| tasks. - PostTasks(tracker, overflow_length, asserts_length, parent_task_id.value(), + PostTasks(tracker, overflow_length, asserts_length, parent_id.value(), nested_tasks_complete); if (assert_last_task && ((overflow_length + half_queue) > TaskAttributionTrackerImpl::kVectorSize)) { // Post another task. task_stack_.push_back(tracker.CreateTaskScope( - script_state, tracker.RunningTaskId(script_state))); + script_state, tracker.RunningTaskAttributionId(script_state))); // Since it goes beyond the queue length and the parent task was // overwritten, we cannot track ancestry. - ASSERT_TRUE(tracker.IsAncestor(script_state, parent_task_id) != + ASSERT_TRUE(tracker.IsAncestor(script_state, parent_id) != TaskAttributionTracker::AncestorStatus::kAncestor); if (nested_tasks_complete) { task_stack_.pop_back(); @@ -146,19 +148,19 @@ TEST_F(TaskAttributionTrackerTest, NotAncestor) { TaskAttributionTrackerImpl tracker; MockV8ForTracker(tracker); - TaskId first_task_id(0); + TaskAttributionId first_id(0); ScriptState* script_state = ToScriptStateForMainWorld(&GetFrame()); // Start a task, get its ID and complete it. { auto scope = tracker.CreateTaskScope(script_state, absl::nullopt); - first_task_id = tracker.RunningTaskId(script_state).value(); + first_id = tracker.RunningTaskAttributionId(script_state).value(); } // Start an incomplete task. auto scope = tracker.CreateTaskScope(script_state, absl::nullopt); // Make sure that the first task is not an ancestor. - ASSERT_TRUE(tracker.IsAncestor(script_state, first_task_id) == + ASSERT_TRUE(tracker.IsAncestor(script_state, first_id) == TaskAttributionTracker::AncestorStatus::kNotAncestor); }
diff --git a/third_party/blink/renderer/platform/bindings/callback_function_base.h b/third_party/blink/renderer/platform/bindings/callback_function_base.h index fc559ebd9..a78b704 100644 --- a/third_party/blink/renderer/platform/bindings/callback_function_base.h +++ b/third_party/blink/renderer/platform/bindings/callback_function_base.h
@@ -6,11 +6,11 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_CALLBACK_FUNCTION_BASE_H_ #include "base/callback.h" +#include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/renderer/platform/bindings/name_client.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" -#include "third_party/blink/renderer/platform/scheduler/public/task_id.h" namespace blink { @@ -89,11 +89,11 @@ callback_function_.Reset(); } - absl::optional<scheduler::TaskId> GetParentTaskId() const { + absl::optional<scheduler::TaskAttributionId> GetParentTaskId() const { return parent_task_id_; } - void SetParentTaskId(absl::optional<scheduler::TaskId> task_id) { + void SetParentTaskId(absl::optional<scheduler::TaskAttributionId> task_id) { parent_task_id_ = task_id; } @@ -117,7 +117,7 @@ // https://webidl.spec.whatwg.org/#dfn-callback-context Member<ScriptState> incumbent_script_state_; - absl::optional<scheduler::TaskId> parent_task_id_; + absl::optional<scheduler::TaskAttributionId> parent_task_id_; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/bindings/callback_interface_base.h b/third_party/blink/renderer/platform/bindings/callback_interface_base.h index 6d33ee6..bf091371 100644 --- a/third_party/blink/renderer/platform/bindings/callback_interface_base.h +++ b/third_party/blink/renderer/platform/bindings/callback_interface_base.h
@@ -5,11 +5,11 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_CALLBACK_INTERFACE_BASE_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_CALLBACK_INTERFACE_BASE_H_ +#include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/renderer/platform/bindings/name_client.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" -#include "third_party/blink/renderer/platform/scheduler/public/task_id.h" namespace blink { @@ -83,7 +83,7 @@ DOMWrapperWorld& GetWorld() const { return incumbent_script_state_->World(); } - absl::optional<scheduler::TaskId> GetParentTaskId() const { + absl::optional<scheduler::TaskAttributionId> GetParentTaskId() const { return absl::nullopt; }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 0333bbe..54908d9 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2560,7 +2560,7 @@ }, { name: "WebCodecsDequeueEvent", - status: "experimental", + status: "stable", }, { name: "WebGLColorManagement",
diff --git a/third_party/blink/renderer/platform/scheduler/BUILD.gn b/third_party/blink/renderer/platform/scheduler/BUILD.gn index e397674..d5c1fb0d 100644 --- a/third_party/blink/renderer/platform/scheduler/BUILD.gn +++ b/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -132,7 +132,6 @@ "public/scheduling_lifecycle_state.h", "public/scheduling_policy.h", "public/task_attribution_tracker.h", - "public/task_id.h", "public/thread.h", "public/thread_cpu_throttler.h", "public/thread_scheduler.h",
diff --git a/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h b/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h index d1f461f..d19feb6 100644 --- a/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h +++ b/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h
@@ -6,9 +6,9 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_TASK_ATTRIBUTION_TRACKER_H_ #include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/platform_export.h" -#include "third_party/blink/renderer/platform/scheduler/public/task_id.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" namespace blink { @@ -43,7 +43,7 @@ class Observer : public GarbageCollectedMixin { public: - virtual void OnCreateTaskScope(const TaskId&) = 0; + virtual void OnCreateTaskScope(const TaskAttributionId&) = 0; }; virtual ~TaskAttributionTracker() = default; @@ -51,17 +51,19 @@ // Create a new task scope. virtual std::unique_ptr<TaskScope> CreateTaskScope( ScriptState*, - absl::optional<TaskId> parent_task_id) = 0; + absl::optional<TaskAttributionId> parent_task_id) = 0; // Get the ID of the currently running task. - virtual absl::optional<TaskId> RunningTaskId(ScriptState*) const = 0; + virtual absl::optional<TaskAttributionId> RunningTaskAttributionId( + ScriptState*) const = 0; // Check for ancestry of the currently running task against an input // |parentId|. - virtual AncestorStatus IsAncestor(ScriptState*, TaskId parentId) = 0; + virtual AncestorStatus IsAncestor(ScriptState*, + TaskAttributionId parentId) = 0; virtual AncestorStatus HasAncestorInSet( ScriptState*, - const WTF::HashSet<scheduler::TaskIdType>&) = 0; + const WTF::HashSet<scheduler::TaskAttributionIdType>&) = 0; // Register an observer to be notified when a task is started. Only one // observer can be set at every point in time.
diff --git a/third_party/blink/renderer/platform/scheduler/public/task_id.h b/third_party/blink/renderer/platform/scheduler/public/task_id.h deleted file mode 100644 index 84267f9..0000000 --- a/third_party/blink/renderer/platform/scheduler/public/task_id.h +++ /dev/null
@@ -1,35 +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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_TASK_ID_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_TASK_ID_H_ - -#include <cstdint> -#include "base/types/strong_alias.h" - -namespace blink::scheduler { - -using TaskIdType = uint32_t; - -// TaskId represents the ID of a task, enabling comparison and incrementation -// operations on it, while abstracting the underlying value from callers. -class TaskId { - public: - explicit TaskId(TaskIdType value) : value_(value) {} - TaskId(const TaskId&) = default; - TaskId& operator=(const TaskId&) = default; - scheduler::TaskIdType value() const { return value_; } - - bool operator==(const TaskId& id) const { return id.value_ == value_; } - bool operator!=(const TaskId& id) const { return id.value_ != value_; } - bool operator<(const TaskId& id) const { return value_ < id.value_; } - TaskId NextTaskId() const { return TaskId(value_ + 1); } - - private: - TaskIdType value_; -}; - -} // namespace blink::scheduler - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_TASK_ID_H_
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 402377e..bac317db 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2395,7 +2395,7 @@ crbug.com/922618 external/wpt/html/semantics/document-metadata/the-link-element/link-multiple-load-events.html [ Timeout ] # crbug.com/1095379: These are flaky-slow, but are already present in SlowTests -crbug.com/73609 http/tests/media/video-play-stall.html [ Pass Timeout ] +crbug.com/73609 http/tests/media/video-play-stall.html [ Pass Timeout Failure ] crbug.com/518987 http/tests/xmlhttprequest/navigation-abort-detaches-frame.html [ Pass Timeout ] crbug.com/538717 [ Win ] http/tests/permissions/chromium/test-request-worker.html [ Pass Timeout ] crbug.com/829740 fast/history/history-back-twice-with-subframes-assert.html [ Pass Timeout ] @@ -6145,6 +6145,8 @@ crbug.com/1249176 [ Mac12-arm64 ] media/video-replaces-poster.html [ Skip ] crbug.com/1249176 [ Mac11-arm64 ] virtual/gpu-rasterization/images/color-jpeg-with-color-profile.html [ Failure ] crbug.com/1249176 [ Mac12-arm64 ] virtual/gpu-rasterization/images/color-jpeg-with-color-profile.html [ Failure ] +crbug.com/1249176 [ Mac11-arm64 ] media/controls/overflow-menu-focus.html [ Failure Pass ] +crbug.com/1249176 [ Mac12-arm64 ] media/controls/overflow-menu-focus.html [ Failure Pass ] # Failures that surfaced on the mac12-arm64 waterfall crbug.com/1249176 [ Mac12-arm64 ] media/color-profile-video-seek.html [ Failure ] @@ -6169,7 +6171,7 @@ crbug.com/1249176 [ Mac12 ] fast/dom/Element/scrollTop-scrollLeft-body.html [ Failure Pass ] crbug.com/1249176 [ Mac12-arm64 ] external/wpt/html/rendering/replaced-elements/embedded-content/cross-domain-iframe-in-multicol.sub.html [ Failure Pass ] crbug.com/1249176 [ Mac12-arm64 ] fast/js/instanceof-test.html [ Failure Pass ] -crbug.com/1249176 [ Mac12-arm64 ] media/controls/overflow-menu-focus.html [ Failure Pass ] + # Sheriff 2022-07-04 crbug.com/1341689 [ Linux ] media/controls/overflow-menu-focus.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/W3CImportExpectations b/third_party/blink/web_tests/W3CImportExpectations index 6260046..9e72a67 100644 --- a/third_party/blink/web_tests/W3CImportExpectations +++ b/third_party/blink/web_tests/W3CImportExpectations
@@ -423,6 +423,9 @@ external/wpt/webdriver/tests/find_element_from_shadow_root/find.py [ Skip ] external/wpt/webdriver/tests/find_elements_from_shadow_root/find.py [ Skip ] +# This test failed presubmit check. Skip for now. +external/wpt/editing/crashtests/indent-outdent-after-closing-editable-dialog-element.html [ Skip ] + # Sheriff 16/09/2021, crbug.com/1250215 external/wpt/html/dom/idlharness.worker.html [ Skip ] external/wpt/html/dom/idlharness.https.html [ Skip ]
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/resources/scrolling.js b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/resources/scrolling.js index 1e96a7f..43c6938 100644 --- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/resources/scrolling.js +++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/resources/scrolling.js
@@ -4,7 +4,7 @@ target.addEventListener(eventName, function (event) { cancelable = event.cancelable; arrived = true; - }, {passive}); + }, {passive:passive, once:true}); promise_test(async (t) => { t.add_cleanup(() => {
diff --git a/third_party/blink/web_tests/external/wpt/reporting/document-reporting-default-endpoint.https.sub.html b/third_party/blink/web_tests/external/wpt/reporting/document-reporting-default-endpoint.https.sub.html index 24c1216a..f1951e3 100644 --- a/third_party/blink/web_tests/external/wpt/reporting/document-reporting-default-endpoint.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/reporting/document-reporting-default-endpoint.https.sub.html
@@ -19,7 +19,7 @@ observer.observe(); }, "report generated"); </script> -<script>window.webkitStorageInfo;</script> +<script>webkitRequestAnimationFrame(() => {});</script> <script> const base_url = `${location.protocol}//${location.host}`; const endpoint = `${base_url}/reporting/resources/report.py`;
diff --git a/third_party/blink/web_tests/external/wpt/reporting/document-reporting-path-absolute.https.sub.html b/third_party/blink/web_tests/external/wpt/reporting/document-reporting-path-absolute.https.sub.html index e23dd85..48be010a 100644 --- a/third_party/blink/web_tests/external/wpt/reporting/document-reporting-path-absolute.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/reporting/document-reporting-path-absolute.https.sub.html
@@ -21,7 +21,7 @@ observer.observe(); }, "report generated"); </script> -<script>window.webkitStorageInfo;</script> +<script>window.webkitCancelAnimationFrame(() => {});</script> <script> const base_url = `${location.protocol}//${location.host}`; const endpoint = `${base_url}/reporting/resources/report.py`;
diff --git a/third_party/blink/web_tests/external/wpt/reporting/resources/generate-report-once.py b/third_party/blink/web_tests/external/wpt/reporting/resources/generate-report-once.py index 076d500..163846a 100644 --- a/third_party/blink/web_tests/external/wpt/reporting/resources/generate-report-once.py +++ b/third_party/blink/web_tests/external/wpt/reporting/resources/generate-report-once.py
@@ -29,6 +29,6 @@ <meta charset=utf-8> <title>Generate deprecation report</title> <script> - window.webkitStorageInfo; + webkitRequestAnimationFrame(() => {}); </script> """
diff --git a/third_party/blink/web_tests/external/wpt/reporting/resources/generate-report.https.sub.html b/third_party/blink/web_tests/external/wpt/reporting/resources/generate-report.https.sub.html index ee40c46e..f1f4e963 100644 --- a/third_party/blink/web_tests/external/wpt/reporting/resources/generate-report.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/reporting/resources/generate-report.https.sub.html
@@ -2,5 +2,5 @@ <meta charset=utf-8> <title>Generate deprecation report</title> <script> - window.webkitStorageInfo; + webkitRequestAnimationFrame(() => {}); </script>
diff --git a/third_party/blink/web_tests/fast/events/touch/touch-slider-othogonal-movement.html b/third_party/blink/web_tests/fast/events/touch/touch-slider-othogonal-movement.html deleted file mode 100644 index d95c094..0000000 --- a/third_party/blink/web_tests/fast/events/touch/touch-slider-othogonal-movement.html +++ /dev/null
@@ -1,46 +0,0 @@ -<!DOCTYPE html> -<title>Orthogonal touch movement should not change slider value</title> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> -<input id="slider" type="range" value="0" style="width:200px; height: 50px"> -<script> -const w = slider.offsetWidth; -const h = slider.offsetHeight; - -test(() => { - assert_own_property(window, 'eventSender', 'This test needs eventSender to emulate touch'); - - // Emulate a touch that starts inside slider and moves vertically. - const x = slider.offsetLeft + w / 2; - const startY = slider.offsetTop + h / 2; - const endY = startY + h; - - eventSender.clearTouchPoints(); - eventSender.addTouchPoint(x, startY); - eventSender.touchStart(); - - eventSender.updateTouchPoint(0, x, endY); - eventSender.touchMove(); - - eventSender.releaseTouchPoint(0); - eventSender.touchEnd(); - - assert_equals(slider.value, "0"); -}, 'Orthogonal touch movement should not change slider value'); - -test(() => { - assert_own_property(window, 'eventSender', 'This test needs eventSender to emulate touch'); - - // Emulate a tap on the slider. - const x = slider.offsetLeft + w / 2; - const y = slider.offsetTop + h / 2; - - eventSender.clearTouchPoints(); - eventSender.addTouchPoint(x, y); - eventSender.touchStart(); - eventSender.releaseTouchPoint(0); - eventSender.touchEnd(); - - assert_not_equals(slider.value, "0"); -}, 'Tapping should still change slider value'); -</script>
diff --git a/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt index 14a0c62..22458ad 100644 --- a/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -36,6 +36,7 @@ [Worker] static method isConfigSupported [Worker] attribute @@toStringTag [Worker] getter decodeQueueSize +[Worker] getter ondequeue [Worker] getter state [Worker] method close [Worker] method configure @@ -43,10 +44,12 @@ [Worker] method decode [Worker] method flush [Worker] method reset +[Worker] setter ondequeue [Worker] interface AudioEncoder : EventTarget [Worker] static method isConfigSupported [Worker] attribute @@toStringTag [Worker] getter encodeQueueSize +[Worker] getter ondequeue [Worker] getter state [Worker] method close [Worker] method configure @@ -54,6 +57,7 @@ [Worker] method encode [Worker] method flush [Worker] method reset +[Worker] setter ondequeue [Worker] interface BackgroundFetchManager [Worker] attribute @@toStringTag [Worker] method constructor @@ -1687,6 +1691,7 @@ [Worker] static method isConfigSupported [Worker] attribute @@toStringTag [Worker] getter decodeQueueSize +[Worker] getter ondequeue [Worker] getter state [Worker] method close [Worker] method configure @@ -1694,10 +1699,12 @@ [Worker] method decode [Worker] method flush [Worker] method reset +[Worker] setter ondequeue [Worker] interface VideoEncoder : EventTarget [Worker] static method isConfigSupported [Worker] attribute @@toStringTag [Worker] getter encodeQueueSize +[Worker] getter ondequeue [Worker] getter state [Worker] method close [Worker] method configure @@ -1705,6 +1712,7 @@ [Worker] method encode [Worker] method flush [Worker] method reset +[Worker] setter ondequeue [Worker] interface VideoFrame [Worker] attribute @@toStringTag [Worker] getter codedHeight
diff --git a/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-expected.txt index 54fcae3d..ec65ec90 100644 --- a/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -173,6 +173,7 @@ static method isConfigSupported attribute @@toStringTag getter decodeQueueSize + getter ondequeue getter state method close method configure @@ -180,6 +181,7 @@ method decode method flush method reset + setter ondequeue interface AudioDestinationNode : AudioNode attribute @@toStringTag getter maxChannelCount @@ -188,6 +190,7 @@ static method isConfigSupported attribute @@toStringTag getter encodeQueueSize + getter ondequeue getter state method close method configure @@ -195,6 +198,7 @@ method encode method flush method reset + setter ondequeue interface AudioListener attribute @@toStringTag getter forwardX @@ -8231,6 +8235,7 @@ static method isConfigSupported attribute @@toStringTag getter decodeQueueSize + getter ondequeue getter state method close method configure @@ -8238,10 +8243,12 @@ method decode method flush method reset + setter ondequeue interface VideoEncoder : EventTarget static method isConfigSupported attribute @@toStringTag getter encodeQueueSize + getter ondequeue getter state method close method configure @@ -8249,6 +8256,7 @@ method encode method flush method reset + setter ondequeue interface VideoFrame attribute @@toStringTag getter codedHeight
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-body-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-body-expected.txt deleted file mode 100644 index 867b5e2..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-body-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL non-passive mousewheel event listener on body assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-div-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-div-expected.txt deleted file mode 100644 index 07cf21e2..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-div-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL non-passive mousewheel event listener on div assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document-expected.txt deleted file mode 100644 index de8a413..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL non-passive mousewheel event listener on document assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-root-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-root-expected.txt deleted file mode 100644 index 39aafa1..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-root-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL non-passive mousewheel event listener on root assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-window-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-window-expected.txt deleted file mode 100644 index 0c62421..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-window-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL non-passive mousewheel event listener on window assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-body-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-body-expected.txt deleted file mode 100644 index 25539dd..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-body-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL non-passive wheel event listener on body assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-div-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-div-expected.txt deleted file mode 100644 index aa0e869..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-div-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL non-passive wheel event listener on div assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-document-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-document-expected.txt deleted file mode 100644 index 33c1b82..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-document-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL non-passive wheel event listener on document assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-root-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-root-expected.txt deleted file mode 100644 index 4dbaa29..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-root-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL non-passive wheel event listener on root assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-window-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-window-expected.txt deleted file mode 100644 index a90d20c..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-window-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL non-passive wheel event listener on window assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/wpt_internal/reporting/buffer-overflow.html b/third_party/blink/web_tests/wpt_internal/reporting/buffer-overflow.html index cd43a3d..4bce75d 100644 --- a/third_party/blink/web_tests/wpt_internal/reporting/buffer-overflow.html +++ b/third_party/blink/web_tests/wpt_internal/reporting/buffer-overflow.html
@@ -23,7 +23,7 @@ for (var i = 0; i != 110; ++i) { causeIntervention(); } - window.webkitStorageInfo; + webkitRequestAnimationFrame(() => {}); observer3.observe(); observer3.disconnect();
diff --git a/third_party/blink/web_tests/wpt_internal/reporting/buffering.html b/third_party/blink/web_tests/wpt_internal/reporting/buffering.html index bbd916a..b04df48 100644 --- a/third_party/blink/web_tests/wpt_internal/reporting/buffering.html +++ b/third_party/blink/web_tests/wpt_internal/reporting/buffering.html
@@ -23,7 +23,7 @@ // and one after calling observe(). causeIntervention(); observer1.observe(); - window.webkitStorageInfo; + webkitCancelAnimationFrame(() => {}); observer1.disconnect(); }, "Buffered reports observed");
diff --git a/third_party/blink/web_tests/wpt_internal/reporting/reporting-api.html b/third_party/blink/web_tests/wpt_internal/reporting/reporting-api.html index 5750332..8edc077 100644 --- a/third_party/blink/web_tests/wpt_internal/reporting/reporting-api.html +++ b/third_party/blink/web_tests/wpt_internal/reporting/reporting-api.html
@@ -55,7 +55,7 @@ let promise = proxy.promise; // Use a deprecated feature. - window.webkitStorageInfo; + webkitRequestAnimationFrame(() => {}); // Ensure the deprecation report is generated and routed to the reporting mojo // interface.
diff --git a/third_party/blink/web_tests/wpt_internal/reporting/resources/deprecation.js b/third_party/blink/web_tests/wpt_internal/reporting/resources/deprecation.js index 84bf037..73f6eed 100644 --- a/third_party/blink/web_tests/wpt_internal/reporting/resources/deprecation.js +++ b/third_party/blink/web_tests/wpt_internal/reporting/resources/deprecation.js
@@ -53,6 +53,6 @@ window.gc(); // Use two deprecated features to generate two deprecation reports. - window.webkitStorageInfo; + window.webkitCancelAnimationFrame(() => {}); window.webkitRequestAnimationFrame(() => {}); }, "Deprecation reports");
diff --git a/third_party/blink/web_tests/wpt_internal/reporting/type-filtering.html b/third_party/blink/web_tests/wpt_internal/reporting/type-filtering.html index bf8a487..25dbe17 100644 --- a/third_party/blink/web_tests/wpt_internal/reporting/type-filtering.html +++ b/third_party/blink/web_tests/wpt_internal/reporting/type-filtering.html
@@ -44,7 +44,7 @@ observer2.observe(); // Generate a deprecation report and an intervention report. - window.webkitStorageInfo; + webkitCancelAnimationFrame(() => {}); causeIntervention(); observer2.disconnect();
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index b64a418..21288f5 100644 --- a/third_party/nearby/README.chromium +++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@ Name: Nearby Connections Library Short Name: Nearby URL: https://github.com/google/nearby -Version: c495cf830fe2fc59de34beacfe0356f4405f9c0d +Version: 0a8f1f1c39af06dff550d8ca96c6e087994155b7 License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/puffin/BUILD.gn b/third_party/puffin/BUILD.gn index a47a988..c60092a 100644 --- a/third_party/puffin/BUILD.gn +++ b/third_party/puffin/BUILD.gn
@@ -39,11 +39,13 @@ "//base", "//components/zucchini:zucchini_lib", "//third_party/brotli:dec", + "//third_party/brotli:enc", ] sources = [ "src/bit_reader.cc", "src/bit_writer.cc", "src/brotli_util.cc", + "src/file_stream.cc", "src/huffer.cc", "src/huffman_table.cc", "src/memory_stream.cc", @@ -61,6 +63,7 @@ ":libpuffin-proto", "//base", "//components/zucchini:zucchini_lib", + "//third_party/brotli:dec", "//third_party/brotli:enc", ] sources = [ @@ -113,8 +116,7 @@ "src/unittest_common.cc", "src/utils_unittest.cc", ] - data_deps = - [ "//chrome/test/data/updater/puffin_patch_test:puffin_patch_test_files" ] + data_deps = [ "//components/test/data/update_client/puffin_patch_test:puffin_patch_test_files" ] deps = [ ":libpuffdiff", ":libpuffpatch",
diff --git a/third_party/puffin/README.chromium b/third_party/puffin/README.chromium index e14113f..dd75cc5 100644 --- a/third_party/puffin/README.chromium +++ b/third_party/puffin/README.chromium
@@ -33,4 +33,12 @@ - Added puffin::Status enum to help disambiguate errors from puffin::PuffPatch - Added puffin::ApplyPuffPatch API which allows chromium libraries to call puffin::PuffPatch without having worry about UniqueStreamPtr's and Buffer's. -- Added ApplyPuffPatchTest to patching_unittest to test the new method. \ No newline at end of file +- Added ApplyPuffPatchTest to patching_unittest to test the new method. +- Updated puffin/BUILD.gn to grab the new puffin_patch_test_files target under +components +- Updated puffin::ApplyPuffPatch test to use the new patch files under +components. +- Updated puffin::ApplyPuffPatch test to make sure the output files are deleted +so the tests will pass in back-to-back runs. +- Updated puffin::ApplyPuffPatch test to use base::ContentsEqual rather than +manually reading each file and comparing the results. \ No newline at end of file
diff --git a/third_party/puffin/scripts/test_corpus.py b/third_party/puffin/scripts/test_corpus.py index e62b6807..eebe7cc 100755 --- a/third_party/puffin/scripts/test_corpus.py +++ b/third_party/puffin/scripts/test_corpus.py
@@ -5,7 +5,7 @@ # found in the LICENSE file. # -"""A tool for running puffin tests in a corpus of deflate compressed files.""" +"""A tool for running Puffin tests in a corpus of deflate compressed files.""" import argparse import filecmp
diff --git a/third_party/puffin/src/file_stream.cc b/third_party/puffin/src/file_stream.cc index b7a2ab5..aa6a2a67 100644 --- a/third_party/puffin/src/file_stream.cc +++ b/third_party/puffin/src/file_stream.cc
@@ -38,6 +38,10 @@ return UniqueStreamPtr(new FileStream(file_path, flags)); } +UniqueStreamPtr FileStream::CreateStreamFromFile(base::File file) { + return UniqueStreamPtr(new FileStream(std::move(file))); +} + bool FileStream::GetSize(uint64_t* size) { TEST_AND_RETURN_FALSE(file_.IsValid()); int64_t result = file_.GetLength();
diff --git a/third_party/puffin/src/include/puffin/common.h b/third_party/puffin/src/include/puffin/common.h index f76c538..ff9b00f 100644 --- a/third_party/puffin/src/include/puffin/common.h +++ b/third_party/puffin/src/include/puffin/common.h
@@ -26,15 +26,15 @@ namespace puffin { enum class CompressorType : uint8_t { - kNoCompression = 0, // Unsupported by chromium/src's puffin implementation. - kBZ2 = 1, // Unsupported by chromium/src's puffin implementation. + kNoCompression = 0, // Unsupported by chromium/src's Puffin implementation. + kBZ2 = 1, // Unsupported by chromium/src's Puffin implementation. kBrotli = 2, }; using Buffer = std::vector<uint8_t>; // This class is similar to the protobuf generated for |ProtoByteExtent|. We -// defined an extra class so the users of puffin do not have to include +// defined an extra class so the users of Puffin do not have to include // puffin.pb.h and deal with its use. struct ByteExtent { constexpr ByteExtent(uint64_t offset, uint64_t length)
diff --git a/third_party/puffin/src/include/puffin/file_stream.h b/third_party/puffin/src/include/puffin/file_stream.h index 466983b..9ebb3cf9 100644 --- a/third_party/puffin/src/include/puffin/file_stream.h +++ b/third_party/puffin/src/include/puffin/file_stream.h
@@ -22,9 +22,12 @@ file_.Initialize(path, flags); Seek(0); } + + FileStream(base::File file) : file_(std::move(file)) {} ~FileStream() override = default; static UniqueStreamPtr Open(const std::string& path, bool read, bool write); + static UniqueStreamPtr CreateStreamFromFile(base::File file); bool GetSize(uint64_t* size) override; bool GetOffset(uint64_t* offset) override;
diff --git a/third_party/puffin/src/include/puffin/puffpatch.h b/third_party/puffin/src/include/puffin/puffpatch.h index b7a6ac71..272a6ff 100644 --- a/third_party/puffin/src/include/puffin/puffpatch.h +++ b/third_party/puffin/src/include/puffin/puffpatch.h
@@ -5,6 +5,7 @@ #ifndef SRC_INCLUDE_PUFFIN_PUFFPATCH_H_ #define SRC_INCLUDE_PUFFIN_PUFFPATCH_H_ +#include "base/files/file.h" #include "base/files/file_path.h" #include "puffin/common.h" #include "puffin/stream.h" @@ -51,7 +52,7 @@ P_INPUT_NOT_RECOGNIZED = 24, // Unrecognized input (not a crx) }; -// Applies the puffin patch to deflate stream |src| to create deflate stream +// Applies the Puffin patch to deflate stream |src| to create deflate stream // |dst|. This function is used in the client and internally uses bspatch to // apply the patch. The input streams are of type |shared_ptr| because // |PuffPatch| needs to wrap these streams into another ones and we don't want @@ -73,6 +74,10 @@ const base::FilePath& patch_path, const base::FilePath& output_path); +Status ApplyPuffPatch(base::File input_file, + base::File patch_file, + base::File output_file); + } // namespace puffin #endif // SRC_INCLUDE_PUFFIN_PUFFPATCH_H_
diff --git a/third_party/puffin/src/include/puffin/stream.h b/third_party/puffin/src/include/puffin/stream.h index c305c4d..f62a346 100644 --- a/third_party/puffin/src/include/puffin/stream.h +++ b/third_party/puffin/src/include/puffin/stream.h
@@ -11,7 +11,7 @@ namespace puffin { -// The base stream interface used by puffin for all operations. This interface +// The base stream interface used by Puffin for all operations. This interface // is designed to be as simple as possible. class StreamInterface { public:
diff --git a/third_party/puffin/src/patching_unittest.cc b/third_party/puffin/src/patching_unittest.cc index d8b9ddb..ea90568 100644 --- a/third_party/puffin/src/patching_unittest.cc +++ b/third_party/puffin/src/patching_unittest.cc
@@ -149,26 +149,26 @@ } TEST(PatchingTest, ApplyPuffPatchTest) { - ASSERT_EQ(ApplyPuffPatch(out_test_file("puffin_app_v1.crx3"), - out_test_file("puffin_app_v1_to_v2.puff"), - out_test_file("puffin_app_v1_to_v2.crx3")), - Status::P_OK); - std::string expected, actual; - ASSERT_TRUE( - base::ReadFileToString(out_test_file("puffin_app_v2.crx3"), &expected)); - ASSERT_TRUE(base::ReadFileToString(out_test_file("puffin_app_v1_to_v2.crx3"), - &actual)); - ASSERT_EQ(expected.compare(actual), 0); + base::FilePath app_v1_crx = out_test_file("puffin_app_v1.crx3"); + base::FilePath app_v2_crx = out_test_file("puffin_app_v2.crx3"); + base::FilePath patch_v1_to_v2_puff = + out_test_file("puffin_app_v1_to_v2.puff"); + base::FilePath patch_v2_to_v1_puff = + out_test_file("puffin_app_v2_to_v1.puff"); + base::FilePath app_v1_to_v2_crx = out_test_file("puffin_app_v1_to_v2.crx3"); + base::FilePath app_v2_to_v1_crx = out_test_file("puffin_app_v2_to_v1.crx3"); - ASSERT_EQ(ApplyPuffPatch(out_test_file("puffin_app_v2.crx3"), - out_test_file("puffin_app_v2_to_v1.puff"), - out_test_file("puffin_app_v2_to_v1.crx3")), + // Test patching v1 to v2: + ASSERT_TRUE(base::DeleteFile(app_v1_to_v2_crx)); + ASSERT_EQ(ApplyPuffPatch(app_v1_crx, patch_v1_to_v2_puff, app_v1_to_v2_crx), Status::P_OK); - ASSERT_TRUE( - base::ReadFileToString(out_test_file("puffin_app_v1.crx3"), &expected)); - ASSERT_TRUE(base::ReadFileToString(out_test_file("puffin_app_v2_to_v1.crx3"), - &actual)); - ASSERT_EQ(expected.compare(actual), 0); + EXPECT_TRUE(base::ContentsEqual(app_v2_crx, app_v1_to_v2_crx)); + + // Test patching v2 to v1: + ASSERT_TRUE(base::DeleteFile(app_v2_to_v1_crx)); + ASSERT_EQ(ApplyPuffPatch(app_v2_crx, patch_v2_to_v1_puff, app_v2_to_v1_crx), + Status::P_OK); + EXPECT_TRUE(base::ContentsEqual(app_v1_crx, app_v2_to_v1_crx)); } // TODO(ahassani): add tests for:
diff --git a/third_party/puffin/src/puffdiff.cc b/third_party/puffin/src/puffdiff.cc index 381b26e..1c1fc0f7 100644 --- a/third_party/puffin/src/puffdiff.cc +++ b/third_party/puffin/src/puffdiff.cc
@@ -44,7 +44,7 @@ } } -// Structure of a puffin patch +// Structure of a Puffin patch // +-------+------------------+-------------+--------------+ // |P|U|F|1| PatchHeader Size | PatchHeader | raw patch | // +-------+------------------+-------------+--------------+
diff --git a/third_party/puffin/src/puffer.cc b/third_party/puffin/src/puffer.cc index 6da93ac..5796147 100644 --- a/third_party/puffin/src/puffer.cc +++ b/third_party/puffin/src/puffer.cc
@@ -182,14 +182,14 @@ auto bits_to_cache = cur_ht->DistanceMaxBits(); if (!br->CacheBits(bits_to_cache)) { // This is a corner case that is present in the older versions of the - // puffin. So we need to catch it and correctly discard this kind of + // Puffin. So we need to catch it and correctly discard this kind of // deflate when we encounter it. See crbug.com/915559 for more info. bits_to_cache = br->BitsRemaining(); TEST_AND_RETURN_FALSE(br->CacheBits(bits_to_cache)); if (exclude_bad_distance_caches_) { include_deflate = false; } - LOG(WARNING) << "A rare condition that older puffin clients fail to" + LOG(WARNING) << "A rare condition that older Puffin clients fail to" << " recognize happened. Nothing to worry about." << " See crbug.com/915559"; }
diff --git a/third_party/puffin/src/puffpatch.cc b/third_party/puffin/src/puffpatch.cc index 93e52a19..00d9938 100644 --- a/third_party/puffin/src/puffpatch.cc +++ b/third_party/puffin/src/puffpatch.cc
@@ -166,7 +166,7 @@ const uint8_t* patch, size_t patch_length, size_t max_cache_size) { - size_t patch_offset; // raw patch offset in puffin |patch|. + size_t patch_offset; // raw patch offset in Puffin |patch|. size_t raw_patch_size = 0; vector<BitExtent> src_deflates, dst_deflates; vector<ByteExtent> src_puffs, dst_puffs; @@ -237,4 +237,35 @@ puffdiff_delta.size(), kDefaultPuffCacheSize); } +Status ApplyPuffPatch(base::File input_file, + base::File patch_file, + base::File output_file) { + puffin::UniqueStreamPtr input_stream = + puffin::FileStream::CreateStreamFromFile(std::move(input_file)); + if (!input_stream) { + return Status::P_READ_OPEN_ERROR; + } + puffin::UniqueStreamPtr output_stream = + puffin::FileStream::CreateStreamFromFile(std::move(output_file)); + if (!output_stream) { + return Status::P_WRITE_OPEN_ERROR; + } + puffin::UniqueStreamPtr patch_stream = + puffin::FileStream::CreateStreamFromFile(std::move(patch_file)); + if (!patch_stream) { + return Status::P_READ_OPEN_ERROR; + } + uint64_t patch_size = 0; + if (!patch_stream->GetSize(&patch_size)) { + return Status::P_STREAM_ERROR; + } + puffin::Buffer puffdiff_delta(patch_size); + if (!patch_stream->Read(puffdiff_delta.data(), puffdiff_delta.size())) { + return Status::P_READ_ERROR; + } + return puffin::PuffPatch(std::move(input_stream), std::move(output_stream), + std::move(puffdiff_delta.data()), + puffdiff_delta.size(), kDefaultPuffCacheSize); +} + } // namespace puffin
diff --git a/tools/gritsettings/translation_expectations.pyl b/tools/gritsettings/translation_expectations.pyl index ede3585..176ed2b 100644 --- a/tools/gritsettings/translation_expectations.pyl +++ b/tools/gritsettings/translation_expectations.pyl
@@ -34,9 +34,10 @@ "chrome/app/chromium_strings.grd", "chrome/app/generated_resources.grd", "chrome/app/google_chrome_strings.grd", + "chrome/browser/password_check/android/internal/java/strings/android_password_check_strings.grd", "chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings.grd", "chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd", - "chrome/browser/password_check/android/internal/java/strings/android_password_check_strings.grd", + "chrome/browser/ui/android/fast_checkout/internal/java/strings/android_fast_checkout_strings.grd", "chrome/browser/ui/android/strings/android_chrome_strings.grd", "chrome/credential_provider/gaiacp/gaia_resources.grd", "chromeos/chromeos_strings.grd",
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 32c237b..d42d005 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -1976,11 +1976,11 @@ # Cast Linux takes very long in linking, possibly due to being on GCE # (crbug/794423). 'cast_release_bot_reclient': [ - 'cast', 'release_bot_reclient', 'minimal_symbols', + 'cast_receiver', 'cast_os', 'release_bot_reclient', 'minimal_symbols', ], 'cast_release_trybot': [ - 'cast', 'release_trybot', + 'cast_receiver', 'cast_os', 'release_trybot', ], 'cfi_full_cfi_icall_cfi_diag_recover_release_static_reclient': [ @@ -3791,6 +3791,10 @@ 'gn_args': 'is_cast_audio_only=true' }, + 'cast_os': { + 'gn_args': 'is_castos=true' + }, + 'cast_receiver': { 'gn_args': 'enable_cast_receiver=true' },
diff --git a/tools/mb/mb_config_expectations/chromium.linux.json b/tools/mb/mb_config_expectations/chromium.linux.json index 9ea6c28..ff6c6ddb 100644 --- a/tools/mb/mb_config_expectations/chromium.linux.json +++ b/tools/mb/mb_config_expectations/chromium.linux.json
@@ -13,7 +13,8 @@ "Cast Linux": { "gn_args": { "dcheck_always_on": false, - "is_chromecast": true, + "enable_cast_receiver": true, + "is_castos": true, "is_component_build": false, "is_debug": false, "symbol_level": 1,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json index 4dce4418..714e5f15 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
@@ -23,7 +23,8 @@ "cast_shell_linux": { "gn_args": { "dcheck_always_on": true, - "is_chromecast": true, + "enable_cast_receiver": true, + "is_castos": true, "is_component_build": false, "is_debug": false, "symbol_level": 0,
diff --git a/tools/metrics/actions/PRESUBMIT.py b/tools/metrics/actions/PRESUBMIT.py index eb47b1b..ee1390c 100644 --- a/tools/metrics/actions/PRESUBMIT.py +++ b/tools/metrics/actions/PRESUBMIT.py
@@ -24,7 +24,7 @@ if exit_code != 0: return [output_api.PresubmitError( 'actions.xml is not up to date or is not formatted correctly; ' - 'run extract_actions.py to fix')] + 'run tools/metrics/actions/extract_actions.py to fix')] return []
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index e148264..3fe69a6 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -32139,6 +32139,7 @@ <int value="998" label="EnterpriseProfileCreationKeepBrowsingData"/> <int value="999" label="KerberosDomainAutocomplete"/> <int value="1000" label="KerberosDefaultConfiguration"/> + <int value="1001" label="UnmanagedDeviceSignalsConsentFlowEnabled"/> </enum> <enum name="EnterprisePoliciesSources"> @@ -41174,6 +41175,7 @@ <int value="27" label="ManifestListTooBig"/> <int value="28" label="DisabledEmbargo"/> <int value="29" label="UserInterfaceTimedOut"/> + <int value="30" label="RpPageNotVisible"/> </enum> <enum name="FedCmRevokeStatus">
diff --git a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS index 10055dfc..a767e0e 100644 --- a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS +++ b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
@@ -47,6 +47,7 @@ iclelland@chromium.org ioanap@chromium.org jihanli@chromium.org +jimmyxgong@chromium.org joenotcharles@google.com johnidel@chromium.org jonross@chromium.org
diff --git a/tools/metrics/histograms/metadata/ash/OWNERS b/tools/metrics/histograms/metadata/ash/OWNERS index 68b7725..07c6957d 100644 --- a/tools/metrics/histograms/metadata/ash/OWNERS +++ b/tools/metrics/histograms/metadata/ash/OWNERS
@@ -3,4 +3,5 @@ # Prefer sending CLs to the owners listed below. # Use chromium-metrics-reviews@google.com as a backup. tby@chromium.org -zentaro@chromium.org +jimmyxgong@chromium.org +zentaro@chromium.org \ No newline at end of file
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 41a6f0f..1a96e1de 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -3197,6 +3197,22 @@ </token> </histogram> +<histogram name="Ash.NotifierFramework.Toast.Dismissed.{TimeRange}" + enum="ToastCatalogName" expires_after="2023-02-10"> + <owner>kradtke@google.com</owner> + <owner>cros-status-area-eng@google.com</owner> + <summary> + Tracks the time a specific toast spends on screen before being dismissed by + the user or system. Records the toast catalog name in one of the time + buckets available when toast is dismissed either manually or by time out. + </summary> + <token key="TimeRange"> + <variant name="After7s"/> + <variant name="Within2s"/> + <variant name="Within7s"/> + </token> +</histogram> + <histogram name="Ash.NotifierFramework.Toast.ShownCount" enum="ToastCatalogName" expires_after="2023-01-15"> <owner>kradtke@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml index 2e9b945..b71724be 100644 --- a/tools/metrics/histograms/metadata/blink/histograms.xml +++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -2451,40 +2451,6 @@ </summary> </histogram> -<histogram name="Blink.Tokenizer.MainDocument.ATypicalStates" units="bitmask" - expires_after="2022-09-01"> - <owner>sky@chromium.org</owner> - <owner>swarm-team@google.com</owner> - <summary> - This metric is reported for the main document when tokenizing of the input - completes. The histogram is a bitmask of values capturing how often - non-typical states are encountered. A value of 0 means none were - encountered. Bitmask values are: - - Bit 1: Set if document.write() is encountered. - - Bit 2: Set if the tokenizer state as determined by HTMLTreeBuilder does not - match the speculative state from HTMLTokenizer. - - Bit 3: Set if the input contains a null character. - - Bit 4: Set if input contains CDATA. - </summary> -</histogram> - -<histogram name="Blink.Tokenizer.MainDocument.LocationOfFirstATypicalState" - units="location" expires_after="2022-09-01"> - <owner>sky@chromium.org</owner> - <owner>swarm-team@google.com</owner> - <summary> - This metric is reported for the main document when tokenizing of the input - completes. This is emitted if a non-typical tokenization state is - encountered (see Blink.Tokenizer.MainDocument.ATypicalStates for more - details). The value is the location in the input stream of the first - non-typical state. - </summary> -</histogram> - <histogram name="Blink.UpdateViewportIntersection.UpdateTime" units="microseconds" expires_after="2022-12-11"> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePreFCPSuffixes" -->
diff --git a/tools/metrics/histograms/metadata/chromeos_hps/OWNERS b/tools/metrics/histograms/metadata/chromeos_hps/OWNERS index 293c497..241c4eb 100644 --- a/tools/metrics/histograms/metadata/chromeos_hps/OWNERS +++ b/tools/metrics/histograms/metadata/chromeos_hps/OWNERS
@@ -10,4 +10,5 @@ khorimoto@chromium.org tby@chromium.org tsergeant@chromium.org +jimmyxgong@chromium.org zentaro@chromium.org
diff --git a/tools/metrics/histograms/metadata/diagnostics/OWNERS b/tools/metrics/histograms/metadata/diagnostics/OWNERS new file mode 100644 index 0000000..96d6a8a --- /dev/null +++ b/tools/metrics/histograms/metadata/diagnostics/OWNERS
@@ -0,0 +1,8 @@ +per-file OWNERS=file://tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS + +# Prefer sending CLs to the owners listed below. +# Use chromium-metrics-reviews@google.com as a backup. +# Primary reviewers +jimmyxgong@chromium.org +# Secondary reviewers +zentaro@chromium.org \ No newline at end of file
diff --git a/tools/metrics/histograms/metadata/input/histograms.xml b/tools/metrics/histograms/metadata/input/histograms.xml index 9519344..8e09cc1f 100644 --- a/tools/metrics/histograms/metadata/input/histograms.xml +++ b/tools/metrics/histograms/metadata/input/histograms.xml
@@ -401,7 +401,7 @@ </histogram> <histogram name="InputMethod.CharactersPerSession{InputModality}" - units="characters" expires_after="2022-06-30"> + units="characters" expires_after="2022-12-04"> <owner>keithlee@chromium.org</owner> <owner>essential-inputs-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index a0d9c44..b6c1027ba 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -2014,6 +2014,29 @@ </summary> </histogram> +<histogram name="Media.D3D11.UnusedPictureBufferCount.MultiTexture" + units="instances" expires_after="2022-11-01"> + <owner>liberato@chromium.org</owner> + <owner>tmathmeyer@chromium.org</owner> + <summary> + This histogram lets us count how many PictureBuffers we've overallocated + when we're allocating each texture separately. This case is relatively + simple to optimize compared to SingleTexture. + </summary> +</histogram> + +<histogram name="Media.D3D11.UnusedPictureBufferCount.SingleTexture" + units="instances" expires_after="2022-11-01"> + <owner>liberato@chromium.org</owner> + <owner>tmathmeyer@chromium.org</owner> + <summary> + This histogram lets us count how many PictureBuffers we've overallocated + when we're allocating in contiguous blocks. This case is harder to optimize + than the MultiTexture variant, but it is good to know the proportion of the + two of them to determine usage. + </summary> +</histogram> + <histogram name="Media.DetectedAudioCodecHash" enum="FFmpegCodecHashes" expires_after="never"> <!-- expires-never: Codec support planning metric. -->
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml index cf025f1..5ca378b1 100644 --- a/tools/metrics/histograms/metadata/navigation/histograms.xml +++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -571,6 +571,18 @@ </summary> </histogram> +<histogram name="Navigation.CrossOtr.ContextMenu.RefreshCount" units="count" + expires_after="2023-01-02"> + <owner>mreichhoff@chromium.org</owner> + <owner>wanderview@chromium.org</owner> + <owner>bcl@chromium.org</owner> + <owner>dc-komics@google.com</owner> + <summary> + The count of refreshes on the first document after a cross-OTR navigation + completes. This metric is written when default classifications were applied. + </summary> +</histogram> + <histogram name="Navigation.CrossOtr.ContextMenu.RefreshCountExperimental" units="count" expires_after="2023-01-02"> <owner>mreichhoff@chromium.org</owner> @@ -584,6 +596,21 @@ </summary> </histogram> +<histogram name="Navigation.CrossOtr.ContextMenu.ResponseCode" + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-01-02"> + <owner>mreichhoff@chromium.org</owner> + <owner>wanderview@chromium.org</owner> + <owner>bcl@chromium.org</owner> + <owner>dc-komics@google.com</owner> + <summary> + Http response codes seen when opening links from non-OTR to OTR browsing. + Logged when using the "Open Link in Incognito Window" menu item. + Note that, in the case of redirects, multiple entries will be written for a + single navigation. This metric is written when default classifications were + applied. + </summary> +</histogram> + <histogram name="Navigation.CrossOtr.ContextMenu.ResponseCodeExperimental" enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-01-02"> <owner>mreichhoff@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/OWNERS b/tools/metrics/histograms/metadata/others/OWNERS index 86929a4..995da070 100644 --- a/tools/metrics/histograms/metadata/others/OWNERS +++ b/tools/metrics/histograms/metadata/others/OWNERS
@@ -5,6 +5,9 @@ per-file histograms.xml=file://tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS # For display, mouse, and input related histograms. +# Primary reviewers +jimmyxgong@chromium.org +# Secondary reviewers zentaro@chromium.org # For Conversions.* histograms: johnidel@chromium.org
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index 4bebc984..48813a3 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -6142,6 +6142,17 @@ </summary> </histogram> +<histogram name="FirstRun.TermsOfServicesPromoDisplayTime" units="ms" + expires_after="2023-08-08"> + <owner>ginnyhuang@chromium.org</owner> + <owner>bling-get-set-up@google.com</owner> + <summary> + Records the time it takes for the user to accept Terms of Services after + it's shown in the first Promo screen on First Run. Note: This is not + available for the legacy FRE. + </summary> +</histogram> + <histogram name="FirstUserAction.BackgroundTime" units="minutes" expires_after="2022-09-12"> <!-- Name completed by histogram_suffixes name="FirstUserActionType" and name="FirstUserActionTypeDevice" -->
diff --git a/tools/metrics/histograms/metadata/print/OWNERS b/tools/metrics/histograms/metadata/print/OWNERS index 5a3a767..ff41ce21 100644 --- a/tools/metrics/histograms/metadata/print/OWNERS +++ b/tools/metrics/histograms/metadata/print/OWNERS
@@ -3,4 +3,5 @@ # Prefer sending CLs to the owners listed below. # Use chromium-metrics-reviews@google.com as a backup. awscreen@chromium.org +jimmyxgong@chromium.org zentaro@chromium.org
diff --git a/tools/metrics/histograms/metadata/printing/OWNERS b/tools/metrics/histograms/metadata/printing/OWNERS index 5a3a767..ff41ce21 100644 --- a/tools/metrics/histograms/metadata/printing/OWNERS +++ b/tools/metrics/histograms/metadata/printing/OWNERS
@@ -3,4 +3,5 @@ # Prefer sending CLs to the owners listed below. # Use chromium-metrics-reviews@google.com as a backup. awscreen@chromium.org +jimmyxgong@chromium.org zentaro@chromium.org
diff --git a/tools/metrics/histograms/metadata/scanning/OWNERS b/tools/metrics/histograms/metadata/scanning/OWNERS index d4a1d59..4f6eba0 100644 --- a/tools/metrics/histograms/metadata/scanning/OWNERS +++ b/tools/metrics/histograms/metadata/scanning/OWNERS
@@ -2,4 +2,7 @@ # Prefer sending CLs to the owners listed below. # Use chromium-metrics-reviews@google.com as a backup. +# Primary reviewers +jimmyxgong@chromium.org +# Secondary reviewers zentaro@chromium.org
diff --git a/tools/metrics/histograms/metadata/security/histograms.xml b/tools/metrics/histograms/metadata/security/histograms.xml index bc13c16f..ef95c64 100644 --- a/tools/metrics/histograms/metadata/security/histograms.xml +++ b/tools/metrics/histograms/metadata/security/histograms.xml
@@ -791,7 +791,7 @@ </histogram> <histogram name="SiteIsolation.IsPasswordFormSubmittedInDedicatedProcess" - enum="SiteIsolationIsDedicatedProcess" expires_after="2022-08-07"> + enum="SiteIsolationIsDedicatedProcess" expires_after="2023-08-07"> <owner>alexmos@chromium.org</owner> <owner>lukasza@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/stability/histograms.xml b/tools/metrics/histograms/metadata/stability/histograms.xml index a90764c..1a54054 100644 --- a/tools/metrics/histograms/metadata/stability/histograms.xml +++ b/tools/metrics/histograms/metadata/stability/histograms.xml
@@ -240,7 +240,7 @@ </histogram> <histogram name="Stability.ChildFrameCrash.ShownAfterCrashingReason" - enum="ShownAfterCrashingReason" expires_after="2022-12-25"> + enum="ShownAfterCrashingReason" expires_after="2023-08-09"> <owner>alexmos@chromium.org</owner> <owner>boliu@chromium.org</owner> <owner>lukasza@chromium.org</owner> @@ -252,7 +252,7 @@ </histogram> <histogram name="Stability.ChildFrameCrash.TabMarkedForReload" - enum="BooleanMarkedForReload" expires_after="2022-08-18"> + enum="BooleanMarkedForReload" expires_after="2023-08-09"> <owner>alexmos@chromium.org</owner> <owner>boliu@chromium.org</owner> <summary> @@ -262,7 +262,7 @@ </histogram> <histogram name="Stability.ChildFrameCrash.TabMarkedForReload.Visibility" - enum="FrameVisibility" expires_after="2022-11-20"> + enum="FrameVisibility" expires_after="2023-08-09"> <owner>alexmos@chromium.org</owner> <owner>boliu@chromium.org</owner> <summary> @@ -273,7 +273,7 @@ </histogram> <histogram name="Stability.ChildFrameCrash.Visibility" enum="CrashVisibility" - expires_after="2022-12-25"> + expires_after="2023-08-09"> <owner>alexmos@chromium.org</owner> <owner>boliu@chromium.org</owner> <owner>lfg@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/uma/histograms.xml b/tools/metrics/histograms/metadata/uma/histograms.xml index c7c6311..3277719 100644 --- a/tools/metrics/histograms/metadata/uma/histograms.xml +++ b/tools/metrics/histograms/metadata/uma/histograms.xml
@@ -893,7 +893,7 @@ </histogram> <histogram name="UMA.UnsentLogs.PersistedSizeInKB" units="KB" - expires_after="2022-08-01"> + expires_after="2023-08-01"> <owner>michaelbai@chromium.org</owner> <owner>asvitkine@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> @@ -905,7 +905,7 @@ </histogram> <histogram name="UMA.UnsentLogs.SentCount" units="samples" - expires_after="2022-08-01"> + expires_after="2023-08-01"> <owner>michaelbai@chromium.org</owner> <owner>asvitkine@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> @@ -916,7 +916,7 @@ </histogram> <histogram name="UMA.UnsentLogs.UnsentCount" units="samples" - expires_after="2022-08-01"> + expires_after="2023-08-01"> <owner>michaelbai@chromium.org</owner> <owner>asvitkine@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> @@ -927,7 +927,7 @@ </histogram> <histogram name="UMA.UnsentLogs.UnsentPercentage" units="%" - expires_after="2022-08-01"> + expires_after="2023-08-01"> <owner>michaelbai@chromium.org</owner> <owner>asvitkine@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner>
diff --git a/tools/metrics/histograms/metadata/variations/histograms.xml b/tools/metrics/histograms/metadata/variations/histograms.xml index 557b750c..cca3f5d 100644 --- a/tools/metrics/histograms/metadata/variations/histograms.xml +++ b/tools/metrics/histograms/metadata/variations/histograms.xml
@@ -468,6 +468,19 @@ </token> </histogram> +<histogram name="Variations.SeedFetchTimeOnFirstRun" units="ms" + expires_after="2023-02-09"> + <owner>ginnyhuang@chromium.org</owner> + <owner>src/base/metrics/OWNERS</owner> + <summary> + The latency of fetching an initial variations seed during first run on + non-Android platforms. Only considers cases where an HTTP 200 result was + received. + + The respective metric for Android's is Variations.FirstRun.SeedFetchTime. + </summary> +</histogram> + <histogram name="Variations.SeedFreshness" units="minutes" expires_after="2023-01-15"> <owner>asvitkine@chromium.org</owner>
diff --git a/tools/metrics/histograms/update_net_trust_anchors.py b/tools/metrics/histograms/update_net_trust_anchors.py index d34a018..3661ee5 100755 --- a/tools/metrics/histograms/update_net_trust_anchors.py +++ b/tools/metrics/histograms/update_net_trust_anchors.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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.
diff --git a/ui/base/ime/linux/OWNERS b/ui/base/ime/linux/OWNERS new file mode 100644 index 0000000..b641050 --- /dev/null +++ b/ui/base/ime/linux/OWNERS
@@ -0,0 +1,2 @@ +hidehiko@chromium.org +thomasanderson@chromium.org
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc index 2b69a00..7feb867 100644 --- a/ui/base/ui_base_features.cc +++ b/ui/base/ui_base_features.cc
@@ -95,10 +95,6 @@ "LacrosResourcesFileSharing", base::FEATURE_DISABLED_BY_DEFAULT}; #endif // BUILDFLAG(IS_CHROMEOS_ASH) -// Enable or disable multitouch for virtual keyboard on ChromeOS. -const base::Feature kVirtualKeyboardMultitouch{ - "VirtualKeyboardMultitouch", base::FEATURE_DISABLED_BY_DEFAULT}; - // Update of the virtual keyboard settings UI as described in // https://crbug.com/876901. const base::Feature kInputMethodSettingsUiUpdate = {
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h index b190c0d..2584490 100644 --- a/ui/base/ui_base_features.h +++ b/ui/base/ui_base_features.h
@@ -38,8 +38,6 @@ extern const base::Feature kSystemKeyboardLock; COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kUiCompositorScrollWithLayers; -COMPONENT_EXPORT(UI_BASE_FEATURES) -extern const base::Feature kVirtualKeyboardMultitouch; COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsUiGpuRasterizationEnabled();
diff --git a/ui/chromeos/shill_error.cc b/ui/chromeos/shill_error.cc index a64e62cf..d874c4d 100644 --- a/ui/chromeos/shill_error.cc +++ b/ui/chromeos/shill_error.cc
@@ -17,7 +17,7 @@ namespace { const ash::NetworkState* GetNetworkState(const std::string& network_id) { - return chromeos::NetworkHandler::Get() + return ash::NetworkHandler::Get() ->network_state_handler() ->GetNetworkStateFromGuid(network_id); }
diff --git a/ui/gl/gl_display.cc b/ui/gl/gl_display.cc index 9fc104a2..d17614675 100644 --- a/ui/gl/gl_display.cc +++ b/ui/gl/gl_display.cc
@@ -5,11 +5,13 @@ #include "ui/gl/gl_display.h" #include <string> +#include <type_traits> #include <vector> #include "base/command_line.h" #include "base/containers/contains.h" #include "base/debug/crash_logging.h" +#include "base/export_template.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/notreached.h" @@ -585,7 +587,7 @@ #else AddInitDisplay(init_displays, ANGLE_OPENGL); AddInitDisplay(init_displays, ANGLE_OPENGLES); -#endif +#endif // BUILDFLAG(IS_ANDROID) } else { if (requested_renderer == kANGLEImplementationOpenGLName) { AddInitDisplay(init_displays, ANGLE_OPENGL); @@ -660,11 +662,47 @@ supports_angle_metal, command_line, init_displays); } -GLDisplay::GLDisplay(uint64_t system_device_id) - : system_device_id_(system_device_id) {} +GLDisplay::GLDisplay(uint64_t system_device_id, DisplayPlatform type) + : system_device_id_(system_device_id), type_(type) {} GLDisplay::~GLDisplay() = default; +template <typename GLDisplayPlatform> +GLDisplayPlatform* GLDisplay::GetAs() { + bool type_checked = false; + switch (type_) { + case NONE: + NOTREACHED(); + break; + + case EGL: +#if defined(USE_EGL) + type_checked = std::is_same<GLDisplayPlatform, GLDisplayEGL>::value; +#endif // defined(USE_EGL) + break; + + case X11: +#if defined(USE_GLX) + type_checked = std::is_same<GLDisplayPlatform, GLDisplayX11>::value; +#endif // defined(USE_GLX) + break; + } + if (type_checked) + return static_cast<GLDisplayPlatform*>(this); + + return nullptr; +} + +#if defined(USE_EGL) +template EXPORT_TEMPLATE_DEFINE(GL_EXPORT) + GLDisplayEGL* GLDisplay::GetAs<GLDisplayEGL>(); +#endif // defined(USE_EGL) + +#if defined(USE_GLX) +template EXPORT_TEMPLATE_DEFINE(GL_EXPORT) + GLDisplayX11* GLDisplay::GetAs<GLDisplayX11>(); +#endif // defined(USE_GLX) + #if defined(USE_EGL) GLDisplayEGL::EGLGpuSwitchingObserver::EGLGpuSwitchingObserver( EGLDisplay display) @@ -678,9 +716,8 @@ } GLDisplayEGL::GLDisplayEGL(uint64_t system_device_id) - : GLDisplay(system_device_id) { + : GLDisplay(system_device_id, EGL), display_(EGL_NO_DISPLAY) { ext = std::make_unique<DisplayExtensionsEGL>(); - display_ = EGL_NO_DISPLAY; } GLDisplayEGL::~GLDisplayEGL() = default; @@ -709,6 +746,10 @@ egl_android_native_fence_sync_supported_ = false; } +bool GLDisplayEGL::IsInitialized() { + return display_ != EGL_NO_DISPLAY; +} + void GLDisplayEGL::SetDisplay(EGLDisplay display) { display_ = display; } @@ -935,7 +976,7 @@ if (!is_angle) { egl_surfaceless_context_supported_ = false; } -#endif +#endif // BUILDFLAG(IS_ANDROID) if (egl_surfaceless_context_supported_) { // EGL_KHR_surfaceless_context is supported but ensure @@ -976,13 +1017,13 @@ base::SysInfo::GetAndroidHardwareEGL() != "emulation") { egl_android_native_fence_sync_supported_ = true; } -#endif +#endif // BUILDFLAG(IS_ANDROID) } #endif // defined(USE_EGL) #if defined(USE_GLX) GLDisplayX11::GLDisplayX11(uint64_t system_device_id) - : GLDisplay(system_device_id) {} + : GLDisplay(system_device_id, X11) {} GLDisplayX11::~GLDisplayX11() = default; @@ -991,6 +1032,10 @@ } void GLDisplayX11::Shutdown() {} + +bool GLDisplayX11::IsInitialized() { + return true; +} #endif // defined(USE_GLX) } // namespace gl
diff --git a/ui/gl/gl_display.h b/ui/gl/gl_display.h index 6114678..b44710c0 100644 --- a/ui/gl/gl_display.h +++ b/ui/gl/gl_display.h
@@ -71,6 +71,12 @@ DISPLAY_TYPE_MAX = 19, }; +enum DisplayPlatform { + NONE = 0, + EGL = 1, + X11 = 2, +}; + GL_EXPORT void GetEGLInitDisplaysForTesting( bool supports_angle_d3d, bool supports_angle_opengl, @@ -93,11 +99,16 @@ virtual void* GetDisplay() = 0; virtual void Shutdown() = 0; + virtual bool IsInitialized() = 0; + + template <typename GLDisplayPlatform> + GLDisplayPlatform* GetAs(); protected: - explicit GLDisplay(uint64_t system_device_id); + GLDisplay(uint64_t system_device_id, DisplayPlatform type); uint64_t system_device_id_ = 0; + DisplayPlatform type_ = NONE; }; #if defined(USE_EGL) @@ -112,6 +123,7 @@ EGLDisplay GetDisplay() override; void Shutdown() override; + bool IsInitialized() override; void SetDisplay(EGLDisplay display); EGLDisplayPlatform GetNativeDisplay() const; @@ -169,6 +181,7 @@ void* GetDisplay() override; void Shutdown() override; + bool IsInitialized() override; private: friend class GLDisplayManager<GLDisplayX11>;
diff --git a/ui/gl/gl_display_manager.h b/ui/gl/gl_display_manager.h index 7325e20..54a908f 100644 --- a/ui/gl/gl_display_manager.h +++ b/ui/gl/gl_display_manager.h
@@ -73,6 +73,11 @@ return GetDisplay(system_device_id); } + bool IsEmpty() { + base::AutoLock auto_lock(lock_); + return displays_.empty(); + } + private: friend class base::NoDestructor<GLDisplayManager<GLDisplayPlatform>>; #if defined(USE_EGL)
diff --git a/ui/gl/gl_surface_egl_unittest.cc b/ui/gl/gl_surface_egl_unittest.cc index 9bbf088..7f80b9fc 100644 --- a/ui/gl/gl_surface_egl_unittest.cc +++ b/ui/gl/gl_surface_egl_unittest.cc
@@ -43,6 +43,11 @@ void TearDown() override { GLSurfaceTestSupport::ShutdownGL(display_); } + GLDisplay* GetTestDisplay() { + EXPECT_NE(display_, nullptr); + return display_; + } + private: raw_ptr<GLDisplay> display_ = nullptr; }; @@ -54,8 +59,8 @@ surface_format.SetDepthBits(24); surface_format.SetStencilBits(8); surface_format.SetSamples(0); - scoped_refptr<GLSurface> surface = - init::CreateOffscreenGLSurfaceWithFormat(gfx::Size(1, 1), surface_format); + scoped_refptr<GLSurface> surface = init::CreateOffscreenGLSurfaceWithFormat( + GetTestDisplay(), gfx::Size(1, 1), surface_format); EGLConfig config = surface->GetConfig(); EXPECT_TRUE(config);
diff --git a/ui/gl/gl_utils.cc b/ui/gl/gl_utils.cc index 2bc87f2..a14b13ed 100644 --- a/ui/gl/gl_utils.cc +++ b/ui/gl/gl_utils.cc
@@ -189,6 +189,23 @@ } #endif // BUILDFLAG(IS_WIN) +GLDisplay* GetDisplay(GpuPreference gpu_preference) { +#if defined(USE_GLX) + if (!GLDisplayManagerX11::GetInstance()->IsEmpty()) { + return GLDisplayManagerX11::GetInstance()->GetDisplay(gpu_preference); + } +#endif +#if defined(USE_EGL) + return GLDisplayManagerEGL::GetInstance()->GetDisplay(gpu_preference); +#endif + NOTREACHED(); + return nullptr; +} + +GLDisplay* GetDefaultDisplay() { + return GetDisplay(GpuPreference::kDefault); +} + #if defined(USE_EGL) void SetGpuPreferenceEGL(GpuPreference preference, uint64_t system_device_id) { GLDisplayManagerEGL::GetInstance()->SetGpuPreference(preference,
diff --git a/ui/gl/gl_utils.h b/ui/gl/gl_utils.h index 844bc41..3b2f82de 100644 --- a/ui/gl/gl_utils.h +++ b/ui/gl/gl_utils.h
@@ -29,6 +29,7 @@ #if defined(USE_GLX) class GLDisplayX11; #endif // USE_GLX +class GLDisplay; GL_EXPORT void Crash(); GL_EXPORT void Hang(); @@ -73,6 +74,14 @@ GL_EXPORT void SetGpuPreferenceEGL(GpuPreference preference, uint64_t system_device_id); +// Query the default GLDisplay. May return either a GLDisplayEGL or +// GLDisplayX11. +GL_EXPORT GLDisplay* GetDefaultDisplay(); + +// Query the GLDisplay by |gpu_preference|. May return either a GLDisplayEGL or +// GLDisplayX11. +GL_EXPORT GLDisplay* GetDisplay(GpuPreference gpu_preference); + // Query the default GLDisplayEGL. GL_EXPORT GLDisplayEGL* GetDefaultDisplayEGL();
diff --git a/ui/gl/init/gl_factory.cc b/ui/gl/init/gl_factory.cc index ff574eb..68afa64 100644 --- a/ui/gl/init/gl_factory.cc +++ b/ui/gl/init/gl_factory.cc
@@ -248,8 +248,9 @@ SetGLImplementation(kGLImplementationNone); } -scoped_refptr<GLSurface> CreateOffscreenGLSurface(const gfx::Size& size) { - return CreateOffscreenGLSurfaceWithFormat(size, GLSurfaceFormat()); +scoped_refptr<GLSurface> CreateOffscreenGLSurface(gl::GLDisplay* display, + const gfx::Size& size) { + return CreateOffscreenGLSurfaceWithFormat(display, size, GLSurfaceFormat()); } void DisableANGLE() {
diff --git a/ui/gl/init/gl_factory.h b/ui/gl/init/gl_factory.h index 218f4d9..581a7ad 100644 --- a/ui/gl/init/gl_factory.h +++ b/ui/gl/init/gl_factory.h
@@ -91,6 +91,7 @@ // Creates a GL surface that renders directly to a view. GL_INIT_EXPORT scoped_refptr<GLSurface> CreateViewGLSurface( + GLDisplay* display, gfx::AcceleratedWidget window); #if defined(USE_OZONE) @@ -99,15 +100,19 @@ // be presented as an overlay. If surfaceless mode is not supported or // enabled it will return a null pointer. GL_INIT_EXPORT scoped_refptr<GLSurface> CreateSurfacelessViewGLSurface( + GLDisplay* display, gfx::AcceleratedWidget window); #endif // defined(USE_OZONE) // Creates a GL surface used for offscreen rendering. GL_INIT_EXPORT scoped_refptr<GLSurface> CreateOffscreenGLSurface( + GLDisplay* display, const gfx::Size& size); GL_INIT_EXPORT scoped_refptr<GLSurface> CreateOffscreenGLSurfaceWithFormat( - const gfx::Size& size, GLSurfaceFormat format); + GLDisplay* display, + const gfx::Size& size, + GLSurfaceFormat format); // Set platform dependent disabled extensions and re-initialize extension // bindings.
diff --git a/ui/gl/init/gl_factory_android.cc b/ui/gl/init/gl_factory_android.cc index c508a04e..1816ea7 100644 --- a/ui/gl/init/gl_factory_android.cc +++ b/ui/gl/init/gl_factory_android.cc
@@ -116,7 +116,8 @@ } } -scoped_refptr<GLSurface> CreateViewGLSurface(gfx::AcceleratedWidget window) { +scoped_refptr<GLSurface> CreateViewGLSurface(GLDisplay* display, + gfx::AcceleratedWidget window) { TRACE_EVENT0("gpu", "gl::init::CreateViewGLSurface"); CHECK_NE(kGLImplementationNone, GetGLImplementation()); switch (GetGLImplementation()) { @@ -124,7 +125,7 @@ case kGLImplementationEGLANGLE: if (window != gfx::kNullAcceleratedWidget) { return InitializeGLSurface(new NativeViewGLSurfaceEGL( - GLSurfaceEGL::GetGLDisplayEGL(), window, nullptr)); + display->GetAs<gl::GLDisplayEGL>(), window, nullptr)); } else { return InitializeGLSurface(new GLSurfaceStub()); } @@ -135,20 +136,22 @@ } scoped_refptr<GLSurface> CreateOffscreenGLSurfaceWithFormat( - const gfx::Size& size, GLSurfaceFormat format) { + GLDisplay* display, + const gfx::Size& size, + GLSurfaceFormat format) { TRACE_EVENT0("gpu", "gl::init::CreateOffscreenGLSurface"); CHECK_NE(kGLImplementationNone, GetGLImplementation()); switch (GetGLImplementation()) { case kGLImplementationEGLGLES2: case kGLImplementationEGLANGLE: { - if (GLSurfaceEGL::GetGLDisplayEGL()->IsEGLSurfacelessContextSupported() && + GLDisplayEGL* display_egl = display->GetAs<gl::GLDisplayEGL>(); + if (display_egl->IsEGLSurfacelessContextSupported() && (size.width() == 0 && size.height() == 0)) { return InitializeGLSurfaceWithFormat( - new SurfacelessEGL(GLSurfaceEGL::GetGLDisplayEGL(), size), format); + new SurfacelessEGL(display_egl, size), format); } else { return InitializeGLSurfaceWithFormat( - new PbufferGLSurfaceEGL(GLSurfaceEGL::GetGLDisplayEGL(), size), - format); + new PbufferGLSurfaceEGL(display_egl, size), format); } } case kGLImplementationMockGL:
diff --git a/ui/gl/init/gl_factory_mac.cc b/ui/gl/init/gl_factory_mac.cc index 95a53815..e308645d 100644 --- a/ui/gl/init/gl_factory_mac.cc +++ b/ui/gl/init/gl_factory_mac.cc
@@ -107,7 +107,8 @@ } } -scoped_refptr<GLSurface> CreateViewGLSurface(gfx::AcceleratedWidget window) { +scoped_refptr<GLSurface> CreateViewGLSurface(GLDisplay* display, + gfx::AcceleratedWidget window) { TRACE_EVENT0("gpu", "gl::init::CreateViewGLSurface"); switch (GetGLImplementation()) { case kGLImplementationDesktopGL: @@ -127,7 +128,9 @@ } scoped_refptr<GLSurface> CreateOffscreenGLSurfaceWithFormat( - const gfx::Size& size, GLSurfaceFormat format) { + GLDisplay* display, + const gfx::Size& size, + GLSurfaceFormat format) { TRACE_EVENT0("gpu", "gl::init::CreateOffscreenGLSurface"); switch (GetGLImplementation()) { case kGLImplementationDesktopGL: @@ -136,16 +139,17 @@ new NoOpGLSurface(size), format); #if defined(USE_EGL) case kGLImplementationEGLGLES2: - case kGLImplementationEGLANGLE: - if (GLSurfaceEGL::GetGLDisplayEGL()->IsEGLSurfacelessContextSupported() && + case kGLImplementationEGLANGLE: { + GLDisplayEGL* display_egl = display->GetAs<gl::GLDisplayEGL>(); + if (display_egl->IsEGLSurfacelessContextSupported() && size.width() == 0 && size.height() == 0) { return InitializeGLSurfaceWithFormat( - new SurfacelessEGL(GLSurfaceEGL::GetGLDisplayEGL(), size), format); + new SurfacelessEGL(display_egl, size), format); } else { return InitializeGLSurfaceWithFormat( - new PbufferGLSurfaceEGL(GLSurfaceEGL::GetGLDisplayEGL(), size), - format); + new PbufferGLSurfaceEGL(display_egl, size), format); } + } #endif // defined(USE_EGL) case kGLImplementationMockGL: case kGLImplementationStubGL:
diff --git a/ui/gl/init/gl_factory_ozone.cc b/ui/gl/init/gl_factory_ozone.cc index 57b4c97..8760e21 100644 --- a/ui/gl/init/gl_factory_ozone.cc +++ b/ui/gl/init/gl_factory_ozone.cc
@@ -58,11 +58,12 @@ return nullptr; } -scoped_refptr<GLSurface> CreateViewGLSurface(gfx::AcceleratedWidget window) { +scoped_refptr<GLSurface> CreateViewGLSurface(GLDisplay* display, + gfx::AcceleratedWidget window) { TRACE_EVENT0("gpu", "gl::init::CreateViewGLSurface"); if (HasGLOzone()) - return GetGLOzone()->CreateViewGLSurface(window); + return GetGLOzone()->CreateViewGLSurface(display, window); switch (GetGLImplementation()) { case kGLImplementationMockGL: @@ -76,13 +77,16 @@ } scoped_refptr<GLSurface> CreateSurfacelessViewGLSurface( + GLDisplay* display, gfx::AcceleratedWidget window) { TRACE_EVENT0("gpu", "gl::init::CreateSurfacelessViewGLSurface"); - return HasGLOzone() ? GetGLOzone()->CreateSurfacelessViewGLSurface(window) - : nullptr; + return HasGLOzone() + ? GetGLOzone()->CreateSurfacelessViewGLSurface(display, window) + : nullptr; } scoped_refptr<GLSurface> CreateOffscreenGLSurfaceWithFormat( + GLDisplay* display, const gfx::Size& size, GLSurfaceFormat format) { TRACE_EVENT0("gpu", "gl::init::CreateOffscreenGLSurface"); @@ -93,7 +97,7 @@ } if (HasGLOzone()) - return GetGLOzone()->CreateOffscreenGLSurface(size); + return GetGLOzone()->CreateOffscreenGLSurface(display, size); switch (GetGLImplementation()) { case kGLImplementationMockGL:
diff --git a/ui/gl/init/gl_factory_win.cc b/ui/gl/init/gl_factory_win.cc index f61749a..ea69bdba 100644 --- a/ui/gl/init/gl_factory_win.cc +++ b/ui/gl/init/gl_factory_win.cc
@@ -59,13 +59,14 @@ } } -scoped_refptr<GLSurface> CreateViewGLSurface(gfx::AcceleratedWidget window) { +scoped_refptr<GLSurface> CreateViewGLSurface(GLDisplay* display, + gfx::AcceleratedWidget window) { TRACE_EVENT0("gpu", "gl::init::CreateViewGLSurface"); switch (GetGLImplementation()) { case kGLImplementationEGLANGLE: { DCHECK_NE(window, gfx::kNullAcceleratedWidget); return InitializeGLSurface(base::MakeRefCounted<NativeViewGLSurfaceEGL>( - GLSurfaceEGL::GetGLDisplayEGL(), window, + display->GetAs<gl::GLDisplayEGL>(), window, std::make_unique<VSyncProviderWin>(window))); } case kGLImplementationMockGL: @@ -78,19 +79,22 @@ } scoped_refptr<GLSurface> CreateOffscreenGLSurfaceWithFormat( - const gfx::Size& size, GLSurfaceFormat format) { + GLDisplay* display, + const gfx::Size& size, + GLSurfaceFormat format) { TRACE_EVENT0("gpu", "gl::init::CreateOffscreenGLSurface"); switch (GetGLImplementation()) { - case kGLImplementationEGLANGLE: - if (GLSurfaceEGL::GetGLDisplayEGL()->IsEGLSurfacelessContextSupported() && + case kGLImplementationEGLANGLE: { + GLDisplayEGL* display_egl = display->GetAs<gl::GLDisplayEGL>(); + if (display_egl->IsEGLSurfacelessContextSupported() && size.width() == 0 && size.height() == 0) { return InitializeGLSurfaceWithFormat( - new SurfacelessEGL(GLSurfaceEGL::GetGLDisplayEGL(), size), format); + new SurfacelessEGL(display_egl, size), format); } else { return InitializeGLSurfaceWithFormat( - new PbufferGLSurfaceEGL(GLSurfaceEGL::GetGLDisplayEGL(), size), - format); + new PbufferGLSurfaceEGL(display_egl, size), format); } + } case kGLImplementationMockGL: case kGLImplementationStubGL: return new GLSurfaceStub; @@ -121,7 +125,7 @@ switch (implementation) { case kGLImplementationEGLANGLE: return InitializeExtensionSettingsOneOffEGL( - static_cast<GLDisplayEGL*>(display)); + display->GetAs<GLDisplayEGL>()); case kGLImplementationMockGL: case kGLImplementationStubGL: return true;
diff --git a/ui/gl/test/gl_image_test_template.h b/ui/gl/test/gl_image_test_template.h index 3e1ae06..e5eb4bcb 100644 --- a/ui/gl/test/gl_image_test_template.h +++ b/ui/gl/test/gl_image_test_template.h
@@ -75,7 +75,7 @@ void SetUp() override { auto prefered_impl = delegate_.GetPreferedGLImplementation(); display_ = GLImageTestSupport::InitializeGL(prefered_impl); - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + surface_ = gl::init::CreateOffscreenGLSurface(display_, gfx::Size()); context_ = gl::init::CreateGLContext(nullptr, surface_.get(), GLContextAttribs()); context_->MakeCurrent(surface_.get());
diff --git a/ui/ozone/common/gl_ozone_egl.cc b/ui/ozone/common/gl_ozone_egl.cc index f175dc87..7e7bb78 100644 --- a/ui/ozone/common/gl_ozone_egl.cc +++ b/ui/ozone/common/gl_ozone_egl.cc
@@ -86,6 +86,7 @@ } scoped_refptr<gl::GLSurface> GLOzoneEGL::CreateSurfacelessViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) { // This will usually not be implemented by the platform specific version. return nullptr;
diff --git a/ui/ozone/common/gl_ozone_egl.h b/ui/ozone/common/gl_ozone_egl.h index 0560d835..6aca58a 100644 --- a/ui/ozone/common/gl_ozone_egl.h +++ b/ui/ozone/common/gl_ozone_egl.h
@@ -49,10 +49,13 @@ gl::GLSurface* compatible_surface, const gl::GLContextAttribs& attribs) override; scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override = 0; scoped_refptr<gl::GLSurface> CreateSurfacelessViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override; scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) override = 0; protected:
diff --git a/ui/ozone/common/gl_surface_egl_readback.cc b/ui/ozone/common/gl_surface_egl_readback.cc index 8d14021..bf711f2 100644 --- a/ui/ozone/common/gl_surface_egl_readback.cc +++ b/ui/ozone/common/gl_surface_egl_readback.cc
@@ -19,8 +19,8 @@ } // namespace -GLSurfaceEglReadback::GLSurfaceEglReadback() - : PbufferGLSurfaceEGL(GLSurfaceEGL::GetGLDisplayEGL(), gfx::Size(1, 1)), +GLSurfaceEglReadback::GLSurfaceEglReadback(gl::GLDisplayEGL* display) + : PbufferGLSurfaceEGL(display, gfx::Size(1, 1)), task_runner_(base::ThreadTaskRunnerHandle::Get()) {} bool GLSurfaceEglReadback::Resize(const gfx::Size& size,
diff --git a/ui/ozone/common/gl_surface_egl_readback.h b/ui/ozone/common/gl_surface_egl_readback.h index d0ad9790e..44620ad1 100644 --- a/ui/ozone/common/gl_surface_egl_readback.h +++ b/ui/ozone/common/gl_surface_egl_readback.h
@@ -22,7 +22,7 @@ // there is no FBO implementation for Ozone. class GLSurfaceEglReadback : public gl::PbufferGLSurfaceEGL { public: - GLSurfaceEglReadback(); + explicit GLSurfaceEglReadback(gl::GLDisplayEGL* display); GLSurfaceEglReadback(const GLSurfaceEglReadback&) = delete; GLSurfaceEglReadback& operator=(const GLSurfaceEglReadback&) = delete;
diff --git a/ui/ozone/demo/simple_renderer_factory.cc b/ui/ozone/demo/simple_renderer_factory.cc index da58010..6dcad2d5 100644 --- a/ui/ozone/demo/simple_renderer_factory.cc +++ b/ui/ozone/demo/simple_renderer_factory.cc
@@ -9,6 +9,7 @@ #include "base/command_line.h" #include "base/logging.h" +#include "ui/gl/gl_display.h" #include "ui/gl/gl_surface.h" #include "ui/gl/init/gl_factory.h" #include "ui/ozone/demo/gl_renderer.h" @@ -35,12 +36,13 @@ const char kEnableVulkan[] = "enable-vulkan"; #endif -scoped_refptr<gl::GLSurface> CreateGLSurface(gfx::AcceleratedWidget widget) { +scoped_refptr<gl::GLSurface> CreateGLSurface(gl::GLDisplay* display, + gfx::AcceleratedWidget widget) { scoped_refptr<gl::GLSurface> surface; if (!base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableSurfaceless)) - surface = gl::init::CreateSurfacelessViewGLSurface(widget); + surface = gl::init::CreateSurfacelessViewGLSurface(display, widget); if (!surface) - surface = gl::init::CreateViewGLSurface(widget); + surface = gl::init::CreateViewGLSurface(display, widget); return surface; } @@ -48,7 +50,12 @@ SimpleRendererFactory::SimpleRendererFactory() {} -SimpleRendererFactory::~SimpleRendererFactory() {} +SimpleRendererFactory::~SimpleRendererFactory() { + if (display_) { + gl::init::ShutdownGL(display_, false); + display_ = nullptr; + } +} bool SimpleRendererFactory::Initialize() { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); @@ -65,9 +72,13 @@ } } #endif - if (!command_line->HasSwitch(kDisableGpu) && - gl::init::InitializeGLOneOff(/*system_device_id=*/0)) { - type_ = GL; + if (!command_line->HasSwitch(kDisableGpu)) { + display_ = gl::init::InitializeGLOneOff(/*system_device_id=*/0); + if (display_) { + type_ = GL; + } else { + type_ = SOFTWARE; + } } else { type_ = SOFTWARE; } @@ -84,7 +95,7 @@ surface_factory_ozone->CreatePlatformWindowSurface(widget); switch (type_) { case GL: { - scoped_refptr<gl::GLSurface> surface = CreateGLSurface(widget); + scoped_refptr<gl::GLSurface> surface = CreateGLSurface(display_, widget); if (!surface) LOG(FATAL) << "Failed to create GL surface"; if (surface->IsSurfaceless()) {
diff --git a/ui/ozone/demo/simple_renderer_factory.h b/ui/ozone/demo/simple_renderer_factory.h index eb1ef76..94a1b23 100644 --- a/ui/ozone/demo/simple_renderer_factory.h +++ b/ui/ozone/demo/simple_renderer_factory.h
@@ -14,6 +14,10 @@ #include "gpu/vulkan/vulkan_implementation.h" #endif +namespace gl { +class GLDisplay; +}; + namespace ui { class SimpleRendererFactory : public RendererFactory { @@ -43,6 +47,7 @@ #endif RendererType type_ = SOFTWARE; + gl::GLDisplay* display_ = nullptr; }; } // namespace ui
diff --git a/ui/ozone/demo/skia/skia_renderer_factory.cc b/ui/ozone/demo/skia/skia_renderer_factory.cc index bbad1df..812e50db 100644 --- a/ui/ozone/demo/skia/skia_renderer_factory.cc +++ b/ui/ozone/demo/skia/skia_renderer_factory.cc
@@ -9,6 +9,7 @@ #include "base/command_line.h" #include "base/logging.h" +#include "ui/gl/gl_display.h" #include "ui/gl/gl_surface.h" #include "ui/gl/init/gl_factory.h" #include "ui/ozone/demo/skia/skia_gl_renderer.h" @@ -22,12 +23,13 @@ const char kDisableSurfaceless[] = "disable-surfaceless"; -scoped_refptr<gl::GLSurface> CreateGLSurface(gfx::AcceleratedWidget widget) { +scoped_refptr<gl::GLSurface> CreateGLSurface(gl::GLDisplay* display, + gfx::AcceleratedWidget widget) { scoped_refptr<gl::GLSurface> surface; if (!base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableSurfaceless)) - surface = gl::init::CreateSurfacelessViewGLSurface(widget); + surface = gl::init::CreateSurfacelessViewGLSurface(display, widget); if (!surface) - surface = gl::init::CreateViewGLSurface(widget); + surface = gl::init::CreateViewGLSurface(display, widget); return surface; } @@ -35,10 +37,16 @@ SkiaRendererFactory::SkiaRendererFactory() {} -SkiaRendererFactory::~SkiaRendererFactory() {} +SkiaRendererFactory::~SkiaRendererFactory() { + if (display_) { + gl::init::ShutdownGL(display_, false); + display_ = nullptr; + } +} bool SkiaRendererFactory::Initialize() { - if (!gl::init::InitializeGLOneOff(/*system_device_id=*/0)) { + display_ = gl::init::InitializeGLOneOff(/*system_device_id=*/0); + if (!display_) { LOG(FATAL) << "Failed to initialize GL"; } @@ -52,7 +60,7 @@ OzonePlatform::GetInstance()->GetSurfaceFactoryOzone(); auto window_surface = surface_factory_ozone->CreatePlatformWindowSurface(widget); - scoped_refptr<gl::GLSurface> gl_surface = CreateGLSurface(widget); + scoped_refptr<gl::GLSurface> gl_surface = CreateGLSurface(display_, widget); if (!gl_surface) LOG(FATAL) << "Failed to create GL surface"; if (gl_surface->IsSurfaceless()) {
diff --git a/ui/ozone/demo/skia/skia_renderer_factory.h b/ui/ozone/demo/skia/skia_renderer_factory.h index 96688375..372382d 100644 --- a/ui/ozone/demo/skia/skia_renderer_factory.h +++ b/ui/ozone/demo/skia/skia_renderer_factory.h
@@ -11,6 +11,10 @@ #include "ui/gfx/native_widget_types.h" #include "ui/ozone/demo/renderer_factory.h" +namespace gl { +class GLDisplay; +}; + namespace ui { class Renderer; @@ -32,6 +36,9 @@ bool Initialize() override; std::unique_ptr<Renderer> CreateRenderer(gfx::AcceleratedWidget widget, const gfx::Size& size) override; + + private: + gl::GLDisplay* display_ = nullptr; }; } // namespace ui
diff --git a/ui/ozone/platform/cast/gl_ozone_egl_cast.cc b/ui/ozone/platform/cast/gl_ozone_egl_cast.cc index 779f213..42a05a82 100644 --- a/ui/ozone/platform/cast/gl_ozone_egl_cast.cc +++ b/ui/ozone/platform/cast/gl_ozone_egl_cast.cc
@@ -87,18 +87,21 @@ } scoped_refptr<gl::GLSurface> GLOzoneEglCast::CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget widget) { // Verify requested widget dimensions match our current display size. DCHECK_EQ(static_cast<int>(widget >> 16), display_size_.width()); DCHECK_EQ(static_cast<int>(widget & 0xffff), display_size_.height()); - return gl::InitializeGLSurface(new GLSurfaceCast(widget, this)); + return gl::InitializeGLSurface( + new GLSurfaceCast(display->GetAs<gl::GLDisplayEGL>(), widget, this)); } scoped_refptr<gl::GLSurface> GLOzoneEglCast::CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) { return gl::InitializeGLSurface( - new gl::PbufferGLSurfaceEGL(gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + new gl::PbufferGLSurfaceEGL(display->GetAs<gl::GLDisplayEGL>(), size)); } gl::EGLDisplayPlatform GLOzoneEglCast::GetNativeDisplay() {
diff --git a/ui/ozone/platform/cast/gl_ozone_egl_cast.h b/ui/ozone/platform/cast/gl_ozone_egl_cast.h index 0fe5369..b5e77f7 100644 --- a/ui/ozone/platform/cast/gl_ozone_egl_cast.h +++ b/ui/ozone/platform/cast/gl_ozone_egl_cast.h
@@ -32,8 +32,10 @@ // GLOzoneEGL implementation: scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget widget) override; scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) override; gl::EGLDisplayPlatform GetNativeDisplay() override; bool LoadGLES2Bindings(
diff --git a/ui/ozone/platform/cast/gl_surface_cast.cc b/ui/ozone/platform/cast/gl_surface_cast.cc index 80eccd2..0db51672 100644 --- a/ui/ozone/platform/cast/gl_surface_cast.cc +++ b/ui/ozone/platform/cast/gl_surface_cast.cc
@@ -43,10 +43,11 @@ namespace ui { -GLSurfaceCast::GLSurfaceCast(gfx::AcceleratedWidget widget, +GLSurfaceCast::GLSurfaceCast(gl::GLDisplayEGL* display, + gfx::AcceleratedWidget widget, GLOzoneEglCast* parent) : NativeViewGLSurfaceEGL( - GLSurfaceEGL::GetGLDisplayEGL(), + display, parent->GetNativeWindow(), std::make_unique<gfx::FixedVSyncProvider>(base::TimeTicks(), GetVSyncInterval())),
diff --git a/ui/ozone/platform/cast/gl_surface_cast.h b/ui/ozone/platform/cast/gl_surface_cast.h index 4727050..663d321 100644 --- a/ui/ozone/platform/cast/gl_surface_cast.h +++ b/ui/ozone/platform/cast/gl_surface_cast.h
@@ -20,7 +20,9 @@ class GLSurfaceCast : public gl::NativeViewGLSurfaceEGL { public: - GLSurfaceCast(gfx::AcceleratedWidget widget, GLOzoneEglCast* parent); + GLSurfaceCast(gl::GLDisplayEGL* display, + gfx::AcceleratedWidget widget, + GLOzoneEglCast* parent); GLSurfaceCast(const GLSurfaceCast&) = delete; GLSurfaceCast& operator=(const GLSurfaceCast&) = delete;
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc index fce88d6..648759c 100644 --- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc +++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -133,23 +133,26 @@ } scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override { return nullptr; } scoped_refptr<gl::GLSurface> CreateSurfacelessViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override { return gl::InitializeGLSurface(new GbmSurfaceless( - surface_factory_, drm_thread_proxy_->CreateDrmWindowProxy(window), - window)); + surface_factory_, display->GetAs<gl::GLDisplayEGL>(), + drm_thread_proxy_->CreateDrmWindowProxy(window), window)); } scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) override { DCHECK_EQ(size.width(), 0); DCHECK_EQ(size.height(), 0); return gl::InitializeGLSurface( - new gl::SurfacelessEGL(gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + new gl::SurfacelessEGL(display->GetAs<gl::GLDisplayEGL>(), size)); } protected:
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc index 60b3bfa..e12811f 100644 --- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc +++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -38,16 +38,16 @@ } // namespace GbmSurfaceless::GbmSurfaceless(GbmSurfaceFactory* surface_factory, + gl::GLDisplayEGL* display, std::unique_ptr<DrmWindowProxy> window, gfx::AcceleratedWidget widget) - : SurfacelessEGL(gl::GLSurfaceEGL::GetGLDisplayEGL(), gfx::Size()), + : SurfacelessEGL(display, gfx::Size()), surface_factory_(surface_factory), window_(std::move(window)), widget_(widget), has_implicit_external_sync_( - GetGLDisplayEGL()->ext->b_EGL_ARM_implicit_external_sync), - has_image_flush_external_( - GetGLDisplayEGL()->ext->b_EGL_EXT_image_flush_external) { + display->ext->b_EGL_ARM_implicit_external_sync), + has_image_flush_external_(display->ext->b_EGL_EXT_image_flush_external) { surface_factory_->RegisterSurface(window_->widget(), this); supports_plane_gpu_fences_ = window_->SupportsGpuFences(); unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h index 0025fa45..558ab79c 100644 --- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h +++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -33,6 +33,7 @@ class GbmSurfaceless : public gl::SurfacelessEGL { public: GbmSurfaceless(GbmSurfaceFactory* surface_factory, + gl::GLDisplayEGL* display, std::unique_ptr<DrmWindowProxy> window, gfx::AcceleratedWidget widget);
diff --git a/ui/ozone/platform/flatland/flatland_surface_factory.cc b/ui/ozone/platform/flatland/flatland_surface_factory.cc index b2691601..e02430a 100644 --- a/ui/ozone/platform/flatland/flatland_surface_factory.cc +++ b/ui/ozone/platform/flatland/flatland_surface_factory.cc
@@ -44,18 +44,20 @@ // GLOzone: scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override { // GL rendering to Flatland views is not supported. This function is // used only for unittests. Return an off-screen surface, so the tests pass. // TODO(crbug.com/1271760): Use Vulkan in unittests and remove this hack. return gl::InitializeGLSurface(base::MakeRefCounted<gl::SurfacelessEGL>( - gl::GLSurfaceEGL::GetGLDisplayEGL(), gfx::Size(100, 100))); + display->GetAs<gl::GLDisplayEGL>(), gfx::Size(100, 100))); } scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) override { return gl::InitializeGLSurface(base::MakeRefCounted<gl::SurfacelessEGL>( - gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + display->GetAs<gl::GLDisplayEGL>(), size)); } gl::EGLDisplayPlatform GetNativeDisplay() override {
diff --git a/ui/ozone/platform/headless/headless_surface_factory.cc b/ui/ozone/platform/headless/headless_surface_factory.cc index fbcf7a52..9b0fce0 100644 --- a/ui/ozone/platform/headless/headless_surface_factory.cc +++ b/ui/ozone/platform/headless/headless_surface_factory.cc
@@ -107,8 +107,8 @@ class FileGLSurface : public GLSurfaceEglReadback { public: - explicit FileGLSurface(const base::FilePath& location) - : location_(location) {} + FileGLSurface(gl::GLDisplayEGL* display, const base::FilePath& location) + : GLSurfaceEglReadback(display), location_(location) {} FileGLSurface(const FileGLSurface&) = delete; FileGLSurface& operator=(const FileGLSurface&) = delete; @@ -188,16 +188,19 @@ // GLOzone: scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override { return gl::InitializeGLSurface(base::MakeRefCounted<FileGLSurface>( + display->GetAs<gl::GLDisplayEGL>(), GetPathForWidget(base_path_, window))); } scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) override { return gl::InitializeGLSurface( base::MakeRefCounted<gl::PbufferGLSurfaceEGL>( - gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + display->GetAs<gl::GLDisplayEGL>(), size)); } protected:
diff --git a/ui/ozone/platform/scenic/scenic_surface_factory.cc b/ui/ozone/platform/scenic/scenic_surface_factory.cc index 6e39541d..98740640 100644 --- a/ui/ozone/platform/scenic/scenic_surface_factory.cc +++ b/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -56,18 +56,20 @@ // GLOzone: scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override { // GL rendering to Flatland views is not supported. This function is // used only for unittests. Return an off-screen surface, so the tests pass. // TODO(crbug.com/1271760): Use Vulkan in unittests and remove this hack. return gl::InitializeGLSurface(base::MakeRefCounted<gl::SurfacelessEGL>( - gl::GLSurfaceEGL::GetGLDisplayEGL(), gfx::Size(100, 100))); + display->GetAs<gl::GLDisplayEGL>(), gfx::Size(100, 100))); } scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) override { return gl::InitializeGLSurface(base::MakeRefCounted<gl::SurfacelessEGL>( - gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + display->GetAs<gl::GLDisplayEGL>(), size)); } gl::EGLDisplayPlatform GetNativeDisplay() override {
diff --git a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc index 94f2571..44630f4 100644 --- a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc +++ b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
@@ -111,9 +111,10 @@ } GbmSurfacelessWayland::GbmSurfacelessWayland( + gl::GLDisplayEGL* display, WaylandBufferManagerGpu* buffer_manager, gfx::AcceleratedWidget widget) - : SurfacelessEGL(gl::GLSurfaceEGL::GetGLDisplayEGL(), gfx::Size()), + : SurfacelessEGL(display, gfx::Size()), buffer_manager_(buffer_manager), widget_(widget), solid_color_buffers_holder_(std::make_unique<SolidColorBufferHolder>()),
diff --git a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h index 9821ea3..ec69bd0 100644 --- a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h +++ b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
@@ -30,7 +30,8 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, public WaylandSurfaceGpu { public: - GbmSurfacelessWayland(WaylandBufferManagerGpu* buffer_manager, + GbmSurfacelessWayland(gl::GLDisplayEGL* display, + WaylandBufferManagerGpu* buffer_manager, gfx::AcceleratedWidget widget); GbmSurfacelessWayland(const GbmSurfacelessWayland&) = delete;
diff --git a/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc b/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc index ba537ea..8452279ad 100644 --- a/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc +++ b/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc
@@ -27,9 +27,12 @@ GLSurfaceEglReadbackWayland::PixelBuffer::~PixelBuffer() = default; GLSurfaceEglReadbackWayland::GLSurfaceEglReadbackWayland( + gl::GLDisplayEGL* display, gfx::AcceleratedWidget widget, WaylandBufferManagerGpu* buffer_manager) - : widget_(widget), buffer_manager_(buffer_manager) { + : GLSurfaceEglReadback(display), + widget_(widget), + buffer_manager_(buffer_manager) { buffer_manager_->RegisterSurface(widget_, this); }
diff --git a/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h b/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h index 6a48c48..df7d6a92 100644 --- a/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h +++ b/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h
@@ -33,7 +33,8 @@ class GLSurfaceEglReadbackWayland : public GLSurfaceEglReadback, public WaylandSurfaceGpu { public: - GLSurfaceEglReadbackWayland(gfx::AcceleratedWidget widget, + GLSurfaceEglReadbackWayland(gl::GLDisplayEGL* display, + gfx::AcceleratedWidget widget, WaylandBufferManagerGpu* buffer_manager); GLSurfaceEglReadbackWayland(const GLSurfaceEglReadbackWayland&) = delete; GLSurfaceEglReadbackWayland& operator=(const GLSurfaceEglReadbackWayland&) =
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc index 59ab6ab..0cbfdb8 100644 --- a/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc +++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
@@ -60,12 +60,15 @@ GLuint texture_id) override; scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget widget) override; scoped_refptr<gl::GLSurface> CreateSurfacelessViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override; scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) override; protected: @@ -95,6 +98,7 @@ } scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget widget) { // Only EGLGLES2 is supported with surfaceless view gl. if ((gl::GetGLImplementation() != gl::kGLImplementationEGLGLES2) || @@ -112,22 +116,23 @@ if (!egl_window) return nullptr; return gl::InitializeGLSurface(new GLSurfaceWayland( - gl::GLSurfaceEGL::GetGLDisplayEGL(), std::move(egl_window), window)); + display->GetAs<gl::GLDisplayEGL>(), std::move(egl_window), window)); } scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateSurfacelessViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) { if (gl::IsSoftwareGLImplementation(gl::GetGLImplementationParts())) { return gl::InitializeGLSurface( - base::MakeRefCounted<GLSurfaceEglReadbackWayland>(window, - buffer_manager_)); + base::MakeRefCounted<GLSurfaceEglReadbackWayland>( + display->GetAs<gl::GLDisplayEGL>(), window, buffer_manager_)); } else { #if defined(WAYLAND_GBM) // If there is a gbm device available, use surfaceless gl surface. if (!buffer_manager_->GetGbmDevice()) return nullptr; - return gl::InitializeGLSurface( - new GbmSurfacelessWayland(buffer_manager_, window)); + return gl::InitializeGLSurface(new GbmSurfacelessWayland( + display->GetAs<gl::GLDisplayEGL>(), buffer_manager_, window)); #else return nullptr; #endif @@ -135,14 +140,15 @@ } scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) { - if (gl::GLSurfaceEGL::GetGLDisplayEGL()->IsEGLSurfacelessContextSupported() && + if (display->GetAs<gl::GLDisplayEGL>()->IsEGLSurfacelessContextSupported() && size.width() == 0 && size.height() == 0) { return gl::InitializeGLSurface( - new gl::SurfacelessEGL(gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + new gl::SurfacelessEGL(display->GetAs<gl::GLDisplayEGL>(), size)); } else { return gl::InitializeGLSurface( - new gl::PbufferGLSurfaceEGL(gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + new gl::PbufferGLSurfaceEGL(display->GetAs<gl::GLDisplayEGL>(), size)); } }
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc index 8224a73b..b8d5fc3 100644 --- a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc +++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -23,6 +23,7 @@ #include "ui/gfx/overlay_plane_data.h" #include "ui/gfx/overlay_priority_hint.h" #include "ui/gl/gl_image_egl.h" +#include "ui/gl/gl_utils.h" #include "ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h" #include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h" #include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h" @@ -237,7 +238,8 @@ auto* gl_ozone = surface_factory_->GetGLOzone( gl::GLImplementationParts(gl::kGLImplementationEGLGLES2)); - auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface( + gl::GetDefaultDisplay(), widget_); EXPECT_TRUE(gl_surface); gl_surface->SetRelyOnImplicitSync(); static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get()) @@ -529,7 +531,8 @@ auto* gl_ozone = surface_factory_->GetGLOzone( gl::GLImplementationParts(gl::kGLImplementationEGLGLES2)); - auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface( + gl::GetDefaultDisplay(), widget_); EXPECT_TRUE(gl_surface); gl_surface->SetRelyOnImplicitSync(); static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get()) @@ -864,7 +867,8 @@ auto* gl_ozone = surface_factory_->GetGLOzone( gl::GLImplementationParts(gl::kGLImplementationEGLGLES2)); EXPECT_TRUE(gl_ozone); - auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface( + gl::GetDefaultDisplay(), widget_); EXPECT_FALSE(gl_surface); // Now, set gbm. @@ -872,20 +876,23 @@ // It's still impossible to create the device if supports_dmabuf is false. EXPECT_FALSE(buffer_manager_gpu_->GetGbmDevice()); - gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(gl::GetDefaultDisplay(), + widget_); EXPECT_FALSE(gl_surface); // Now set supports_dmabuf. buffer_manager_gpu_->supports_dmabuf_ = true; EXPECT_TRUE(buffer_manager_gpu_->GetGbmDevice()); - gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(gl::GetDefaultDisplay(), + widget_); EXPECT_TRUE(gl_surface); // Reset gbm now. WaylandConnectionProxy can reset it when zwp is not // available. And factory must behave the same way as previously. buffer_manager_gpu_->gbm_device_ = nullptr; EXPECT_FALSE(buffer_manager_gpu_->GetGbmDevice()); - gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(gl::GetDefaultDisplay(), + widget_); EXPECT_FALSE(gl_surface); } @@ -904,7 +911,8 @@ auto* gl_ozone = surface_factory_->GetGLOzone( gl::GLImplementationParts(gl::kGLImplementationEGLGLES2)); - auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface( + gl::GetDefaultDisplay(), widget_); EXPECT_TRUE(gl_surface); gl_surface->SetRelyOnImplicitSync(); static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get())
diff --git a/ui/ozone/platform/x11/gl_ozone_glx.cc b/ui/ozone/platform/x11/gl_ozone_glx.cc index 06dc614..23ff67c 100644 --- a/ui/ozone/platform/x11/gl_ozone_glx.cc +++ b/ui/ozone/platform/x11/gl_ozone_glx.cc
@@ -120,16 +120,19 @@ } scoped_refptr<gl::GLSurface> GLOzoneGLX::CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) { return gl::InitializeGLSurface(new gl::GLSurfaceGLXX11(window)); } scoped_refptr<gl::GLSurface> GLOzoneGLX::CreateSurfacelessViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) { return nullptr; } scoped_refptr<gl::GLSurface> GLOzoneGLX::CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) { return gl::InitializeGLSurface(new gl::UnmappedNativeViewGLSurfaceGLX(size)); }
diff --git a/ui/ozone/platform/x11/gl_ozone_glx.h b/ui/ozone/platform/x11/gl_ozone_glx.h index e518299d..05f3b43b 100644 --- a/ui/ozone/platform/x11/gl_ozone_glx.h +++ b/ui/ozone/platform/x11/gl_ozone_glx.h
@@ -44,10 +44,13 @@ gl::GLSurface* compatible_surface, const gl::GLContextAttribs& attribs) override; scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override; scoped_refptr<gl::GLSurface> CreateSurfacelessViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override; scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) override; };
diff --git a/ui/ozone/platform/x11/gl_surface_egl_readback_x11.cc b/ui/ozone/platform/x11/gl_surface_egl_readback_x11.cc index c76733f..7118a30 100644 --- a/ui/ozone/platform/x11/gl_surface_egl_readback_x11.cc +++ b/ui/ozone/platform/x11/gl_surface_egl_readback_x11.cc
@@ -18,8 +18,10 @@ } -GLSurfaceEglReadbackX11::GLSurfaceEglReadbackX11(gfx::AcceleratedWidget window) - : window_(static_cast<x11::Window>(window)), +GLSurfaceEglReadbackX11::GLSurfaceEglReadbackX11(gl::GLDisplayEGL* display, + gfx::AcceleratedWidget window) + : GLSurfaceEglReadback(display), + window_(static_cast<x11::Window>(window)), connection_(x11::Connection::Get()) {} bool GLSurfaceEglReadbackX11::Initialize(gl::GLSurfaceFormat format) {
diff --git a/ui/ozone/platform/x11/gl_surface_egl_readback_x11.h b/ui/ozone/platform/x11/gl_surface_egl_readback_x11.h index 0f85f5c78f..63cc4211 100644 --- a/ui/ozone/platform/x11/gl_surface_egl_readback_x11.h +++ b/ui/ozone/platform/x11/gl_surface_egl_readback_x11.h
@@ -14,7 +14,8 @@ // GLSurface implementation that copies pixels from readback to an XWindow. class GLSurfaceEglReadbackX11 : public GLSurfaceEglReadback { public: - explicit GLSurfaceEglReadbackX11(gfx::AcceleratedWidget window); + GLSurfaceEglReadbackX11(gl::GLDisplayEGL* display, + gfx::AcceleratedWidget window); GLSurfaceEglReadbackX11(const GLSurfaceEglReadbackX11&) = delete; GLSurfaceEglReadbackX11& operator=(const GLSurfaceEglReadbackX11&) = delete;
diff --git a/ui/ozone/platform/x11/x11_surface_factory.cc b/ui/ozone/platform/x11/x11_surface_factory.cc index 72107d0..b19cfb1 100644 --- a/ui/ozone/platform/x11/x11_surface_factory.cc +++ b/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -65,21 +65,23 @@ } scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override { if (is_swiftshader_) { return gl::InitializeGLSurface( - base::MakeRefCounted<GLSurfaceEglReadbackX11>(window)); + base::MakeRefCounted<GLSurfaceEglReadbackX11>( + display->GetAs<gl::GLDisplayEGL>(), window)); } else { switch (gl::GetGLImplementation()) { case gl::kGLImplementationEGLGLES2: DCHECK(window != gfx::kNullAcceleratedWidget); return gl::InitializeGLSurface(new gl::NativeViewGLSurfaceEGLX11GLES2( - gl::GLSurfaceEGL::GetGLDisplayEGL(), + display->GetAs<gl::GLDisplayEGL>(), static_cast<x11::Window>(window))); case gl::kGLImplementationEGLANGLE: DCHECK(window != gfx::kNullAcceleratedWidget); return gl::InitializeGLSurface(new gl::NativeViewGLSurfaceEGLX11( - gl::GLSurfaceEGL::GetGLDisplayEGL(), + display->GetAs<gl::GLDisplayEGL>(), static_cast<x11::Window>(window))); default: NOTREACHED(); @@ -89,15 +91,15 @@ } scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) override { - if (gl::GLSurfaceEGL::GetGLDisplayEGL() - ->IsEGLSurfacelessContextSupported() && - size.width() == 0 && size.height() == 0) { - return InitializeGLSurface( - new gl::SurfacelessEGL(gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + gl::GLDisplayEGL* egl_display = display->GetAs<gl::GLDisplayEGL>(); + if (egl_display->IsEGLSurfacelessContextSupported() && size.width() == 0 && + size.height() == 0) { + return InitializeGLSurface(new gl::SurfacelessEGL(egl_display, size)); } else { - return InitializeGLSurface(new gl::PbufferGLSurfaceEGL( - gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + return InitializeGLSurface( + new gl::PbufferGLSurfaceEGL(egl_display, size)); } }
diff --git a/ui/ozone/platform/x11/x11_window.cc b/ui/ozone/platform/x11/x11_window.cc index b059e31..a466ffe 100644 --- a/ui/ozone/platform/x11/x11_window.cc +++ b/ui/ozone/platform/x11/x11_window.cc
@@ -536,8 +536,10 @@ req.y = new_bounds_in_pixels.y(); } - if (origin_changed || size_changed) + if (origin_changed || size_changed) { + bounds_change_in_flight_ = true; connection_->ConfigureWindow(req); + } // Assume that the resize will go through as requested, which should be the // case if we're running without a window manager. If there's a window @@ -666,15 +668,16 @@ bool origin_changed = bounds_in_pixels_.origin() != new_bounds_px.origin(); bounds_in_pixels_ = new_bounds_px; - // If there is a restore in flight, then set a flag to ignore the single - // configure event (hopefully) coming from that restore. This prevents any - // in-flight restore requests from changing the bounds in a way that conflicts - // with the `bounds_in_pixels_` setting above. This is not perfect, and if - // there is some other in-flight bounds change for some reason, or if the - // ordering of events from the WM behaves differently, this will not prevent - // the issue. See: http://crbug.com/1227451 - ignore_next_configure_ = restore_in_flight_; - + // If there is a restore and/or bounds change in flight, then set a flag to + // ignore the next one or two configure events (hopefully) coming from those + // requests. This prevents any in-flight restore requests from changing the + // bounds in a way that conflicts with the `bounds_in_pixels_` setting above. + // This is not perfect, and if there is some other in-flight bounds change for + // some reason, or if the ordering of events from the WM behaves differently, + // this will not prevent the issue. See: http://crbug.com/1227451 + ignore_next_configures_ = restore_in_flight_ ? 1 : 0; + if (bounds_change_in_flight_) + ignore_next_configures_++; // This must be the final call in this function, as `this` may be deleted // during the observation of this event. platform_window_delegate_->OnBoundsChanged({origin_changed}); @@ -2266,15 +2269,24 @@ pending_counter_value_ = 0; } - // During a Restore() -> ToggleFullscreen() sequence, ignore the configure - // event from the restore if we're waiting on fullscreen. After + // During a Restore() -> ToggleFullscreen() or Restore() -> SetBounds() -> + // ToggleFullscreen() sequence, ignore the configure events from the Restore + // and SetBounds requests, if we're waiting on fullscreen. After // OnXWindowStateChanged unsets this flag, there will be a configuration event // that will set the bounds to the final fullscreen bounds. - if (ignore_next_configure_) { - ignore_next_configure_ = false; + if (ignore_next_configures_ > 0) { + ignore_next_configures_--; return; } + // Note: This OnConfigureEvent might not necessarily correspond to a previous + // SetBounds request. Due to limitations in X11 there isn't a way to + // match events to its original request. For now, we assume that the next + // OnConfigureEvent event after a SetBounds (ConfigureWindow) request is from + // that request. This would break in some scenarios (for example calling + // SetBounds more than once quickly). See crbug.com/1227451. + bounds_change_in_flight_ = false; + // It's possible that the X window may be resized by some other means than // from within aura (e.g. the X window manager can change the size). Make // sure the root window size is maintained properly.
diff --git a/ui/ozone/platform/x11/x11_window.h b/ui/ozone/platform/x11/x11_window.h index f033a9f0..28ed150d3 100644 --- a/ui/ozone/platform/x11/x11_window.h +++ b/ui/ozone/platform/x11/x11_window.h
@@ -490,10 +490,14 @@ // cross-display fullscreening, there is a Restore() (called by BrowserView) // that may cause configuration bounds updates that make this window appear to // temporarily be on a different screen than its destination screen. This - // restore only happens if the window is maximized. - bool ignore_next_configure_ = false; + // restore only happens if the window is maximized. The integer represents how + // many events to ignore. + int ignore_next_configures_ = 0; // True between Restore() and the next OnXWindowStateChanged(). bool restore_in_flight_ = false; + // True between SetBoundsInPixels (when the bounds actually change) and the + // next OnConfigureEvent. + bool bounds_change_in_flight_ = false; base::CancelableOnceClosure delayed_resize_task_;
diff --git a/ui/ozone/public/gl_ozone.h b/ui/ozone/public/gl_ozone.h index c490e0ec..31f243b 100644 --- a/ui/ozone/public/gl_ozone.h +++ b/ui/ozone/public/gl_ozone.h
@@ -91,6 +91,7 @@ // Creates a GL surface that renders directly to a view. virtual scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) = 0; // Creates a GL surface that renders directly into a window with surfaceless @@ -99,10 +100,12 @@ // unsupported. // TODO(spang): Consider deprecating this and using OverlaySurface for GL. virtual scoped_refptr<gl::GLSurface> CreateSurfacelessViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) = 0; // Creates a GL surface used for offscreen rendering. virtual scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) = 0; };
diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn index f8a56b5..5f0cfe0 100644 --- a/ui/webui/resources/BUILD.gn +++ b/ui/webui/resources/BUILD.gn
@@ -165,7 +165,7 @@ checked_in_dts_files = [ "cr_elements/cr_button/cr_button.m.d.ts", - "cr_elements/cr_checkbox/cr_checkbox.m.d.ts", + "cr_elements/cr_checkbox/cr_checkbox.d.ts", "cr_elements/cr_container_shadow_behavior.m.d.ts", "cr_elements/cr_dialog/cr_dialog.m.d.ts", "cr_elements/cr_icon_button/cr_icon_button.d.ts",
diff --git a/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.ts b/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.ts index ace147e..32cb43e 100644 --- a/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.ts +++ b/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.ts
@@ -9,7 +9,7 @@ * - edit the trust level of an already existing certificate authority. */ import '../../cr_elements/cr_button/cr_button.m.js'; -import '../../cr_elements/cr_checkbox/cr_checkbox.m.js'; +import '../../cr_elements/cr_checkbox/cr_checkbox.js'; import '../../cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; import './certificate_shared.css.js'; @@ -17,7 +17,7 @@ import {PaperSpinnerLiteElement} from 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {CrCheckboxElement} from '../../cr_elements/cr_checkbox/cr_checkbox.m.js'; +import {CrCheckboxElement} from '../../cr_elements/cr_checkbox/cr_checkbox.js'; import {CrDialogElement} from '../../cr_elements/cr_dialog/cr_dialog.m.js'; import {I18nMixin} from '../../js/i18n_mixin.js'; import {loadTimeData} from '../../js/load_time_data.m.js';
diff --git a/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn b/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn index a5aeb3a..8d90e43b 100644 --- a/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn +++ b/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn
@@ -19,7 +19,7 @@ deps = [ ":smb_browser_proxy", "//ui/webui/resources/cr_elements/cr_button:cr_button.m", - "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox.m", + "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox", "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m", "//ui/webui/resources/cr_elements/cr_input:cr_input.m", "//ui/webui/resources/js:cr.m",
diff --git a/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js b/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js index 20c0b55..9d1af7dba 100644 --- a/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js +++ b/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js
@@ -10,7 +10,7 @@ */ import '../../../cr_elements/cr_button/cr_button.m.js'; -import '../../../cr_elements/cr_checkbox/cr_checkbox.m.js'; +import '../../../cr_elements/cr_checkbox/cr_checkbox.js'; import '../../../cr_elements/cr_dialog/cr_dialog.m.js'; import '../../../cr_elements/cr_input/cr_input.m.js'; import '../../../cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js';
diff --git a/ui/webui/resources/cr_components/history_clusters/cluster.html b/ui/webui/resources/cr_components/history_clusters/cluster.html index ed08663..df5732b 100644 --- a/ui/webui/resources/cr_components/history_clusters/cluster.html +++ b/ui/webui/resources/cr_components/history_clusters/cluster.html
@@ -7,6 +7,10 @@ padding-bottom: var(--cluster-padding-vertical); } + :host([in-side-panel]) { + padding-bottom: 0; + } + :host-context(.focus-outline-visible):host(:focus) #container { box-shadow: inset 0 0 0 2px var(--cr-focus-outline-color); } @@ -17,16 +21,20 @@ margin-bottom: var(--cluster-padding-vertical); } + :host([in-side-panel]) #container { + border-bottom: 3px solid var(--cr-separator-color); + } + /* We need an inner container div to apply spacing between clusters. This is because iron-list ignores the margin on the host element. */ - #container { + :host(:not([in-side-panel])) #container { background-color: var(--cr-card-background-color); border-radius: var(--cr-card-border-radius); box-shadow: var(--cr-card-shadow); padding: var(--cluster-padding-vertical) 0; } - #label-row { + .label-row { align-items: center; display: flex; flex-grow: 1; @@ -37,12 +45,20 @@ user-select: none; } - #label { + .label { color: var(--cr-primary-text-color); font-size: 1rem; /* 16px */ font-weight: 500; } + #label-and-timestamp { + align-items: center; + display: flex; + flex-direction: column; + flex-shrink: 0; + row-gap: 6px; + } + #related-searches { display: flex; flex-wrap: wrap; @@ -99,8 +115,18 @@ on-open-all-visits="onOpenAllVisits_" on-remove-all-visits="onRemoveAllVisits_" on-remove-visit="onRemoveVisit_"> - <div id="label-row"> - <div id="label"></div> + <!-- In the side panel the label and timestamp should be stacked on the + left, while outside the side panel the timestamp and the menu should + be side by side on the right. --> + <div class="label-row" hidden="[[!inSidePanel]]"> + <div id="label-and-timestamp"> + <div id="labelSidePanel" class="label"></div> + <div class="timestamp">[[cluster.visits.0.relativeDate]]</div> + </div> + <menu-container></menu-container> + </div> + <div class="label-row" hidden="[[inSidePanel]]"> + <div id="label" class="label"></div> <div class="timestamp-and-menu"> <div class="timestamp">[[cluster.visits.0.relativeDate]]</div> <menu-container></menu-container>
diff --git a/ui/webui/resources/cr_components/history_clusters/cluster.ts b/ui/webui/resources/cr_components/history_clusters/cluster.ts index 0287cfb..0b2f7693 100644 --- a/ui/webui/resources/cr_components/history_clusters/cluster.ts +++ b/ui/webui/resources/cr_components/history_clusters/cluster.ts
@@ -37,6 +37,7 @@ interface HistoryClusterElement { $: { label: HTMLElement, + labelSidePanel: HTMLElement, container: HTMLElement, }; } @@ -66,6 +67,15 @@ }, /** + * Whether the cluster is in the side panel. + */ + inSidePanel: { + type: Boolean, + value: () => loadTimeData.getBoolean('inSidePanel'), + reflectToAttribute: true, + }, + + /** * The current query for which related clusters are requested and shown. */ query: String, @@ -113,6 +123,7 @@ cluster: Cluster; index: number; + inSidePanel: boolean; query: string; private callbackRouter_: PageCallbackRouter; private expanded_: boolean; @@ -300,8 +311,9 @@ return 'no_label'; } + const label = this.inSidePanel ? this.$.labelSidePanel : this.$.label; insertHighlightedTextWithMatchesIntoElement( - this.$.label, this.cluster.label!, this.cluster.labelMatchPositions); + label, this.cluster.label!, this.cluster.labelMatchPositions); return this.cluster.label!; }
diff --git a/ui/webui/resources/cr_components/history_clusters/clusters.html b/ui/webui/resources/cr_components/history_clusters/clusters.html index 2cde804..51d4060 100644 --- a/ui/webui/resources/cr_components/history_clusters/clusters.html +++ b/ui/webui/resources/cr_components/history_clusters/clusters.html
@@ -13,6 +13,11 @@ padding: var(--first-cluster-padding-top) var(--cluster-padding-horizontal) 0; } + :host([in-side-panel]) #clusters { + min-width: 0; + padding: 0 0 0; + } + #placeholder { align-items: center; color: var(--md-loading-message-color);
diff --git a/ui/webui/resources/cr_components/history_clusters/clusters.ts b/ui/webui/resources/cr_components/history_clusters/clusters.ts index 1f24556..8cbd434 100644 --- a/ui/webui/resources/cr_components/history_clusters/clusters.ts +++ b/ui/webui/resources/cr_components/history_clusters/clusters.ts
@@ -68,6 +68,15 @@ static get properties() { return { /** + * Whether the clusters are in the side panel. + */ + inSidePanel: { + type: Boolean, + value: () => loadTimeData.getBoolean('inSidePanel'), + reflectToAttribute: true, + }, + + /** * The current query for which related clusters are requested and shown. */ query: { @@ -113,6 +122,7 @@ // Properties //============================================================================ + inSidePanel: boolean; query: string; private callbackRouter_: PageCallbackRouter; private headerText_: string;
diff --git a/ui/webui/resources/cr_components/history_clusters/shared_vars.css b/ui/webui/resources/cr_components/history_clusters/shared_vars.css index 6146827..05ffceb 100644 --- a/ui/webui/resources/cr_components/history_clusters/shared_vars.css +++ b/ui/webui/resources/cr_components/history_clusters/shared_vars.css
@@ -31,6 +31,11 @@ /* Sizes: */ html { + --card-max-width: 960px; + --card-min-width: 550px; + --card-padding-between: 16px; + --card-padding-side: 24px; + --first-card-padding-top: 24px; --cluster-max-width: var(--card-max-width); --cluster-min-width: var(--card-min-width); --cluster-padding-horizontal: var(--card-padding-side);
diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn index 425ff12..5a15887 100644 --- a/ui/webui/resources/cr_elements/BUILD.gn +++ b/ui/webui/resources/cr_elements/BUILD.gn
@@ -86,8 +86,6 @@ "cr_actionable_row_style.html", "cr_button/cr_button.html", "cr_button/cr_button.js", - "cr_checkbox/cr_checkbox.html", - "cr_checkbox/cr_checkbox.js", "cr_container_shadow_behavior.html", "cr_container_shadow_behavior.js", "cr_dialog/cr_dialog.html", @@ -139,7 +137,7 @@ "action_link_css.m.js", "cr_actionable_row_style.m.js", "cr_button/cr_button.m.js", - "cr_checkbox/cr_checkbox.m.js", + "cr_checkbox/cr_checkbox.js", "cr_container_shadow_behavior.m.js", "cr_dialog/cr_dialog.m.js", "cr_icon_button/cr_icon_button.js", @@ -175,7 +173,6 @@ group("closure_compile") { deps = [ ":cr_elements_resources", - "cr_checkbox:closure_compile", "cr_dialog:closure_compile", "cr_input:closure_compile", "cr_lottie:closure_compile", @@ -293,7 +290,7 @@ ":shared_style_css_module", ":shared_vars_css_module", "cr_button:cr_button_module", - "cr_checkbox:cr_checkbox_module", + "cr_checkbox:web_components", "cr_dialog:cr_dialog_module", "cr_icon_button:web_components", "cr_input:polymer3_elements",
diff --git a/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn b/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn index f7f9dee..ee1c18e 100644 --- a/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn +++ b/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn
@@ -3,35 +3,20 @@ # found in the LICENSE file. import("//third_party/closure_compiler/compile_js.gni") -import("//tools/polymer/polymer.gni") +import("//tools/polymer/html_to_js.gni") -js_type_check("closure_compile") { - uses_legacy_modules = true - deps = [ ":cr_checkbox" ] -} - -js_library("cr_checkbox") { - deps = [ "//third_party/polymer/v1_0/components-chromium/paper-behaviors:paper-ripple-behavior-extracted" ] -} - -polymer_modulizer("cr_checkbox") { - js_file = "cr_checkbox.js" - html_file = "cr_checkbox.html" - html_type = "dom-module" +html_to_js("web_components") { + js_files = [ "cr_checkbox.js" ] } js_type_check("closure_compile_module") { is_polymer3 = true - deps = [ ":cr_checkbox.m" ] + deps = [ ":cr_checkbox" ] } -js_library("cr_checkbox.m") { - sources = [ - "$root_gen_dir/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.m.js", - ] +js_library("cr_checkbox") { deps = [ "//third_party/polymer/v3_0/components-chromium/paper-behaviors:paper-ripple-behavior", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", ] - extra_deps = [ ":cr_checkbox_module" ] }
diff --git a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.m.d.ts b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.d.ts similarity index 100% rename from ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.m.d.ts rename to ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.d.ts
diff --git a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html index 844b1f0..66cbbbb 100644 --- a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html +++ b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html
@@ -1,26 +1,3 @@ -<link rel="import" href="../../html/polymer.html"> - -<link rel="import" href="chrome://resources/polymer/v1_0/paper-behaviors/paper-ripple-behavior.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> -<link rel="import" href="../shared_vars_css.html"> - -<!-- -List of customizable styles: - - --cr-checkbox-border-size - --cr-checkbox-checked-box-background-color - --cr-checkbox-checked-box-color - --cr-checkbox-label-color - --cr-checkbox-label-padding-start - --cr-checkbox-mark-color - --cr-checkbox-ripple-checked-color - --cr-checkbox-ripple-size - --cr-checkbox-ripple-unchecked-color - --cr-checkbox-size - --cr-checkbox-unchecked-box-color ---> -<dom-module id="cr-checkbox"> - <template> <style> :host { -webkit-tap-highlight-color: transparent; @@ -172,6 +149,3 @@ <slot></slot> </div> <div id="ariaDescription" aria-hidden="true">[[ariaDescription]]</div> - </template> - <script src="cr_checkbox.js"></script> -</dom-module>
diff --git a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js index 04709bc..a2d559df 100644 --- a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js +++ b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js
@@ -8,12 +8,33 @@ * interaction. By default it assumes there will be child(ren) passed in to be * used as labels. If no label will be provided, a .no-label class should be * added to hide the spacing between the checkbox and the label container. + * + * List of customizable styles: + * --cr-checkbox-border-size + * --cr-checkbox-checked-box-background-color + * --cr-checkbox-checked-box-color + * --cr-checkbox-label-color + * --cr-checkbox-label-padding-start + * --cr-checkbox-mark-color + * --cr-checkbox-ripple-checked-color + * --cr-checkbox-ripple-size + * --cr-checkbox-ripple-unchecked-color + * --cr-checkbox-size + * --cr-checkbox-unchecked-box-color */ +import '//resources/polymer/v3_0/paper-styles/color.js'; +import '../shared_vars_css.m.js'; + +import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js'; +import {html, Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + Polymer({ is: 'cr-checkbox', + _template: html`{__html_template__}`, + behaviors: [ - Polymer.PaperRippleBehavior, + PaperRippleBehavior, ], properties: { @@ -155,11 +176,10 @@ // customize the element's ripple _createRipple() { this._rippleContainer = this.$.checkbox; - const ripple = Polymer.PaperRippleBehavior._createRipple(); + const ripple = PaperRippleBehavior._createRipple(); ripple.id = 'ink'; ripple.setAttribute('recenters', ''); ripple.classList.add('circle', 'toggle-ink'); return ripple; }, }); -/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');