diff --git a/DEPS b/DEPS index 1eabc40..0e3b1244 100644 --- a/DEPS +++ b/DEPS
@@ -309,7 +309,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '064cf12ad0cce462f4c2871ddbe6642746bc91ee', + 'skia_revision': '310062ae6aee31778717d28b8fb33536dc642a4b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -329,7 +329,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. - 'boringssl_revision': 'b6b33a84ed7badd0441cec1324ba3ef7f1d897e2', + 'boringssl_revision': '0226f30467f540a3f62ef48d453f93927da199b6', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Fuchsia sdk # and whatever else without interference from each other. @@ -421,7 +421,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': 'f1d98befa15c18fddc72c68ea9f5278800fb813b', + 'dawn_revision': '7e45e468cf42e3c0d21d539010fc06b839021b62', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -529,7 +529,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. - 'compiler_rt_revision': '0c75031f1b7a0556a6cc07b6aa97a260278c5e0d', + 'compiler_rt_revision': '514effe33889c9cd899c10ef7ad1f79fb86ef388', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling clusterfuzz-data # and whatever else without interference from each other. @@ -1201,7 +1201,7 @@ 'packages': [ { 'package': 'chromium/chrome/android/orderfiles/arm', - 'version': 'AFoVTwjpRw8r8lgSatRpwiL2QkWkDECz063PWEffFqUC', + 'version': 'iLqyq0OJbkb07A2XBhEXl-wkg-fo0TrQZ0Govmvo2igC', }, ], 'condition': 'checkout_android', @@ -1212,7 +1212,7 @@ 'packages': [ { 'package': 'chromium/chrome/android/orderfiles/arm64', - 'version': 'adjHfRaBecwZ_WoRzkIuxnkbcLsqdK3yWwa8I7jOrhIC', + 'version': 'iyYOxdaIkUQzhd86m2bxHDSasCY4MDHOJ0WZbT1y4CcC', }, ], 'condition': 'checkout_android', @@ -1602,7 +1602,7 @@ 'packages': [ { 'package': 'chromium/chrome/test/data/variations/cipd', - 'version': '4Wxj6G1nbxmGpqhJFFili5C1Ly15LngIQAiaFmKk1DcC', + 'version': 'oysm4wyMa-wEEu7CEakwg5WYPMC2Sm8NWV9TZ-Ah_rMC', }, ], 'dep_type': 'cipd', @@ -1613,7 +1613,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '5e36fab7a4bfa7d98ad3a9ba760f39af8c2c12eb', + '73faa4938c6a3d50fccccdcdba2813f0f74d5c01', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1834,7 +1834,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_build_tools/error_prone', - 'version': '47nFaUKq3UemCr0EHmMYPJ63Y9hRnNII7iNn5zYK9qsC', + 'version': '_xvKMGMJix5ysOYKkNTfSBd8CHQlf-DqEmAYYoEP3wgC', }, ], 'condition': 'checkout_android and non_git_source', @@ -1856,7 +1856,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_build_tools/lint', - 'version': '_v7pAuSk9urtP9QU6HH2OCUTGys9gUV74h8gJu1csI8C', + 'version': 'd6CQ9eCLBIOopQEbwq-Sax2LJTcnhF8kso6FeFopbkgC', }, ], 'condition': 'checkout_android and non_git_source', @@ -1867,7 +1867,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_build_tools/manifest_merger', - 'version': 'lKMwtNMqvRbDnUel3vBQLv-Of-xpdg_Rc54QKgdOCx0C', + 'version': 'MFlelAeq9AjbPFiLMR9nSNIXDKTdmo99j3cyOZk_MPkC', }, ], 'condition': 'checkout_android and non_git_source', @@ -2344,7 +2344,7 @@ 'packages': [ { 'package': 'chromium/third_party/kotlin_stdlib', - 'version': 'oWawDQgUnvOKIXGZEvlJh9_3V_8yrKEM1C3TH9si7QkC', + 'version': 'lJ1ajSYdxA0t3wZsp2zpIONZcyNduY7KYeswoOrtMd8C', }, ], 'condition': 'checkout_android and non_git_source', @@ -2641,7 +2641,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '67f0bdf7285d15783e7ee55c1e5d524887d43f33', + Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '93825934c10d3a8179e1b8b840bbe1fd7f64a913', 'src/base/tracing/test/data': { 'bucket': 'perfetto', @@ -3012,7 +3012,7 @@ Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'), 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '0b497723227dcfa52047ca9d136b1ffbe130ea68', + Var('webrtc_git') + '/src.git' + '@' + '981d111a875397315b34fa6889809c8862feb60d', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -3156,7 +3156,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': '2rHUg6orSG3ymd4TUQiQiTuR5Ho0FmpyrTde7lUwTrcC', + 'version': '4ZGHAcrjscwpb9U0z_Iqybjr2-zbHIYRhmYxyVTq1B8C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3167,7 +3167,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'ZMM7YKBIpxed9hu1p5KOOM51JUXmDjjdYkbGYauV6ygC', + 'version': 'JSPNBKrJTsgGEPGhmC-tSIFmtrPRr8dNteLUrPNYznAC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3200,7 +3200,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/projector_app/app', - 'version': 'Y-QBg0h9cHTRkaH_PMSvm11TgZvtn47Kro8BBuM5ssMC', + 'version': 'xRvlx0alnmSj6RfDIVuiRsCxk_DilhFe1Po_wEDAhL0C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3793,7 +3793,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - 'd7e03032fddf9552e94070778f3cfb775ab89dd2', + '21d8a0cb8e9d5392de3dee97d473f17ca97def28', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/ash/clipboard/clipboard_history_controller_unittest.cc b/ash/clipboard/clipboard_history_controller_unittest.cc index a7a68fe..aad41a5 100644 --- a/ash/clipboard/clipboard_history_controller_unittest.cc +++ b/ash/clipboard/clipboard_history_controller_unittest.cc
@@ -168,7 +168,11 @@ static_cast<int>(ClipboardHistoryControllerShowSource::kMinValue); i <= static_cast<int>(ClipboardHistoryControllerShowSource::kMaxValue); ++i) { - sources.push_back(static_cast<ClipboardHistoryControllerShowSource>(i)); + // kControlVLongpress is deprecated. + if (static_cast<ClipboardHistoryControllerShowSource>(i) != + ClipboardHistoryControllerShowSource::kControlVLongpress) { + sources.push_back(static_cast<ClipboardHistoryControllerShowSource>(i)); + } } return sources; } @@ -801,10 +805,6 @@ // Tests that `ShowMenu()` returns whether the menu was shown successfully. TEST_P(ClipboardHistoryControllerShowSourceTest, ShowMenuReturnsSuccess) { - if (GetSource() == ClipboardHistoryControllerShowSource::kControlVLongpress) { - GTEST_SKIP(); - } - base::HistogramTester histogram_tester; // Try to show the menu without populating the clipboard. The menu should not
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.cc b/ash/clipboard/clipboard_history_menu_model_adapter.cc index 2558d78..c948e3753 100644 --- a/ash/clipboard/clipboard_history_menu_model_adapter.cc +++ b/ash/clipboard/clipboard_history_menu_model_adapter.cc
@@ -72,9 +72,6 @@ crosapi::mojom::ClipboardHistoryControllerShowSource show_source, const std::optional<base::Time>& menu_last_time_shown, const std::optional<base::Time>& nudge_last_time_shown) { - // A footer is always required when the menu is shown via Ctrl+V long press. - using crosapi::mojom::ClipboardHistoryControllerShowSource; - // A footer is required if the menu hasn't been shown in the past 60 days. if (TimeSince(menu_last_time_shown.value_or(base::Time())) >= base::Days(60)) {
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter_unittest.cc b/ash/clipboard/clipboard_history_menu_model_adapter_unittest.cc index 758f9d6..b7ad0d3 100644 --- a/ash/clipboard/clipboard_history_menu_model_adapter_unittest.cc +++ b/ash/clipboard/clipboard_history_menu_model_adapter_unittest.cc
@@ -66,7 +66,11 @@ static_cast<int>(ClipboardHistoryControllerShowSource::kMinValue); i <= static_cast<int>(ClipboardHistoryControllerShowSource::kMaxValue); ++i) { - sources.push_back(static_cast<ClipboardHistoryControllerShowSource>(i)); + // kControlVLongpress is deprecated. + if (static_cast<ClipboardHistoryControllerShowSource>(i) != + ClipboardHistoryControllerShowSource::kControlVLongpress) { + sources.push_back(static_cast<ClipboardHistoryControllerShowSource>(i)); + } } return sources; } @@ -291,10 +295,6 @@ TEST_P(ClipboardHistoryMenuModelAdapterMenuItemTest, HeaderAndFooterConditionallyPresent) { - if (GetSource() == ClipboardHistoryControllerShowSource::kControlVLongpress) { - GTEST_SKIP(); - } - // Write items to clipboard history so that the menu can show. WriteTextToClipboardAndFlushMessageLoop(u"A"); WriteTextToClipboardAndFlushMessageLoop(u"B");
diff --git a/base/allocator/partition_allocator/src/partition_alloc/third_party/apple_apsl/README.chromium b/base/allocator/partition_allocator/src/partition_alloc/third_party/apple_apsl/README.chromium index d6172a7..7193f27 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/third_party/apple_apsl/README.chromium +++ b/base/allocator/partition_allocator/src/partition_alloc/third_party/apple_apsl/README.chromium
@@ -27,7 +27,7 @@ Version: CF-635 Security Critical: yes Shipped: yes -License: Apple Public Source License 2.0 +License: APSL-2.0 License File: LICENSE Local Modifications:
diff --git a/base/third_party/symbolize/README.chromium b/base/third_party/symbolize/README.chromium index 0ddd458..64b8725 100644 --- a/base/third_party/symbolize/README.chromium +++ b/base/third_party/symbolize/README.chromium
@@ -3,6 +3,7 @@ License: BSD-3-Clause License File: LICENSE Shipped: yes +Security Critical: yes The following files were copied from: https://github.com/google/glog/tree/b70ea80433c2a8f20b832be97b90f1f82b0d29e9
diff --git a/chrome/VERSION b/chrome/VERSION index 7627e22c..c7de9b79 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=142 MINOR=0 -BUILD=7399 +BUILD=7401 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java index 0500a40..0bb5536 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -724,18 +724,12 @@ @Override protected void updateCustomActionButton(int index, Drawable drawable, String description) { - ImageButton button; - if (ChromeFeatureList.sCctToolbarRefactor.isEnabled()) { - button = - (ImageButton) - mCustomButtonsParent.getChildAt( - mCustomButtonsParent.getChildCount() - 1 - index); - } else { - // |index| -> childIndex should ignore the optional button always present at the end. - int childIndex = mCustomActionButtons.getChildCount() - 2 - index; - assert 0 <= childIndex && childIndex <= mCustomActionButtons.getChildCount() - 2; - button = (ImageButton) mCustomActionButtons.getChildAt(childIndex); - } + if (ChromeFeatureList.sCctToolbarRefactor.isEnabled()) return; + + // |index| -> childIndex should ignore the optional button always present at the end. + int childIndex = mCustomActionButtons.getChildCount() - 2 - index; + assert 0 <= childIndex && childIndex <= mCustomActionButtons.getChildCount() - 2; + ImageButton button = (ImageButton) mCustomActionButtons.getChildAt(childIndex); assert button != null; updateCustomActionButtonVisuals(button, drawable, description); adjustCustomActionButtonPadding(index, button);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java index 19ee803..ddf604b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java
@@ -23,6 +23,7 @@ import org.chromium.base.Callback; import org.chromium.build.annotations.Nullable; +import org.chromium.chrome.R; import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.CustomTabProfileType; @@ -105,6 +106,7 @@ omniboxEnabled, titleVisible, isIncognito); + view.setTag(R.id.view_model, mModel); CustomTabToolbarButtonsViewBinder viewBinder = new CustomTabToolbarButtonsViewBinder(); PropertyModelChangeProcessor.create(mModel, view, viewBinder); mCustomActionButtonsMcp = @@ -195,6 +197,17 @@ mModel.set(CUSTOM_ACTION_BUTTONS_VISIBLE, visible); } + /** + * Updates the visual appearance of a custom action button. + * + * @param index The index of the button. + * @param drawable The icon for the button. + * @param description The content description for the button. + */ + public void updateCustomActionButton(int index, Drawable drawable, String description) { + mMediator.updateCustomActionButton(index, drawable, description); + } + static PropertyListModel<PropertyModel, PropertyKey> getCustomActionButtonsModel( Context context, BrowserServicesIntentDataProvider intentDataProvider,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsMediator.java index 4f198639..a0bd865 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsMediator.java
@@ -8,6 +8,8 @@ import static org.chromium.build.NullUtil.assumeNonNull; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.CUSTOM_ACTION_BUTTONS; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.CUSTOM_ACTION_BUTTONS_VISIBLE; +import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.DESCRIPTION; +import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.ICON; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.IS_INCOGNITO; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.MINIMIZE_BUTTON; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.OMNIBOX_ENABLED; @@ -17,6 +19,7 @@ import android.app.Activity; import android.content.res.Configuration; +import android.graphics.drawable.Drawable; import android.os.Handler; import android.view.View; import android.view.ViewGroup; @@ -122,6 +125,12 @@ mModel.set(MINIMIZE_BUTTON, getMinimizeButtonData()); } + void updateCustomActionButton(int index, Drawable drawable, String description) { + var model = mModel.get(CUSTOM_ACTION_BUTTONS).get(index); + model.set(ICON, drawable); + model.set(DESCRIPTION, description); + } + void setOptionalButtonData(@Nullable ButtonData buttonData) { boolean showOptionalButton = mOptionalButtonCoordinator == null ? initializeOptionalButton() : true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java index 07b037b..009a823 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java
@@ -150,11 +150,8 @@ int index, int count, @Nullable PropertyKey payload) { - for (int i = index; i < index + count; i++) { - PropertyModel customButtonModel = model.get(i); - view.updateCustomActionButton( - index, customButtonModel.get(ICON), customButtonModel.get(DESCRIPTION)); - } + inflateAndPositionToolbarElements( + view, (PropertyModel) view.getTag(R.id.view_model), mVisFlipper); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java index 1fb951e..a905208 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java
@@ -342,6 +342,15 @@ assert false; return false; } + + if (ChromeFeatureList.sCctToolbarRefactor.isEnabled()) { + if (mToolbarButtonsCoordinator == null) return false; + + mToolbarButtonsCoordinator.updateCustomActionButton( + index, params.getIcon(mActivity), params.getDescription()); + return true; + } + if (mToolbarManager == null) { return false; }
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt index 4c5c0bb..2b42ddf6 100644 --- a/chrome/android/profiles/arm.newest.txt +++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-142.0.7395.0_pre1511283_rc-r1-merged.afdo.bz2 +chromeos-chrome-arm-142.0.7399.0_pre1512109_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index fe7e53d..2d5fdff 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-142.0.7395.0_pre1511283_rc-r1-merged.afdo.bz2 +chromeos-chrome-amd64-142.0.7400.0_pre1512128_rc-r1-merged.afdo.bz2
diff --git a/chrome/browser/accessibility/leaked_node_detection_browsertest.cc b/chrome/browser/accessibility/leaked_node_detection_browsertest.cc index 53bdd70..8810577 100644 --- a/chrome/browser/accessibility/leaked_node_detection_browsertest.cc +++ b/chrome/browser/accessibility/leaked_node_detection_browsertest.cc
@@ -70,7 +70,10 @@ WaitForNodeCounts({0U, 0U, 0U, 0U}); } -IN_PROC_BROWSER_TEST_P(LeakedNodeDetectionBrowsertest, TerminateClient) { +// Disabled due to flaky failures. It seems that not all machines perform +// rundown quckily upon disappearance of the client. +IN_PROC_BROWSER_TEST_P(LeakedNodeDetectionBrowsertest, + DISABLED_TerminateClient) { // Initialize the UI Automation client; giving it this window. ASSERT_HRESULT_SUCCEEDED(InitializeClient(browser()));
diff --git a/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc b/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc index c4dfe37..a79a8e3 100644 --- a/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc +++ b/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc
@@ -87,11 +87,6 @@ profile_builder.SetProfileName(kFakePrimaryUsername); profile_ = IdentityTestEnvironmentProfileAdaptor:: CreateProfileForIdentityTestEnvironment(profile_builder); - auto* factory = - g_browser_process->platform_part()->GetAccountManagerFactory(); - account_manager_ = factory->GetAccountManager(profile()->GetPath().value()); - account_manager_facade_ = - GetAccountManagerFacade(profile()->GetPath().value()); identity_test_environment_adaptor_ = std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile_.get()); @@ -106,11 +101,14 @@ primary_account_info.gaia)); // Add accounts in Account Manager. - account_manager_->UpsertAccount( + auto* account_manager = + ash::AccountManagerFactory::Get()->GetAccountManager( + profile_->GetPath().value()); + account_manager->UpsertAccount( ::account_manager::AccountKey::FromGaiaId(primary_account_info.gaia), primary_account_info.email, account_manager::AccountManager::kInvalidToken); - account_manager_->UpsertAccount( + account_manager->UpsertAccount( ::account_manager::AccountKey::FromGaiaId(kFakeSecondaryGaiaId), kFakeSecondaryUsername, account_manager::AccountManager::kInvalidToken); @@ -124,11 +122,14 @@ } std::vector<::account_manager::Account> GetAccountManagerAccounts() { - CHECK(account_manager_facade_); + auto* account_manager_facade = + ash::AccountManagerFactory::Get()->GetAccountManagerFacade( + profile_->GetPath().value()); + CHECK(account_manager_facade); base::test::TestFuture<const std::vector<::account_manager::Account>&> future; - account_manager_facade_->GetAccounts(future.GetCallback()); + account_manager_facade->GetAccounts(future.GetCallback()); return future.Get(); } @@ -141,10 +142,6 @@ private: base::ScopedTempDir temp_dir_; - raw_ptr<account_manager::AccountManager, DanglingUntriaged> account_manager_ = - nullptr; - raw_ptr<account_manager::AccountManagerFacade> account_manager_facade_ = - nullptr; std::unique_ptr<Profile> profile_; std::unique_ptr<IdentityTestEnvironmentProfileAdaptor> identity_test_environment_adaptor_;
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarMediator.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarMediator.java index 94d40ad..32466d66 100644 --- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarMediator.java +++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarMediator.java
@@ -17,6 +17,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.ViewParent; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; @@ -47,6 +48,7 @@ import org.chromium.components.browser_ui.widget.BrowserUiListMenuUtils; import org.chromium.components.image_fetcher.ImageFetcherConfig; import org.chromium.components.image_fetcher.ImageFetcherFactory; +import org.chromium.ui.base.KeyNavigationUtil; import org.chromium.ui.listmenu.BasicListMenu; import org.chromium.ui.listmenu.ListItemType; import org.chromium.ui.listmenu.ListMenuItemProperties; @@ -790,43 +792,96 @@ // Builds and returns an OnKeyListener for every item in the popup menu. private View.OnKeyListener createPopupMenuItemKeyListener( PropertyModel model, BookmarkItem bookmarkItem) { + // view is the root View object inflated from list_menu_item.xml. return (view, keyCode, event) -> { - // Only proceed if the user has released the Enter key. - if (event.getAction() != KeyEvent.ACTION_UP || keyCode != KeyEvent.KEYCODE_ENTER) { - return false; - } - if (bookmarkItem == null) return false; - - if (bookmarkItem.isFolder()) { - // Get the pre-made "open submenu" click listener from the model. - View.OnClickListener clickListener = - model.get(ListMenuItemProperties.CLICK_LISTENER); - if (clickListener != null) { - // Calls ListMenuUtils#onItemWithSubmenuClicked. - clickListener.onClick(view); + // ACTION_DOWN is used because KeyNavigationUtil#isGoBackward depends on isActionDown to + // be true. + if (event.getAction() == KeyEvent.ACTION_DOWN) { + // Handle Left Arrow to go back to the parent menu. + if (KeyNavigationUtil.isGoBackward(event)) { + // Directly find the submenu header, which the go back onClickListener is + // attached to. + View headerView = findMenuHeaderView(view); + if (headerView != null) { + // Calls headerBackClick.run() in ListMenuUtils. + headerView.performClick(); + // We've handled the left arrow, so consume the event. + return true; + } } - } else if (event.isCtrlPressed()) { - // Not a folder and ctrl pressed. Open bookmark in new tab. - mBookmarkOpener.openBookmarksInNewTabs( - List.of(bookmarkItem.getId()), - mProfileSupplier.get().isOffTheRecord(), - Optional.of(TabLaunchType.FROM_BOOKMARK_BAR_BACKGROUND)); - // Dismiss only when opening a bookmark (webpage) and not a folder. - if (mAnchoredPopupWindow != null) mAnchoredPopupWindow.dismiss(); - } else { - // Not a folder and ctrl not pressed. This is a plain enter key press. Open bookmark - // in current tab, - mBookmarkOpener.openBookmarkInCurrentTab( - bookmarkItem.getId(), mProfileSupplier.get().isOffTheRecord()); - // Dismiss only when opening a bookmark (webpage) and not a folder. - if (mAnchoredPopupWindow != null) mAnchoredPopupWindow.dismiss(); + + // Handle Right Arrow to drill-down only if the item is a folder. + if (KeyNavigationUtil.isGoForward(event) && bookmarkItem.isFolder()) { + // Get the pre-made "open submenu" click listener from the model. + View.OnClickListener clickListener = + model.get(ListMenuItemProperties.CLICK_LISTENER); + if (clickListener != null) { + // Calls ListMenuUtils#onItemWithSubmenuClicked. + clickListener.onClick(view); + } + // We've handled the right arrow, so consume the event. + return true; + } } - // Always consume the event to prevent fallback. - return true; + + // Only proceed if the user has released the Enter key. + if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_ENTER) { + if (bookmarkItem.isFolder()) { + // Get the pre-made "open submenu" click listener from the model. + View.OnClickListener clickListener = + model.get(ListMenuItemProperties.CLICK_LISTENER); + if (clickListener != null) { + // Calls ListMenuUtils#onItemWithSubmenuClicked. + clickListener.onClick(view); + } + } else if (event.isCtrlPressed()) { + // Not a folder and ctrl pressed. Open bookmark in new tab. + mBookmarkOpener.openBookmarksInNewTabs( + List.of(bookmarkItem.getId()), + mProfileSupplier.get().isOffTheRecord(), + Optional.of(TabLaunchType.FROM_BOOKMARK_BAR_BACKGROUND)); + // Dismiss only when opening a bookmark (webpage) and not a folder. + if (mAnchoredPopupWindow != null) mAnchoredPopupWindow.dismiss(); + } else { + // Not a folder and ctrl not pressed. This is a plain enter key press. Open + // bookmark in current tab, + mBookmarkOpener.openBookmarkInCurrentTab( + bookmarkItem.getId(), mProfileSupplier.get().isOffTheRecord()); + // Dismiss only when opening a bookmark (webpage) and not a folder. + if (mAnchoredPopupWindow != null) mAnchoredPopupWindow.dismiss(); + } + // Always consume the event to prevent fallback. + return true; + } + return false; }; } + /** + * Finds the header view within the current popup menu by traversing up from a given item + * (list_menu_item.xml). This method is used to trigger the back navigation for the left arrow + * key. + * + * @param currentItemView The view of a currently focused menu item. + * @return The menu header view if found, otherwise null. + */ + private @Nullable View findMenuHeaderView(View currentItemView) { + ViewParent parent = currentItemView.getParent(); + // Walk up the tree until we find a parent that contains R.id.menu_header. + while (parent instanceof View) { + View parentView = (View) parent; + ListView headerListView = parentView.findViewById(R.id.menu_header); + if (headerListView != null && headerListView.getChildCount() > 0) { + // If headerListView is not null, there will only be one item inside it, + // the headerView that acts as the back button. + return headerListView.getChildAt(0); + } + parent = parentView.getParent(); + } + return null; + } + void setAnchoredPopupWindowForTesting(AnchoredPopupWindow anchoredPopupWindow) { mAnchoredPopupWindow = anchoredPopupWindow; }
diff --git a/chrome/browser/resource_coordinator/session_restore_policy.cc b/chrome/browser/resource_coordinator/session_restore_policy.cc index abb7c29..0ca7a9b 100644 --- a/chrome/browser/resource_coordinator/session_restore_policy.cc +++ b/chrome/browser/resource_coordinator/session_restore_policy.cc
@@ -38,8 +38,9 @@ #include "third_party/blink/public/common/permissions/permission_utils.h" #if !BUILDFLAG(IS_ANDROID) -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_list.h" +// TODO(crbug.com/407105162): Remove nogncheck when crbug.com/40147906 is fixed. +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" // nogncheck +#include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h" // nogncheck #include "chrome/browser/ui/tabs/tab_strip_model.h" #endif @@ -124,16 +125,16 @@ // this! // In theory all tabs should belong to a tab-strip, but in tests this isn't // necessarily true. - auto* browser_list = BrowserList::GetInstance(); - for (size_t i = 0; i < browser_list->size(); ++i) { - auto* browser = browser_list->get(i); - auto* tab_strip = browser->tab_strip_model(); - int tab_index = tab_strip->GetIndexOfWebContents(contents); - if (tab_index == TabStripModel::kNoTab) - continue; - tab_data->is_pinned = tab_strip->IsTabPinned(tab_index); - break; - } + ForEachCurrentBrowserWindowInterfaceOrderedByActivation( + [&](BrowserWindowInterface* browser) { + auto* const tab_strip = browser->GetTabStripModel(); + const int tab_index = tab_strip->GetIndexOfWebContents(contents); + if (tab_index == TabStripModel::kNoTab) { + return true; // continue iteration. + } + tab_data->is_pinned = tab_strip->IsTabPinned(tab_index); + return false; // end iteration. + }); #endif // !BUILDFLAG(IS_ANDROID) // Cache a handful of other properties.
diff --git a/chrome/browser/signin/chrome_signin_helper.h b/chrome/browser/signin/chrome_signin_helper.h index 47b3ecc..760f8fd 100644 --- a/chrome/browser/signin/chrome_signin_helper.h +++ b/chrome/browser/signin/chrome_signin_helper.h
@@ -73,6 +73,9 @@ virtual void SetDestructionCallback(base::OnceClosure closure) = 0; }; +// `ResponseAdapter` provides an interface for accessing and modifying +// properties of a network response. It is used by `HeaderModificationDelegate` +// to process response headers for sign-in related requests. class ResponseAdapter { public: ResponseAdapter(); @@ -82,15 +85,32 @@ virtual ~ResponseAdapter(); + // Returns a getter for the `WebContents` associated with the request that + // received this response. virtual content::WebContents::Getter GetWebContentsGetter() const = 0; + // Returns true if the response is for an outermost main frame request. virtual bool IsOutermostMainFrame() const = 0; + // Returns the URL of the response. This may be different from the initial + // request URL if there were redirects. virtual GURL GetUrl() const = 0; + // Returns the origin that initiated the request. This may be empty for + // browser-initiated requests. virtual std::optional<url::Origin> GetRequestInitiator() const = 0; + // Returns the top-frame origin of the request. This may be empty for + // renderer-initiated requests, as those requests do not set "trusted" + // parameters. virtual const url::Origin* GetRequestTopFrameOrigin() const = 0; + // Returns a pointer to the HTTP response headers. + // May return null if a response doesn't have associated headers. virtual const net::HttpResponseHeaders* GetHeaders() const = 0; + // Removes a header from the HTTP response headers. virtual void RemoveHeader(const std::string& name) = 0; + // Retrieves user data associated with this response. virtual base::SupportsUserData::Data* GetUserData(const void* key) const = 0; + // Associates user data with this response. + // If `data` is `nullptr`, this method removes data previously associated with + // the `key`. virtual void SetUserData( const void* key, std::unique_ptr<base::SupportsUserData::Data> data) = 0;
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc index 4783dd684..9320ed02 100644 --- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc +++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
@@ -270,12 +270,9 @@ class ProxyingURLLoaderFactory::InProgressRequest::ProxyResponseAdapter : public ResponseAdapter { public: - ProxyResponseAdapter(InProgressRequest* in_progress_request, + ProxyResponseAdapter(InProgressRequest& in_progress_request, net::HttpResponseHeaders* headers) - : in_progress_request_(in_progress_request), headers_(headers) { - DCHECK(in_progress_request_); - DCHECK(headers_); - } + : in_progress_request_(in_progress_request), headers_(headers) {} ProxyResponseAdapter(const ProxyResponseAdapter&) = delete; ProxyResponseAdapter& operator=(const ProxyResponseAdapter&) = delete; @@ -306,7 +303,9 @@ } void RemoveHeader(const std::string& name) override { - headers_->RemoveHeader(name); + if (headers_) { + headers_->RemoveHeader(name); + } } base::SupportsUserData::Data* GetUserData(const void* key) const override { @@ -320,7 +319,7 @@ } private: - const raw_ptr<InProgressRequest> in_progress_request_; + const raw_ref<InProgressRequest> in_progress_request_; const raw_ptr<net::HttpResponseHeaders> headers_; }; @@ -422,7 +421,7 @@ // Even though |head| is const we can get a non-const pointer to the headers // and modifications we made are passed to the target client. { - ProxyResponseAdapter adapter(this, head->headers.get()); + ProxyResponseAdapter adapter(*this, head->headers.get()); factory_->delegate_->ProcessResponse(&adapter, GURL() /* redirect_url */); // The `adapter` must be destroyed before moving the `head` in the // `target_client_`. @@ -437,7 +436,7 @@ // Even though |head| is const we can get a non-const pointer to the headers // and modifications we made are passed to the target client. { - ProxyResponseAdapter adapter(this, head->headers.get()); + ProxyResponseAdapter adapter(*this, head->headers.get()); factory_->delegate_->ProcessResponse(&adapter, redirect_info.new_url); // The `adapter` must be destroyed before moving the `head` in the // `target_client_`.
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc index 1059d336..6af26fd 100644 --- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc +++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
@@ -10,7 +10,9 @@ #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/run_loop.h" +#include "base/task/current_thread.h" #include "base/test/mock_callback.h" +#include "base/test/test_future.h" #include "chrome/browser/signin/chrome_signin_helper.h" #include "chrome/browser/signin/header_modification_delegate.h" #include "content/public/test/browser_task_environment.h" @@ -40,13 +42,19 @@ ~MockDelegate() override = default; - MOCK_METHOD1(ShouldInterceptNavigation, bool(content::WebContents* contents)); - MOCK_METHOD2(ProcessRequest, - void(ChromeRequestAdapter* request_adapter, - const GURL& redirect_url)); - MOCK_METHOD2(ProcessResponse, - void(ResponseAdapter* response_adapter, - const GURL& redirect_url)); + MOCK_METHOD(bool, + ShouldInterceptNavigation, + (content::WebContents * contents), + (override)); + MOCK_METHOD(void, + ProcessRequest, + (ChromeRequestAdapter * request_adapter, + const GURL& redirect_url), + (override)); + MOCK_METHOD(void, + ProcessResponse, + (ResponseAdapter * response_adapter, const GURL& redirect_url), + (override)); base::WeakPtr<MockDelegate> GetWeakPtr() { return weak_factory_.GetWeakPtr(); @@ -95,10 +103,7 @@ test_factory_receiver_.BindNewPipeAndPassRemote())); loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( - factory_remote.get(), - base::BindOnce( - &ChromeSigninProxyingURLLoaderFactoryTest::OnDownloadComplete, - base::Unretained(this))); + factory_remote.get(), request_complete_future_.GetCallback()); return delegate_weak; } @@ -107,10 +112,9 @@ network::TestURLLoaderFactory* factory() { return &test_factory_; } network::SimpleURLLoader* loader() { return loader_.get(); } - std::string* response_body() { return response_body_.get(); } - - void OnDownloadComplete(std::unique_ptr<std::string> body) { - response_body_ = std::move(body); + base::test::TestFuture<std::unique_ptr<std::string>>& + request_complete_future() { + return request_complete_future_; } private: @@ -124,7 +128,7 @@ std::unique_ptr<ProxyingURLLoaderFactory> proxying_factory_; network::TestURLLoaderFactory test_factory_; mojo::Receiver<network::mojom::URLLoaderFactory> test_factory_receiver_; - std::unique_ptr<std::string> response_body_; + base::test::TestFuture<std::unique_ptr<std::string>> request_complete_future_; }; TEST_F(ChromeSigninProxyingURLLoaderFactoryTest, NoModification) { @@ -134,10 +138,11 @@ factory()->AddResponse("https://google.com/", "Hello."); base::WeakPtr<MockDelegate> delegate = StartRequest(std::move(request)); - base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(request_complete_future().Wait()); + std::string* response_body = request_complete_future().Get().get(); EXPECT_EQ(net::OK, loader()->NetError()); - ASSERT_TRUE(response_body()); - EXPECT_EQ("Hello.", *response_body()); + ASSERT_TRUE(response_body); + EXPECT_EQ("Hello.", *response_body); } TEST_F(ChromeSigninProxyingURLLoaderFactoryTest, ModifyHeaders) { @@ -164,7 +169,7 @@ // The delegate will be called twice to process a request, first when the // request is started and again when the request is redirected. - EXPECT_CALL(*delegate, ProcessRequest(_, _)) + EXPECT_CALL(*delegate, ProcessRequest) .WillOnce( Invoke([&](ChromeRequestAdapter* adapter, const GURL& redirect_url) { EXPECT_EQ(kTestURL, adapter->GetUrl()); @@ -219,7 +224,7 @@ // The delegate will also be called twice to process a response, first when // the redirect is received and again for the redirect response. - EXPECT_CALL(*delegate, ProcessResponse(_, _)) + EXPECT_CALL(*delegate, ProcessResponse) .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) { EXPECT_EQ(kTestURL, adapter->GetUrl()); EXPECT_TRUE(adapter->IsOutermostMainFrame()); @@ -284,19 +289,23 @@ } // Wait for the request to complete and check the response. - base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(request_complete_future().Wait()); + std::string* response_body = request_complete_future().Get().get(); EXPECT_EQ(net::OK, loader()->NetError()); const network::mojom::URLResponseHead* response_head = loader()->ResponseInfo(); ASSERT_TRUE(response_head && response_head->headers); EXPECT_FALSE(response_head->headers->HasHeader("X-Response-3")); EXPECT_TRUE(response_head->headers->HasHeader("X-Response-4")); - ASSERT_TRUE(response_body()); - EXPECT_EQ("Hello.", *response_body()); + ASSERT_TRUE(response_body); + EXPECT_EQ("Hello.", *response_body); // NOTE: TestURLLoaderFactory currently does not expose modifications to // request headers and so we cannot verify that the modifications have been // passed to the target URLLoader. + + // `delegate` should be destroyed shortly. + base::test::RunUntil([&] { return delegate == nullptr; }); } TEST_F(ChromeSigninProxyingURLLoaderFactoryTest, TargetFactoryFailure) { @@ -307,7 +316,7 @@ // Without a target factory the proxy will process no requests. auto delegate = std::make_unique<MockDelegate>(); - EXPECT_CALL(*delegate, ProcessRequest(_, _)).Times(0); + EXPECT_CALL(*delegate, ProcessRequest).Times(0); network::URLLoaderFactoryBuilder factory_builder; @@ -331,13 +340,9 @@ auto loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( - factory_remote.get(), - base::BindOnce( - &ChromeSigninProxyingURLLoaderFactoryTest::OnDownloadComplete, - base::Unretained(this))); - base::RunLoop().RunUntilIdle(); - - EXPECT_FALSE(response_body()); + factory_remote.get(), request_complete_future().GetCallback()); + ASSERT_TRUE(request_complete_future().Wait()); + EXPECT_FALSE(request_complete_future().Get()); EXPECT_EQ(net::ERR_FAILED, loader->NetError()); } @@ -359,12 +364,79 @@ // Complete the request. factory()->AddResponse("https://google.com", "Hello."); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(delegate); + ASSERT_TRUE(request_complete_future().Wait()); + std::string* response_body = request_complete_future().Get().get(); EXPECT_EQ(net::OK, loader()->NetError()); - ASSERT_TRUE(response_body()); - EXPECT_EQ("Hello.", *response_body()); + ASSERT_TRUE(response_body); + EXPECT_EQ("Hello.", *response_body); + + // `delegate` should be destroyed shortly. + base::test::RunUntil([&] { return delegate == nullptr; }); + EXPECT_FALSE(delegate); +} + +// Regression test for https://crbug.com/441955793. +TEST_F(ChromeSigninProxyingURLLoaderFactoryTest, ResponseWithNullHeaders) { + const GURL kTestURL("https://google.com/index.html"); + const GURL kTestReferrer("https://chrome.com/referrer.html"); + const GURL kTestRedirectURL("https://youtube.com/index.html"); + + // Set up the request. + auto request = std::make_unique<network::ResourceRequest>(); + request->url = kTestURL; + request->referrer = kTestReferrer; + + base::WeakPtr<MockDelegate> delegate = StartRequest(std::move(request)); + + // The delegate will be called twice to process a request, first when the + // request is started and again when the request is redirected. + EXPECT_CALL(*delegate, ProcessRequest).Times(2); + + // The delegate will also be called twice to process a response, first when + // the redirect is received and again for the redirect response. + EXPECT_CALL(*delegate, ProcessResponse) + .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) { + EXPECT_EQ(kTestURL, adapter->GetUrl()); + EXPECT_EQ(kTestRedirectURL, redirect_url); + // This should not crash. + adapter->RemoveHeader("TestHeader"); + EXPECT_FALSE(adapter->GetHeaders()); + })) + .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) { + EXPECT_EQ(kTestRedirectURL, adapter->GetUrl()); + EXPECT_EQ(GURL(), redirect_url); + // This should not crash. + adapter->RemoveHeader("TestHeader"); + EXPECT_FALSE(adapter->GetHeaders()); + })); + + // Set up a redirect and final response. + { + net::RedirectInfo redirect_info; + redirect_info.new_url = kTestRedirectURL; + // An HTTPS to HTTPS redirect such as this wouldn't normally change the + // referrer but we do for testing purposes. + redirect_info.new_referrer = kTestURL.spec(); + + // Response head with null headers. + auto redirect_head = network::mojom::URLResponseHead::New(); + auto response_head = network::mojom::URLResponseHead::New(); + + network::TestURLLoaderFactory::Redirects redirects; + redirects.emplace_back(redirect_info, std::move(redirect_head)); + + factory()->AddResponse( + kTestURL, std::move(response_head), /*content=*/std::string(), + network::URLLoaderCompletionStatus(), std::move(redirects)); + } + + // Wait for the request to complete and check the response. + ASSERT_TRUE(request_complete_future().Wait()); + const network::mojom::URLResponseHead* response_head = + loader()->ResponseInfo(); + ASSERT_TRUE(response_head); + EXPECT_FALSE(response_head->headers); } } // namespace signin
diff --git a/chrome/browser/signin/chrome_signin_url_loader_throttle.cc b/chrome/browser/signin/chrome_signin_url_loader_throttle.cc index bce48c9..fd0f90a1 100644 --- a/chrome/browser/signin/chrome_signin_url_loader_throttle.cc +++ b/chrome/browser/signin/chrome_signin_url_loader_throttle.cc
@@ -62,7 +62,7 @@ class URLLoaderThrottle::ThrottleResponseAdapter : public ResponseAdapter { public: - ThrottleResponseAdapter(URLLoaderThrottle* throttle, + ThrottleResponseAdapter(URLLoaderThrottle& throttle, net::HttpResponseHeaders* headers) : throttle_(throttle), headers_(headers) {} @@ -95,7 +95,9 @@ } void RemoveHeader(const std::string& name) override { - headers_->RemoveHeader(name); + if (headers_) { + headers_->RemoveHeader(name); + } } base::SupportsUserData::Data* GetUserData(const void* key) const override { @@ -109,8 +111,8 @@ } private: - const raw_ptr<URLLoaderThrottle> throttle_; - raw_ptr<net::HttpResponseHeaders> headers_; + const raw_ref<URLLoaderThrottle> throttle_; + const raw_ptr<net::HttpResponseHeaders> headers_; }; // static @@ -179,7 +181,7 @@ // Modifications to |response_head.headers| will be passed to the // URLLoaderClient even though |response_head| is const. - ThrottleResponseAdapter response_adapter(this, response_head.headers.get()); + ThrottleResponseAdapter response_adapter(*this, response_head.headers.get()); delegate_->ProcessResponse(&response_adapter, redirect_info->new_url); request_url_ = redirect_info->new_url; @@ -190,7 +192,7 @@ const GURL& response_url, network::mojom::URLResponseHead* response_head, bool* defer) { - ThrottleResponseAdapter adapter(this, response_head->headers.get()); + ThrottleResponseAdapter adapter(*this, response_head->headers.get()); delegate_->ProcessResponse(&adapter, GURL() /* redirect_url */); }
diff --git a/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc b/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc index ea3e22b..78774ecf 100644 --- a/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc +++ b/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc
@@ -32,13 +32,19 @@ ~MockDelegate() override = default; - MOCK_METHOD1(ShouldInterceptNavigation, bool(content::WebContents* contents)); - MOCK_METHOD2(ProcessRequest, - void(ChromeRequestAdapter* request_adapter, - const GURL& redirect_url)); - MOCK_METHOD2(ProcessResponse, - void(ResponseAdapter* response_adapter, - const GURL& redirect_url)); + MOCK_METHOD(bool, + ShouldInterceptNavigation, + (content::WebContents * contents), + (override)); + MOCK_METHOD(void, + ProcessRequest, + (ChromeRequestAdapter * request_adapter, + const GURL& redirect_url), + (override)); + MOCK_METHOD(void, + ProcessResponse, + (ResponseAdapter * response_adapter, const GURL& redirect_url), + (override)); }; content::WebContents::Getter NullWebContentsGetter() { @@ -50,14 +56,14 @@ TEST(ChromeSigninURLLoaderThrottleTest, NoIntercept) { auto* delegate = new MockDelegate(); - EXPECT_CALL(*delegate, ShouldInterceptNavigation(_)).WillOnce(Return(false)); + EXPECT_CALL(*delegate, ShouldInterceptNavigation).WillOnce(Return(false)); EXPECT_FALSE(URLLoaderThrottle::MaybeCreate(base::WrapUnique(delegate), NullWebContentsGetter())); } TEST(ChromeSigninURLLoaderThrottleTest, Intercept) { auto* delegate = new MockDelegate(); - EXPECT_CALL(*delegate, ShouldInterceptNavigation(_)).WillOnce(Return(true)); + EXPECT_CALL(*delegate, ShouldInterceptNavigation).WillOnce(Return(true)); auto throttle = URLLoaderThrottle::MaybeCreate(base::WrapUnique(delegate), NullWebContentsGetter()); ASSERT_TRUE(throttle); @@ -67,7 +73,7 @@ const GURL kTestURL("https://google.com/index.html"); const GURL kTestReferrer("https://chrome.com/referrer.html"); base::MockCallback<base::OnceClosure> destruction_callback; - EXPECT_CALL(*delegate, ProcessRequest(_, _)) + EXPECT_CALL(*delegate, ProcessRequest) .WillOnce( Invoke([&](ChromeRequestAdapter* adapter, const GURL& redirect_url) { EXPECT_EQ(kTestURL, adapter->GetUrl()); @@ -114,7 +120,7 @@ base::SupportsUserData::Data* response_user_data_ptr = response_user_data.get(); - EXPECT_CALL(*delegate, ProcessResponse(_, _)) + EXPECT_CALL(*delegate, ProcessResponse) .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) { EXPECT_EQ(kTestURL, adapter->GetUrl()); EXPECT_TRUE(adapter->IsOutermostMainFrame()); @@ -133,7 +139,7 @@ })); base::MockCallback<base::OnceClosure> ignored_destruction_callback; - EXPECT_CALL(*delegate, ProcessRequest(_, _)) + EXPECT_CALL(*delegate, ProcessRequest) .WillOnce( Invoke([&](ChromeRequestAdapter* adapter, const GURL& redirect_url) { EXPECT_EQ(network::mojom::RequestDestination::kDocument, @@ -194,7 +200,7 @@ // Phase 3: Complete the request. - EXPECT_CALL(*delegate, ProcessResponse(_, _)) + EXPECT_CALL(*delegate, ProcessResponse) .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) { EXPECT_EQ(kTestRedirectURL, adapter->GetUrl()); EXPECT_TRUE(adapter->IsOutermostMainFrame()); @@ -233,12 +239,12 @@ TEST(ChromeSigninURLLoaderThrottleTest, InterceptSubFrame) { auto* delegate = new MockDelegate(); - EXPECT_CALL(*delegate, ShouldInterceptNavigation(_)).WillOnce(Return(true)); + EXPECT_CALL(*delegate, ShouldInterceptNavigation).WillOnce(Return(true)); auto throttle = URLLoaderThrottle::MaybeCreate(base::WrapUnique(delegate), NullWebContentsGetter()); ASSERT_TRUE(throttle); - EXPECT_CALL(*delegate, ProcessRequest(_, _)) + EXPECT_CALL(*delegate, ProcessRequest) .Times(2) .WillRepeatedly( [](ChromeRequestAdapter* adapter, const GURL& redirect_url) { @@ -256,7 +262,7 @@ throttle->WillStartRequest(&request, &defer); EXPECT_FALSE(defer); - EXPECT_CALL(*delegate, ProcessResponse(_, _)) + EXPECT_CALL(*delegate, ProcessResponse) .Times(2) .WillRepeatedly(([](ResponseAdapter* adapter, const GURL& redirect_url) { EXPECT_FALSE(adapter->IsOutermostMainFrame()); @@ -282,4 +288,75 @@ EXPECT_FALSE(defer); } +// Regression test for https://crbug.com/441955793. +TEST(ChromeSigninURLLoaderThrottleTest, InterceptNullHeaders) { + auto* delegate = new MockDelegate(); + EXPECT_CALL(*delegate, ShouldInterceptNavigation).WillOnce(Return(true)); + auto throttle = URLLoaderThrottle::MaybeCreate(base::WrapUnique(delegate), + NullWebContentsGetter()); + ASSERT_TRUE(throttle); + + // Phase 1: Start a HTTPS request. + + const GURL kTestURL("https://google.com/index.html"); + const GURL kTestReferrer("https://chrome.com/referrer.html"); + EXPECT_CALL(*delegate, ProcessRequest); + + network::ResourceRequest request; + request.url = kTestURL; + request.referrer = kTestReferrer; + bool defer = false; + throttle->WillStartRequest(&request, &defer); + EXPECT_FALSE(defer); + testing::Mock::VerifyAndClearExpectations(delegate); + + // Phase 2: Redirect the request to a header-less URL. + + const GURL kTestRedirectURL("chrome-extension://abcd/index.html"); + EXPECT_CALL(*delegate, ProcessResponse) + .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) { + EXPECT_EQ(kTestURL, adapter->GetUrl()); + EXPECT_FALSE(adapter->GetHeaders()); + // This should not crash. + adapter->RemoveHeader("TestHeader"); + EXPECT_EQ(kTestRedirectURL, redirect_url); + })); + EXPECT_CALL(*delegate, ProcessRequest); + + net::RedirectInfo redirect_info; + redirect_info.new_url = kTestRedirectURL; + redirect_info.new_referrer = kTestURL.spec(); + + // Response head with null headers. + auto response_head = network::mojom::URLResponseHead::New(); + std::vector<std::string> request_headers_to_remove; + net::HttpRequestHeaders modified_request_headers; + net::HttpRequestHeaders modified_cors_exempt_request_headers; + throttle->WillRedirectRequest( + &redirect_info, *response_head, &defer, &request_headers_to_remove, + &modified_request_headers, &modified_cors_exempt_request_headers); + EXPECT_FALSE(defer); + + EXPECT_FALSE(response_head->headers); + testing::Mock::VerifyAndClearExpectations(delegate); + + // Phase 3: Complete the request. + + EXPECT_CALL(*delegate, ProcessResponse) + .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) { + EXPECT_EQ(kTestRedirectURL, adapter->GetUrl()); + EXPECT_FALSE(adapter->GetHeaders()); + // This should not crash. + adapter->RemoveHeader("TestHeader"); + EXPECT_EQ(GURL(), redirect_url); + })); + + // Response head with null headers. + response_head = network::mojom::URLResponseHead::New(); + throttle->WillProcessResponse(kTestRedirectURL, response_head.get(), &defer); + + EXPECT_FALSE(response_head->headers); + EXPECT_FALSE(defer); +} + } // namespace signin
diff --git a/chrome/browser/ui/tabs/BUILD.gn b/chrome/browser/ui/tabs/BUILD.gn index b33a90c..8558f0c 100644 --- a/chrome/browser/ui/tabs/BUILD.gn +++ b/chrome/browser/ui/tabs/BUILD.gn
@@ -549,7 +549,6 @@ "//components/sync_sessions", "//components/tab_groups", "//components/tabs", - "//components/wallet/content/browser", "//components/wallet/core/common:features", "//net", "//ui/base/unowned_user_data", @@ -567,6 +566,10 @@ if (!is_android) { deps += [ "//chrome/browser/ui/views/zoom" ] } + + if (is_win || is_mac || is_linux || is_chromeos) { + deps += [ "//chrome/browser/wallet" ] + } } # This is a separate component to avoid possible circular deps.
diff --git a/chrome/browser/ui/tabs/public/tab_features.h b/chrome/browser/ui/tabs/public/tab_features.h index 22dfeb93..315c65c 100644 --- a/chrome/browser/ui/tabs/public/tab_features.h +++ b/chrome/browser/ui/tabs/public/tab_features.h
@@ -114,6 +114,13 @@ class TabContextualizationController; } // namespace lens +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ + BUILDFLAG(IS_CHROMEOS) +namespace wallet { +class ChromeWalletablePassClient; +} // namespace wallet +#endif + namespace tabs { class TabAlertController; @@ -432,6 +439,10 @@ std::unique_ptr<lens::TabContextualizationController> tab_contextualization_controller_; +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ + BUILDFLAG(IS_CHROMEOS) + std::unique_ptr<wallet::ChromeWalletablePassClient> walletable_pass_client_; +#endif // Must be the last member. base::WeakPtrFactory<TabFeatures> weak_factory_{this}; };
diff --git a/chrome/browser/ui/tabs/tab_features.cc b/chrome/browser/ui/tabs/tab_features.cc index db509e6..c8adbac 100644 --- a/chrome/browser/ui/tabs/tab_features.cc +++ b/chrome/browser/ui/tabs/tab_features.cc
@@ -77,6 +77,10 @@ #include "chrome/browser/ui/views/zoom/zoom_view_controller.h" #include "chrome/browser/ui/web_applications/pwa_install_page_action.h" #include "chrome/browser/ui/webui/webui_embedding_context.h" +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ + BUILDFLAG(IS_CHROMEOS) +#include "chrome/browser/wallet/chrome_walletable_pass_client.h" +#endif #include "chrome/browser/web_applications/web_app_tab_helper.h" #include "chrome/browser/web_applications/web_app_utils.h" #include "chrome/common/chrome_features.h" @@ -91,7 +95,6 @@ #include "components/permissions/permission_indicators_tab_data.h" #include "components/security_interstitials/core/features.h" #include "components/tabs/public/tab_interface.h" -#include "components/wallet/content/browser/content_walletable_pass_ingestion_controller.h" #include "components/wallet/core/common/wallet_features.h" #include "net/base/features.h" #include "ui/base/unowned_user_data/user_data_factory.h" @@ -375,11 +378,8 @@ std::make_unique<InactiveWindowMouseEventController>(); if (base::FeatureList::IsEnabled(wallet::kWalletablePassDetection)) { - if (auto* opt_guide = - OptimizationGuideKeyedServiceFactory::GetForProfile(profile)) { - wallet::ContentWalletablePassIngestionController::CreateForWebContents( - tab.GetContents(), opt_guide); - } + walletable_pass_client_ = + std::make_unique<wallet::ChromeWalletablePassClient>(&tab); } #endif
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc index ec24160..60c4c765 100644 --- a/chrome/browser/ui/views/frame/browser_view_layout.cc +++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -617,11 +617,13 @@ top_container_separator_->SetBounds( available_bounds.x(), available_bounds.y(), available_bounds.width(), separator_height); + multi_contents_view_->SetShouldShowTopSeparator(false); + } else { + // If the loading bar will be shown, it's supposed to replace the + // separator. + multi_contents_view_->SetShouldShowTopSeparator(!loading_bar_); + SetViewVisibility(top_container_separator_, false); } - // If the loading bar will be shown, it's supposed to replace the - // separator. - multi_contents_view_->SetShouldShowTopSeparator( - !show_overlay_contents_separator && !loading_bar_); } else { separator_height = top_container_separator_->GetPreferredSize().height(); SetViewVisibility(top_container_separator_, true);
diff --git a/chrome/browser/wallet/BUILD.gn b/chrome/browser/wallet/BUILD.gn new file mode 100644 index 0000000..4a1ca9a --- /dev/null +++ b/chrome/browser/wallet/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2024 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +static_library("wallet") { + sources = [ + "chrome_walletable_pass_client.cc", + "chrome_walletable_pass_client.h", + ] + + deps = [ + "//base", + "//chrome/browser/optimization_guide", + "//chrome/browser/profiles", + "//components/optimization_guide/core", + "//components/wallet/content/browser", + "//components/wallet/core/browser", + ] +}
diff --git a/chrome/browser/wallet/DEPS b/chrome/browser/wallet/DEPS new file mode 100644 index 0000000..c0118526 --- /dev/null +++ b/chrome/browser/wallet/DEPS
@@ -0,0 +1,6 @@ +include_rules = [ + # go/keep-sorted start + "+components/wallet/content/browser", + "+components/wallet/core/browser", + # go/keep-sorted end +]
diff --git a/chrome/browser/wallet/chrome_walletable_pass_client.cc b/chrome/browser/wallet/chrome_walletable_pass_client.cc new file mode 100644 index 0000000..a08af58 --- /dev/null +++ b/chrome/browser/wallet/chrome_walletable_pass_client.cc
@@ -0,0 +1,37 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/wallet/chrome_walletable_pass_client.h" + +#include "base/check_deref.h" +#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h" +#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "components/optimization_guide/core/hints/optimization_guide_decider.h" +#include "components/optimization_guide/core/optimization_guide_model_executor.h" +#include "components/tabs/public/tab_interface.h" +#include "content/public/browser/web_contents.h" + +namespace wallet { + +ChromeWalletablePassClient::ChromeWalletablePassClient(tabs::TabInterface* tab) + : tab_(CHECK_DEREF(tab)), controller_(tab_->GetContents(), this) {} + +ChromeWalletablePassClient::~ChromeWalletablePassClient() = default; + +optimization_guide::OptimizationGuideDecider* +ChromeWalletablePassClient::GetOptimizationGuideDecider() { + Profile* profile = + Profile::FromBrowserContext(tab_->GetContents()->GetBrowserContext()); + return OptimizationGuideKeyedServiceFactory::GetForProfile(profile); +} + +optimization_guide::OptimizationGuideModelExecutor* +ChromeWalletablePassClient::GetOptimizationGuideModelExecutor() { + Profile* profile = + Profile::FromBrowserContext(tab_->GetContents()->GetBrowserContext()); + return OptimizationGuideKeyedServiceFactory::GetForProfile(profile); +} + +} // namespace wallet
diff --git a/chrome/browser/wallet/chrome_walletable_pass_client.h b/chrome/browser/wallet/chrome_walletable_pass_client.h new file mode 100644 index 0000000..33deefc3 --- /dev/null +++ b/chrome/browser/wallet/chrome_walletable_pass_client.h
@@ -0,0 +1,51 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WALLET_CHROME_WALLETABLE_PASS_CLIENT_H_ +#define CHROME_BROWSER_WALLET_CHROME_WALLETABLE_PASS_CLIENT_H_ + +#include "base/memory/raw_ref.h" +#include "components/wallet/content/browser/content_walletable_pass_ingestion_controller.h" +#include "components/wallet/core/browser/walletable_pass_client.h" + +namespace optimization_guide { +class OptimizationGuideDecider; +class OptimizationGuideModelExecutor; +} // namespace optimization_guide + +namespace tabs { +class TabInterface; +} // namespace tabs + +namespace wallet { + +class ContentWalletablePassIngestionController; + +// The Chrome implementation of `wallet::WalletablePassClient`. +// +// This class bridges the core wallet component with browser services, such as +// the Optimization Guide and UI interactions (e.g., showing a saving pass +// bubble). Its lifecycle is scoped to a single tab and managed by +// `TabFeatures`. +class ChromeWalletablePassClient : public WalletablePassClient { + public: + explicit ChromeWalletablePassClient(tabs::TabInterface* tab); + + ~ChromeWalletablePassClient() override; + + // WalleablePassClient implementation. + optimization_guide::OptimizationGuideDecider* GetOptimizationGuideDecider() + override; + optimization_guide::OptimizationGuideModelExecutor* + GetOptimizationGuideModelExecutor() override; + + private: + const raw_ref<tabs::TabInterface> tab_; + + ContentWalletablePassIngestionController controller_; +}; + +} // namespace wallet + +#endif // CHROME_BROWSER_WALLET_CHROME_WALLETABLE_PASS_CLIENT_H_
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index 4a77129..128e34f2 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1757180102-166c06c7ee4ce6104f6e8bb226d3019ce4116d5f-5b31578217d3cdd1df34c58236011f941a5ddb5d.profdata +chrome-android32-main-1757246363-2880d1d14437a119c991e1cc7a326bac35208bfa-aaccc0c9b286ebc29b52814c35ccd31543414a4a.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index a9c6d23..ebae5cec 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1757192256-65f3202086b24a61257f2c80fba7766abed2ba81-75ef9c359dea932eab72da60e5f3b9d3ad850c83.profdata +chrome-android64-main-1757283738-16e09bca18c213a5430517a2a3d270f8e88b2556-81273a91e6978b2f8d28dae019823085961ce80b.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt index a56a246b..bb149ff 100644 --- a/chrome/build/android-desktop-x64.pgo.txt +++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@ -chrome-android-desktop-x64-main-1757180102-c202664934b1ec4742de06b04c9e16e25ca45e34-5b31578217d3cdd1df34c58236011f941a5ddb5d.profdata +chrome-android-desktop-x64-main-1757287645-ff4b3752328d1fe1263c552dfa4a68c1ff258572-f77f925a2c6b576b533f03c8e7427a87d8a205ce.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index fa335402..1103562 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1757180102-bbbf2fa8b50b1b2455ab2e28e1da1c5c30074c77-5b31578217d3cdd1df34c58236011f941a5ddb5d.profdata +chrome-mac-main-1757267985-a242d9feb4b25f4dbd95970c70396aeaf34b4fe3-b477c9f0e43efecb7c6b9621b0d0735004a58688.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index c275b2c..54f6c177 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1757170509-12a8214cf0824f098f6e3a2ef5998f5e6e178ef9-9bd75e0392503aed07d8dc1a0d1f696d46eb04ff.profdata +chrome-win32-main-1757267985-68887a69027a37dae62d932a9f85d78c79201a3a-b477c9f0e43efecb7c6b9621b0d0735004a58688.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 879f785..e6092d3 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1757180102-17631aa2f1c48bc44cebdd68cc8c7ae09985dea3-5b31578217d3cdd1df34c58236011f941a5ddb5d.profdata +chrome-win64-main-1757267985-368bbc529a16ac1f96b4e6429f595488dc90740f-b477c9f0e43efecb7c6b9621b0d0735004a58688.profdata
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 7fc05a7..263d569 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -16410.0.0-1071539 \ No newline at end of file +16410.0.0-1071545 \ No newline at end of file
diff --git a/chromeos/ash/components/account_manager/account_manager_facade_factory.cc b/chromeos/ash/components/account_manager/account_manager_facade_factory.cc index 6a8a7945..e1a1ae3f 100644 --- a/chromeos/ash/components/account_manager/account_manager_facade_factory.cc +++ b/chromeos/ash/components/account_manager/account_manager_facade_factory.cc
@@ -4,76 +4,15 @@ #include "chromeos/ash/components/account_manager/account_manager_facade_factory.h" -#include <limits> -#include <map> -#include <memory> -#include <utility> +#include <string> -#include "base/no_destructor.h" #include "chromeos/ash/components/account_manager/account_manager_factory.h" -#include "components/account_manager_core/account_manager_facade_impl.h" -#include "components/account_manager_core/chromeos/account_manager.h" -#include "components/account_manager_core/chromeos/account_manager_mojo_service.h" namespace ash { -namespace { - -crosapi::AccountManagerMojoService* GetAccountManagerMojoService( - const std::string& profile_path) { - crosapi::AccountManagerMojoService* account_manager_mojo_service = - ash::AccountManagerFactory::Get()->GetAccountManagerMojoService( - profile_path); - DCHECK(account_manager_mojo_service); - - return account_manager_mojo_service; -} - -// Map from |profile_path| to AccountManagerFacade. -std::map<std::string, - std::unique_ptr<account_manager::AccountManagerFacadeImpl>>& -GetMap() { - static base::NoDestructor<std::map< - std::string, std::unique_ptr<account_manager::AccountManagerFacadeImpl>>> - account_manager_facade_map; - return *account_manager_facade_map.get(); -} - -} // namespace - account_manager::AccountManagerFacade* GetAccountManagerFacade( const std::string& profile_path) { - auto& account_manager_facade_map = GetMap(); - - auto it = account_manager_facade_map.find(profile_path); - if (it == account_manager_facade_map.end()) { - mojo::Remote<crosapi::mojom::AccountManager> remote; - GetAccountManagerMojoService(profile_path) - ->BindReceiver(remote.BindNewPipeAndPassReceiver()); - - // This is set to a sentinel value which will pass all minimum version - // checks. - // Calls within Ash are in the same process and don't need to check version - // compatibility with itself. - constexpr uint32_t remote_version = std::numeric_limits<uint32_t>::max(); - // TODO(crbug.com/40800999): to avoid incorrect usage, pass a nullptr - // `AccountManager` when this is not running in a test. - account_manager::AccountManager* account_manager_for_tests = - ash::AccountManagerFactory::Get()->GetAccountManager(profile_path); - auto account_manager_facade = - std::make_unique<account_manager::AccountManagerFacadeImpl>( - std::move(remote), remote_version, - account_manager_for_tests->GetWeakPtr()); - it = account_manager_facade_map - .emplace(profile_path, std::move(account_manager_facade)) - .first; - } - - return it->second.get(); -} - -void DeleteAccountManagerFacadeInstanceForTesting( - const std::string& profile_path) { - GetMap().erase(profile_path); + return ash::AccountManagerFactory::Get()->GetAccountManagerFacade( + profile_path); } } // namespace ash
diff --git a/chromeos/ash/components/account_manager/account_manager_facade_factory.h b/chromeos/ash/components/account_manager/account_manager_facade_factory.h index f022d215..0d9196d3 100644 --- a/chromeos/ash/components/account_manager/account_manager_facade_factory.h +++ b/chromeos/ash/components/account_manager/account_manager_facade_factory.h
@@ -26,13 +26,6 @@ account_manager::AccountManagerFacade* GetAccountManagerFacade( const std::string& profile_path); -// Deletes existing instances of AccountManagerFacade. -// TODO(crbug.com/421058020): Integrate `GetAccountManagerFacade` into -// `AccountManagerFactory` and remove this. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_ACCOUNT_MANAGER) -void DeleteAccountManagerFacadeInstanceForTesting( - const std::string& profile_path); - } // namespace ash #endif // CHROMEOS_ASH_COMPONENTS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_FACADE_FACTORY_H_
diff --git a/chromeos/ash/components/account_manager/account_manager_factory.cc b/chromeos/ash/components/account_manager/account_manager_factory.cc index 0da7115..fdc6005 100644 --- a/chromeos/ash/components/account_manager/account_manager_factory.cc +++ b/chromeos/ash/components/account_manager/account_manager_factory.cc
@@ -7,8 +7,11 @@ #include <string> #include <utility> +#include "base/callback_list.h" #include "base/check.h" #include "base/check_op.h" +#include "base/functional/callback.h" +#include "components/account_manager_core/account_manager_facade_impl.h" #include "components/account_manager_core/chromeos/account_manager.h" #include "components/account_manager_core/chromeos/account_manager_mojo_service.h" @@ -22,6 +25,8 @@ g_instance = this; } AccountManagerFactory::~AccountManagerFactory() { + on_destruction_callbacks_.Notify(); + CHECK_EQ(g_instance, this); g_instance = nullptr; } @@ -47,12 +52,28 @@ .account_manager_mojo_service.get(); } +account_manager::AccountManagerFacade* +AccountManagerFactory::GetAccountManagerFacade( + const std::string& profile_path) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + return GetAccountManagerHolder(profile_path).account_manager_facade.get(); +} + +base::CallbackListSubscription AccountManagerFactory::AddOnDestructionCallback( + base::OnceClosure callback) { + return on_destruction_callbacks_.Add(std::move(callback)); +} + AccountManagerFactory::AccountManagerHolder::AccountManagerHolder( std::unique_ptr<account_manager::AccountManager> account_manager, std::unique_ptr<crosapi::AccountManagerMojoService> - account_manager_mojo_service) + account_manager_mojo_service, + std::unique_ptr<account_manager::AccountManagerFacade> + account_manager_facade) : account_manager(std::move(account_manager)), - account_manager_mojo_service(std::move(account_manager_mojo_service)) {} + account_manager_mojo_service(std::move(account_manager_mojo_service)), + account_manager_facade(std::move(account_manager_facade)) {} AccountManagerFactory::AccountManagerHolder::~AccountManagerHolder() = default; @@ -65,11 +86,30 @@ auto account_manager_mojo_service = std::make_unique<crosapi::AccountManagerMojoService>( account_manager.get()); + + mojo::Remote<crosapi::mojom::AccountManager> remote; + account_manager_mojo_service->BindReceiver( + remote.BindNewPipeAndPassReceiver()); + + // This is set to a sentinel value which will pass all minimum version + // checks. + // Calls within Ash are in the same process and don't need to check version + // compatibility with itself. + constexpr uint32_t remote_version = std::numeric_limits<uint32_t>::max(); + // TODO(crbug.com/40800999): to avoid incorrect usage, pass a nullptr + // `AccountManager` when this is not running in a test. + base::WeakPtr<account_manager::AccountManager> account_manager_for_tests = + account_manager->GetWeakPtr(); + auto account_manager_facade = + std::make_unique<account_manager::AccountManagerFacadeImpl>( + std::move(remote), remote_version, account_manager_for_tests); + it = account_managers_ .emplace( std::piecewise_construct, std::forward_as_tuple(profile_path), std::forward_as_tuple(std::move(account_manager), - std::move(account_manager_mojo_service))) + std::move(account_manager_mojo_service), + std::move(account_manager_facade))) .first; } return it->second;
diff --git a/chromeos/ash/components/account_manager/account_manager_factory.h b/chromeos/ash/components/account_manager/account_manager_factory.h index 9320f66..5313dcf 100644 --- a/chromeos/ash/components/account_manager/account_manager_factory.h +++ b/chromeos/ash/components/account_manager/account_manager_factory.h
@@ -9,11 +9,14 @@ #include <string> #include <unordered_map> +#include "base/callback_list.h" #include "base/component_export.h" +#include "base/functional/callback.h" #include "base/sequence_checker.h" namespace account_manager { class AccountManager; +class AccountManagerFacade; } // namespace account_manager namespace crosapi { @@ -51,12 +54,23 @@ crosapi::AccountManagerMojoService* GetAccountManagerMojoService( const std::string& profile_path); + // Returns the `AccountManagerFacade` corresponding to the given + // `profile_path`. + account_manager::AccountManagerFacade* GetAccountManagerFacade( + const std::string& profile_path); + + // Register a callback that will be called on ~AccountManagerFactory(). + base::CallbackListSubscription AddOnDestructionCallback( + base::OnceClosure callback); + private: struct AccountManagerHolder { AccountManagerHolder( std::unique_ptr<account_manager::AccountManager> account_manager, std::unique_ptr<crosapi::AccountManagerMojoService> - account_manager_mojo_service); + account_manager_mojo_service, + std::unique_ptr<account_manager::AccountManagerFacade> + account_manager_facade); AccountManagerHolder(const AccountManagerHolder&) = delete; AccountManagerHolder& operator=(const AccountManagerHolder&) = delete; ~AccountManagerHolder(); @@ -64,6 +78,8 @@ const std::unique_ptr<account_manager::AccountManager> account_manager; const std::unique_ptr<crosapi::AccountManagerMojoService> account_manager_mojo_service; + const std::unique_ptr<account_manager::AccountManagerFacade> + account_manager_facade; }; const AccountManagerHolder& GetAccountManagerHolder( @@ -73,6 +89,8 @@ // Account Managers and AccountManagerMojoService objects. std::unordered_map<std::string, AccountManagerHolder> account_managers_; + base::OnceCallbackList<void()> on_destruction_callbacks_; + SEQUENCE_CHECKER(sequence_checker_); };
diff --git a/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc b/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc index f7c6e24..fe226b25 100644 --- a/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc +++ b/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc
@@ -105,13 +105,13 @@ const net::NetworkTrafficAnnotationTag& annotation_tag) { return std::make_unique<EndpointFetcher>( /*url_loader_factory=*/std::move(url_loader_factory), - /*url=*/url, - /*content_type=*/kHttpContentType, - /*timeout=*/kTimeout, - /*post_data=*/"", - /*headers=*/std::vector<std::string>(), - /*cors_exempt_headers=*/std::vector<std::string>(), ash::GetChannel(), + /*identity_manager=*/nullptr, EndpointFetcher::RequestParams::Builder(kHttpMethod, annotation_tag) + .SetAuthType(endpoint_fetcher::CHROME_API_KEY) + .SetChannel(ash::GetChannel()) + .SetContentType(kHttpContentType) + .SetTimeout(kTimeout) + .SetUrl(url) .Build()); }
diff --git a/chromeos/crosapi/mojom/clipboard_history.mojom b/chromeos/crosapi/mojom/clipboard_history.mojom index 57050bb1..6e2a94e1 100644 --- a/chromeos/crosapi/mojom/clipboard_history.mojom +++ b/chromeos/crosapi/mojom/clipboard_history.mojom
@@ -28,7 +28,7 @@ [Default] kUnknown, // Deprecated: Shown by a toast. [MinVersion=1] kToast, - // Shown by long-pressing Ctrl+V. + // Deprecated: Shown by long-pressing Ctrl+V. [MinVersion=2] kControlVLongpress, // Shown from the submenu embedded in a render view's context memu. [MinVersion=3] kRenderViewContextSubmenu,
diff --git a/clank b/clank index 5e36fab..73faa49 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 5e36fab7a4bfa7d98ad3a9ba760f39af8c2c12eb +Subproject commit 73faa4938c6a3d50fccccdcdba2813f0f74d5c01
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json index 523e34c..53f1c77 100644 --- a/components/certificate_transparency/data/log_list.json +++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@ { - "version": "66.2", - "log_list_timestamp": "2025-09-06T12:53:29Z", + "version": "66.3", + "log_list_timestamp": "2025-09-07T12:54:02Z", "operators": [ { "name": "Google",
diff --git a/components/signin/internal/identity_manager/BUILD.gn b/components/signin/internal/identity_manager/BUILD.gn index a4ce0d8..2f17b8c 100644 --- a/components/signin/internal/identity_manager/BUILD.gn +++ b/components/signin/internal/identity_manager/BUILD.gn
@@ -112,6 +112,7 @@ ] deps += [ "//ash/constants", + "//chromeos/ash/components/account_manager", "//components/account_manager_core", ] } @@ -203,6 +204,7 @@ deps += [ "//ash/constants", + "//chromeos/ash/components/account_manager", "//components/account_manager_core:test_support", ] }
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc index 45929df4..3082464 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
@@ -8,10 +8,12 @@ #include <utility> #include <vector> +#include "base/check_deref.h" #include "base/containers/contains.h" #include "base/functional/bind.h" #include "base/logging.h" #include "build/build_config.h" +#include "chromeos/ash/components/account_manager/account_manager_factory.h" #include "components/account_manager_core/account.h" #include "components/signin/internal/identity_manager/account_tracker_service.h" #include "components/signin/public/base/signin_client.h" @@ -138,6 +140,23 @@ is_regular_profile_(is_regular_profile), weak_factory_(this) { network_connection_tracker_->AddNetworkConnectionObserver(this); + + // In production, AccountManagerFactory should always outlive `this`, but in + // tests, it may be destroyed before `this` and `account_manager_facade_` may + // dangle. So, observe AccountManagerFactory and reset the raw_ptr on its + // destruction. + // TODO(crbug.com/421058020): Fix tests to properly mimic the production + // construction/destruction order, and remove the observer. + account_manager_factory_cb_subscription_ = + CHECK_DEREF(ash::AccountManagerFactory::Get()) + .AddOnDestructionCallback(base::BindOnce( + [](base::WeakPtr<ProfileOAuth2TokenServiceDelegateChromeOS> + self) { + if (self) { + self->account_manager_facade_ = nullptr; + } + }, + weak_factory_.GetWeakPtr())); } ProfileOAuth2TokenServiceDelegateChromeOS::
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h index 660d4cd..a9cedd62 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h
@@ -11,9 +11,11 @@ #include <string> #include <vector> +#include "base/callback_list.h" #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "base/sequence_checker.h" #include "components/account_manager_core/account.h" #include "components/account_manager_core/account_manager_facade.h" @@ -100,7 +102,8 @@ const raw_ptr<AccountTrackerService, DanglingUntriaged> account_tracker_service_; const raw_ptr<network::NetworkConnectionTracker> network_connection_tracker_; - const raw_ptr<account_manager::AccountManagerFacade> account_manager_facade_; + raw_ptr<account_manager::AccountManagerFacade> account_manager_facade_ = + nullptr; // When the delegate receives an account from either `GetAccounts` or // `OnAccountUpserted`, this account is first added to pending accounts, until @@ -116,6 +119,8 @@ // Is |this| attached to a regular (non-Signin && non-LockScreen) Profile. const bool is_regular_profile_; + base::CallbackListSubscription account_manager_factory_cb_subscription_; + SEQUENCE_CHECKER(sequence_checker_); base::WeakPtrFactory<ProfileOAuth2TokenServiceDelegateChromeOS> weak_factory_; };
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc index 2a43c5ec..f14e7ba 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
@@ -20,6 +20,7 @@ #include "base/scoped_observation.h" #include "base/test/gmock_callback_support.h" #include "base/test/task_environment.h" +#include "chromeos/ash/components/account_manager/account_manager_factory.h" #include "components/account_manager_core/account.h" #include "components/account_manager_core/account_manager_facade.h" #include "components/account_manager_core/account_manager_facade_impl.h" @@ -168,6 +169,36 @@ token_service_observation_{this}; }; +AccountManager::DelayNetworkCallRunner ImmediateCallbackRunner() { + return base::BindRepeating( + [](base::OnceClosure closure) { std::move(closure).Run(); }); +} + +AccountInfo CreateAccountInfoTestFixture( + const AccountTrackerService& account_tracker_service, + const GaiaId& gaia_id, + const std::string& email) { + AccountInfo account_info; + + account_info.gaia = gaia_id; + account_info.email = email; + account_info.full_name = "name"; + account_info.given_name = "name"; + account_info.hosted_domain = "example.com"; + account_info.locale = "en"; + account_info.picture_url = "https://example.com"; + account_info.account_id = account_tracker_service.PickAccountIdForAccount( + account_info.gaia, account_info.email); + AccountCapabilitiesTestMutator(&account_info.capabilities) + .set_is_subject_to_enterprise_features(true); + + // Cannot use |ASSERT_TRUE| due to a |void| return type in an |ASSERT_TRUE| + // branch. + EXPECT_TRUE(account_info.IsValid()); + + return account_info; +} + } // namespace class ProfileOAuth2TokenServiceDelegateChromeOSTest : public testing::Test { @@ -183,26 +214,29 @@ protected: void SetUp() override { - ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir()); + ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); AccountTrackerService::RegisterPrefs(pref_service_.registry()); AccountManager::RegisterPrefs(pref_service_.registry()); client_ = std::make_unique<TestSigninClient>(&pref_service_); - account_manager_.Initialize(tmp_dir_.GetPath(), - client_->GetURLLoaderFactory(), - immediate_callback_runner_); - account_manager_.SetPrefService(&pref_service_); - task_environment_.RunUntilIdle(); + account_manager_ = ash::AccountManagerFactory::Get()->GetAccountManager( + profile_dir_.GetPath().value()); + account_manager_->Initialize(profile_dir_.GetPath(), + client_->GetURLLoaderFactory(), + ImmediateCallbackRunner()); + account_manager_->SetPrefService(&pref_service_); - account_manager_mojo_service_ = - std::make_unique<crosapi::AccountManagerMojoService>(&account_manager_); account_manager_facade_ = - CreateAccountManagerFacade(account_manager_mojo_service_.get()); + ash::AccountManagerFactory::Get()->GetAccountManagerFacade( + profile_dir_.GetPath().value()); + + task_environment_.RunUntilIdle(); account_tracker_service_.Initialize(&pref_service_, base::FilePath()); - account_info_ = CreateAccountInfoTestFixture(kGaiaId, kUserEmail); + account_info_ = CreateAccountInfoTestFixture(account_tracker_service_, + kGaiaId, kUserEmail); account_tracker_service_.SeedAccountInfo(account_info_); ResetProfileOAuth2TokenServiceDelegateChromeOS(); } @@ -225,29 +259,6 @@ return account_manager::AccountKey::FromGaiaId(account_info_.gaia); } - AccountInfo CreateAccountInfoTestFixture(const GaiaId& gaia_id, - const std::string& email) { - AccountInfo account_info; - - account_info.gaia = gaia_id; - account_info.email = email; - account_info.full_name = "name"; - account_info.given_name = "name"; - account_info.hosted_domain = "example.com"; - account_info.locale = "en"; - account_info.picture_url = "https://example.com"; - account_info.account_id = account_tracker_service_.PickAccountIdForAccount( - account_info.gaia, account_info.email); - AccountCapabilitiesTestMutator(&account_info.capabilities) - .set_is_subject_to_enterprise_features(true); - - // Cannot use |ASSERT_TRUE| due to a |void| return type in an |ASSERT_TRUE| - // branch. - EXPECT_TRUE(account_info.IsValid()); - - return account_info; - } - void AddSuccessfulOAuthTokenResponse() { client_->GetTestURLLoaderFactory()->AddResponse( GaiaUrls::GetInstance()->oauth2_token_url().spec(), @@ -277,7 +288,7 @@ base::RunLoop run_loop; EXPECT_CALL(observer, OnRefreshTokenAvailable(testing::_)) .WillOnce(base::test::RunClosure(run_loop.QuitClosure())); - account_manager_.UpsertAccount(account_key, raw_email, token); + account_manager_->UpsertAccount(account_key, raw_email, token); run_loop.Run(); } @@ -288,36 +299,21 @@ base::RunLoop run_loop; EXPECT_CALL(observer, OnRefreshTokenRevoked(testing::_)) .WillOnce(base::test::RunClosure(run_loop.QuitClosure())); - account_manager_.RemoveAccount(account_key); + account_manager_->RemoveAccount(account_key); run_loop.Run(); } - std::unique_ptr<AccountManagerFacade> CreateAccountManagerFacade( - crosapi::AccountManagerMojoService* account_manager_mojo_service) { - DCHECK(account_manager_mojo_service); - mojo::Remote<crosapi::mojom::AccountManager> remote; - account_manager_mojo_service->BindReceiver( - remote.BindNewPipeAndPassReceiver()); - return std::make_unique<account_manager::AccountManagerFacadeImpl>( - std::move(remote), - /*remote_version=*/std::numeric_limits<uint32_t>::max(), - /*account_manager_for_tests=*/nullptr); - } - base::test::TaskEnvironment task_environment_; + ash::AccountManagerFactory account_manager_factory_; - base::ScopedTempDir tmp_dir_; + base::ScopedTempDir profile_dir_; AccountInfo account_info_; AccountTrackerService account_tracker_service_; - AccountManager account_manager_; - std::unique_ptr<crosapi::AccountManagerMojoService> - account_manager_mojo_service_; - std::unique_ptr<account_manager::AccountManagerFacade> - account_manager_facade_; + + raw_ptr<AccountManager> account_manager_ = nullptr; + raw_ptr<account_manager::AccountManagerFacade> account_manager_facade_ = + nullptr; std::unique_ptr<signin::ProfileOAuth2TokenServiceDelegateChromeOS> delegate_; - AccountManager::DelayNetworkCallRunner immediate_callback_runner_ = - base::BindRepeating( - [](base::OnceClosure closure) -> void { std::move(closure).Run(); }); sync_preferences::TestingPrefServiceSyncable pref_service_; std::unique_ptr<TestSigninClient> client_; }; @@ -410,7 +406,7 @@ // after adding a new account on ChromeOS. EXPECT_CALL(observer, OnAuthErrorChanged); EXPECT_CALL(observer, OnEndBatchChanges); - account_manager_.UpsertAccount(gaia_account_key(), kUserEmail, kGaiaToken); + account_manager_->UpsertAccount(gaia_account_key(), kUserEmail, kGaiaToken); upsert_run_loop.Run(); testing::Mock::VerifyAndClearExpectations(&observer); } @@ -424,7 +420,7 @@ // changing its error state. EXPECT_CALL(observer, OnAuthErrorChanged); EXPECT_CALL(observer, OnEndBatchChanges); - account_manager_.UpdateToken(gaia_account_key(), "new-gaia-token"); + account_manager_->UpdateToken(gaia_account_key(), "new-gaia-token"); update_run_loop.Run(); testing::Mock::VerifyAndClearExpectations(&observer); } @@ -543,8 +539,8 @@ // UpsertAccountAndWaitForCompletion can't be used here, as it uses an // observer to wait for completion. Observers aren't called in this flow, so // UpsertAccountAndWaitForCompletion would hang here. - account_manager_.UpsertAccount(gaia_account_key(), account_info_.email, - kGaiaToken); + account_manager_->UpsertAccount(gaia_account_key(), account_info_.email, + kGaiaToken); task_environment_.RunUntilIdle(); EXPECT_TRUE(observer.account_ids_.empty()); @@ -562,64 +558,6 @@ EXPECT_EQ(account_info_.account_id, observer.batch_change_records_[0][0]); } -// If observers register themselves with |ProfileOAuth2TokenServiceDelegate| -// before |AccountManager| has been initialized, they should receive all the -// accounts stored in |AccountManager| in a single batch. -TEST_F(ProfileOAuth2TokenServiceDelegateChromeOSTest, - BatchChangeObserversAreNotifiedOncePerBatch) { - // Setup - AccountInfo account1 = CreateAccountInfoTestFixture( - GaiaId("1"), "user1@example.com" /* email */); - AccountInfo account2 = CreateAccountInfoTestFixture( - GaiaId("2"), "user2@example.com" /* email */); - - account_tracker_service_.SeedAccountInfo(account1); - account_tracker_service_.SeedAccountInfo(account2); - account_manager_.UpsertAccount( - account_manager::AccountKey::FromGaiaId(account1.gaia), - "user1@example.com", "token1"); - account_manager_.UpsertAccount( - account_manager::AccountKey::FromGaiaId(account2.gaia), - "user2@example.com", "token2"); - task_environment_.RunUntilIdle(); - - AccountManager account_manager; - // AccountManager will not be fully initialized until - // |task_environment_.RunUntilIdle()| is called. - account_manager.Initialize(tmp_dir_.GetPath(), client_->GetURLLoaderFactory(), - immediate_callback_runner_); - account_manager.SetPrefService(&pref_service_); - - auto account_manager_mojo_service = - std::make_unique<crosapi::AccountManagerMojoService>(&account_manager); - auto account_manager_facade = - CreateAccountManagerFacade(account_manager_mojo_service.get()); - - // Register callbacks before AccountManager has been fully initialized. - auto delegate = - std::make_unique<signin::ProfileOAuth2TokenServiceDelegateChromeOS>( - client_.get(), &account_tracker_service_, - network::TestNetworkConnectionTracker::GetInstance(), - account_manager_facade.get(), - /*is_regular_profile=*/true); - delegate->LoadCredentials(account1.account_id /* primary_account_id */); - TestOAuth2TokenServiceObserver observer(delegate.get()); - // Wait until AccountManager is fully initialized. - task_environment_.RunUntilIdle(); - - // Tests - - // The observer should receive at least one batch change callback: batch of - // all accounts stored in AccountManager: because of the delegate's - // invocation of |AccountManagerFacade::GetAccounts| in |LoadCredentials|. - EXPECT_FALSE(observer.batch_change_records_.empty()); - const std::vector<CoreAccountId>& first_batch = - observer.batch_change_records_[0]; - EXPECT_EQ(2UL, first_batch.size()); - EXPECT_TRUE(base::Contains(first_batch, account1.account_id)); - EXPECT_TRUE(base::Contains(first_batch, account2.account_id)); -} - TEST_F(ProfileOAuth2TokenServiceDelegateChromeOSTest, GetAccountsReturnsGaiaAccounts) { EXPECT_TRUE(delegate_->GetAccounts().empty()); @@ -660,7 +598,7 @@ account_manager::AccountKey gaia_account_key2 = account_manager::AccountKey::FromGaiaId(GaiaId("random-gaia-id")); account_tracker_service_.SeedAccountInfo(CreateAccountInfoTestFixture( - GaiaId(gaia_account_key2.id()), kUserEmail2)); + account_tracker_service_, GaiaId(gaia_account_key2.id()), kUserEmail2)); UpsertAccountAndWaitForCompletion(gaia_account_key2, kUserEmail2, AccountManager::kInvalidToken); @@ -709,9 +647,9 @@ // `UpsertAccount` will asynchronously send a notification through // `AccountManagerFacade`, so `RemoveAccount` should remove the account before // `ProfileOAuth2TokenServiceDelegateChromeOS` can add this account. - account_manager_.UpsertAccount(gaia_account_key(), account_info_.email, - kGaiaToken); - account_manager_.RemoveAccount(gaia_account_key()); + account_manager_->UpsertAccount(gaia_account_key(), account_info_.email, + kGaiaToken); + account_manager_->RemoveAccount(gaia_account_key()); task_environment_.RunUntilIdle(); @@ -733,9 +671,9 @@ EXPECT_CALL(observer, OnRefreshTokenRevoked(account_info_.account_id)) .WillOnce(base::test::RunClosure(run_loop.QuitClosure())); - account_manager_.UpsertAccount(gaia_account_key(), account_info_.email, - AccountManager::kInvalidToken); - account_manager_.RemoveAccount(gaia_account_key()); + account_manager_->UpsertAccount(gaia_account_key(), account_info_.email, + AccountManager::kInvalidToken); + account_manager_->RemoveAccount(gaia_account_key()); run_loop.Run(); @@ -885,3 +823,101 @@ EXPECT_EQ(account_info_.account_id, observer.last_err_account_id_); EXPECT_EQ(error, observer.last_err_); } + +class ProfileOAuth2TokenServiceDelegateChromeOSObserverTest + : public testing::Test { + public: + void SetUp() override { + account_manager_factory_ = std::make_unique<ash::AccountManagerFactory>(); + + ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); + + AccountTrackerService::RegisterPrefs(pref_service_.registry()); + AccountManager::RegisterPrefs(pref_service_.registry()); + + client_ = std::make_unique<TestSigninClient>(ProfilePrefs()); + account_tracker_service_.Initialize(ProfilePrefs(), base::FilePath()); + } + + protected: + PrefService* ProfilePrefs() { return &pref_service_; } + base::FilePath ProfilePath() { return profile_dir_.GetPath(); } + + base::test::TaskEnvironment task_environment_; + std::unique_ptr<ash::AccountManagerFactory> account_manager_factory_; + + base::ScopedTempDir profile_dir_; + sync_preferences::TestingPrefServiceSyncable pref_service_; + std::unique_ptr<TestSigninClient> client_; + AccountTrackerService account_tracker_service_; +}; + +// If observers register themselves with |ProfileOAuth2TokenServiceDelegate| +// before |AccountManager| has been initialized, they should receive all the +// accounts stored in |AccountManager| in a single batch. +TEST_F(ProfileOAuth2TokenServiceDelegateChromeOSObserverTest, + BatchChangeObserversAreNotifiedOncePerBatch) { + // Setup + AccountInfo account1 = CreateAccountInfoTestFixture( + account_tracker_service_, GaiaId("1"), "user1@example.com"); + AccountInfo account2 = CreateAccountInfoTestFixture( + account_tracker_service_, GaiaId("2"), "user2@example.com"); + + account_tracker_service_.SeedAccountInfo(account1); + account_tracker_service_.SeedAccountInfo(account2); + + { + auto* account_manager = + ash::AccountManagerFactory::Get()->GetAccountManager( + ProfilePath().value()); + account_manager->Initialize(ProfilePath(), client_->GetURLLoaderFactory(), + ImmediateCallbackRunner()); + + account_manager->SetPrefService(ProfilePrefs()); + task_environment_.RunUntilIdle(); + + account_manager->UpsertAccount( + account_manager::AccountKey::FromGaiaId(account1.gaia), + "user1@example.com", "token1"); + account_manager->UpsertAccount( + account_manager::AccountKey::FromGaiaId(account2.gaia), + "user2@example.com", "token2"); + task_environment_.RunUntilIdle(); + } + + // Re-create AccountManager. + account_manager_factory_.reset(); + account_manager_factory_ = std::make_unique<ash::AccountManagerFactory>(); + auto* account_manager = ash::AccountManagerFactory::Get()->GetAccountManager( + ProfilePath().value()); + // AccountManager will not be fully initialized until `RunUntilIdle`. + account_manager->Initialize(ProfilePath(), client_->GetURLLoaderFactory(), + ImmediateCallbackRunner()); + account_manager->SetPrefService(ProfilePrefs()); + + // Register callbacks before AccountManager has been fully initialized. + auto delegate = + std::make_unique<signin::ProfileOAuth2TokenServiceDelegateChromeOS>( + client_.get(), &account_tracker_service_, + network::TestNetworkConnectionTracker::GetInstance(), + ash::AccountManagerFactory::Get()->GetAccountManagerFacade( + ProfilePath().value()), + /*is_regular_profile=*/true); + delegate->LoadCredentials(account1.account_id /* primary_account_id */); + TestOAuth2TokenServiceObserver observer(delegate.get()); + + // Wait until AccountManager is fully initialized. + task_environment_.RunUntilIdle(); + + // Tests + + // The observer should receive at least one batch change callback: batch of + // all accounts stored in AccountManager: because of the delegate's + // invocation of |AccountManagerFacade::GetAccounts| in |LoadCredentials|. + EXPECT_FALSE(observer.batch_change_records_.empty()); + const std::vector<CoreAccountId>& first_batch = + observer.batch_change_records_[0]; + EXPECT_EQ(2UL, first_batch.size()); + EXPECT_TRUE(base::Contains(first_batch, account1.account_id)); + EXPECT_TRUE(base::Contains(first_batch, account2.account_id)); +}
diff --git a/components/signin/public/identity_manager/identity_manager_builder_unittest.cc b/components/signin/public/identity_manager/identity_manager_builder_unittest.cc index d58c1cc..589369b 100644 --- a/components/signin/public/identity_manager/identity_manager_builder_unittest.cc +++ b/components/signin/public/identity_manager/identity_manager_builder_unittest.cc
@@ -26,7 +26,7 @@ #endif #if BUILDFLAG(IS_CHROMEOS) -#include "components/account_manager_core/mock_account_manager_facade.h" +#include "chromeos/ash/components/account_manager/account_manager_factory.h" #endif #if BUILDFLAG(IS_IOS) @@ -81,7 +81,7 @@ TEST_F(IdentityManagerBuilderTest, BuildIdentityManagerInitParameters) { base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - base::FilePath dest_path = temp_dir.GetPath(); + base::FilePath profile_path = temp_dir.GetPath(); #if BUILDFLAG(IS_ANDROID) SetUpFakeAccountManagerFacade(); @@ -94,7 +94,7 @@ params.network_connection_tracker = network::TestNetworkConnectionTracker::GetInstance(); params.pref_service = GetPrefService(); - params.profile_path = dest_path; + params.profile_path = profile_path; params.signin_client = GetSigninClient(); #if BUILDFLAG(IS_IOS) @@ -105,9 +105,13 @@ #endif #if BUILDFLAG(IS_CHROMEOS) - auto account_manager_facade = - std::make_unique<account_manager::MockAccountManagerFacade>(); - params.account_manager_facade = account_manager_facade.get(); + // This enables `AccountManagerFactory::Get()`, which is needed for + // `ProfileOAuth2TokenServiceDelegateChromeOS`. + ash::AccountManagerFactory account_manager_factory; + + params.account_manager_facade = + ash::AccountManagerFactory::Get()->GetAccountManagerFacade( + profile_path.value()); params.is_regular_profile = true; #endif
diff --git a/components/signin/public/identity_manager/identity_test_environment.cc b/components/signin/public/identity_manager/identity_test_environment.cc index a5d458c..e4e91b46 100644 --- a/components/signin/public/identity_manager/identity_test_environment.cc +++ b/components/signin/public/identity_manager/identity_test_environment.cc
@@ -64,25 +64,6 @@ namespace signin { -#if BUILDFLAG(IS_CHROMEOS) -int ScopedIdentityTestEnvironmentTracker::count_ = 0; - -ScopedIdentityTestEnvironmentTracker::ScopedIdentityTestEnvironmentTracker() { - ++count_; -} - -ScopedIdentityTestEnvironmentTracker::~ScopedIdentityTestEnvironmentTracker() { - --count_; - if (count_ == 0) { - // TODO(crbug.com/421058020): Integrate `GetAccountManagerFacade` into - // `AccountManagerFactory` and let it manage the lifetime. - // Remove the facade for the empty path as it was previously a separate - // instance and reset after each test. - ash::DeleteAccountManagerFacadeInstanceForTesting(""); - } -} -#endif // BUILDFLAG(IS_CHROMEOS) - class IdentityManagerDependenciesOwner { public: IdentityManagerDependenciesOwner(
diff --git a/components/signin/public/identity_manager/identity_test_environment.h b/components/signin/public/identity_manager/identity_test_environment.h index a8d5d0e..bef48824 100644 --- a/components/signin/public/identity_manager/identity_test_environment.h +++ b/components/signin/public/identity_manager/identity_test_environment.h
@@ -41,24 +41,6 @@ class IdentityManagerDependenciesOwner; class TestIdentityManagerObserver; -#if BUILDFLAG(IS_CHROMEOS) -// TODO(crbug.com/421058020): This is needed for managing lifetime of -// AccountManagerFactoryFacadeImpl. Remove this once we've integrated the facade -// factory into AccountManagerFactory. -class ScopedIdentityTestEnvironmentTracker { - public: - ScopedIdentityTestEnvironmentTracker(); - ScopedIdentityTestEnvironmentTracker( - const ScopedIdentityTestEnvironmentTracker&) = delete; - ScopedIdentityTestEnvironmentTracker& operator=( - const ScopedIdentityTestEnvironmentTracker&) = delete; - ~ScopedIdentityTestEnvironmentTracker(); - - private: - static int count_; -}; -#endif // BUILDFLAG(IS_CHROMEOS) - // Arguments for `IdentityTestEnvironment::MakeAccountAvailable()`. Keeps // references, so do not rely on it for storage. // @@ -495,11 +477,6 @@ base::OnceClosure on_access_token_requested_callback_; std::vector<AccessTokenRequestState> requesters_; -#if BUILDFLAG(IS_CHROMEOS) - ScopedIdentityTestEnvironmentTracker - scoped_identity_test_environment_tracker_; -#endif // BUILDFLAG(IS_CHROMEOS) - base::WeakPtrFactory<IdentityTestEnvironment> weak_ptr_factory_{this}; };
diff --git a/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc b/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc index ffb500b..d559307 100644 --- a/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc +++ b/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc
@@ -10,14 +10,10 @@ namespace wallet { ContentWalletablePassIngestionController:: - ContentWalletablePassIngestionController( - content::WebContents* web_contents, - optimization_guide::OptimizationGuideDecider* - optimization_guide_decider) - : WalletablePassIngestionController(optimization_guide_decider), - content::WebContentsObserver(web_contents), - content::WebContentsUserData<ContentWalletablePassIngestionController>( - *web_contents) {} + ContentWalletablePassIngestionController(content::WebContents* web_contents, + WalletablePassClient* client) + : WalletablePassIngestionController(client), + content::WebContentsObserver(web_contents) {} ContentWalletablePassIngestionController:: ~ContentWalletablePassIngestionController() = default; @@ -32,6 +28,4 @@ // TODO(crbug.com/422366321): Add walletable pass detection logic here. } -WEB_CONTENTS_USER_DATA_KEY_IMPL(ContentWalletablePassIngestionController); - } // namespace wallet
diff --git a/components/wallet/content/browser/content_walletable_pass_ingestion_controller.h b/components/wallet/content/browser/content_walletable_pass_ingestion_controller.h index 886af1c..912591c 100644 --- a/components/wallet/content/browser/content_walletable_pass_ingestion_controller.h +++ b/components/wallet/content/browser/content_walletable_pass_ingestion_controller.h
@@ -7,7 +7,6 @@ #include "components/wallet/core/browser/walletable_pass_ingestion_controller.h" #include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/web_contents_user_data.h" namespace content { class RenderFrameHost; @@ -22,10 +21,11 @@ // observing the `WebContents` it is attached to. class ContentWalletablePassIngestionController : public WalletablePassIngestionController, - public content::WebContentsObserver, - public content::WebContentsUserData< - ContentWalletablePassIngestionController> { + public content::WebContentsObserver { public: + ContentWalletablePassIngestionController(content::WebContents* web_contents, + WalletablePassClient* client); + ContentWalletablePassIngestionController( const ContentWalletablePassIngestionController&) = delete; ContentWalletablePassIngestionController& operator=( @@ -36,15 +36,6 @@ // content::WebContentsObserver: void DidFinishLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url) override; - - private: - friend class content::WebContentsUserData< - ContentWalletablePassIngestionController>; - ContentWalletablePassIngestionController( - content::WebContents* web_contents, - optimization_guide::OptimizationGuideDecider* optimization_guide_decider); - - WEB_CONTENTS_USER_DATA_KEY_DECL(); }; } // namespace wallet
diff --git a/components/wallet/core/browser/BUILD.gn b/components/wallet/core/browser/BUILD.gn index 1da21abd4..77236139 100644 --- a/components/wallet/core/browser/BUILD.gn +++ b/components/wallet/core/browser/BUILD.gn
@@ -2,8 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//components/optimization_guide/features.gni") + static_library("browser") { sources = [ + "walletable_pass_client.h", "walletable_pass_ingestion_controller.cc", "walletable_pass_ingestion_controller.h", "walletable_pass_service.cc", @@ -17,17 +20,28 @@ ] } -source_set("unit_tests") { +source_set("test_support") { testonly = true - sources = [ - "walletable_pass_ingestion_controller_unittest.cc", - "walletable_pass_service_unittest.cc", - ] + sources = [ "walletable_pass_ingestion_controller_test_api.h" ] deps = [ ":browser", "//base", + "//url", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ "walletable_pass_service_unittest.cc" ] + if (build_with_model_execution) { + sources += [ "walletable_pass_ingestion_controller_unittest.cc" ] + } + deps = [ + ":browser", + ":test_support", + "//base", "//base/test:test_support", - "//components/optimization_guide/core:hints_test_support", + "//components/optimization_guide/core:test_support", "//testing/gmock", "//testing/gtest", "//url",
diff --git a/components/wallet/core/browser/walletable_pass_client.h b/components/wallet/core/browser/walletable_pass_client.h new file mode 100644 index 0000000..97668de --- /dev/null +++ b/components/wallet/core/browser/walletable_pass_client.h
@@ -0,0 +1,36 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_CLIENT_H_ +#define COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_CLIENT_H_ + +namespace optimization_guide { +class OptimizationGuideDecider; +class OptimizationGuideModelExecutor; +} // namespace optimization_guide + +namespace wallet { + +// A client interface that must be supplied to the Wallet component by the +// embedder (e.g., Chrome). The client's goal is to provide access to +// browser-level services required for walletable pass detection and extraction, +// such as the Optimization Guide. This allows the component to function without +// a direct dependency on the browser's implementation details. +// +// An implementation of this client is associated with a single tab and its +// lifecycle. +class WalletablePassClient { + public: + virtual ~WalletablePassClient() = default; + + virtual optimization_guide::OptimizationGuideDecider* + GetOptimizationGuideDecider() = 0; + + virtual optimization_guide::OptimizationGuideModelExecutor* + GetOptimizationGuideModelExecutor() = 0; +}; + +} // namespace wallet + +#endif // COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_CLIENT_H_
diff --git a/components/wallet/core/browser/walletable_pass_ingestion_controller.cc b/components/wallet/core/browser/walletable_pass_ingestion_controller.cc index 287901d0..03572764 100644 --- a/components/wallet/core/browser/walletable_pass_ingestion_controller.cc +++ b/components/wallet/core/browser/walletable_pass_ingestion_controller.cc
@@ -4,15 +4,18 @@ #include "components/wallet/core/browser/walletable_pass_ingestion_controller.h" +#include "base/check_deref.h" #include "components/optimization_guide/core/hints/optimization_guide_decider.h" +#include "components/optimization_guide/core/optimization_guide_model_executor.h" +#include "components/optimization_guide/proto/features/walletable_pass_extraction.pb.h" #include "components/optimization_guide/proto/hints.pb.h" #include "url/gurl.h" namespace wallet { WalletablePassIngestionController::WalletablePassIngestionController( - optimization_guide::OptimizationGuideDecider* optimization_guide_decider) - : optimization_guide_decider_(optimization_guide_decider) { + WalletablePassClient* client) + : client_(CHECK_DEREF(client)) { RegisterOptimizationTypes(); } @@ -26,7 +29,7 @@ } // Check if URL is allowlisted via optimization guide - return optimization_guide_decider_->CanApplyOptimization( + return client_->GetOptimizationGuideDecider()->CanApplyOptimization( url, optimization_guide::proto::WALLETABLE_PASS_DETECTION_ALLOWLIST, /*optimization_metadata=*/nullptr) == @@ -34,8 +37,52 @@ } void WalletablePassIngestionController::RegisterOptimizationTypes() { - optimization_guide_decider_->RegisterOptimizationTypes( + client_->GetOptimizationGuideDecider()->RegisterOptimizationTypes( {optimization_guide::proto::WALLETABLE_PASS_DETECTION_ALLOWLIST}); } +void WalletablePassIngestionController::ExtractWalletablePass( + const std::string& url, + optimization_guide::proto::AnnotatedPageContent annotated_page_content) { + // Construct request + optimization_guide::proto::WalletablePassExtractionRequest request; + request.mutable_page_context()->set_url(url); + *request.mutable_page_context()->mutable_annotated_page_content() = + std::move(annotated_page_content); + + client_->GetOptimizationGuideModelExecutor()->ExecuteModel( + optimization_guide::ModelBasedCapabilityKey::kWalletablePassExtraction, + std::move(request), + /*execution_timeout=*/std::nullopt, + base::BindOnce( + &WalletablePassIngestionController::OnExtractWalletablePass, + weak_ptr_factory_.GetWeakPtr())); +} + +void WalletablePassIngestionController::OnExtractWalletablePass( + optimization_guide::OptimizationGuideModelExecutionResult result, + std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry) { + // Handle model execution failure first. + if (!result.response.has_value()) { + // TODO(crbug.com/441892746): Report model execution failure to UMA + return; + } + + // The execution succeeded, now attempt to parse the response. + auto parsed_response = optimization_guide::ParsedAnyMetadata< + optimization_guide::proto::WalletablePassExtractionResponse>( + *result.response); + if (!parsed_response) { + // TODO(crbug.com/441892746): Report invalid or unparsable response to UMA + return; + } + + if (parsed_response->walletable_pass_size() == 0) { + // TODO(crbug.com/441892746): Report no walletable pass found to UMA + return; + } + + // TODO(crbug.com/441830204): Get the first walletable pass and show in UI. +} + } // namespace wallet
diff --git a/components/wallet/core/browser/walletable_pass_ingestion_controller.h b/components/wallet/core/browser/walletable_pass_ingestion_controller.h index c39581e..35dae65 100644 --- a/components/wallet/core/browser/walletable_pass_ingestion_controller.h +++ b/components/wallet/core/browser/walletable_pass_ingestion_controller.h
@@ -5,12 +5,18 @@ #ifndef COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_INGESTION_CONTROLLER_H_ #define COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_INGESTION_CONTROLLER_H_ -#include "base/memory/raw_ptr.h" +#include <string> + +#include "base/memory/raw_ref.h" +#include "base/memory/weak_ptr.h" +#include "components/optimization_guide/proto/features/common_quality_data.pb.h" +#include "components/wallet/core/browser/walletable_pass_client.h" class GURL; namespace optimization_guide { -class OptimizationGuideDecider; +class ModelQualityLogEntry; +struct OptimizationGuideModelExecutionResult; } // namespace optimization_guide namespace wallet { @@ -18,8 +24,8 @@ // Controls the detection of walletable passes on a web page. class WalletablePassIngestionController { public: - explicit WalletablePassIngestionController( - optimization_guide::OptimizationGuideDecider* optimization_guide_decider); + explicit WalletablePassIngestionController(WalletablePassClient* client); + virtual ~WalletablePassIngestionController(); // Not copyable or movable. @@ -28,18 +34,35 @@ WalletablePassIngestionController& operator=( const WalletablePassIngestionController&) = delete; - // Checks if the URL is eligible for pass extraction. This is determined by - // consulting an allowlist managed by the Optimization Guide. - bool IsEligibleForExtraction(const GURL& url) const; - protected: // Registers optimization types with the Optimization Guide to query the pass // extraction allowlist. void RegisterOptimizationTypes(); + // Checks if the URL is eligible for pass extraction. This is determined by + // consulting an allowlist managed by the Optimization Guide. + bool IsEligibleForExtraction(const GURL& url) const; + + // Extracts a walletable pass from the provided page content. This method + // invokes the Optimization Guide's model executor to perform the extraction. + void ExtractWalletablePass( + const std::string& url, + optimization_guide::proto::AnnotatedPageContent annotated_page_content); + private: - raw_ptr<optimization_guide::OptimizationGuideDecider> - optimization_guide_decider_; + friend class WalletablePassIngestionControllerTestApi; + + // Callback for when the pass extraction from the model executor is complete. + void OnExtractWalletablePass( + optimization_guide::OptimizationGuideModelExecutionResult result, + std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry); + + // A raw reference to the client, which owns `this` and therefore outlives + // it. + const raw_ref<WalletablePassClient> client_; + + base::WeakPtrFactory<WalletablePassIngestionController> weak_ptr_factory_{ + this}; }; } // namespace wallet
diff --git a/components/wallet/core/browser/walletable_pass_ingestion_controller_test_api.h b/components/wallet/core/browser/walletable_pass_ingestion_controller_test_api.h new file mode 100644 index 0000000..65321c6 --- /dev/null +++ b/components/wallet/core/browser/walletable_pass_ingestion_controller_test_api.h
@@ -0,0 +1,49 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_INGESTION_CONTROLLER_TEST_API_H_ +#define COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_INGESTION_CONTROLLER_TEST_API_H_ + +#include <string> + +#include "base/check_deref.h" +#include "base/memory/raw_ref.h" +#include "components/wallet/core/browser/walletable_pass_ingestion_controller.h" +#include "url/gurl.h" + +namespace optimization_guide::proto { +class AnnotatedPageContent; +} + +namespace wallet { + +// Exposes some testing operations for WalletablePassIngestionController. +class WalletablePassIngestionControllerTestApi { + public: + explicit WalletablePassIngestionControllerTestApi( + WalletablePassIngestionController* controller) + : controller_(CHECK_DEREF(controller)) {} + + bool IsEligibleForExtraction(const GURL& url) { + return controller_->IsEligibleForExtraction(url); + } + + void ExtractWalletablePass( + const std::string& url, + const optimization_guide::proto::AnnotatedPageContent& content) { + controller_->ExtractWalletablePass(url, content); + } + + private: + const raw_ref<WalletablePassIngestionController> controller_; +}; + +inline WalletablePassIngestionControllerTestApi test_api( + WalletablePassIngestionController* controller) { + return WalletablePassIngestionControllerTestApi(controller); +} + +} // namespace wallet + +#endif // COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_INGESTION_CONTROLLER_TEST_API_H_
diff --git a/components/wallet/core/browser/walletable_pass_ingestion_controller_unittest.cc b/components/wallet/core/browser/walletable_pass_ingestion_controller_unittest.cc index 4a26fe2..1a6d87d 100644 --- a/components/wallet/core/browser/walletable_pass_ingestion_controller_unittest.cc +++ b/components/wallet/core/browser/walletable_pass_ingestion_controller_unittest.cc
@@ -4,64 +4,111 @@ #include "components/wallet/core/browser/walletable_pass_ingestion_controller.h" +#include <memory> + #include "components/optimization_guide/core/hints/mock_optimization_guide_decider.h" +#include "components/optimization_guide/core/mock_optimization_guide_model_executor.h" +#include "components/wallet/core/browser/walletable_pass_client.h" +#include "components/wallet/core/browser/walletable_pass_ingestion_controller_test_api.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" -using testing::Eq; -using testing::Matcher; +using optimization_guide::ModelBasedCapabilityKey::kWalletablePassExtraction; +using optimization_guide::OptimizationGuideDecision::kFalse; +using optimization_guide::OptimizationGuideDecision::kTrue; +using optimization_guide::proto::WALLETABLE_PASS_DETECTION_ALLOWLIST; +using testing::_; using testing::Return; namespace wallet { namespace { -class WalletablePassIngestionControllerTest : public testing::Test { +class MockWalletablePassClient : public WalletablePassClient { public: - WalletablePassIngestionControllerTest() : controller_(&mock_decider_) {} + MOCK_METHOD(optimization_guide::OptimizationGuideDecider*, + GetOptimizationGuideDecider, + (), + (override)); + MOCK_METHOD(optimization_guide::OptimizationGuideModelExecutor*, + GetOptimizationGuideModelExecutor, + (), + (override)); +}; +class WalletablePassIngestionControllerTest : public testing::Test { protected: + WalletablePassIngestionControllerTest() = default; + + void SetUp() override { + ON_CALL(mock_client_, GetOptimizationGuideDecider()) + .WillByDefault(Return(&mock_decider_)); + ON_CALL(mock_client_, GetOptimizationGuideModelExecutor()) + .WillByDefault(Return(&mock_model_executor_)); + controller_ = + std::make_unique<WalletablePassIngestionController>(&mock_client_); + } + + WalletablePassIngestionController* controller() { return controller_.get(); } + optimization_guide::MockOptimizationGuideDecider& mock_decider() { + return mock_decider_; + } + optimization_guide::MockOptimizationGuideModelExecutor& + mock_model_executor() { + return mock_model_executor_; + } + + private: testing::NiceMock<optimization_guide::MockOptimizationGuideDecider> mock_decider_; + testing::NiceMock<optimization_guide::MockOptimizationGuideModelExecutor> + mock_model_executor_; + testing::NiceMock<MockWalletablePassClient> mock_client_; - WalletablePassIngestionController controller_; + std::unique_ptr<WalletablePassIngestionController> controller_; }; TEST_F(WalletablePassIngestionControllerTest, IsEligibleForExtraction_NonHttpUrl_NotEligible) { GURL file_url("file:///test.html"); - EXPECT_FALSE(controller_.IsEligibleForExtraction(file_url)); + EXPECT_FALSE(test_api(controller()).IsEligibleForExtraction(file_url)); GURL ftp_url("ftp://example.com"); - EXPECT_FALSE(controller_.IsEligibleForExtraction(ftp_url)); + EXPECT_FALSE(test_api(controller()).IsEligibleForExtraction(ftp_url)); } TEST_F(WalletablePassIngestionControllerTest, IsEligibleForExtraction_AllowlistedUrl) { GURL https_url("https://example.com"); - EXPECT_CALL( - mock_decider_, - CanApplyOptimization( - Eq(https_url), - Eq(optimization_guide::proto::WALLETABLE_PASS_DETECTION_ALLOWLIST), - Matcher<optimization_guide::OptimizationMetadata*>(Eq(nullptr)))) - .WillOnce(Return(optimization_guide::OptimizationGuideDecision::kTrue)); + EXPECT_CALL(mock_decider(), + CanApplyOptimization( + https_url, WALLETABLE_PASS_DETECTION_ALLOWLIST, nullptr)) + .WillOnce(Return(kTrue)); - EXPECT_TRUE(controller_.IsEligibleForExtraction(https_url)); + EXPECT_TRUE(test_api(controller()).IsEligibleForExtraction(https_url)); } TEST_F(WalletablePassIngestionControllerTest, IsEligibleForExtraction_NotAllowlistedUrl) { GURL http_url("http://example.com"); - EXPECT_CALL( - mock_decider_, - CanApplyOptimization( - Eq(http_url), - Eq(optimization_guide::proto::WALLETABLE_PASS_DETECTION_ALLOWLIST), - Matcher<optimization_guide::OptimizationMetadata*>(Eq(nullptr)))) - .WillOnce(Return(optimization_guide::OptimizationGuideDecision::kFalse)); + EXPECT_CALL(mock_decider(), + CanApplyOptimization( + http_url, WALLETABLE_PASS_DETECTION_ALLOWLIST, nullptr)) + .WillOnce(Return(kFalse)); - EXPECT_FALSE(controller_.IsEligibleForExtraction(http_url)); + EXPECT_FALSE(test_api(controller()).IsEligibleForExtraction(http_url)); +} + +TEST_F(WalletablePassIngestionControllerTest, + ExtractWalletablePass_CallsModelExecutor) { + std::string url = "https://example.com"; + optimization_guide::proto::AnnotatedPageContent content; + content.set_tab_id(123); + + EXPECT_CALL(mock_model_executor(), + ExecuteModel(kWalletablePassExtraction, _, _, _)); + + test_api(controller()).ExtractWalletablePass(url, content); } } // namespace
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc index 9d1b26f..57de7917 100644 --- a/content/browser/accessibility/accessibility_win_browsertest.cc +++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -6659,4 +6659,82 @@ win_event_waiter.Wait(); } +class AccessibilityWinNarratorContainmentEnabledBrowserTest + : public AccessibilityWinUIABrowserTest { + private: + base::test::ScopedFeatureList scoped_feature_list_; + void SetUp() override { + // UIA provider is already enabled by AccessibilityWinUIABrowserTest. + // Only enable the mitigation flag here. + scoped_feature_list_.InitAndEnableFeature( + ::features::kFixNarratorWebContentContainment); + AccessibilityWinUIABrowserTest::SetUp(); + } +}; + +// TODO: Enable this test. Currently disabled because the parent in the test environment +// isn't the same as the parent in prod. +IN_PROC_BROWSER_TEST_F(AccessibilityWinNarratorContainmentEnabledBrowserTest, + DISABLED_ParentClassNameIsChromeWidgetWin1) { + LoadInitialAccessibilityTreeFromHtml(R"HTML(<!doctype html><html></html>)HTML"); + + // 1. Get the HWND that hosts the web contents, then the UIA element for it. + RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>( + shell()->web_contents()->GetRenderWidgetHostView()); + ASSERT_NE(nullptr, rwhva); + HWND hwnd = rwhva->AccessibilityGetAcceleratedWidget(); + ASSERT_NE(gfx::kNullAcceleratedWidget, hwnd); + + Microsoft::WRL::ComPtr<IUIAutomation> uia; + ASSERT_HRESULT_SUCCEEDED(CoCreateInstance(CLSID_CUIAutomation, nullptr, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&uia))); + + Microsoft::WRL::ComPtr<IUIAutomationElement> hwnd_elem; + ASSERT_HRESULT_SUCCEEDED(uia->ElementFromHandle(hwnd, &hwnd_elem)); + ASSERT_NE(nullptr, hwnd_elem.Get()); + + // 2) Get the parent of the web content element with a walker. + Microsoft::WRL::ComPtr<IUIAutomationTreeWalker> walker; + ASSERT_HRESULT_SUCCEEDED(uia->get_ControlViewWalker(&walker)); + + Microsoft::WRL::ComPtr<IUIAutomationElement> content_root; + ASSERT_HRESULT_SUCCEEDED(walker->GetFirstChildElement(hwnd_elem.Get(), + &content_root)); + ASSERT_NE(nullptr, content_root.Get()); + + Microsoft::WRL::ComPtr<IUIAutomationElement> parent_elem; + ASSERT_HRESULT_SUCCEEDED(walker->GetParentElement(content_root.Get(), + &parent_elem)); + ASSERT_NE(nullptr, parent_elem.Get()); + + // 3) Assert ClassName. + // + // Windows Narrator’s Scan Mode only contains navigation within web content when + // the UIA parent of the document reports the class name "Chrome_WidgetWin_1". + // Chromium currently supplies that via a temporary mitigation in + // ViewAccessibility::OnViewAddedToWidget(), gated by + // features::kFixNarratorWebContentContainment. + // + // If this test fails: + // 1) You likely broke Narrator’s web-content containment (users may arrow + // out of the page in Scan Mode). + // 2) If the failure is due to a class name change, update the string we set + // in ViewAccessibility::OnViewAddedToWidget() to the new expected value, + // and adjust this assertion to match. + // 3) If the behavior changed or you’re unsure, reach out to the Accessibility team. + // + // Notes: + // - This intentionally asserts the *exact* UIA class name. + // - There is a paired test with the feature disabled that expects + // "ContentsContainerView" to guard the baseline. + // - This is a stopgap until Narrator updates its tab-boundary heuristic. + // - See crbug.com/443225250 for background. + base::win::ScopedBstr class_name; + ASSERT_HRESULT_SUCCEEDED( + parent_elem->get_CurrentClassName(class_name.Receive())); + ASSERT_TRUE(class_name.Get() != nullptr); + EXPECT_STREQ(L"Chrome_WidgetWin_1", class_name.Get()); +} + } // namespace content
diff --git a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc index 0eea939..c3c28a0 100644 --- a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc +++ b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
@@ -1287,23 +1287,22 @@ wgpu::Device device_b = GetNewDevice(); // Associate both mailboxes - gpu::webgpu::ReservedTexture reservation_a = - webgpu()->ReserveTexture(device_a.Get()); - webgpu()->AssociateMailbox( - reservation_a.deviceId, reservation_a.deviceGeneration, reservation_a.id, - reservation_a.generation, WGPUTextureUsage_RenderAttachment, - webgpu::WEBGPU_MAILBOX_NONE, shared_image_a->mailbox()); + wgpu::TextureDescriptor desc = {.usage = + wgpu::TextureUsage::RenderAttachment}; - gpu::webgpu::ReservedTexture reservation_b = - webgpu()->ReserveTexture(device_b.Get()); - webgpu()->AssociateMailbox( - reservation_b.deviceId, reservation_b.deviceGeneration, reservation_b.id, - reservation_b.generation, WGPUTextureUsage_RenderAttachment, - webgpu::WEBGPU_MAILBOX_NONE, shared_image_b->mailbox()); + std::unique_ptr<WebGPUTextureScopedAccess> webgpu_scoped_access_a = + shared_image_a->BeginWebGPUTextureAccess( + webgpu(), sii->GenVerifiedSyncToken(), device_a, desc, /*usage=*/0, + webgpu::WEBGPU_MAILBOX_NONE); + + std::unique_ptr<WebGPUTextureScopedAccess> webgpu_scoped_access_b = + shared_image_b->BeginWebGPUTextureAccess( + webgpu(), sii->GenVerifiedSyncToken(), device_b, desc, /*usage=*/0, + webgpu::WEBGPU_MAILBOX_NONE); // Dissociate both mailboxes in the same order. - webgpu()->DissociateMailbox(reservation_a.id, reservation_a.generation); - webgpu()->DissociateMailbox(reservation_b.id, reservation_b.generation); + WebGPUTextureScopedAccess::EndAccess(std::move(webgpu_scoped_access_a)); + WebGPUTextureScopedAccess::EndAccess(std::move(webgpu_scoped_access_b)); // Send all the previous commands to the WebGPU decoder. webgpu()->FlushCommands(); @@ -1312,51 +1311,6 @@ // Test that passing a descriptor to ReserveTexture produces a client-side // WGPUTexture that correctly reflects said descriptor. TEST_P(WebGPUMailboxTextureTest, ReflectionOfDescriptor) { - // Check that reserving a texture with a full descriptor give the same data - // back through reflection. - wgpu::TextureDescriptor desc1 = {}; - desc1.size = {1, 2, 3}; - desc1.format = wgpu::TextureFormat::R32Float; - desc1.usage = wgpu::TextureUsage::CopyDst; - desc1.dimension = wgpu::TextureDimension::e2D; - desc1.sampleCount = 1; - desc1.mipLevelCount = 1; - gpu::webgpu::ReservedTexture reservation1 = webgpu()->ReserveTexture( - device_.Get(), reinterpret_cast<const WGPUTextureDescriptor*>(&desc1)); - wgpu::Texture texture1 = wgpu::Texture::Acquire(reservation1.texture); - - ASSERT_EQ(desc1.size.width, texture1.GetWidth()); - ASSERT_EQ(desc1.size.height, texture1.GetHeight()); - ASSERT_EQ(desc1.size.depthOrArrayLayers, texture1.GetDepthOrArrayLayers()); - ASSERT_EQ(desc1.format, texture1.GetFormat()); - ASSERT_EQ(desc1.usage, texture1.GetUsage()); - ASSERT_EQ(desc1.dimension, texture1.GetDimension()); - ASSERT_EQ(desc1.sampleCount, texture1.GetSampleCount()); - ASSERT_EQ(desc1.mipLevelCount, texture1.GetMipLevelCount()); - - // Test with a different descriptor to check data is not hardcoded. Not that - // this is actually not a valid descriptor (diimension == 1D with height != - // 1), but that it should still be reflected exactly. - wgpu::TextureDescriptor desc2 = {}; - desc2.size = {4, 5, 6}; - desc2.format = wgpu::TextureFormat::RGBA8Unorm; - desc2.usage = wgpu::TextureUsage::CopySrc; - desc2.dimension = wgpu::TextureDimension::e1D; - desc2.sampleCount = 4; - desc2.mipLevelCount = 3; - gpu::webgpu::ReservedTexture reservation2 = webgpu()->ReserveTexture( - device_.Get(), reinterpret_cast<const WGPUTextureDescriptor*>(&desc2)); - wgpu::Texture texture2 = wgpu::Texture::Acquire(reservation2.texture); - - ASSERT_EQ(desc2.size.width, texture2.GetWidth()); - ASSERT_EQ(desc2.size.height, texture2.GetHeight()); - ASSERT_EQ(desc2.size.depthOrArrayLayers, texture2.GetDepthOrArrayLayers()); - ASSERT_EQ(desc2.format, texture2.GetFormat()); - ASSERT_EQ(desc2.usage, texture2.GetUsage()); - ASSERT_EQ(desc2.dimension, texture2.GetDimension()); - ASSERT_EQ(desc2.sampleCount, texture2.GetSampleCount()); - ASSERT_EQ(desc2.mipLevelCount, texture2.GetMipLevelCount()); - // Associate mailboxes so that releasing the reserved wgpu::Textures does not // fail. Note that these texture parameters do not match. It doesn't matter // since the textures are not used in this test except for frontend @@ -1376,14 +1330,60 @@ GetSharedImageUsage(AccessType::Read), "TestLabel"}, kNullSurfaceHandle); - webgpu()->AssociateMailbox( - reservation1.deviceId, reservation1.deviceGeneration, reservation1.id, - reservation1.generation, static_cast<WGPUTextureUsage>(desc1.usage), - webgpu::WEBGPU_MAILBOX_NONE, shared_image1->mailbox()); - webgpu()->AssociateMailbox( - reservation2.deviceId, reservation2.deviceGeneration, reservation2.id, - reservation2.generation, static_cast<WGPUTextureUsage>(desc2.usage), - webgpu::WEBGPU_MAILBOX_NONE, shared_image2->mailbox()); + + // Check that reserving a texture with a full descriptor give the same data + // back through reflection. + wgpu::TextureDescriptor desc1 = {}; + desc1.size = {1, 2, 3}; + desc1.format = wgpu::TextureFormat::R32Float; + desc1.usage = wgpu::TextureUsage::CopyDst; + desc1.dimension = wgpu::TextureDimension::e2D; + desc1.sampleCount = 1; + desc1.mipLevelCount = 1; + + // Test with a different descriptor to check data is not hardcoded. Not that + // this is actually not a valid descriptor (diimension == 1D with height != + // 1), but that it should still be reflected exactly. + wgpu::TextureDescriptor desc2 = {}; + desc2.size = {4, 5, 6}; + desc2.format = wgpu::TextureFormat::RGBA8Unorm; + desc2.usage = wgpu::TextureUsage::CopySrc; + desc2.dimension = wgpu::TextureDimension::e1D; + desc2.sampleCount = 4; + desc2.mipLevelCount = 3; + + std::unique_ptr<WebGPUTextureScopedAccess> webgpu_scoped_access1 = + shared_image1->BeginWebGPUTextureAccess( + webgpu(), sii->GenVerifiedSyncToken(), device_, desc1, /*usage=*/0, + webgpu::WEBGPU_MAILBOX_NONE); + std::unique_ptr<WebGPUTextureScopedAccess> webgpu_scoped_access2 = + shared_image2->BeginWebGPUTextureAccess( + webgpu(), sii->GenVerifiedSyncToken(), device_, desc2, /*usage=*/0, + webgpu::WEBGPU_MAILBOX_NONE); + + wgpu::Texture texture1 = webgpu_scoped_access1->texture(); + wgpu::Texture texture2 = webgpu_scoped_access2->texture(); + + ASSERT_EQ(desc1.size.width, texture1.GetWidth()); + ASSERT_EQ(desc1.size.height, texture1.GetHeight()); + ASSERT_EQ(desc1.size.depthOrArrayLayers, texture1.GetDepthOrArrayLayers()); + ASSERT_EQ(desc1.format, texture1.GetFormat()); + ASSERT_EQ(desc1.usage, texture1.GetUsage()); + ASSERT_EQ(desc1.dimension, texture1.GetDimension()); + ASSERT_EQ(desc1.sampleCount, texture1.GetSampleCount()); + ASSERT_EQ(desc1.mipLevelCount, texture1.GetMipLevelCount()); + + ASSERT_EQ(desc2.size.width, texture2.GetWidth()); + ASSERT_EQ(desc2.size.height, texture2.GetHeight()); + ASSERT_EQ(desc2.size.depthOrArrayLayers, texture2.GetDepthOrArrayLayers()); + ASSERT_EQ(desc2.format, texture2.GetFormat()); + ASSERT_EQ(desc2.usage, texture2.GetUsage()); + ASSERT_EQ(desc2.dimension, texture2.GetDimension()); + ASSERT_EQ(desc2.sampleCount, texture2.GetSampleCount()); + ASSERT_EQ(desc2.mipLevelCount, texture2.GetMipLevelCount()); + + WebGPUTextureScopedAccess::EndAccess(std::move(webgpu_scoped_access1)); + WebGPUTextureScopedAccess::EndAccess(std::move(webgpu_scoped_access2)); } // Test that passing a texture with invalid view formats to AssociateMailbox @@ -1396,9 +1396,6 @@ desc.dimension = wgpu::TextureDimension::e2D; desc.sampleCount = 1; desc.mipLevelCount = 1; - gpu::webgpu::ReservedTexture reservation = webgpu()->ReserveTexture( - device_.Get(), reinterpret_cast<const WGPUTextureDescriptor*>(&desc)); - wgpu::Texture texture = wgpu::Texture::Acquire(reservation.texture); SharedImageInterface* sii = GetSharedImageInterface(); scoped_refptr<gpu::ClientSharedImage> shared_image = @@ -1408,23 +1405,25 @@ GetSharedImageUsage(AccessType::ReadWrite), "TestLabel"}, kNullSurfaceHandle); - WGPUTextureFormat view_formats = { - WGPUTextureFormat_R8Unorm, - }; + wgpu::TextureFormat view_formats = wgpu::TextureFormat::R8Unorm; + desc.viewFormats = &view_formats; + desc.viewFormatCount = 1; // AssociateMailbox may cause validation errors, given the invalid // viewFormats, so wrap it in an error scope. device_.PushErrorScope(wgpu::ErrorFilter::Validation); - webgpu()->AssociateMailbox( - reservation.deviceId, reservation.deviceGeneration, reservation.id, - reservation.generation, static_cast<WGPUTextureUsage>(desc.usage), - &view_formats, 1, webgpu::WEBGPU_MAILBOX_NONE, shared_image->mailbox()); + + std::unique_ptr<WebGPUTextureScopedAccess> webgpu_scoped_access = + shared_image->BeginWebGPUTextureAccess( + webgpu(), sii->GenVerifiedSyncToken(), device_, desc, /*usage=*/0, + webgpu::WEBGPU_MAILBOX_NONE); + device_.PopErrorScope( wgpu::CallbackMode::AllowSpontaneous, [](wgpu::PopErrorScopeStatus, wgpu::ErrorType, wgpu::StringView) {}); // DissociateMailbox should NOT cause validation errors. - webgpu()->DissociateMailbox(reservation.id, reservation.generation); + WebGPUTextureScopedAccess::EndAccess(std::move(webgpu_scoped_access)); } // Test that if some other GL context is current when
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 index c794177..1682af0 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -9c085f15d837f050161bedce2390fa702e289c12 \ No newline at end of file +0c46153b8d84c5f0d98bcae9a1874d4a867c54ac \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 index a544a04..898f9f0f 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -db113675c2ad8cf60d9778600f9710221ba9e5d3 \ No newline at end of file +f200f73ce2452bf3d90e0fe0aa604cc6051b3404 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 index ea3826dc..f186195 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -bdc0dabe504df546455a114409bdea441250ec75 \ No newline at end of file +7efe2dbb38ec876898411a503983285d4063c281 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 index 7f1d67f..13759649d 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -4ccff6cdc582f2f724e9a0c33f1a637bb1aebe91 \ No newline at end of file +3dfe7bd9c8595a284f3370540d679e276e6320c1 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 index 92b7e696..cafc8333 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -45b562afec6106366b603eb5d9aff9a724980f10 \ No newline at end of file +c821f98d7ce81949a05392ddc328fcc833e30532 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 index 396deb8a..dfb251d 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -45ceee3d0178c6a95cad5a8a738896f2b9876c0d \ No newline at end of file +4b389893aeb237f16878ddfc1377e4c9000c59c8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 index 32c2cd60..ed44f18a 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -51a02889ec54352d7db19bafeac6e26030181fc0 \ No newline at end of file +3f38bc273b1ecd66c70da0053dc17b72776b0ab4 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 index 2c86dbb4..4a6ce9e 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -9f347a994255c6dbb9b6fbd11baf65f282a54f0a \ No newline at end of file +2f2bfecb8be6d8c3b977d9086225b8d8737c4419 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 index 8e7a4d9..4b9001a2 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -223e9972022523869e3841f2075d4907648a75e0 \ No newline at end of file +54acb71c2a8746650316c114dabac6d25357d766 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 46383f45..ce38796 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -d96062b89764c89f5334e062757d9b3b2c949785 \ No newline at end of file +536fe04bfa239bace4bac680a86f5325a12da670 \ No newline at end of file
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 6c23927..bea74f66 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 @@ -f1378b14b3b00e79ce5c77116f205cc3c813db82 \ No newline at end of file +8865f29e0edb409401e46dc1ecb7f4bfccef52d8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 index c9cee59..9274ebd8 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -9dace594374b3ce6ed8808d4bb0fe1948b081de7 \ No newline at end of file +d88fed13a1ede7101fbe6d6d7e08d893641e2c7a \ 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 53c7e5f..f0509770 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 @@ -fcf8694a707a6b2cbb50c03e7b78b3a79cc0847b \ No newline at end of file +8fb64219f562488d69e0f4520d6c6ce6a7f8b4d2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 1136925d..111fee0 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -75d8831b35949fd000ad2ceaf6a71c9b84bf45e8 \ No newline at end of file +d05bd82f7515b51c6d51d77bd8768beb18f4d8f1 \ 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 af8d4f8..7fbf237 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 @@ -89f791fdd3073869ab38159b0712dd8bead7dfab \ No newline at end of file +6b55678b743d70466806be708c662136386f8745 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 index ca52ed7..184f8d5 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -f46538a724326fd8318633e6c1114902020429db \ No newline at end of file +794710b30392f08f5cd5fc13056e651c659302cd \ 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 d9a8cb6..c91648d 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 @@ -b3b15e68ca4fd0a2081f123e24f3c35d1bc38a67 \ No newline at end of file +c0482c73232a817821e2f398e97c8c66de512f9d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 index bc23270..8e1fb25 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -3d6e8afa5f346f6361a0747f0e10877546c6268c \ No newline at end of file +107373232828d604ed67204c2e6f1fde74bfaa9c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 index 10c3adf8..43f1daa3 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -806d92d7a3301826135c4a1f8fd70ffe882ed67f \ No newline at end of file +29678ebfcf30150d20539d7c7ec3dace753d1cdd \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 index 87df133..0e31bcd 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -d9ea8a7adc8a1819b80b4f07d7a37e329a50d3b5 \ No newline at end of file +d60bf7194300a79a85b4241c92d84df231de092d \ 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 e406889c..78351e7e4 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 @@ -eeb698facd71f556e6b6609d7b2d8030023188f8 \ No newline at end of file +ae2ac2094093926efbcafc466e596b393cc4c1c4 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 index 0919943..538b0f4 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -e2e1a4372f520263fa7e03cc151acbec99f9402f \ No newline at end of file +fb49e5aaf78e4afc2b6155a7db6978ec8839fb8b \ 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 75e613a14..fdbdc25 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 @@ -37ed1334026702a1512b0d61eead18258ac2c3d1 \ No newline at end of file +65bac264352e14cde048804f7c9012211aa7d3d0 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 index ea68634..0985370a 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -f7e102adb07906a278476c5a87b6a185443e113d \ No newline at end of file +5813bd6fe923699acfa8cac29b6a81fdea2b22e1 \ 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 0cf23b4..2ba3356 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 @@ -262d1823d35332473beed8a5394ddabc465be200 \ No newline at end of file +d2f444f71ca4a4d787cffa451efeb5596baf76e8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 index 4dc39da..9db98e78 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -e69cbd8f9f14aea24453f208308c514f7a9f6149 \ No newline at end of file +dfbdd29a93af4c8d6d5b47bd9ed7896d3b4e1393 \ 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 827b63e6..b29e03d 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 @@ -d7010338ddb97daf4d9dd63d71127671330a148c \ No newline at end of file +d9aa10b0f393917956dff4eb685a84e4f8b09f34 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 76138dfc..9fe5fe7 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -a9e0f201a5c75f1fea44d41fbf95d4de34d378d8 \ No newline at end of file +d88f91ae48ae255b62e13f78b036b61a74237042 \ No newline at end of file
diff --git a/ios_internal b/ios_internal index d7e0303..21d8a0c 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit d7e03032fddf9552e94070778f3cfb775ab89dd2 +Subproject commit 21d8a0cb8e9d5392de3dee97d473f17ca97def28
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins index a9fb9653a..a7199ae 100644 --- a/net/http/transport_security_state_static.pins +++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@ # hash function for preloaded entries again (we have already done so once). # -# Last updated: 2025-09-06 12:53 UTC +# Last updated: 2025-09-07 12:54 UTC PinsListTimestamp -1757163209 +1757249642 TestSPKI sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/net/http/transport_security_state_static_pins.json b/net/http/transport_security_state_static_pins.json index 96441aa..782993f6 100644 --- a/net/http/transport_security_state_static_pins.json +++ b/net/http/transport_security_state_static_pins.json
@@ -31,7 +31,7 @@ // the 'static_spki_hashes' and 'bad_static_spki_hashes' fields in 'pinsets' // refer to, and the timestamp at which the pins list was last updated. // -// Last updated: 2025-09-06 12:53 UTC +// Last updated: 2025-09-07 12:54 UTC // { "pinsets": [
diff --git a/net/third_party/uri_template/README.chromium b/net/third_party/uri_template/README.chromium index c041106..badef8c 100644 --- a/net/third_party/uri_template/README.chromium +++ b/net/third_party/uri_template/README.chromium
@@ -3,10 +3,11 @@ URL: https://github.com/google/google-api-cpp-client/ Revision: d0bbe169d81a50936ec5fcea4e6dbcfb97303f13 Update Mechanism: Manual -Date: August 6, 2018 +Date: 2018-08-06 License: Apache-2.0 License File: LICENSE Shipped: yes +Security Critical: yes Description: This code is derived from the URI template parsing code in the Google API C++
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index d8c010da..36c20b4 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -332509,6 +332509,10 @@ ] }, "sandbox": { + "autoplay-disabled-by-csp-expected.txt": [ + "2d040081d02082ef1e6ad2e27ec67d2b5cba8cee", + [] + ], "service-worker-sandbox.https-expected.txt": [ "e6a2b864198427d716bd6ef32c826dc1d0717a24", [] @@ -332518,6 +332522,14 @@ [] ], "support": { + "autoplay.html": [ + "62d0adc3d204f2df9337bf30343591bfb1958e67", + [] + ], + "autoplay.html.headers": [ + "09e65834224c8b917d0a6a2fae17f79ff251fcb6", + [] + ], "empty.html": [ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", [] @@ -332542,6 +332554,18 @@ "c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b", [] ], + "sandboxed-last-directive-csp.headers": [ + "371abe3b936e686c901cc9f6f366b8c68e6f3f8b", + [] + ], + "sandboxed-last-directive-csp.html": [ + "9480e521de21ef930674721de943f96e1fd1219a", + [] + ], + "sandboxed-post-message-to-parent.headers": [ + "0368ae01896a2cadb6019ab2c1eb5346d9c3b764", + [] + ], "sandboxed-post-message-to-parent.html": [ "ef4b1a0b95a7e00275c423d49dd28f98545950d3", [] @@ -497894,6 +497918,13 @@ ] }, "sandbox": { + "autoplay-disabled-by-csp.html": [ + "1d1ed0e50b7182ed0d1f8ab7d1b7c7b98e709030", + [ + null, + {} + ] + ], "iframe-inside-csp.sub.html": [ "cd402bdba0198bf763e1733004c2005614b9a542", [ @@ -497930,7 +497961,14 @@ ] ], "sandbox-empty.sub.html": [ - "47034710203a1fb8a3326cd7c8d8367166837628", + "47c3aa1e3657cf2eb5acfeb06bd1936b6e117d0f", + [ + null, + {} + ] + ], + "sandbox-last-directive-csp.html": [ + "b4b2cdbe3296dff091594f73dafb4f4791e5ca72", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp-expected.txt b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp-expected.txt new file mode 100644 index 0000000..2d04008 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SecurityError: Failed to read a named property 'document' from 'Window': Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame. +[TIMEOUT] csp-derived sandboxing flags prevent autoplay. + Test timed out +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp.html b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp.html new file mode 100644 index 0000000..1d1ed0e5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> + <head> + <link rel="help" href="https://html.spec.whatwg.org/multipage/#eligible-for-autoplay" /> + <title>Test that autoplay is blocked by a document's active sandboxing flags</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src='../support/logTest.sub.js?logs=["Loaded iframe"]'></script> + <script src="/common/media.js"></script> + </head> + <body> + <iframe id="iframe" src="support/autoplay.html"></iframe> + <script> + async_test((t) => { + iframe.addEventListener('load', () => { + log('Loaded iframe'); + var v = iframe.contentWindow.document.getElementById('v'); + + v.addEventListener('playing', t.unreached_func( + 'video should not autoplay due to sandboxing flags' + )); + + v.src = getVideoURI('/media/movie_5') + '?' + new Date() + Math.random() + t.step_timeout(() => t.done(), 500); + }); + }, 'csp-derived sandboxing flags prevent autoplay.') + </script> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-empty.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-empty.sub.html index 4703471..47c3aa1 100644 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-empty.sub.html +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-empty.sub.html
@@ -18,7 +18,7 @@ } </script> - <iframe src="support/sandboxed-post-message-to-parent.sub.html?sandbox=" + <iframe src="support/sandboxed-post-message-to-parent.html" onload="log('PASS2')"></iframe> </body>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-last-directive-csp.html b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-last-directive-csp.html new file mode 100644 index 0000000..b4b2cdb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-last-directive-csp.html
@@ -0,0 +1,18 @@ +<html> +<head> + <!-- Programmatically converted from a WebKit Reftest, please forgive resulting idiosyncracies.--> + <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' 'self'; connect-src 'self';"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src='../support/logTest.sub.js?logs=["PASS (1/2): Script can execute","PASS (2/2): Eval works"]'></script> + <script src='../support/alertAssert.sub.js?alerts=[]'></script> +</head> +<body> + <script> + window.onmessage = function(e) { + log(e.data); + } + </script> + <iframe src="support/sandboxed-last-directive-csp.html"></iframe> +</body> +</html> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html new file mode 100644 index 0000000..62d0adc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html
@@ -0,0 +1 @@ +<video id="v" autoplay></video>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html.headers new file mode 100644 index 0000000..09e6583 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html.headers
@@ -0,0 +1 @@ +Content-Security-Policy: sandbox \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.headers new file mode 100644 index 0000000..371abe3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.headers
@@ -0,0 +1 @@ +Content-Security-Policy: sandbox; sandbox allow-scripts \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.html b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.html new file mode 100644 index 0000000..9480e52 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.html
@@ -0,0 +1,4 @@ +<script> + window.parent.postMessage('PASS (1/2): Script can execute', '*'); + eval("window.parent.postMessage('PASS (2/2): Eval works', '*')"); +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-post-message-to-parent.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-post-message-to-parent.headers new file mode 100644 index 0000000..0368ae0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-post-message-to-parent.headers
@@ -0,0 +1 @@ +Content-Security-Policy: sandbox
diff --git a/third_party/boringssl/src b/third_party/boringssl/src index b6b33a8..0226f30 160000 --- a/third_party/boringssl/src +++ b/third_party/boringssl/src
@@ -1 +1 @@ -Subproject commit b6b33a84ed7badd0441cec1324ba3ef7f1d897e2 +Subproject commit 0226f30467f540a3f62ef48d453f93927da199b6
diff --git a/third_party/compiler-rt/src b/third_party/compiler-rt/src index 0c75031..514effe 160000 --- a/third_party/compiler-rt/src +++ b/third_party/compiler-rt/src
@@ -1 +1 @@ -Subproject commit 0c75031f1b7a0556a6cc07b6aa97a260278c5e0d +Subproject commit 514effe33889c9cd899c10ef7ad1f79fb86ef388
diff --git a/third_party/crashpad/crashpad/third_party/cpp-httplib/README.crashpad b/third_party/crashpad/crashpad/third_party/cpp-httplib/README.crashpad index df90727..7564e12 100644 --- a/third_party/crashpad/crashpad/third_party/cpp-httplib/README.crashpad +++ b/third_party/crashpad/crashpad/third_party/cpp-httplib/README.crashpad
@@ -6,7 +6,7 @@ Update Mechanism: Manual License: MIT License File: cpp-httplib/LICENSE -Security Critical: no (test only) +Security Critical: no Shipped: no CPEPrefix: cpe:/a:cpp-httplib_project:cpp-httplib
diff --git a/third_party/dawn b/third_party/dawn index f1d98be..7e45e46 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit f1d98befa15c18fddc72c68ea9f5278800fb813b +Subproject commit 7e45e468cf42e3c0d21d539010fc06b839021b62
diff --git a/third_party/fuchsia-gn-sdk/README.chromium b/third_party/fuchsia-gn-sdk/README.chromium index dabbe4a5..24551cf1 100644 --- a/third_party/fuchsia-gn-sdk/README.chromium +++ b/third_party/fuchsia-gn-sdk/README.chromium
@@ -6,9 +6,10 @@ License: BSD-2-Clause License File: LICENSE Date: 2024-02-26 -Update Mechanism: Static +Update Mechanism: Static (https://crbug.com/422063622) Description: +Pending ATL review for Static exception. This directory contains the files that complement the Fuchsia SDK for projects that use the GN build tool. The files in src/ were originally copied from
diff --git a/third_party/perfetto b/third_party/perfetto index 67f0bdf..93825934 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit 67f0bdf7285d15783e7ee55c1e5d524887d43f33 +Subproject commit 93825934c10d3a8179e1b8b840bbe1fd7f64a913
diff --git a/third_party/skia b/third_party/skia index 064cf12..310062a 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 064cf12ad0cce462f4c2871ddbe6642746bc91ee +Subproject commit 310062ae6aee31778717d28b8fb33536dc642a4b
diff --git a/third_party/updater/README.chromium b/third_party/updater/README.chromium index 510e1b1..c4a9a1b 100644 --- a/third_party/updater/README.chromium +++ b/third_party/updater/README.chromium
@@ -1,5 +1,5 @@ Name: ChromiumUpdater -URL: https://chromium.googlesource.com/chromium/src/+/main/chrome/updater/README.md +URL: Internal Version: N/A Revision: DEPS Update Mechanism: Manual @@ -24,3 +24,5 @@ To update the versions of the updater in this directory, wait for the version you want to become available in CIPD, then update /DEPS to point to it. If the files change, you may also have to update ./BUILD.gn. + +For more info see https://chromium.googlesource.com/chromium/src/+/main/chrome/updater/README.md
diff --git a/third_party/webrtc b/third_party/webrtc index 0b49772..981d111 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 0b497723227dcfa52047ca9d136b1ffbe130ea68 +Subproject commit 981d111a875397315b34fa6889809c8862feb60d
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 1f3096e..ae74010 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "full_remote_path": "perfetto-luci-artifacts/d17b40b3b5e36f3744f1d010fe3ba2d3c55559c0/linux-arm64/trace_processor_shell" }, "win": { - "hash": "221d9ddf67dbfe98d176e5b21d7f111eec1ed899", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/67f0bdf7285d15783e7ee55c1e5d524887d43f33/trace_processor_shell.exe" + "hash": "9d3f883a8404ec4cd731460ce94070cb222614b8", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/93825934c10d3a8179e1b8b840bbe1fd7f64a913/trace_processor_shell.exe" }, "linux_arm": { "hash": "d2819bf77c3920780f2b33cc43f328d24cc1e427", @@ -22,7 +22,7 @@ }, "linux": { "hash": "381f28daa9257db8026190b94133a173fe3d6bab", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/67f0bdf7285d15783e7ee55c1e5d524887d43f33/trace_processor_shell" + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/93825934c10d3a8179e1b8b840bbe1fd7f64a913/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc index ff8ee8a..d37256a 100644 --- a/ui/accessibility/accessibility_features.cc +++ b/ui/accessibility/accessibility_features.cc
@@ -196,6 +196,15 @@ } #if BUILDFLAG(IS_WIN) +BASE_FEATURE(kFixNarratorWebContentContainment, + "FixNarratorWebContentContainment", + base::FEATURE_ENABLED_BY_DEFAULT); + +bool IsFixNarratorWebContentContainmentEnabled() { + return base::FeatureList::IsEnabled( + ::features::kFixNarratorWebContentContainment); +} + BASE_FEATURE(kIChromeAccessible, "IChromeAccessible", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h index 3820dea..609a3a46 100644 --- a/ui/accessibility/accessibility_features.h +++ b/ui/accessibility/accessibility_features.h
@@ -154,6 +154,12 @@ AX_BASE_EXPORT bool IsAccessibilityOnScreenAXModeEnabled(); #if BUILDFLAG(IS_WIN) +// When enabled, modify the exposed UIA accessibility tree to match Narrator's +// expectations. This fixes a bug keeping Narrator's cursor contained within +// the web content. +AX_BASE_EXPORT BASE_DECLARE_FEATURE(kFixNarratorWebContentContainment); +AX_BASE_EXPORT bool IsFixNarratorWebContentContainmentEnabled(); + // Use Chrome-specific accessibility COM API. AX_BASE_EXPORT BASE_DECLARE_FEATURE(kIChromeAccessible); AX_BASE_EXPORT bool IsIChromeAccessibleEnabled();
diff --git a/ui/color/color_provider_utils.cc b/ui/color/color_provider_utils.cc index eb000032..e458754 100644 --- a/ui/color/color_provider_utils.cc +++ b/ui/color/color_provider_utils.cc
@@ -143,66 +143,6 @@ ColorProviderUtilsCallbacks::~ColorProviderUtilsCallbacks() = default; -std::string_view ColorModeName(ColorProviderKey::ColorMode color_mode) { - switch (color_mode) { - case ColorProviderKey::ColorMode::kLight: - return "kLight"; - case ColorProviderKey::ColorMode::kDark: - return "kDark"; - default: - return "<invalid>"; - } -} - -std::string_view ContrastModeName( - ColorProviderKey::ContrastMode contrast_mode) { - switch (contrast_mode) { - case ColorProviderKey::ContrastMode::kNormal: - return "kNormal"; - case ColorProviderKey::ContrastMode::kHigh: - return "kHigh"; - default: - return "<invalid>"; - } -} - -std::string_view ForcedColorsName( - ColorProviderKey::ForcedColors forced_colors) { - switch (forced_colors) { - case ColorProviderKey::ForcedColors::kNone: - return "kNone"; - case ColorProviderKey::ForcedColors::kSystem: - return "kSystem"; - case ColorProviderKey::ForcedColors::kDusk: - return "kDusk"; - case ColorProviderKey::ForcedColors::kDesert: - return "kDesert"; - case ColorProviderKey::ForcedColors::kNightSky: - return "kNightSky"; - case ColorProviderKey::ForcedColors::kWhite: - return "kWhite"; - case ColorProviderKey::ForcedColors::kAquatic: - return "kAquatic"; - default: - return "<invalid>"; - } -} - -std::string_view SystemThemeName(ui::SystemTheme system_theme) { - switch (system_theme) { - case ui::SystemTheme::kDefault: - return "kDefault"; -#if BUILDFLAG(IS_LINUX) - case ui::SystemTheme::kGtk: - return "kGtk"; - case ui::SystemTheme::kQt: - return "kQt"; -#endif - default: - return "<invalid>"; - } -} - #include "ui/color/color_id_map_macros.inc" std::string ColorIdName(ColorId color_id) {
diff --git a/ui/color/color_provider_utils.h b/ui/color/color_provider_utils.h index 01c6987..019223a 100644 --- a/ui/color/color_provider_utils.h +++ b/ui/color/color_provider_utils.h
@@ -32,22 +32,6 @@ // logging. Do not retain the results for longer than the scope in which these // functions are called. -// Converts the ColorMode. -std::string_view COMPONENT_EXPORT(COLOR) - ColorModeName(ColorProviderKey::ColorMode color_mode); - -// Converts the ContrastMode. -std::string_view COMPONENT_EXPORT(COLOR) - ContrastModeName(ColorProviderKey::ContrastMode contrast_mode); - -// Converts the ForcedColors. -std::string_view COMPONENT_EXPORT(COLOR) - ForcedColorsName(ColorProviderKey::ForcedColors forced_colors); - -// Converts SystemTheme. -std::string_view COMPONENT_EXPORT(COLOR) - SystemThemeName(ui::SystemTheme system_theme); - // Converts ColorId. std::string COMPONENT_EXPORT(COLOR) ColorIdName(ColorId color_id);
diff --git a/ui/color/win/native_color_mixers_win.cc b/ui/color/win/native_color_mixers_win.cc index 179dc53..f18031f 100644 --- a/ui/color/win/native_color_mixers_win.cc +++ b/ui/color/win/native_color_mixers_win.cc
@@ -21,7 +21,6 @@ #include "ui/color/color_transform.h" #include "ui/color/win/accent_color_observer.h" #include "ui/gfx/color_palette.h" -#include "ui/gfx/color_utils.h" namespace ui {
diff --git a/ui/views/accessibility/view_accessibility.cc b/ui/views/accessibility/view_accessibility.cc index 752ab583..e5943a0 100644 --- a/ui/views/accessibility/view_accessibility.cc +++ b/ui/views/accessibility/view_accessibility.cc
@@ -968,11 +968,27 @@ } void ViewAccessibility::OnViewAddedToWidget() { - // Ideally, we would like to set the class name when the object is created, - // this would be done in the ctor, but due to inheritance and the - // implementation of `GetClassName`, it would not work. As such, we set it - // here, since at this point the view object is fully initialized. - SetClassName(std::string(view_->GetClassName())); + // The accessibility class name is set after the view has been attached + // to a widget, ensuring the object is fully constructed and its class + // name is stable. + std::string effective_class = std::string(view_->GetClassName()); + +#if BUILDFLAG(IS_WIN) + // On Windows, Narrator restricts focus to web content in Scan Mode only when + // the root web area’s parent has class name "Chrome_WidgetWin_1". This is a + // hardcoded behavior. It worked before Chromium enabled UIA by default, since + // the MSAA Proxy added the root web area under a window with that class name. + // We’re collaborating with the Narrator team to update their tab detection + // logic, but rollout will take time. This is a temporary mitigation. See + // https://crbug.com/443225250 for details. + if (::ui::AXPlatform::GetInstance().IsUiaProviderEnabled() && + features::IsFixNarratorWebContentContainmentEnabled() && + effective_class == "ContentsContainerView") { + effective_class = "Chrome_WidgetWin_1"; + } +#endif // BUILDFLAG(IS_WIN) + + SetClassName(effective_class); } void ViewAccessibility::SetPlaceholder(const std::string& placeholder) {
diff --git a/url/third_party/mozilla/README.chromium b/url/third_party/mozilla/README.chromium index 94c80db..bac6348 100644 --- a/url/third_party/mozilla/README.chromium +++ b/url/third_party/mozilla/README.chromium
@@ -1,7 +1,7 @@ Name: url_parse Version: unknown URL: https://hg.mozilla.org/mozilla-central/file/tip/netwerk/base/nsURLParsers.cpp -License: MPLv2 +License: MPL-2 License File: LICENSE.txt Shipped: yes Security Critical: yes