From 2392f37108d54e7570f3e5173d89e009864ba098 Mon Sep 17 00:00:00 2001 From: Andrew Grieve Date: Tue, 21 May 2024 15:31:46 +0000 Subject: [PATCH 01/40] Android: Prevent new Robolectric shadows via an allowlist Bug: b/341267427 Change-Id: I7e02f3ef4ef69930579727735acdb40b0581622c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5545930 Commit-Queue: Andrew Grieve Reviewed-by: Henrique Nakashima Cr-Commit-Position: refs/heads/main@{#1303784} --- .../pylib/junit/junit_test_instance.py | 5 + .../machine/local_machine_junit_test_run.py | 11 ++- build/android/test_runner.py | 2 + build/config/android/internal_rules.gni | 8 ++ styleguide/java/java.md | 12 ++- testing/android/junit/BUILD.gn | 2 + .../org/chromium/testing/local/Allowlist.java | 86 ++++++++++++++++++ .../testing/local/JunitTestArgParser.java | 8 ++ .../chromium/testing/local/JunitTestMain.java | 2 +- .../testing/local/TestListComputer.java | 36 +++++++- .../testing/local/TestListComputerTest.java | 60 ++++++++++++ testing/android/junit/shadows-allowlist.txt | 91 +++++++++++++++++++ 12 files changed, 310 insertions(+), 13 deletions(-) create mode 100644 testing/android/junit/java/src/org/chromium/testing/local/Allowlist.java create mode 100644 testing/android/junit/javatests/src/org/chromium/testing/local/TestListComputerTest.java create mode 100644 testing/android/junit/shadows-allowlist.txt diff --git a/build/android/pylib/junit/junit_test_instance.py b/build/android/pylib/junit/junit_test_instance.py index 1be919b4d24941..4b6b868b56f35a 100644 --- a/build/android/pylib/junit/junit_test_instance.py +++ b/build/android/pylib/junit/junit_test_instance.py @@ -21,6 +21,7 @@ def __init__(self, args, _): self._robolectric_runtime_deps_dir = args.robolectric_runtime_deps_dir self._runner_filter = args.runner_filter self._json_config = args.json_config + self._shadows_allowlist = args.shadows_allowlist self._shards = args.shards self._shard_filter = None if args.shard_filter: @@ -72,6 +73,10 @@ def robolectric_runtime_deps_dir(self): def runner_filter(self): return self._runner_filter + @property + def shadows_allowlist(self): + return self._shadows_allowlist + @property def test_filters(self): return self._test_filters diff --git a/build/android/pylib/local/machine/local_machine_junit_test_run.py b/build/android/pylib/local/machine/local_machine_junit_test_run.py index 553cc17166350f..c35b6e5d2a80b4 100644 --- a/build/android/pylib/local/machine/local_machine_junit_test_run.py +++ b/build/android/pylib/local/machine/local_machine_junit_test_run.py @@ -155,7 +155,10 @@ def _wrapper_path(self): return os.path.join(constants.GetOutDirectory(), 'bin', 'helper', self._test_instance.suite) - def _QueryTestJsonConfig(self, temp_dir, allow_debugging=True): + def _QueryTestJsonConfig(self, + temp_dir, + allow_debugging=True, + enable_shadow_allowlist=False): json_config_path = os.path.join(temp_dir, 'main_test_config.json') cmd = [self._wrapper_path] # Allow debugging of test listing when run as: @@ -166,6 +169,8 @@ def _QueryTestJsonConfig(self, temp_dir, allow_debugging=True): cmd += ['--jvm-args', '"%s"' % ' '.join(jvm_args)] cmd += ['--classpath', self._CreatePropertiesJar(temp_dir)] cmd += ['--list-tests', '--json-config', json_config_path] + if enable_shadow_allowlist and self._test_instance.shadows_allowlist: + cmd += ['--shadows-allowlist', self._test_instance.shadows_allowlist] cmd += self._GetFilterArgs() subprocess.run(cmd, check=True) with open(json_config_path) as f: @@ -227,7 +232,9 @@ def _RunTestsInternal(self, temp_dir, results, raw_logs_fh): # TODO(crbug.com/40878339): This step can take 3-4 seconds for # chrome_junit_tests. try: - json_config = self._QueryTestJsonConfig(temp_dir, allow_debugging=False) + json_config = self._QueryTestJsonConfig(temp_dir, + allow_debugging=False, + enable_shadow_allowlist=True) except subprocess.CalledProcessError: results.append(_MakeUnknownFailureResult('Filter matched no tests')) return diff --git a/build/android/test_runner.py b/build/android/test_runner.py index 8ec41cdbe3c691..3bb2d416518d20 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py @@ -849,6 +849,8 @@ def AddJUnitTestOptions(parser): '--resource-apk', required=True, help='Path to .ap_ containing binary resources for Robolectric.') + parser.add_argument('--shadows-allowlist', + help='Path to Allowlist file for Shadows.') def AddLinkerTestOptions(parser): diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 31b2133b2f318f..82184f683ad11f 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni @@ -932,6 +932,14 @@ template("test_runner_script") { "--robolectric-runtime-deps-dir", "@WrappedPath(${_rebased_robolectric_runtime_deps_dir})", ] + if (build_with_chromium) { + _allowlist = "//testing/android/junit/shadows-allowlist.txt" + data += [ _allowlist ] + executable_args += [ + "--shadows-allowlist", + rebase_path(_allowlist, root_build_dir), + ] + } if (use_jacoco_coverage) { # Set a default coverage output directory (can be overridden by user # passing the same flag). diff --git a/styleguide/java/java.md b/styleguide/java/java.md index d4ee486b052a72..4cbd02613d8c86 100644 --- a/styleguide/java/java.md +++ b/styleguide/java/java.md @@ -345,11 +345,13 @@ In summary: * Use real dependencies when feasible and fast. Use Mockito’s `@Mock` most of the time, but write fakes for frequently used dependencies. -* Do not use Robolectric Shadows for Chromium code. Instead, use - `setForTesting()` methods so that it is clear that test hooks exist. - * When `setForTesting()` methods alter global state, use - [`ResettersForTesting.register()`] to ensure that the state is reset - between tests. Omit resetting them via `@After` methods. +* Do not use Robolectric Shadows for Chromium code. + * Shadows make code harder to refactor. + * Prefer to refactor code to make it more testable. + * When you really need to use a test double for a static method, add a + `setFooForTesting() [...]` method to make the test contract explicit. + * Use [`ResettersForTesting.register()`] from within `ForTesting()` + methods to ensure that state is reset between tests. * Use Robolectric when possible (when tests do not require native). Other times, use on-device tests with one of the following annotations: diff --git a/testing/android/junit/BUILD.gn b/testing/android/junit/BUILD.gn index a0287b8c52ddd8..1579acd706bda3 100644 --- a/testing/android/junit/BUILD.gn +++ b/testing/android/junit/BUILD.gn @@ -10,6 +10,7 @@ robolectric_library("junit_test_support") { annotation_processor_deps = [ "//third_party/android_deps:auto_service_processor" ] sources = [ + "java/src/org/chromium/testing/local/Allowlist.java", "java/src/org/chromium/testing/local/ChromiumAndroidConfigurer.java", "java/src/org/chromium/testing/local/ConfigFilter.java", "java/src/org/chromium/testing/local/CustomShadowApplicationPackageManager.java", @@ -40,5 +41,6 @@ robolectric_binary("junit_unit_tests") { "javatests/src/org/chromium/testing/local/GtestLoggerTest.java", "javatests/src/org/chromium/testing/local/PackageFilterTest.java", "javatests/src/org/chromium/testing/local/RunnerFilterTest.java", + "javatests/src/org/chromium/testing/local/TestListComputerTest.java", ] } diff --git a/testing/android/junit/java/src/org/chromium/testing/local/Allowlist.java b/testing/android/junit/java/src/org/chromium/testing/local/Allowlist.java new file mode 100644 index 00000000000000..efd8624f9bad53 --- /dev/null +++ b/testing/android/junit/java/src/org/chromium/testing/local/Allowlist.java @@ -0,0 +1,86 @@ +// 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. + +package org.chromium.testing.local; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * An prefix-matching allowlist implementation. + * + *
+ * - Rules are defined in a file with one rule per-line.
+ * - # Comments are allowed.
+ * - Rules begin with either: "+" or "-" as a prefix (allow vs deny), and
+ *   are followed by a prefix to match.
+ * - Rules are evaluated in order.
+ * - If no rules match, the default is to allow.
+ * 
+ */ +class Allowlist { + + private static class Rule { + final boolean mAllow; + final String mPrefix; + + Rule(boolean allow, String prefix) { + mAllow = allow; + mPrefix = prefix; + } + } + + private final String mFilename; + private final List mRules; + + private Allowlist(String filename, List rules) { + mFilename = filename; + mRules = rules; + } + + public static Allowlist allowAll() { + return new Allowlist("", Collections.emptyList()); + } + + public static Allowlist fromLines(String filename, List lines) { + ArrayList rules = new ArrayList<>(); + for (String line : lines) { + line = line.strip(); + char firstChar = line.isEmpty() ? '#' : line.charAt(0); + if (firstChar == '#') { + continue; + } + if (firstChar != '+' && firstChar != '-') { + throw new RuntimeException("Expected line to start with + or -: " + line); + } + String prefix = line.substring(1); + if (prefix.isEmpty()) { + throw new RuntimeException("Found empty prefix: " + line); + } + rules.add(new Rule(firstChar == '+', prefix)); + } + return new Allowlist(filename, rules); + } + + public static Allowlist fromFile(Path path) throws IOException { + return fromLines(path.toString(), Files.readAllLines(path)); + } + + public String getFilename() { + return mFilename; + } + + public boolean allow(String className) { + for (Rule r : mRules) { + if (className.startsWith(r.mPrefix)) { + return r.mAllow; + } + } + return true; + } +} diff --git a/testing/android/junit/java/src/org/chromium/testing/local/JunitTestArgParser.java b/testing/android/junit/java/src/org/chromium/testing/local/JunitTestArgParser.java index 97b620ee31a453..7715e28edc2ec2 100644 --- a/testing/android/junit/java/src/org/chromium/testing/local/JunitTestArgParser.java +++ b/testing/android/junit/java/src/org/chromium/testing/local/JunitTestArgParser.java @@ -4,6 +4,8 @@ package org.chromium.testing.local; +import java.io.IOException; +import java.nio.file.Path; import java.util.HashSet; import java.util.Set; @@ -12,6 +14,7 @@ public class JunitTestArgParser { final Set mPackageFilters = new HashSet<>(); final Set> mRunnerFilters = new HashSet<>(); final Set mGtestFilters = new HashSet<>(); + Allowlist mShadowsAllowlist = Allowlist.allowAll(); boolean mListTests; String mJsonConfig; String mJsonOutput; @@ -35,6 +38,8 @@ public static JunitTestArgParser parse(String[] args) { parsed.mJsonOutput = args[++i]; } else if ("json-config".equals(argName)) { parsed.mJsonConfig = args[++i]; + } else if ("shadows-allowlist".equals(argName)) { + parsed.mShadowsAllowlist = Allowlist.fromFile(Path.of(args[++i])); } else { System.out.println("Ignoring flag: \"" + argName + "\""); } @@ -44,6 +49,9 @@ public static JunitTestArgParser parse(String[] args) { } catch (ClassNotFoundException e) { System.err.println("Class not found. (" + e + ")"); System.exit(1); + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); } } else { System.out.println("Ignoring argument: \"" + args[i] + "\""); diff --git a/testing/android/junit/java/src/org/chromium/testing/local/JunitTestMain.java b/testing/android/junit/java/src/org/chromium/testing/local/JunitTestMain.java index dec542347e6149..52c01de2ff81b3 100644 --- a/testing/android/junit/java/src/org/chromium/testing/local/JunitTestMain.java +++ b/testing/android/junit/java/src/org/chromium/testing/local/JunitTestMain.java @@ -100,7 +100,7 @@ private static Class classOrNull(String className) { private static Result listTestMain(JunitTestArgParser parser) throws FileNotFoundException, JSONException { JUnitCore core = new JUnitCore(); - TestListComputer computer = new TestListComputer(); + TestListComputer computer = new TestListComputer(parser.mShadowsAllowlist); Class[] classes = findClassesFromClasspath(); Request testRequest = Request.classes(computer, classes); for (String packageFilter : parser.mPackageFilters) { diff --git a/testing/android/junit/java/src/org/chromium/testing/local/TestListComputer.java b/testing/android/junit/java/src/org/chromium/testing/local/TestListComputer.java index 03bc8d6deb7761..5bc96ec0f1513e 100644 --- a/testing/android/junit/java/src/org/chromium/testing/local/TestListComputer.java +++ b/testing/android/junit/java/src/org/chromium/testing/local/TestListComputer.java @@ -34,8 +34,13 @@ class TestListComputer extends Computer { private final List mDescriptions = new ArrayList<>(); + private final Allowlist mShadowsAllowlist; - private static String computeConfig( + TestListComputer(Allowlist shadowsAllowlist) { + mShadowsAllowlist = shadowsAllowlist; + } + + private String computeConfig( Description description, Set instrumentedPackages, Set instrumentedClasses) { @@ -64,6 +69,9 @@ private static String computeConfig( if (className.isEmpty()) { className = annotation.value().getName(); } + if (!mShadowsAllowlist.allow(className)) { + throwShadowException(clazz.getName(), className); + } instrumentedClasses.add(className); } } @@ -81,6 +89,21 @@ private static String computeConfig( return looperMode + sdkSuffix; } + private void throwShadowException(String shadowClass, String shadowingClass) { + String msg = + """ + + Found non-allowlisted Robolectric shadow: %s (shadowing %s). + Please limit usage of shadows to non-application code by adding explicit test stubbing \ + logic via set*ForTesting() methods. + + See: https://chromium.googlesource.com/chromium/src/+/main/styleguide/java/java.md#testing + Used allowlist: %s + """ + .formatted(shadowClass, shadowingClass, mShadowsAllowlist.getFilename()); + throw new RuntimeException(msg); + } + private class TestListRunner extends Runner implements Filterable { private final Runner mRunner; @@ -147,6 +170,12 @@ private static JSONArray getOrNewArray(JSONObject parent, String key) throws JSO } public void writeJson(File outputFile) throws FileNotFoundException, JSONException { + try (PrintStream stream = new PrintStream(new FileOutputStream(outputFile))) { + stream.print(createJson()); + } + } + + JSONObject createJson() throws JSONException { var instrumentedPackages = new TreeSet(); var instrumentedClasses = new TreeSet(); JSONObject root = new JSONObject(); @@ -171,9 +200,6 @@ public void writeJson(File outputFile) throws FileNotFoundException, JSONExcepti for (String s : instrumentedClasses) { arr.put(s); } - - try (PrintStream stream = new PrintStream(new FileOutputStream(outputFile))) { - stream.print(root); - } + return root; } } diff --git a/testing/android/junit/javatests/src/org/chromium/testing/local/TestListComputerTest.java b/testing/android/junit/javatests/src/org/chromium/testing/local/TestListComputerTest.java new file mode 100644 index 00000000000000..79dcfea807ec73 --- /dev/null +++ b/testing/android/junit/javatests/src/org/chromium/testing/local/TestListComputerTest.java @@ -0,0 +1,60 @@ +// 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. + +package org.chromium.testing.local; + +import org.json.JSONException; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.JUnitCore; +import org.junit.runner.Request; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implements; + +import java.util.Collections; +import java.util.List; + +/** Unit tests for RunnerFilter. */ +@RunWith(BlockJUnit4ClassRunner.class) +public class TestListComputerTest { + + @Implements(TestListComputerTest.class) + public static class Shadow {} + + @RunWith(BlockJUnit4ClassRunner.class) + @Config(shadows = {Shadow.class}) + public static class FakeTestClass { + @Test + public void someTest() {} + } + + private static void doTest(boolean allowClass) throws JSONException { + JUnitCore core = new JUnitCore(); + TestListComputer computer = + new TestListComputer( + Allowlist.fromLines( + "mockfile", + allowClass ? Collections.emptyList() : List.of("-org"))); + Class[] classes = {FakeTestClass.class}; + core.run(Request.classes(computer, classes)); + String expected = + """ + {"configs":{"PAUSED":{"org.chromium.testing.local.TestListComputerTest$FakeTestClass":\ + ["someTest"]}},"instrumentedPackages":[],"instrumentedClasses":\ + ["org.chromium.testing.local.TestListComputerTest"]}"""; + Assert.assertEquals(expected, computer.createJson().toString()); + } + + @Test + public void testAllowed() throws Exception { + doTest(true); + } + + @Test(expected = RuntimeException.class) + public void testNotAllowed() throws Exception { + doTest(false); + } +} diff --git a/testing/android/junit/shadows-allowlist.txt b/testing/android/junit/shadows-allowlist.txt new file mode 100644 index 00000000000000..390eef4e5bc6a0 --- /dev/null +++ b/testing/android/junit/shadows-allowlist.txt @@ -0,0 +1,91 @@ +# 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. +# +# Allowlist of classes that can be shadowed (by @Shadow). +# Please do not add to this list. See: +# https://chromium.googlesource.com/chromium/src/+/main/styleguide/java/java.md#testing + +# TODO(https://crbug.com/341267427): Reduce this list. ++com.google.android.apps.chrome.rlz.RevenueStatsInternal ++org.chromium.base.ApplicationStatus ++org.chromium.base.PathUtils ++org.chromium.base.SysUtils ++org.chromium.base.task.AsyncTask ++org.chromium.base.task.PostTask ++org.chromium.base.version_info.VersionInfo ++org.chromium.chrome.browser.content.WebContentsFactory ++org.chromium.chrome.browser.contextmenu.ContextMenuHeaderCoordinator ++org.chromium.chrome.browser.contextualsearch.ContextualSearchSelectionController ++org.chromium.chrome.browser.device.DeviceConditions ++org.chromium.chrome.browser.dragdrop.ChromeDragAndDropBrowserDelegate$ClipDataItemBuilder ++org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl ++org.chromium.chrome.browser.firstrun.FirstRunUtils ++org.chromium.chrome.browser.homepage.HomepagePolicyManager ++org.chromium.chrome.browser.incognito.IncognitoUtils ++org.chromium.chrome.browser.init.ChromeBrowserInitializer ++org.chromium.chrome.browser.lens.LensController ++org.chromium.chrome.browser.lens.LensPolicyUtils ++org.chromium.chrome.browser.metrics.UmaSessionStats ++org.chromium.chrome.browser.multiwindow.MultiInstanceManagerApi31 ++org.chromium.chrome.browser.night_mode.WebContentsDarkModeController ++org.chromium.chrome.browser.omnibox.geo.GeolocationHeader ++org.chromium.chrome.browser.omnibox.geo.GeolocationTracker ++org.chromium.chrome.browser.omnibox.geo.PlatformNetworksManager ++org.chromium.chrome.browser.omnibox.geo.VisibleNetworksTracker ++org.chromium.chrome.browser.omnibox.styles.OmniboxResourceProvider ++org.chromium.chrome.browser.omnibox.suggestions.CachedZeroSuggestionsManager ++org.chromium.chrome.browser.omnibox.UrlBarData ++org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionUtil ++org.chromium.chrome.browser.partnercustomizations.CustomizationProviderDelegateUpstreamImpl ++org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations ++org.chromium.chrome.browser.profiles.Profile ++org.chromium.chrome.browser.profiles.ProfileManager ++org.chromium.chrome.browser.profiles.ProfileManagerUtils ++org.chromium.chrome.browser.rlz.RevenueStats ++org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory ++org.chromium.chrome.browser.searchwidget.SearchActivityUtils ++org.chromium.chrome.browser.share.android_share_sheet.AndroidShareSheetController ++org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator ++org.chromium.chrome.browser.share.long_screenshots.LongScreenshotsCoordinator ++org.chromium.chrome.browser.share.qrcode.QrCodeDialog ++org.chromium.chrome.browser.share.ShareHelper ++org.chromium.chrome.browser.share.ShareHelper$ChooserActionHelper ++org.chromium.chrome.browser.share.share_sheet.ShareSheetCoordinator ++org.chromium.chrome.browser.share.share_sheet.ShareSheetPropertyModelBuilder ++org.chromium.chrome.browser.tab.SadTab ++org.chromium.chrome.browser.tab.TabBrowserControlsOffsetHelper ++org.chromium.chrome.browser.tab.TabBuilder ++org.chromium.chrome.browser.tab.TabUtils ++org.chromium.chrome.browser.tab.TrustedCdn ++org.chromium.chrome.browser.toolbar.adaptive.OptionalNewTabButtonController$Delegate ++org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeControllerFactory ++org.chromium.chrome.browser.ui.hats.MessageSurveyUiDelegate ++org.chromium.chrome.browser.util.AndroidTaskUtils ++org.chromium.chrome.browser.webapps.WebApkShareTargetUtil ++org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider ++org.chromium.components.browser_ui.share.ShareImageFileUtils ++org.chromium.components.browser_ui.styles.SemanticColorUtils ++org.chromium.components.browser_ui.widget.ContextMenuDialog ++org.chromium.components.browser_ui.widget.InsetsRectProvider$BoundingRectHelper ++org.chromium.components.embedder_support.util.UrlUtilities ++org.chromium.components.media_router.caf.CastMediaSource ++org.chromium.components.stylus_handwriting.DirectWritingSettingsHelper ++org.chromium.components.url_formatter.UrlFormatter ++org.chromium.components.user_prefs.UserPrefs ++org.chromium.content_public.browser.WebContentsStatics ++org.chromium.gms.ChromiumPlayServicesAvailability ++org.chromium.ui.base.MimeTypeUtils ++org.chromium.ui.display.DisplayAndroid ++org.chromium.ui.display.DisplayAndroidManager ++org.chromium.ui.display.DisplayUtil ++org.chromium.ui.resources.dynamics.CaptureUtils ++org.chromium.ui.util.ColorUtils ++org.chromium.ui.util.WindowInsetsUtils ++org.chromium.ui.widget.AnchoredPopupWindow ++org.chromium.url.Origin ++org.chromium.webapk.shell_apk.LaunchHostBrowserSelector + +# Disallow new shadows of chrome-authored code. +-com.google.android.apps.chrome +-org.chromium From 4e6a64846ad4bcb5e9afc1a12bdb1a72b5e58d63 Mon Sep 17 00:00:00 2001 From: Antonio Gomes Date: Tue, 21 May 2024 15:32:30 +0000 Subject: [PATCH 02/40] Remove unused parameter from OverlayCandidateFactory::GetDamageRect() ... and update the declaration comment to reflect what it does. R=petermcneedley@chromium.org Bug: 323856494 Change-Id: I038bd378cebed87b1123f1142df3f31524daad51 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5546242 Commit-Queue: Peter McNeeley Auto-Submit: Antonio Gomes Reviewed-by: Peter McNeeley Cr-Commit-Position: refs/heads/main@{#1303785} --- components/viz/service/display/overlay_candidate_factory.cc | 6 ++---- components/viz/service/display/overlay_candidate_factory.h | 6 +----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/components/viz/service/display/overlay_candidate_factory.cc b/components/viz/service/display/overlay_candidate_factory.cc index 84ef69addecf1a..9312fc7a9eba23 100644 --- a/components/viz/service/display/overlay_candidate_factory.cc +++ b/components/viz/service/display/overlay_candidate_factory.cc @@ -795,7 +795,7 @@ void OverlayCandidateFactory::HandleClipAndSubsampling( void OverlayCandidateFactory::AssignDamage(const DrawQuad* quad, OverlayCandidate& candidate) const { - candidate.damage_rect = GetDamageRect(quad, candidate); + candidate.damage_rect = GetDamageRect(quad); // For underlays the function 'EstimateVisibleDamage()' is called to update // |damage_area_estimate| to more accurately reflect the actual visible // damage. @@ -818,9 +818,7 @@ gfx::RectF OverlayCandidateFactory::GetDamageEstimate( gfx::RectF(unassigned_surface_damage_)); } -gfx::RectF OverlayCandidateFactory::GetDamageRect( - const DrawQuad* quad, - const OverlayCandidate& candidate) const { +gfx::RectF OverlayCandidateFactory::GetDamageRect(const DrawQuad* quad) const { const SharedQuadState* sqs = quad->shared_quad_state; if (!sqs->overlay_damage_index.has_value()) { return gfx::RectF(); diff --git a/components/viz/service/display/overlay_candidate_factory.h b/components/viz/service/display/overlay_candidate_factory.h index 3c386f21bdf01c..7c26207a4cb1b6 100644 --- a/components/viz/service/display/overlay_candidate_factory.h +++ b/components/viz/service/display/overlay_candidate_factory.h @@ -143,11 +143,7 @@ class VIZ_SERVICE_EXPORT OverlayCandidateFactory { void AssignDamage(const DrawQuad* quad, OverlayCandidate& candidate) const; // Damage returned from this function is in target space. - // If quad doesn't have damage from the surface damage list, this returns the - // intersection of unassigned damage and the smallest axis-aligned rectangle - // containing |display_rect| in target space. - gfx::RectF GetDamageRect(const DrawQuad* quad, - const OverlayCandidate& candidate) const; + gfx::RectF GetDamageRect(const DrawQuad* quad) const; gfx::RectF GetDamageEstimate(const OverlayCandidate& candidate) const; From eabb35e536a2a9044ad4ea602f3ed60cea33e489 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Horo Date: Tue, 21 May 2024 15:32:53 +0000 Subject: [PATCH 03/40] Introduce SharedDictionaryHeaderCheckerSourceStream class This class will be used to check the header bytes in the dictionary compressied body stream. This header bytes are defined in the spec: https://www.ietf.org/archive/id/draft-ietf-httpbis-compression-dictionary-04.html#section-4 Bug: 40255884 Change-Id: I75fd2c1ec55d9d397c7eb6711f9477fdc3617d92 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553633 Reviewed-by: Patrick Meenan Commit-Queue: Tsuyoshi Horo Cr-Commit-Position: refs/heads/main@{#1303786} --- services/network/BUILD.gn | 3 + ...dictionary_header_checker_source_stream.cc | 183 ++++++++++ ..._dictionary_header_checker_source_stream.h | 87 +++++ ...y_header_checker_source_stream_unittest.cc | 326 ++++++++++++++++++ 4 files changed, 599 insertions(+) create mode 100644 services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.cc create mode 100644 services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.h create mode 100644 services/network/shared_dictionary/shared_dictionary_header_checker_source_stream_unittest.cc diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn index 2ef0f7aff7518d..c447bab8c1caf7 100644 --- a/services/network/BUILD.gn +++ b/services/network/BUILD.gn @@ -159,6 +159,8 @@ component("network_service") { "shared_dictionary/shared_dictionary_data_pipe_writer.h", "shared_dictionary/shared_dictionary_disk_cache.cc", "shared_dictionary/shared_dictionary_disk_cache.h", + "shared_dictionary/shared_dictionary_header_checker_source_stream.cc", + "shared_dictionary/shared_dictionary_header_checker_source_stream.h", "shared_dictionary/shared_dictionary_in_memory.cc", "shared_dictionary/shared_dictionary_in_memory.h", "shared_dictionary/shared_dictionary_manager.cc", @@ -478,6 +480,7 @@ source_set("tests") { "session_cleanup_cookie_store_unittest.cc", "shared_dictionary/shared_dictionary_data_pipe_writer_unittest.cc", "shared_dictionary/shared_dictionary_disk_cache_unittest.cc", + "shared_dictionary/shared_dictionary_header_checker_source_stream_unittest.cc", "shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc", "shared_dictionary/shared_dictionary_manager_unittest.cc", "shared_dictionary/shared_dictionary_network_transaction_factory_unittest.cc", diff --git a/services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.cc b/services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.cc new file mode 100644 index 00000000000000..46c9f5630c3678 --- /dev/null +++ b/services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.cc @@ -0,0 +1,183 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.h" + +#include "base/check_op.h" +#include "base/containers/span.h" +#include "base/functional/callback_helpers.h" +#include "net/base/hash_value.h" +#include "net/base/io_buffer.h" + +namespace network { +namespace { + +static constexpr unsigned char kCompressionTypeBrotliSignature[] = {0xff, 0x44, + 0x43, 0x42}; +static constexpr unsigned char kCompressionTypeZstdSignature[] = { + 0x5e, 0x2a, 0x4d, 0x18, 0x20, 0x00, 0x00, 0x00}; +static constexpr size_t kCompressionTypeBrotliSignatureSize = + sizeof(kCompressionTypeBrotliSignature); +static constexpr size_t kCompressionTypeZstdSignatureSize = + sizeof(kCompressionTypeZstdSignature); +static constexpr int kCompressionDictionaryHashSize = 32; +static_assert(sizeof(net::SHA256HashValue) == kCompressionDictionaryHashSize, + "kCompressionDictionaryHashSize mismatch"); +static constexpr int kCompressionTypeBrotliHeaderSize = + kCompressionTypeBrotliSignatureSize + kCompressionDictionaryHashSize; +static constexpr int kCompressionTypeZstdHeaderSize = + kCompressionTypeZstdSignatureSize + kCompressionDictionaryHashSize; + +size_t GetSignatureSize(SharedDictionaryHeaderCheckerSourceStream::Type type) { + switch (type) { + case SharedDictionaryHeaderCheckerSourceStream::Type:: + kDictionaryCompressedBrotli: + return kCompressionTypeBrotliSignatureSize; + case SharedDictionaryHeaderCheckerSourceStream::Type:: + kDictionaryCompressedZstd: + return kCompressionTypeZstdSignatureSize; + } +} + +size_t GetHeaderSize(SharedDictionaryHeaderCheckerSourceStream::Type type) { + switch (type) { + case SharedDictionaryHeaderCheckerSourceStream::Type:: + kDictionaryCompressedBrotli: + return kCompressionTypeBrotliHeaderSize; + case SharedDictionaryHeaderCheckerSourceStream::Type:: + kDictionaryCompressedZstd: + return kCompressionTypeZstdHeaderSize; + } +} + +base::span GetExpectedSignature( + SharedDictionaryHeaderCheckerSourceStream::Type type) { + switch (type) { + case SharedDictionaryHeaderCheckerSourceStream::Type:: + kDictionaryCompressedBrotli: + return kCompressionTypeBrotliSignature; + case SharedDictionaryHeaderCheckerSourceStream::Type:: + kDictionaryCompressedZstd: + return kCompressionTypeZstdSignature; + } +} + +} // namespace + +SharedDictionaryHeaderCheckerSourceStream:: + SharedDictionaryHeaderCheckerSourceStream( + std::unique_ptr upstream, + Type type, + const net::SHA256HashValue& dictionary_hash) + : SourceStream(SourceStream::TYPE_NONE), + upstream_(std::move(upstream)), + type_(type), + dictionary_hash_(dictionary_hash), + head_read_buffer_(base::MakeRefCounted()) { + head_read_buffer_->SetCapacity(GetHeaderSize(type_)); + ReadHeader(); +} + +SharedDictionaryHeaderCheckerSourceStream:: + ~SharedDictionaryHeaderCheckerSourceStream() = default; + +int SharedDictionaryHeaderCheckerSourceStream::Read( + net::IOBuffer* dest_buffer, + int buffer_size, + net::CompletionOnceCallback callback) { + if (header_check_result_ == net::OK) { + return upstream_->Read(dest_buffer, buffer_size, std::move(callback)); + } + if (header_check_result_ == net::ERR_IO_PENDING) { + CHECK(head_read_buffer_); + // Still reading header. + pending_read_buf_ = dest_buffer; + pending_read_buf_len_ = buffer_size; + pending_callback_ = std::move(callback); + } + return header_check_result_; +} + +std::string SharedDictionaryHeaderCheckerSourceStream::Description() const { + return "SharedDictionaryHeaderCheckerSourceStream"; +} + +bool SharedDictionaryHeaderCheckerSourceStream::MayHaveMoreBytes() const { + return upstream_->MayHaveMoreBytes(); +} + +void SharedDictionaryHeaderCheckerSourceStream::ReadHeader() { + int result = upstream_->Read( + head_read_buffer_.get(), head_read_buffer_->RemainingCapacity(), + base::BindOnce( + &SharedDictionaryHeaderCheckerSourceStream::OnReadCompleted, + base::Unretained(this))); + if (result != net::ERR_IO_PENDING) { + OnReadCompleted(result); + } +} + +void SharedDictionaryHeaderCheckerSourceStream::OnReadCompleted(int result) { + CHECK_NE(result, net::ERR_IO_PENDING); + if (result <= 0) { + // net::OK means the stream is closed before reading header. + if (result == net::OK) { + result = net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER; + } + HeaderCheckCompleted(result); + return; + } + head_read_buffer_->set_offset(head_read_buffer_->offset() + result); + if (head_read_buffer_->RemainingCapacity() != 0) { + ReadHeader(); + return; + } + HeaderCheckCompleted(CheckHeaderBuffer() + ? net::OK + : net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER); +} + +bool SharedDictionaryHeaderCheckerSourceStream::CheckHeaderBuffer() const { + CHECK(head_read_buffer_->RemainingCapacity() == 0); + if (GetSignatureInBuffer() != GetExpectedSignature(type_)) { + return false; + } + if (GetHashInBuffer() != base::span(dictionary_hash_.data)) { + return false; + } + return true; +} + +void SharedDictionaryHeaderCheckerSourceStream::HeaderCheckCompleted( + int header_check_result) { + CHECK_NE(header_check_result, net::ERR_IO_PENDING); + CHECK_EQ(header_check_result_, net::ERR_IO_PENDING); + + header_check_result_ = header_check_result; + head_read_buffer_.reset(); + + if (!pending_callback_) { + return; + } + + auto callback_split = base::SplitOnceCallback(std::move(pending_callback_)); + int read_result = Read(pending_read_buf_.get(), pending_read_buf_len_, + std::move(callback_split.first)); + if (read_result != net::ERR_IO_PENDING) { + std::move(callback_split.second).Run(read_result); + } +} + +base::span +SharedDictionaryHeaderCheckerSourceStream::GetSignatureInBuffer() const { + return head_read_buffer_->everything().subspan(0, GetSignatureSize(type_)); +} + +base::span +SharedDictionaryHeaderCheckerSourceStream::GetHashInBuffer() const { + return head_read_buffer_->everything().subspan( + GetSignatureSize(type_), kCompressionDictionaryHashSize); +} + +} // namespace network diff --git a/services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.h b/services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.h new file mode 100644 index 00000000000000..c3922bf1a87d84 --- /dev/null +++ b/services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.h @@ -0,0 +1,87 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_HEADER_CHECKER_SOURCE_STREAM_H_ +#define SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_HEADER_CHECKER_SOURCE_STREAM_H_ + +#include +#include + +#include "base/component_export.h" +#include "net/base/completion_once_callback.h" +#include "net/base/hash_value.h" +#include "net/filter/source_stream.h" + +namespace net { +class IOBuffer; +class GrowableIOBuffer; +} // namespace net + +namespace network { + +// This class is used to check the header bytes of "Dictionary-Compressed +// Brotli" stream and "Dictionary-Compressed Zstandard" stream. +// +// The "Dictionary-Compressed Brotli" stream's header is 36 bytes containing: +// - 4 bytes magic number: 0xff, 0x44, 0x43, 0x42 +// - 32 bytes SHA-256 hash digest of the dictionary. +// The "Dictionary-Compressed Zstandard" stream's header is 40 bytes containing: +// - 8 bytes magic number: 0x5e, 0x2a, 0x4d, 0x18, 0x20, 0x00, 0x00, 0x00 +// - 32 bytes SHA-256 hash digest of the dictionary. +// +// When an error occurred while reading the upstream, this class passes the +// error to the reader of this class. When the header bytes from the upstream +// was different from the expected header, this class passes +// net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER to the reader. +// +// This class consumes the header bytes from the upstream. So the reader of +// this class can read the bytes after the header bytes. +class COMPONENT_EXPORT(NETWORK_SERVICE) + SharedDictionaryHeaderCheckerSourceStream : public net::SourceStream { + public: + enum class Type { + kDictionaryCompressedBrotli, + kDictionaryCompressedZstd, + }; + SharedDictionaryHeaderCheckerSourceStream( + std::unique_ptr upstream, + Type type, + const net::SHA256HashValue& dictionary_hash); + SharedDictionaryHeaderCheckerSourceStream( + const SharedDictionaryHeaderCheckerSourceStream&) = delete; + SharedDictionaryHeaderCheckerSourceStream& operator=( + const SharedDictionaryHeaderCheckerSourceStream&) = delete; + ~SharedDictionaryHeaderCheckerSourceStream() override; + + // SourceStream implementation: + int Read(net::IOBuffer* dest_buffer, + int buffer_size, + net::CompletionOnceCallback callback) override; + std::string Description() const override; + bool MayHaveMoreBytes() const override; + + private: + void ReadHeader(); + void OnReadCompleted(int result); + bool CheckHeaderBuffer() const; + void HeaderCheckCompleted(int header_check_result); + + base::span GetSignatureInBuffer() const; + base::span GetHashInBuffer() const; + + std::unique_ptr upstream_; + const Type type_; + const net::SHA256HashValue dictionary_hash_; + + scoped_refptr head_read_buffer_; + int header_check_result_ = net::ERR_IO_PENDING; + + scoped_refptr pending_read_buf_; + int pending_read_buf_len_ = 0; + net::CompletionOnceCallback pending_callback_; +}; + +} // namespace network + +#endif // SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_HEADER_CHECKER_SOURCE_STREAM_H_ diff --git a/services/network/shared_dictionary/shared_dictionary_header_checker_source_stream_unittest.cc b/services/network/shared_dictionary/shared_dictionary_header_checker_source_stream_unittest.cc new file mode 100644 index 00000000000000..234b4684d6914c --- /dev/null +++ b/services/network/shared_dictionary/shared_dictionary_header_checker_source_stream_unittest.cc @@ -0,0 +1,326 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.h" + +#include + +#include "base/containers/span.h" +#include "base/memory/scoped_refptr.h" +#include "base/notreached.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/base/test_completion_callback.h" +#include "net/filter/mock_source_stream.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace network { + +namespace { + +using Type = SharedDictionaryHeaderCheckerSourceStream::Type; + +static constexpr net::SHA256HashValue kTestHash = { + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20}}; + +static constexpr unsigned char kBrotliSignature[] = {0xff, 0x44, 0x43, 0x42}; + +// The first byte is different from the correct signature. +static constexpr unsigned char kWrongBrotliSignature[] = {0xf0, 0x44, 0x43, + 0x42}; +static constexpr unsigned char kBrotliSignatureAndHash[] = { + // kBrotliSignature + 0xff, 0x44, 0x43, 0x42, + // kTestHash + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20}; +static constexpr base::span kTooSmallBrotliHeader = + base::make_span(kBrotliSignatureAndHash) + .subspan(sizeof(kBrotliSignatureAndHash) / 2); + +static constexpr unsigned char kZstdSignature[] = {0x5e, 0x2a, 0x4d, 0x18, + 0x20, 0x00, 0x00, 0x00}; +// The first byte is different from the correct signature. +static constexpr unsigned char kWrongZstdSignature[] = {0x50, 0x2a, 0x4d, 0x18, + 0x20, 0x00, 0x00, 0x00}; +static constexpr unsigned char kZstdSignatureAndHash[] = { + // kZstdSignature + 0x5e, 0x2a, 0x4d, 0x18, 0x20, 0x00, 0x00, 0x00, + // kTestHash + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20}; +static constexpr base::span kTooSmallZstdHeader = + base::make_span(kZstdSignatureAndHash) + .subspan(sizeof(kZstdSignatureAndHash) / 2); +constexpr size_t kOutputBufferSize = 1024; + +static constexpr char kTestBodyData[] = "test body data"; + +} // namespace + +class SharedDictionaryHeaderCheckerSourceStreamTest + : public ::testing::TestWithParam { + public: + SharedDictionaryHeaderCheckerSourceStreamTest() + : mock_stream_(std::make_unique()), + mock_stream_ptr_(mock_stream_.get()), + buffer_( + base::MakeRefCounted(kOutputBufferSize)) {} + ~SharedDictionaryHeaderCheckerSourceStreamTest() override = default; + SharedDictionaryHeaderCheckerSourceStreamTest( + const SharedDictionaryHeaderCheckerSourceStreamTest&) = delete; + SharedDictionaryHeaderCheckerSourceStreamTest& operator=( + const SharedDictionaryHeaderCheckerSourceStreamTest&) = delete; + + protected: + using Mode = net::MockSourceStream::Mode; + Type GetType() const { return GetParam(); } + base::span GetSignature() const { + switch (GetType()) { + case Type::kDictionaryCompressedBrotli: + return kBrotliSignature; + case Type::kDictionaryCompressedZstd: + return kZstdSignature; + } + } + base::span GetSignatureAndHash() const { + switch (GetType()) { + case Type::kDictionaryCompressedBrotli: + return kBrotliSignatureAndHash; + case Type::kDictionaryCompressedZstd: + return kZstdSignatureAndHash; + } + } + base::span GetTooSmallHeader() const { + switch (GetType()) { + case Type::kDictionaryCompressedBrotli: + return kTooSmallBrotliHeader; + case Type::kDictionaryCompressedZstd: + return kTooSmallZstdHeader; + } + } + base::span GetWrongSignature() const { + switch (GetType()) { + case Type::kDictionaryCompressedBrotli: + return kWrongBrotliSignature; + case Type::kDictionaryCompressedZstd: + return kWrongZstdSignature; + } + } + void CreateHeaderCheckerSourceStream() { + stream_ = std::make_unique( + std::move(mock_stream_), GetType(), kTestHash); + } + SharedDictionaryHeaderCheckerSourceStream* stream() { return stream_.get(); } + net::IOBufferWithSize* buffer() { return buffer_.get(); } + + void AddReadResult(base::span span, Mode mode) { + mock_stream_ptr_->AddReadResult(span.data(), span.size(), net::OK, mode); + } + void AddReadResult(base::span span, Mode mode) { + AddReadResult(base::as_chars(span), mode); + } + void AddReadResult(net::Error error, Mode mode) { + mock_stream_ptr_->AddReadResult(nullptr, 0, error, mode); + } + void CompleteNextRead() { mock_stream_ptr_->CompleteNextRead(); } + + void CheckSyncRead(int expected_result) { + net::TestCompletionCallback callback; + EXPECT_EQ(Read(callback.callback()), expected_result); + EXPECT_FALSE(callback.have_result()); + } + void CheckAsyncRead(int expected_result, size_t mock_stream_read_count) { + net::TestCompletionCallback callback; + EXPECT_EQ(Read(callback.callback()), net::ERR_IO_PENDING); + EXPECT_FALSE(callback.have_result()); + for (size_t i = 0; i < mock_stream_read_count - 1; ++i) { + CompleteNextRead(); + EXPECT_FALSE(callback.have_result()); + } + CompleteNextRead(); + EXPECT_TRUE(callback.have_result()); + EXPECT_EQ(callback.WaitForResult(), expected_result); + } + int Read(net::CompletionOnceCallback callback) { + return stream()->Read(buffer(), buffer()->size(), std::move(callback)); + } + + private: + std::unique_ptr mock_stream_; + std::unique_ptr stream_; + raw_ptr mock_stream_ptr_; + scoped_refptr buffer_; +}; + +std::string ToString(Type type) { + switch (type) { + case Type::kDictionaryCompressedBrotli: + return "Brotli"; + case Type::kDictionaryCompressedZstd: + return "Zstd"; + } +} + +INSTANTIATE_TEST_SUITE_P(All, + SharedDictionaryHeaderCheckerSourceStreamTest, + testing::ValuesIn({Type::kDictionaryCompressedBrotli, + Type::kDictionaryCompressedZstd}), + [](const testing::TestParamInfo& info) { + return ToString(info.param); + }); + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, Description) { + AddReadResult(net::OK, Mode::SYNC); + CreateHeaderCheckerSourceStream(); + EXPECT_EQ(stream()->Description(), + "SharedDictionaryHeaderCheckerSourceStream"); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, MayHaveMoreBytes) { + AddReadResult(net::OK, Mode::SYNC); + CreateHeaderCheckerSourceStream(); + EXPECT_TRUE(stream()->MayHaveMoreBytes()); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, SyncReadError) { + AddReadResult(net::ERR_FAILED, Mode::SYNC); + CreateHeaderCheckerSourceStream(); + CheckSyncRead(net::ERR_FAILED); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, AsyncReadError) { + AddReadResult(net::ERR_FAILED, Mode::ASYNC); + CreateHeaderCheckerSourceStream(); + CheckAsyncRead(net::ERR_FAILED, 1); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, EmptyStreamSyncComplete) { + AddReadResult(net::OK, Mode::SYNC); + CreateHeaderCheckerSourceStream(); + CheckSyncRead(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, + EmptyStreamAsyncCompleteBeforeRead) { + AddReadResult(net::OK, Mode::ASYNC); + CreateHeaderCheckerSourceStream(); + CheckAsyncRead(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER, 1); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, + EmptyStreamAsyncCompleteAfterRead) { + AddReadResult(net::OK, Mode::ASYNC); + CreateHeaderCheckerSourceStream(); + CompleteNextRead(); + CheckSyncRead(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, + TooSmallHeaderSyncDataSyncComplete) { + AddReadResult(GetTooSmallHeader(), Mode::SYNC); + AddReadResult(net::OK, Mode::SYNC); + CreateHeaderCheckerSourceStream(); + CheckSyncRead(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, + TooSmallHeaderSyncDataAsyncCompleteBeforeRead) { + AddReadResult(GetTooSmallHeader(), Mode::SYNC); + AddReadResult(net::OK, Mode::ASYNC); + CreateHeaderCheckerSourceStream(); + CompleteNextRead(); + CheckSyncRead(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, + TooSmallHeaderSyncDataAsyncCompleteAfterRead) { + AddReadResult(GetTooSmallHeader(), Mode::SYNC); + AddReadResult(net::OK, Mode::ASYNC); + CreateHeaderCheckerSourceStream(); + CheckAsyncRead(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER, 1); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, HeaderSync) { + AddReadResult(GetSignatureAndHash(), Mode::SYNC); + AddReadResult(kTestBodyData, Mode::SYNC); + AddReadResult(net::OK, Mode::SYNC); + CreateHeaderCheckerSourceStream(); + CheckSyncRead(static_cast(sizeof(kTestBodyData))); + EXPECT_THAT(base::make_span(buffer()->data(), sizeof(kTestBodyData)), + testing::ElementsAreArray(kTestBodyData)); + CheckSyncRead(net::OK); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, HeaderSplittedSync) { + AddReadResult(GetSignature(), Mode::SYNC); + AddReadResult(kTestHash.data, Mode::SYNC); + AddReadResult(kTestBodyData, Mode::SYNC); + AddReadResult(net::OK, Mode::SYNC); + CreateHeaderCheckerSourceStream(); + CheckSyncRead(static_cast(sizeof(kTestBodyData))); + EXPECT_THAT(base::make_span(buffer()->data(), sizeof(kTestBodyData)), + testing::ElementsAreArray(kTestBodyData)); + CheckSyncRead(net::OK); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, HeaderAsync) { + AddReadResult(GetSignatureAndHash(), Mode::ASYNC); + AddReadResult(kTestBodyData, Mode::ASYNC); + AddReadResult(net::OK, Mode::ASYNC); + CreateHeaderCheckerSourceStream(); + CheckAsyncRead(static_cast(sizeof(kTestBodyData)), 2); + EXPECT_THAT(base::make_span(buffer()->data(), sizeof(kTestBodyData)), + testing::ElementsAreArray(kTestBodyData)); + CheckAsyncRead(net::OK, 1); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, HeaderSplittedAsync) { + AddReadResult(GetSignature(), Mode::ASYNC); + AddReadResult(kTestHash.data, Mode::ASYNC); + AddReadResult(kTestBodyData, Mode::ASYNC); + AddReadResult(net::OK, Mode::ASYNC); + CreateHeaderCheckerSourceStream(); + CheckAsyncRead(static_cast(sizeof(kTestBodyData)), 3); + EXPECT_THAT(base::make_span(buffer()->data(), sizeof(kTestBodyData)), + testing::ElementsAreArray(kTestBodyData)); + CheckAsyncRead(net::OK, 1); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, WrongSinatureSync) { + AddReadResult(GetWrongSignature(), Mode::SYNC); + AddReadResult(kTestHash.data, Mode::SYNC); + CreateHeaderCheckerSourceStream(); + CheckSyncRead(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, WrongSinatureAsync) { + AddReadResult(GetWrongSignature(), Mode::ASYNC); + AddReadResult(kTestHash.data, Mode::ASYNC); + CreateHeaderCheckerSourceStream(); + CheckAsyncRead(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER, 2); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, WrongHashSync) { + const net::SHA256HashValue kWrongHash = {{0x01}}; + AddReadResult(GetSignature(), Mode::SYNC); + AddReadResult(kWrongHash.data, Mode::SYNC); + CreateHeaderCheckerSourceStream(); + CheckSyncRead(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER); +} + +TEST_P(SharedDictionaryHeaderCheckerSourceStreamTest, WrongHashAsync) { + const net::SHA256HashValue kWrongHash = {{0x01}}; + AddReadResult(GetSignature(), Mode::ASYNC); + AddReadResult(kWrongHash.data, Mode::ASYNC); + CreateHeaderCheckerSourceStream(); + CheckAsyncRead(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER, 2); +} + +} // namespace network From 26fdabbfa5f1e046f10c88787328c2d362be53bc Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 21 May 2024 15:33:38 +0000 Subject: [PATCH 04/40] Never expire Net.QuicSession.PreferAesGcm This metric reflects capabilities of the user's hardware and is used to monitor what percentage of users have AES hardware support. It is recorded only once per session. This is a core metric that impacts design decisions in everything cryptography-adjacent, because AES is very fast with dedicated hardware and very slow without. Change-Id: Ifced22e1de7774d7b47cc223f16b1e59d9e45f8e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5544694 Commit-Queue: Luc Nguyen Auto-Submit: David Benjamin Reviewed-by: Luc Nguyen Cr-Commit-Position: refs/heads/main@{#1303787} --- tools/metrics/histograms/metadata/net/histograms.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index 9adc64540ed0ab..a463f2d52007d8 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml @@ -3807,7 +3807,9 @@ chromium-metrics-reviews@google.com. + expires_after="never"> + + dschinazi@chromium.org src/net/quic/OWNERS From d01cecc6491600076ea1a386f8abc9e87f311ecd Mon Sep 17 00:00:00 2001 From: Etienne Pierre-doray Date: Tue, 21 May 2024 15:34:00 +0000 Subject: [PATCH 05/40] [tracing] TraceStartupConfig uses static NoDestructor This removes dependancy on AtExitManager, and will allow us to initialize startup tracing earlier, to match Android. See https://chromium-review.googlesource.com/c/chromium/src/+/5545923. Drive-by: return reference instead of pointer. Change-Id: Iae3eabf7f4d3fcfcddc459514789ac3d336a089b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5545934 Commit-Queue: Etienne Pierre-Doray Reviewed-by: Alex Rudenko Reviewed-by: Eric Seckler Cr-Commit-Position: refs/heads/main@{#1303788} --- .../tracing/common/trace_startup_config.cc | 8 +-- .../tracing/common/trace_startup_config.h | 8 +-- .../common/trace_startup_config_unittest.cc | 54 +++++++++---------- .../devtools/protocol/tracing_handler.cc | 8 +-- .../background_startup_tracing_observer.cc | 6 +-- .../tracing/startup_tracing_browsertest.cc | 2 +- .../tracing/startup_tracing_controller.cc | 19 +++---- services/tracing/public/cpp/trace_startup.cc | 22 ++++---- 8 files changed, 64 insertions(+), 63 deletions(-) diff --git a/components/tracing/common/trace_startup_config.cc b/components/tracing/common/trace_startup_config.cc index c1541f5f843993..f65a5b34a7f0b3 100644 --- a/components/tracing/common/trace_startup_config.cc +++ b/components/tracing/common/trace_startup_config.cc @@ -13,7 +13,7 @@ #include "base/files/file_util.h" #include "base/json/json_reader.h" #include "base/logging.h" -#include "base/memory/singleton.h" +#include "base/no_destructor.h" #include "base/strings/string_number_conversions.h" #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/trace_log.h" @@ -61,9 +61,9 @@ const char TraceStartupConfig::kDefaultStartupCategories[] = #endif // static -TraceStartupConfig* TraceStartupConfig::GetInstance() { - return base::Singleton>::get(); +TraceStartupConfig& TraceStartupConfig::GetInstance() { + static base::NoDestructor g_instance; + return *g_instance; } // static diff --git a/components/tracing/common/trace_startup_config.h b/components/tracing/common/trace_startup_config.h index 988c137c135626..85e38a45038529 100644 --- a/components/tracing/common/trace_startup_config.h +++ b/components/tracing/common/trace_startup_config.h @@ -12,7 +12,7 @@ namespace base { template -struct DefaultSingletonTraits; +class NoDestructor; } // namespace base namespace content { @@ -101,7 +101,7 @@ class TRACING_EXPORT TraceStartupConfig { // Exposed for testing. static const char kDefaultStartupCategories[]; - static TraceStartupConfig* GetInstance(); + static TraceStartupConfig& GetInstance(); TraceStartupConfig(const TraceStartupConfig&) = delete; TraceStartupConfig& operator=(const TraceStartupConfig&) = delete; @@ -145,8 +145,8 @@ class TRACING_EXPORT TraceStartupConfig { private: // This allows constructor and destructor to be private and usable only - // by the Singleton class. - friend struct base::DefaultSingletonTraits; + // by the NoDestructor class. + friend class base::NoDestructor; friend class content::CommandlineStartupTracingTest; friend class content::BackgroundStartupTracingTest; diff --git a/components/tracing/common/trace_startup_config_unittest.cc b/components/tracing/common/trace_startup_config_unittest.cc index 7a7329e2ee8826..4936676c688752 100644 --- a/components/tracing/common/trace_startup_config_unittest.cc +++ b/components/tracing/common/trace_startup_config_unittest.cc @@ -59,12 +59,12 @@ TEST(TraceStartupConfigTest, TraceStartupEnabled) { base::ShadowingAtExitManager sem; base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kTraceStartup); - EXPECT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled()); + EXPECT_TRUE(TraceStartupConfig::GetInstance().IsEnabled()); } TEST(TraceStartupConfigTest, TraceStartupConfigNotEnabled) { base::ShadowingAtExitManager sem; - EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled()); + EXPECT_FALSE(TraceStartupConfig::GetInstance().IsEnabled()); } TEST(TraceStartupConfigTest, TraceStartupConfigEnabledWithoutPath) { @@ -72,11 +72,11 @@ TEST(TraceStartupConfigTest, TraceStartupConfigEnabledWithoutPath) { base::CommandLine::ForCurrentProcess()->AppendSwitch( switches::kTraceConfigFile); - ASSERT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled()); + ASSERT_TRUE(TraceStartupConfig::GetInstance().IsEnabled()); EXPECT_EQ(base::trace_event::TraceConfig().ToString(), - TraceStartupConfig::GetInstance()->GetTraceConfig().ToString()); - EXPECT_EQ(5, TraceStartupConfig::GetInstance()->GetStartupDuration()); - EXPECT_TRUE(TraceStartupConfig::GetInstance()->GetResultFile().empty()); + TraceStartupConfig::GetInstance().GetTraceConfig().ToString()); + EXPECT_EQ(5, TraceStartupConfig::GetInstance().GetStartupDuration()); + EXPECT_TRUE(TraceStartupConfig::GetInstance().GetResultFile().empty()); } TEST(TraceStartupConfigTest, TraceStartupConfigEnabledWithInvalidPath) { @@ -85,7 +85,7 @@ TEST(TraceStartupConfigTest, TraceStartupConfigEnabledWithInvalidPath) { switches::kTraceConfigFile, base::FilePath(FILE_PATH_LITERAL("invalid-trace-config-file-path"))); - EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled()); + EXPECT_FALSE(TraceStartupConfig::GetInstance().IsEnabled()); } TEST(TraceStartupConfigTest, ValidContent) { @@ -102,13 +102,13 @@ TEST(TraceStartupConfigTest, ValidContent) { base::CommandLine::ForCurrentProcess()->AppendSwitchPath( switches::kTraceConfigFile, trace_config_file); - ASSERT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled()); + ASSERT_TRUE(TraceStartupConfig::GetInstance().IsEnabled()); EXPECT_STREQ( kTraceConfig, - TraceStartupConfig::GetInstance()->GetTraceConfig().ToString().c_str()); - EXPECT_EQ(10, TraceStartupConfig::GetInstance()->GetStartupDuration()); + TraceStartupConfig::GetInstance().GetTraceConfig().ToString().c_str()); + EXPECT_EQ(10, TraceStartupConfig::GetInstance().GetStartupDuration()); EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("trace_result_file.log")), - TraceStartupConfig::GetInstance()->GetResultFile()); + TraceStartupConfig::GetInstance().GetResultFile()); } TEST(TraceStartupConfigTest, ValidContentWithOnlyTraceConfig) { @@ -124,12 +124,12 @@ TEST(TraceStartupConfigTest, ValidContentWithOnlyTraceConfig) { base::CommandLine::ForCurrentProcess()->AppendSwitchPath( switches::kTraceConfigFile, trace_config_file); - ASSERT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled()); + ASSERT_TRUE(TraceStartupConfig::GetInstance().IsEnabled()); EXPECT_STREQ( kTraceConfig, - TraceStartupConfig::GetInstance()->GetTraceConfig().ToString().c_str()); - EXPECT_EQ(0, TraceStartupConfig::GetInstance()->GetStartupDuration()); - EXPECT_TRUE(TraceStartupConfig::GetInstance()->GetResultFile().empty()); + TraceStartupConfig::GetInstance().GetTraceConfig().ToString().c_str()); + EXPECT_EQ(0, TraceStartupConfig::GetInstance().GetStartupDuration()); + EXPECT_TRUE(TraceStartupConfig::GetInstance().GetResultFile().empty()); } TEST(TraceStartupConfigTest, ContentWithAbsoluteResultFilePath) { @@ -157,9 +157,9 @@ TEST(TraceStartupConfigTest, ContentWithAbsoluteResultFilePath) { base::CommandLine::ForCurrentProcess()->AppendSwitchPath( switches::kTraceConfigFile, trace_config_file); - ASSERT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled()); + ASSERT_TRUE(TraceStartupConfig::GetInstance().IsEnabled()); EXPECT_EQ(result_file_path, - TraceStartupConfig::GetInstance()->GetResultFile()); + TraceStartupConfig::GetInstance().GetResultFile()); } TEST(TraceStartupConfigTest, ContentWithNegtiveDuration) { @@ -175,12 +175,12 @@ TEST(TraceStartupConfigTest, ContentWithNegtiveDuration) { base::CommandLine::ForCurrentProcess()->AppendSwitchPath( switches::kTraceConfigFile, trace_config_file); - ASSERT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled()); + ASSERT_TRUE(TraceStartupConfig::GetInstance().IsEnabled()); EXPECT_STREQ( kTraceConfig, - TraceStartupConfig::GetInstance()->GetTraceConfig().ToString().c_str()); - EXPECT_EQ(0, TraceStartupConfig::GetInstance()->GetStartupDuration()); - EXPECT_TRUE(TraceStartupConfig::GetInstance()->GetResultFile().empty()); + TraceStartupConfig::GetInstance().GetTraceConfig().ToString().c_str()); + EXPECT_EQ(0, TraceStartupConfig::GetInstance().GetStartupDuration()); + EXPECT_TRUE(TraceStartupConfig::GetInstance().GetResultFile().empty()); } TEST(TraceStartupConfigTest, ContentWithoutTraceConfig) { @@ -197,7 +197,7 @@ TEST(TraceStartupConfigTest, ContentWithoutTraceConfig) { base::CommandLine::ForCurrentProcess()->AppendSwitchPath( switches::kTraceConfigFile, trace_config_file); - EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled()); + EXPECT_FALSE(TraceStartupConfig::GetInstance().IsEnabled()); } TEST(TraceStartupConfigTest, InvalidContent) { @@ -213,7 +213,7 @@ TEST(TraceStartupConfigTest, InvalidContent) { base::CommandLine::ForCurrentProcess()->AppendSwitchPath( switches::kTraceConfigFile, trace_config_file); - EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled()); + EXPECT_FALSE(TraceStartupConfig::GetInstance().IsEnabled()); } TEST(TraceStartupConfigTest, EmptyContent) { @@ -226,7 +226,7 @@ TEST(TraceStartupConfigTest, EmptyContent) { base::CommandLine::ForCurrentProcess()->AppendSwitchPath( switches::kTraceConfigFile, trace_config_file); - EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled()); + EXPECT_FALSE(TraceStartupConfig::GetInstance().IsEnabled()); } TEST(TraceStartupConfigTest, TraceStartupDisabledSystemOwner) { @@ -234,7 +234,7 @@ TEST(TraceStartupConfigTest, TraceStartupDisabledSystemOwner) { // Set the owner to 'system' is not sufficient to setup startup tracing. base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( switches::kTraceStartupOwner, "system"); - EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled()); + EXPECT_FALSE(TraceStartupConfig::GetInstance().IsEnabled()); } TEST(TraceStartupConfigTest, TraceStartupEnabledSystemOwner) { @@ -244,9 +244,9 @@ TEST(TraceStartupConfigTest, TraceStartupEnabledSystemOwner) { base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( switches::kTraceStartupOwner, "system"); base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kTraceStartup); - EXPECT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled()); + EXPECT_TRUE(TraceStartupConfig::GetInstance().IsEnabled()); EXPECT_EQ(TraceStartupConfig::SessionOwner::kSystemTracing, - TraceStartupConfig::GetInstance()->GetSessionOwner()); + TraceStartupConfig::GetInstance().GetSessionOwner()); } } // namespace tracing diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc index d17545ffd41228..5b3fa37884d991 100644 --- a/content/browser/devtools/protocol/tracing_handler.cc +++ b/content/browser/devtools/protocol/tracing_handler.cc @@ -875,8 +875,8 @@ void TracingHandler::AttemptAdoptStartupSession( if (session_for_process_filter_) { return; } - auto* startup_config = tracing::TraceStartupConfig::GetInstance(); - if (!startup_config->AttemptAdoptBySessionOwner( + auto& startup_config = tracing::TraceStartupConfig::GetInstance(); + if (!startup_config.AttemptAdoptBySessionOwner( tracing::TraceStartupConfig::SessionOwner::kDevToolsTracingHandler)) { return; } @@ -886,7 +886,7 @@ void TracingHandler::AttemptAdoptStartupSession( proto_format_ = proto_format; base::trace_event::TraceConfig browser_config = - tracing::TraceStartupConfig::GetInstance()->GetTraceConfig(); + tracing::TraceStartupConfig::GetInstance().GetTraceConfig(); perfetto::TraceConfig perfetto_config = CreatePerfettoConfiguration( browser_config, return_as_stream_, proto_format_); @@ -1175,7 +1175,7 @@ void TracingHandler::FrameDeleted(int frame_tree_node_id) { // static bool TracingHandler::IsStartupTracingActive() { - return ::tracing::TraceStartupConfig::GetInstance()->IsEnabled(); + return ::tracing::TraceStartupConfig::GetInstance().IsEnabled(); } // static diff --git a/content/browser/tracing/background_startup_tracing_observer.cc b/content/browser/tracing/background_startup_tracing_observer.cc index 9a5abf48019d72..ed0a97a689592b 100644 --- a/content/browser/tracing/background_startup_tracing_observer.cc +++ b/content/browser/tracing/background_startup_tracing_observer.cc @@ -21,12 +21,12 @@ class PreferenceManagerImpl public: void SetBackgroundStartupTracingEnabled(bool enabled) override { tracing::TraceStartupConfig::GetInstance() - ->SetBackgroundStartupTracingEnabled(enabled); + .SetBackgroundStartupTracingEnabled(enabled); } bool GetBackgroundStartupTracingEnabled() const override { - return tracing::TraceStartupConfig::GetInstance()->IsEnabled() && - tracing::TraceStartupConfig::GetInstance()->GetSessionOwner() == + return tracing::TraceStartupConfig::GetInstance().IsEnabled() && + tracing::TraceStartupConfig::GetInstance().GetSessionOwner() == tracing::TraceStartupConfig::SessionOwner::kBackgroundTracing; } }; diff --git a/content/browser/tracing/startup_tracing_browsertest.cc b/content/browser/tracing/startup_tracing_browsertest.cc index cb3f93c42b11ac..4b7f626aa9e80c 100644 --- a/content/browser/tracing/startup_tracing_browsertest.cc +++ b/content/browser/tracing/startup_tracing_browsertest.cc @@ -98,7 +98,7 @@ class LargeTraceEventData : public base::trace_event::ConvertableToTraceFormat { IN_PROC_BROWSER_TEST_F(StartupTracingInProcessTest, MAYBE_TestFilledStartupBuffer) { auto config = tracing::TraceStartupConfig::GetInstance() - ->GetDefaultBrowserStartupConfig(); + .GetDefaultBrowserStartupConfig(); config.SetTraceBufferSizeInEvents(0); config.SetTraceBufferSizeInKb(0); diff --git a/content/browser/tracing/startup_tracing_controller.cc b/content/browser/tracing/startup_tracing_controller.cc index 26c053330a473a..0a5af3fb211e37 100644 --- a/content/browser/tracing/startup_tracing_controller.cc +++ b/content/browser/tracing/startup_tracing_controller.cc @@ -342,7 +342,7 @@ base::FilePath StartupTracingController::GetOutputPath() { auto* command_line = base::CommandLine::ForCurrentProcess(); base::FilePath path_from_config = - tracing::TraceStartupConfig::GetInstance()->GetResultFile(); + tracing::TraceStartupConfig::GetInstance().GetResultFile(); if (!path_from_config.empty()) return path_from_config; @@ -384,8 +384,8 @@ void StartupTracingController::StartIfNeeded() { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_NE(state_, State::kRunning); - auto* trace_startup_config = tracing::TraceStartupConfig::GetInstance(); - if (!trace_startup_config->AttemptAdoptBySessionOwner( + auto& trace_startup_config = tracing::TraceStartupConfig::GetInstance(); + if (!trace_startup_config.AttemptAdoptBySessionOwner( tracing::TraceStartupConfig::SessionOwner::kTracingController)) { return; } @@ -399,7 +399,7 @@ void StartupTracingController::StartIfNeeded() { base::TaskShutdownBehavior::BLOCK_SHUTDOWN}); auto output_format = - tracing::TraceStartupConfig::GetInstance()->GetOutputFormat(); + tracing::TraceStartupConfig::GetInstance().GetOutputFormat(); BackgroundTracer::WriteMode write_mode; #if BUILDFLAG(IS_WIN) @@ -417,14 +417,14 @@ void StartupTracingController::StartIfNeeded() { #endif const auto& chrome_config = - tracing::TraceStartupConfig::GetInstance()->GetTraceConfig(); + tracing::TraceStartupConfig::GetInstance().GetTraceConfig(); perfetto::TraceConfig perfetto_config = tracing::GetDefaultPerfettoConfig( chrome_config, /*privacy_filtering_enabled=*/false, /*convert_to_legacy_json=*/output_format == tracing::TraceStartupConfig::OutputFormat::kLegacyJSON); int duration_in_seconds = - tracing::TraceStartupConfig::GetInstance()->GetStartupDuration(); + tracing::TraceStartupConfig::GetInstance().GetStartupDuration(); perfetto_config.set_duration_ms(duration_in_seconds * 1000); background_tracer_ = base::SequenceBound( @@ -465,7 +465,7 @@ void StartupTracingController::OnStoppedOnUIThread() { if (on_tracing_finished_) std::move(on_tracing_finished_).Run(); - tracing::TraceStartupConfig::GetInstance()->SetDisabled(); + tracing::TraceStartupConfig::GetInstance().SetDisabled(); } void StartupTracingController::SetUsingTemporaryFile( @@ -477,14 +477,15 @@ void StartupTracingController::SetUsingTemporaryFile( void StartupTracingController::SetDefaultBasename( std::string basename, ExtensionType extension_type) { - if (!tracing::TraceStartupConfig::GetInstance()->IsEnabled()) + if (!tracing::TraceStartupConfig::GetInstance().IsEnabled()) { return; + } if (basename_for_test_set_) return; if (extension_type == ExtensionType::kAppendAppropriate) { - switch (tracing::TraceStartupConfig::GetInstance()->GetOutputFormat()) { + switch (tracing::TraceStartupConfig::GetInstance().GetOutputFormat()) { case tracing::TraceStartupConfig::OutputFormat::kLegacyJSON: basename += ".json"; break; diff --git a/services/tracing/public/cpp/trace_startup.cc b/services/tracing/public/cpp/trace_startup.cc index c407125aee2dc8..eaceed6212803d 100644 --- a/services/tracing/public/cpp/trace_startup.cc +++ b/services/tracing/public/cpp/trace_startup.cc @@ -88,26 +88,26 @@ void EnableStartupTracingIfNeeded() { // Ensure TraceLog is initialized first. // https://crbug.com/764357 TraceLog::GetInstance(); - auto* startup_config = TraceStartupConfig::GetInstance(); + auto& startup_config = TraceStartupConfig::GetInstance(); - if (startup_config->IsEnabled()) { + if (startup_config.IsEnabled()) { // Ensure that data sources are created and registered. TraceEventAgent::GetInstance(); - TraceConfig trace_config = startup_config->GetTraceConfig(); + TraceConfig trace_config = startup_config.GetTraceConfig(); bool privacy_filtering_enabled = - startup_config->GetSessionOwner() == + startup_config.GetSessionOwner() == TraceStartupConfig::SessionOwner::kBackgroundTracing || command_line.HasSwitch(switches::kTraceStartupEnablePrivacyFiltering); - bool convert_to_legacy_json = startup_config->GetOutputFormat() == + bool convert_to_legacy_json = startup_config.GetOutputFormat() == TraceStartupConfig::OutputFormat::kLegacyJSON; perfetto::TraceConfig perfetto_config = tracing::GetDefaultPerfettoConfig( trace_config, privacy_filtering_enabled, convert_to_legacy_json); int duration_in_seconds = - tracing::TraceStartupConfig::GetInstance()->GetStartupDuration(); + tracing::TraceStartupConfig::GetInstance().GetStartupDuration(); if (duration_in_seconds > 0) perfetto_config.set_duration_ms(duration_in_seconds * 1000); perfetto::Tracing::SetupStartupTracingOpts opts; @@ -162,16 +162,16 @@ void PropagateTracingFlagsToChildProcessCmdLine(base::CommandLine* cmd_line) { // TODO(khokhlov): Figure out if we are using custom or system backend and // propagate this info to the child process (after startup tracing w/system // backend is supported in the SDK build). - const auto* startup_config = TraceStartupConfig::GetInstance(); + const auto& startup_config = TraceStartupConfig::GetInstance(); const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); - if (startup_config->IsEnabled()) { - trace_config = startup_config->GetTraceConfig(); + if (startup_config.IsEnabled()) { + trace_config = startup_config.GetTraceConfig(); privacy_filtering_enabled = - startup_config->GetSessionOwner() == + startup_config.GetSessionOwner() == TraceStartupConfig::SessionOwner::kBackgroundTracing || command_line.HasSwitch(switches::kTraceStartupEnablePrivacyFiltering); - convert_to_legacy_json = startup_config->GetOutputFormat() == + convert_to_legacy_json = startup_config.GetOutputFormat() == TraceStartupConfig::OutputFormat::kLegacyJSON; } else if (trace_log->IsEnabled()) { perfetto::DataSourceConfig data_source_config = From 079617d761a1c9aff6a15f7f2a481ed3c04774cb Mon Sep 17 00:00:00 2001 From: Darren Shen Date: Tue, 21 May 2024 15:34:45 +0000 Subject: [PATCH 06/40] Update caps icons. Bug: b/340324022 Change-Id: I484553d4652f3a077100d91374b64287ef68cda3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553210 Commit-Queue: Evan Stade Auto-Submit: Darren Shen Reviewed-by: Evan Stade Cr-Commit-Position: refs/heads/main@{#1303789} --- .../vector_icons/picker_caps_lock_off.icon | 65 ++++++++++++------- .../vector_icons/picker_caps_lock_on.icon | 41 ++++++++---- 2 files changed, 69 insertions(+), 37 deletions(-) diff --git a/ash/resources/vector_icons/picker_caps_lock_off.icon b/ash/resources/vector_icons/picker_caps_lock_off.icon index c62cec7001547a..00093798c03d30 100644 --- a/ash/resources/vector_icons/picker_caps_lock_off.icon +++ b/ash/resources/vector_icons/picker_caps_lock_off.icon @@ -3,31 +3,48 @@ // found in the LICENSE file. CANVAS_DIMENSIONS, 20, -MOVE_TO, 13.59f, 11.31f, -R_H_LINE_TO, 3.62f, -LINE_TO, 10, 1.83f, -R_LINE_TO, -2.54f, 3.34f, -R_LINE_TO, 6.13f, 6.14f, +FILL_RULE_NONZERO, +R_MOVE_TO, 10, 4, +R_LINE_TO, 3.67f, 4.58f, +R_H_LINE_TO, -1.56f, +R_LINE_TO, 1.65f, 1.65f, +R_H_LINE_TO, 1.64f, +R_ARC_TO, 0.83f, 0.83f, 0, 0, 0, 0.65f, -1.35f, +R_LINE_TO, -5.4f, -6.75f, +R_ARC_TO, 0.85f, 0.85f, 0, 0, 0, -1.3f, 0, +LINE_TO, 7.7f, 4.2f, +R_LINE_TO, 1.19f, 1.19f, +LINE_TO, 10, 4, CLOSE, -R_MOVE_TO, -0.49f, 1.74f, -R_CUBIC_TO, -2.05f, -2.04f, -4.31f, -4.3f, -6.61f, -6.61f, -R_LINE_TO, -3.7f, 4.87f, -R_H_LINE_TO, 4.1f, -R_V_LINE_TO, 3.79f, -R_H_LINE_TO, 6.21f, -R_V_LINE_TO, -2.05f, +R_MOVE_TO, 3, 7.89f, +R_LINE_TO, -1.66f, -1.66f, +R_LINE_TO, -3.5f, -3.53f, +R_LINE_TO, -1.18f, -1.19f, +LINE_TO, 3, 1.85f, +LINE_TO, 1.81f, 3, +R_LINE_TO, 3.8f, 3.79f, +LINE_TO, 4, 8.9f, +R_ARC_TO, 0.83f, 0.83f, 0, 0, 0, 0.65f, 1.35f, +H_LINE_TO, 7, +R_V_LINE_TO, 3, +R_ARC_TO, 0.83f, 0.83f, 0, 0, 0, 0.83f, 0.83f, +R_H_LINE_TO, 4.42f, +R_ARC_TO, 0.82f, 0.82f, 0, 0, 0, 0.46f, -0.16f, +R_LINE_TO, 1.79f, 1.79f, +H_LINE_TO, 3.75f, +R_V_LINE_TO, 1.66f, +R_H_LINE_TO, 12.5f, +R_V_LINE_TO, -0.27f, +R_LINE_TO, 1, -1, +LINE_TO, 13, 11.89f, CLOSE, -R_MOVE_TO, -9.27f, 3.51f, -R_V_LINE_TO, 1.73f, -R_H_LINE_TO, 12.33f, -R_V_LINE_TO, -1.73f, -H_LINE_TO, 3.83f, +MOVE_TO, 6.33f, 8.58f, +LINE_TO, 6.79f, 8, +R_LINE_TO, 0.58f, 0.57f, +R_LINE_TO, -1.04f, 0.01f, CLOSE, -NEW_PATH, -FILL_RULE_NONZERO, -MOVE_TO, 17.19f, 19.33f, -CUBIC_TO, 13.29f, 15.43f, 6.67f, 8.88f, 0.67f, 2.79f, -LINE_TO, 1.77f, 1.69f, -R_LINE_TO, 16.52f, 16.54f, -R_LINE_TO, -1.1f, 1.1f, +R_MOVE_TO, 2.29f, 3.8f, +V_LINE_TO, 9.84f, +R_LINE_TO, 2.55f, 2.54f, +H_LINE_TO, 8.62f, CLOSE diff --git a/ash/resources/vector_icons/picker_caps_lock_on.icon b/ash/resources/vector_icons/picker_caps_lock_on.icon index b067e02b087b12..59426bdd59a2ba 100644 --- a/ash/resources/vector_icons/picker_caps_lock_on.icon +++ b/ash/resources/vector_icons/picker_caps_lock_on.icon @@ -4,18 +4,33 @@ CANVAS_DIMENSIONS, 20, FILL_RULE_NONZERO, -MOVE_TO, 6.9f, 15.1f, -R_V_LINE_TO, -3.79f, -H_LINE_TO, 2.79f, -LINE_TO, 10, 1.83f, -R_LINE_TO, 7.21f, 9.48f, -R_H_LINE_TO, -4.1f, -R_V_LINE_TO, 3.79f, -H_LINE_TO, 6.9f, +MOVE_TO, 3.75f, 17.33f, +R_V_LINE_TO, -1.66f, +R_H_LINE_TO, 12.5f, +R_V_LINE_TO, 1.66f, +H_LINE_TO, 3.75f, CLOSE, -R_MOVE_TO, -3.06f, 3.19f, -R_V_LINE_TO, -1.73f, -R_H_LINE_TO, 12.33f, -R_V_LINE_TO, 1.73f, -H_LINE_TO, 3.83f, +MOVE_TO, 12.21f, 14, +H_LINE_TO, 7.79f, +R_ARC_TO, 0.83f, 0.83f, 0, 0, 1, -0.83f, -0.83f, +R_V_LINE_TO, -3, +H_LINE_TO, 4.6f, +R_ARC_TO, 0.83f, 0.83f, 0, 0, 1, -0.75f, -0.47f, +R_ARC_TO, 0.83f, 0.83f, 0, 0, 1, 0.15f, -0.8f, +R_LINE_TO, 5.4f, -6.75f, +R_ARC_TO, 0.85f, 0.85f, 0, 0, 1, 1.3f, 0, +R_LINE_TO, 5.4f, 6.75f, +R_ARC_TO, 0.83f, 0.83f, 0, 0, 1, -0.65f, 1.35f, +H_LINE_TO, 13, +R_V_LINE_TO, 3, +R_ARC_TO, 0.83f, 0.83f, 0, 0, 1, -0.79f, 0.75f, +CLOSE, +R_MOVE_TO, -3.58f, -1.66f, +R_H_LINE_TO, 2.74f, +V_LINE_TO, 8.58f, +R_H_LINE_TO, 2.3f, +LINE_TO, 10, 4, +LINE_TO, 6.33f, 8.58f, +R_H_LINE_TO, 2.3f, +R_V_LINE_TO, 3.76f, CLOSE From da4b21397a10116e944e59397141ae4062ce6329 Mon Sep 17 00:00:00 2001 From: Yue She Date: Tue, 21 May 2024 15:39:21 +0000 Subject: [PATCH 07/40] Change mac_default mixins to mac13 or mac14 part of mac14 upgrade tasks. This will affect Mac builders that run tests on MacOS14 Bug: 341704515 Change-Id: I09c9fbaffc4e72028d9fb8b825b5190f2650b4b9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5550920 Reviewed-by: Ben Pastene Commit-Queue: Yue She Cr-Commit-Position: refs/heads/main@{#1303790} --- infra/config/generated/testing/mixins.pyl | 4 +- infra/config/targets/mixins.star | 4 +- testing/buildbot/chromium.cft.json | 184 +++++++++--------- testing/buildbot/chromium.clang.json | 76 ++++---- testing/buildbot/chromium.coverage.json | 154 +++++++-------- testing/buildbot/chromium.dev.json | 20 +- testing/buildbot/chromium.fyi.json | 8 +- testing/buildbot/chromium.memory.fyi.json | 184 +++++++++--------- testing/buildbot/chromium.memory.json | 156 +++++++-------- testing/buildbot/chromium.rust.json | 16 +- testing/buildbot/chromium.webrtc.fyi.json | 14 +- testing/buildbot/chromium.webrtc.json | 14 +- testing/buildbot/internal.chrome.fyi.json | 2 +- .../buildbot/internal.optimization_guide.json | 40 ++-- testing/buildbot/mixins.pyl | 4 +- 15 files changed, 440 insertions(+), 440 deletions(-) diff --git a/infra/config/generated/testing/mixins.pyl b/infra/config/generated/testing/mixins.pyl index 1a6bccb07b8a01..37b65c0c124966 100644 --- a/infra/config/generated/testing/mixins.pyl +++ b/infra/config/generated/testing/mixins.pyl @@ -957,7 +957,7 @@ 'swarming': { 'dimensions': { 'cpu': 'arm64', - 'os': 'Mac-13', + 'os': 'Mac-13|Mac-14', }, }, }, @@ -965,7 +965,7 @@ 'swarming': { 'dimensions': { 'cpu': 'x86-64', - 'os': 'Mac-13', + 'os': 'Mac-13|Mac-14', }, }, }, diff --git a/infra/config/targets/mixins.star b/infra/config/targets/mixins.star index c735e51be8a54b..22e583eb3ef282 100644 --- a/infra/config/targets/mixins.star +++ b/infra/config/targets/mixins.star @@ -1232,7 +1232,7 @@ targets.mixin( swarming = targets.swarming( dimensions = { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", }, ), ) @@ -1245,7 +1245,7 @@ targets.mixin( swarming = targets.swarming( dimensions = { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", }, ), ) diff --git a/testing/buildbot/chromium.cft.json b/testing/buildbot/chromium.cft.json index 7005d30971319b..a6fd775daabea2 100644 --- a/testing/buildbot/chromium.cft.json +++ b/testing/buildbot/chromium.cft.json @@ -1850,7 +1850,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -1866,7 +1866,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -1882,7 +1882,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -1899,7 +1899,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -1915,7 +1915,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -1931,7 +1931,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -1947,7 +1947,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -1963,7 +1963,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -1987,7 +1987,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2003,7 +2003,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2019,7 +2019,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2039,7 +2039,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 20 @@ -2059,7 +2059,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2075,7 +2075,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2091,7 +2091,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2107,7 +2107,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2123,7 +2123,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2139,7 +2139,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2155,7 +2155,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2171,7 +2171,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 12 @@ -2188,7 +2188,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2204,7 +2204,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2220,7 +2220,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2236,7 +2236,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2252,7 +2252,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2268,7 +2268,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2284,7 +2284,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2301,7 +2301,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2317,7 +2317,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2333,7 +2333,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2349,7 +2349,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2365,7 +2365,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2381,7 +2381,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2397,7 +2397,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2413,7 +2413,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2429,7 +2429,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2445,7 +2445,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2461,7 +2461,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2477,7 +2477,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2493,7 +2493,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2512,7 +2512,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 @@ -2529,7 +2529,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2545,7 +2545,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2562,7 +2562,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2578,7 +2578,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2594,7 +2594,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2610,7 +2610,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2626,7 +2626,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2642,7 +2642,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2658,7 +2658,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2674,7 +2674,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2690,7 +2690,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2706,7 +2706,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2722,7 +2722,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2738,7 +2738,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2754,7 +2754,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2770,7 +2770,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2786,7 +2786,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2802,7 +2802,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2818,7 +2818,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2834,7 +2834,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2850,7 +2850,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2866,7 +2866,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2882,7 +2882,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2898,7 +2898,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2915,7 +2915,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 @@ -2932,7 +2932,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2948,7 +2948,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2964,7 +2964,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2980,7 +2980,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2996,7 +2996,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3012,7 +3012,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3028,7 +3028,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3044,7 +3044,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3060,7 +3060,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3076,7 +3076,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3092,7 +3092,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3108,7 +3108,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3129,7 +3129,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3158,7 +3158,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 12 @@ -3181,7 +3181,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3203,7 +3203,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3219,7 +3219,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3241,7 +3241,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3261,7 +3261,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3281,7 +3281,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3300,7 +3300,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3319,7 +3319,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3338,7 +3338,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -3362,7 +3362,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -3387,7 +3387,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -3411,7 +3411,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json index 6cecbd1abdf124..7af6244fb89c3b 100644 --- a/testing/buildbot/chromium.clang.json +++ b/testing/buildbot/chromium.clang.json @@ -710,7 +710,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -730,7 +730,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -757,7 +757,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 5 @@ -785,7 +785,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 7 @@ -805,7 +805,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -826,7 +826,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -847,7 +847,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -862,7 +862,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -883,7 +883,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -902,7 +902,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -921,7 +921,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -939,7 +939,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -954,7 +954,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -972,7 +972,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -990,7 +990,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1012,7 +1012,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -1036,7 +1036,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -1059,7 +1059,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -1089,7 +1089,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -1121,7 +1121,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1142,7 +1142,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1170,7 +1170,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -1199,7 +1199,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -1220,7 +1220,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1242,7 +1242,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1264,7 +1264,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1280,7 +1280,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1302,7 +1302,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1322,7 +1322,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1342,7 +1342,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1361,7 +1361,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1377,7 +1377,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1396,7 +1396,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1415,7 +1415,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "idempotent": false, @@ -1438,7 +1438,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "idempotent": false, @@ -1463,7 +1463,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "idempotent": false, @@ -1487,7 +1487,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -1510,7 +1510,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json index c3d697ee6108d7..b233cf82b87f24 100644 --- a/testing/buildbot/chromium.coverage.json +++ b/testing/buildbot/chromium.coverage.json @@ -20518,7 +20518,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20534,7 +20534,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20550,7 +20550,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20567,7 +20567,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20583,7 +20583,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20599,7 +20599,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20615,7 +20615,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20631,7 +20631,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20655,7 +20655,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20671,7 +20671,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20687,7 +20687,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20706,7 +20706,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20722,7 +20722,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20738,7 +20738,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20754,7 +20754,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20770,7 +20770,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20786,7 +20786,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20802,7 +20802,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20821,7 +20821,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 8 @@ -20838,7 +20838,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20854,7 +20854,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20870,7 +20870,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20886,7 +20886,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20902,7 +20902,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20918,7 +20918,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20934,7 +20934,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20951,7 +20951,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20967,7 +20967,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20983,7 +20983,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -20999,7 +20999,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21015,7 +21015,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21031,7 +21031,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21047,7 +21047,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21063,7 +21063,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21079,7 +21079,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21095,7 +21095,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21111,7 +21111,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21127,7 +21127,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21143,7 +21143,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21162,7 +21162,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 3 @@ -21179,7 +21179,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21195,7 +21195,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21212,7 +21212,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21228,7 +21228,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21244,7 +21244,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21260,7 +21260,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21276,7 +21276,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21292,7 +21292,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21308,7 +21308,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21324,7 +21324,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21340,7 +21340,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21356,7 +21356,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21372,7 +21372,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21388,7 +21388,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21404,7 +21404,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21420,7 +21420,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21436,7 +21436,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21452,7 +21452,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21468,7 +21468,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21484,7 +21484,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21500,7 +21500,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21516,7 +21516,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21532,7 +21532,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21548,7 +21548,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21567,7 +21567,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 3 @@ -21584,7 +21584,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21600,7 +21600,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21616,7 +21616,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21632,7 +21632,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21648,7 +21648,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21664,7 +21664,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21680,7 +21680,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21696,7 +21696,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21712,7 +21712,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21728,7 +21728,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21744,7 +21744,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -21760,7 +21760,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, diff --git a/testing/buildbot/chromium.dev.json b/testing/buildbot/chromium.dev.json index d41dfa174bbd9d..57ee909b839ea0 100644 --- a/testing/buildbot/chromium.dev.json +++ b/testing/buildbot/chromium.dev.json @@ -174,7 +174,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" }, @@ -189,7 +189,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" }, @@ -204,7 +204,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" }, @@ -219,7 +219,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" }, @@ -234,7 +234,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" }, @@ -253,7 +253,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" }, @@ -268,7 +268,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" }, @@ -283,7 +283,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" }, @@ -298,7 +298,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" }, @@ -313,7 +313,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" }, diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 732841ede75f85..dc1e152f80548f 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json @@ -47989,7 +47989,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chromium.tests.finch" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -48010,7 +48010,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chromium.tests.finch" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -48030,7 +48030,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chromium.tests.finch" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -48050,7 +48050,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chromium.tests.finch" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" diff --git a/testing/buildbot/chromium.memory.fyi.json b/testing/buildbot/chromium.memory.fyi.json index 52e4b63a0f8625..6c34deba3bbc55 100644 --- a/testing/buildbot/chromium.memory.fyi.json +++ b/testing/buildbot/chromium.memory.fyi.json @@ -2812,7 +2812,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2830,7 +2830,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2848,7 +2848,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2866,7 +2866,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2884,7 +2884,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2908,7 +2908,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2926,7 +2926,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2944,7 +2944,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2962,7 +2962,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2980,7 +2980,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -2998,7 +2998,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3016,7 +3016,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3034,7 +3034,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3052,7 +3052,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3074,7 +3074,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3092,7 +3092,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3110,7 +3110,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3129,7 +3129,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3147,7 +3147,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3165,7 +3165,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3183,7 +3183,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3201,7 +3201,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3225,7 +3225,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3243,7 +3243,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3261,7 +3261,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3279,7 +3279,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 10 @@ -3299,7 +3299,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3317,7 +3317,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3335,7 +3335,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3353,7 +3353,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3371,7 +3371,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3389,7 +3389,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3407,7 +3407,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3425,7 +3425,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 8 @@ -3444,7 +3444,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3462,7 +3462,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3480,7 +3480,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3498,7 +3498,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3516,7 +3516,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3534,7 +3534,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3552,7 +3552,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3571,7 +3571,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3589,7 +3589,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3607,7 +3607,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3625,7 +3625,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3643,7 +3643,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3661,7 +3661,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3679,7 +3679,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3697,7 +3697,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3715,7 +3715,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3733,7 +3733,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3751,7 +3751,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3769,7 +3769,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3787,7 +3787,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3805,7 +3805,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 3 @@ -3824,7 +3824,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3842,7 +3842,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3861,7 +3861,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3879,7 +3879,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3897,7 +3897,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3915,7 +3915,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3933,7 +3933,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3951,7 +3951,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3969,7 +3969,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -3987,7 +3987,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4005,7 +4005,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4023,7 +4023,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4041,7 +4041,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4059,7 +4059,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4077,7 +4077,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4095,7 +4095,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4113,7 +4113,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4131,7 +4131,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4149,7 +4149,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4167,7 +4167,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4185,7 +4185,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4203,7 +4203,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4221,7 +4221,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4239,7 +4239,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4257,7 +4257,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 3 @@ -4276,7 +4276,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4294,7 +4294,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4312,7 +4312,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4330,7 +4330,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4348,7 +4348,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4366,7 +4366,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4384,7 +4384,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4402,7 +4402,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4420,7 +4420,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4438,7 +4438,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4456,7 +4456,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -4474,7 +4474,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 29796fcfb091da..6b627aa5091dab 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json @@ -9102,7 +9102,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9120,7 +9120,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9138,7 +9138,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9157,7 +9157,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9175,7 +9175,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9193,7 +9193,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9211,7 +9211,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9229,7 +9229,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9253,7 +9253,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9271,7 +9271,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9289,7 +9289,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9309,7 +9309,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 30 @@ -9329,7 +9329,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9347,7 +9347,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9365,7 +9365,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9383,7 +9383,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9401,7 +9401,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9419,7 +9419,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9437,7 +9437,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9456,7 +9456,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 8 @@ -9475,7 +9475,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9493,7 +9493,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9511,7 +9511,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9529,7 +9529,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9547,7 +9547,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9565,7 +9565,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9583,7 +9583,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9602,7 +9602,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9620,7 +9620,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9638,7 +9638,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9656,7 +9656,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9674,7 +9674,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9692,7 +9692,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9710,7 +9710,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9728,7 +9728,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9746,7 +9746,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9764,7 +9764,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9782,7 +9782,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9800,7 +9800,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9818,7 +9818,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9837,7 +9837,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 3 @@ -9856,7 +9856,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9874,7 +9874,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9893,7 +9893,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9911,7 +9911,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9929,7 +9929,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9947,7 +9947,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9965,7 +9965,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -9983,7 +9983,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10001,7 +10001,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10019,7 +10019,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10037,7 +10037,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10055,7 +10055,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10073,7 +10073,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10091,7 +10091,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10109,7 +10109,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10127,7 +10127,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10145,7 +10145,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10163,7 +10163,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10181,7 +10181,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10199,7 +10199,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10217,7 +10217,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10235,7 +10235,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10253,7 +10253,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10271,7 +10271,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10289,7 +10289,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 3 @@ -10308,7 +10308,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10326,7 +10326,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10344,7 +10344,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10362,7 +10362,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 @@ -10381,7 +10381,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10399,7 +10399,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10417,7 +10417,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10435,7 +10435,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10453,7 +10453,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10471,7 +10471,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10489,7 +10489,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -10507,7 +10507,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, diff --git a/testing/buildbot/chromium.rust.json b/testing/buildbot/chromium.rust.json index 2ebcb028b23634..5ec0edded7d2fe 100644 --- a/testing/buildbot/chromium.rust.json +++ b/testing/buildbot/chromium.rust.json @@ -661,7 +661,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -679,7 +679,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -694,7 +694,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -709,7 +709,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -724,7 +724,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -739,7 +739,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -754,7 +754,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -771,7 +771,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, diff --git a/testing/buildbot/chromium.webrtc.fyi.json b/testing/buildbot/chromium.webrtc.fyi.json index c444990ae11f98..37a7816988eb2f 100644 --- a/testing/buildbot/chromium.webrtc.fyi.json +++ b/testing/buildbot/chromium.webrtc.fyi.json @@ -313,7 +313,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -333,7 +333,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -351,7 +351,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -371,7 +371,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -392,7 +392,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -410,7 +410,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -428,7 +428,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, diff --git a/testing/buildbot/chromium.webrtc.json b/testing/buildbot/chromium.webrtc.json index 254df8f766500c..c99d8ee1852370 100644 --- a/testing/buildbot/chromium.webrtc.json +++ b/testing/buildbot/chromium.webrtc.json @@ -231,7 +231,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -251,7 +251,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -269,7 +269,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -289,7 +289,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -310,7 +310,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -328,7 +328,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -346,7 +346,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13" + "os": "Mac-13|Mac-14" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, diff --git a/testing/buildbot/internal.chrome.fyi.json b/testing/buildbot/internal.chrome.fyi.json index 0bcee5203a745a..119a09142a9ae7 100644 --- a/testing/buildbot/internal.chrome.fyi.json +++ b/testing/buildbot/internal.chrome.fyi.json @@ -157,7 +157,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests.finch" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" diff --git a/testing/buildbot/internal.optimization_guide.json b/testing/buildbot/internal.optimization_guide.json index 95c4d14c4a77b3..f40379151515f3 100644 --- a/testing/buildbot/internal.optimization_guide.json +++ b/testing/buildbot/internal.optimization_guide.json @@ -121,7 +121,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -140,7 +140,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -159,7 +159,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -175,7 +175,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -191,7 +191,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -220,7 +220,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -243,7 +243,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -270,7 +270,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -296,7 +296,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -316,7 +316,7 @@ "swarming": { "dimensions": { "cpu": "arm64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -340,7 +340,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -359,7 +359,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -378,7 +378,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -394,7 +394,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -410,7 +410,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -439,7 +439,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -462,7 +462,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -489,7 +489,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -515,7 +515,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -535,7 +535,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-13", + "os": "Mac-13|Mac-14", "pool": "chrome.tests" }, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index 1a6bccb07b8a01..37b65c0c124966 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl @@ -957,7 +957,7 @@ 'swarming': { 'dimensions': { 'cpu': 'arm64', - 'os': 'Mac-13', + 'os': 'Mac-13|Mac-14', }, }, }, @@ -965,7 +965,7 @@ 'swarming': { 'dimensions': { 'cpu': 'x86-64', - 'os': 'Mac-13', + 'os': 'Mac-13|Mac-14', }, }, }, From dab0a5c374e258ae037610e904bef3c22bd087fe Mon Sep 17 00:00:00 2001 From: chromium-autoroll Date: Tue, 21 May 2024 15:39:30 +0000 Subject: [PATCH 08/40] Roll FreeType from 4ccdc9f98291 to 347276c1f6dc (2 revisions) https://chromium.googlesource.com/chromium/src/third_party/freetype2.git/+log/4ccdc9f98291..347276c1f6dc 2024-05-21 apodtele@gmail.com * src/truetype/ttgxvar.c (tt_var_get_item_delta): Align with specs. 2024-05-21 apodtele@gmail.com * src/truetype/ttgxvar.c (tt_var_get_item_delta): Minor refactoring. If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/freetype-chromium Please CC bungeman@google.com,drott@google.com,thestig@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Chromium: https://bugs.chromium.org/p/chromium/issues/entry To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md Cq-Include-Trybots: luci.chromium.try:linux_chromium_msan_rel_ng;luci.chromium.try:linux-blink-rel;luci.chromium.try:mac10.15-blink-rel;luci.chromium.try:win10.20h2-blink-rel Tbr: bungeman@google.com,drott@google.com,thestig@google.com Change-Id: If96fefa52545e618e19a80fa770b32eca5c2f0c5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5554944 Reviewed-by: Ben Wagner Commit-Queue: Ben Wagner Bot-Commit: chromium-autoroll Cr-Commit-Position: refs/heads/main@{#1303791} --- DEPS | 2 +- third_party/freetype/README.chromium | 4 ++-- third_party/freetype/src | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index 7d53a06a83f057..6254bfb0439197 100644 --- a/DEPS +++ b/DEPS @@ -359,7 +359,7 @@ vars = { # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. - 'freetype_revision': '4ccdc9f98291fe40c2e32cc9914e327810d845ec', + 'freetype_revision': '347276c1f6dcbc0eed3f0880b3695167a91c205d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium index 4dd32b7459662c..bf0d7c50d0b19c 100644 --- a/third_party/freetype/README.chromium +++ b/third_party/freetype/README.chromium @@ -1,7 +1,7 @@ Name: FreeType URL: http://www.freetype.org/ -Version: VER-2-13-2-150-g4ccdc9f98 -Revision: 4ccdc9f98291fe40c2e32cc9914e327810d845ec +Version: VER-2-13-2-152-g347276c1f +Revision: 347276c1f6dcbc0eed3f0880b3695167a91c205d CPEPrefix: cpe:/a:freetype:freetype:2.13.2 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent JPEG Group) licenses" diff --git a/third_party/freetype/src b/third_party/freetype/src index 4ccdc9f98291fe..347276c1f6dcbc 160000 --- a/third_party/freetype/src +++ b/third_party/freetype/src @@ -1 +1 @@ -Subproject commit 4ccdc9f98291fe40c2e32cc9914e327810d845ec +Subproject commit 347276c1f6dcbc0eed3f0880b3695167a91c205d From a98ba9f17a659ce9c64f02295ae9ddf7af05cb28 Mon Sep 17 00:00:00 2001 From: Dibyajyoti Pal Date: Tue, 21 May 2024 15:44:19 +0000 Subject: [PATCH 09/40] [PWA] Remove WebAppInstallDialogCoordinator for install dialog tracking This CL removes the WebAppInstallDialogCoordinator entirely, and instead uses the WebContentsModalDialogManager to verify if any installation dialog is being shown for a specific web contents. To do these, the following changes were made: 1. Some tests were modified to use views::test::AnyWidgetShownObserver and WidgetDestroyedWaiter to verify if a widget is being shown or is being destroyed. 2. Creating a new function observing the dialog destruction to measure WebApp.InstallConfirmation.CloseReason for install dialogs based on when it is closed. The purpose of the histogram has been fulfilled, so even if there is a minor loss of accuracy, it is not a huge deal. 3. Changes in PWAConfirmationBubbleView made in crrev.com/c/5299871 has been reverted. This is done because this is the old install dialog which is heavily anchored to the PWA install page action view. Since the dialog will be going away soon (within a few milestones once Universal Install ramps up), this change should be fine (and a no-op, since that is dead code now). This is being kept around till Universal Install ramps up to 100% in Stable (already in progress). See IconVisibilityAfterTabSwitchingWhenPWAConfirmationBubbleViewShowing as an exmaple of how these 2 classes are so tightly coupled. Bug: 338641380 Change-Id: Ic980a24d927cee3d5c0179eafbf0527d97eeb9fe Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5545726 Commit-Queue: Dibyajyoti Pal Reviewed-by: Mike Wasserman Reviewed-by: Callistus Tan Cr-Commit-Position: refs/heads/main@{#1303792} --- .../ash/system_web_apps/apps/help_app/DEPS | 5 - .../help_app_integration_browsertest.cc | 12 +- chrome/browser/ui/BUILD.gn | 2 - .../ui/views/page_action/pwa_install_view.cc | 19 +-- .../pwa_install_view_browsertest.cc | 31 ++-- .../web_apps/pwa_confirmation_bubble_view.cc | 29 +++- .../web_apps/pwa_confirmation_bubble_view.h | 8 +- ..._install_dialog_bubble_view_browsertest.cc | 152 ++++++++++-------- .../web_app_detailed_install_dialog.cc | 21 ++- .../web_apps/web_app_diy_install_dialog.cc | 14 +- .../web_app_install_dialog_coordinator.cc | 82 ---------- .../web_app_install_dialog_coordinator.h | 45 ------ .../web_app_install_dialog_delegate.cc | 32 +++- .../web_app_install_dialog_delegate.h | 5 + .../web_apps/web_app_simple_install_dialog.cc | 16 +- 15 files changed, 204 insertions(+), 269 deletions(-) delete mode 100644 chrome/browser/ash/system_web_apps/apps/help_app/DEPS delete mode 100644 chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.cc delete mode 100644 chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h diff --git a/chrome/browser/ash/system_web_apps/apps/help_app/DEPS b/chrome/browser/ash/system_web_apps/apps/help_app/DEPS deleted file mode 100644 index 116d69a543f6b1..00000000000000 --- a/chrome/browser/ash/system_web_apps/apps/help_app/DEPS +++ /dev/null @@ -1,5 +0,0 @@ -specific_include_rules = { - "help_app_integration_browsertest.cc": [ - "+chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h", - ], -} diff --git a/chrome/browser/ash/system_web_apps/apps/help_app/help_app_integration_browsertest.cc b/chrome/browser/ash/system_web_apps/apps/help_app/help_app_integration_browsertest.cc index 43e4c53636cdf9..877f77b07ab2a8 100644 --- a/chrome/browser/ash/system_web_apps/apps/help_app/help_app_integration_browsertest.cc +++ b/chrome/browser/ash/system_web_apps/apps/help_app/help_app_integration_browsertest.cc @@ -48,7 +48,6 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/chrome_pages.h" -#include "chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h" #include "chrome/browser/ui/webui/ash/system_web_dialog_delegate.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_utils.h" @@ -84,6 +83,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/views/widget/any_widget_observer.h" +#include "ui/views/widget/widget.h" #include "url/url_constants.h" namespace ash { @@ -791,13 +791,9 @@ IN_PROC_BROWSER_TEST_P(HelpAppIntegrationTest, // The active tab should be the `test_url` we opened. EXPECT_EQ(test_url, GetActiveWebContents()->GetVisibleURL()); - // Wait for the PWA install dialog to show up. Internally, this is called the - // PWAConfirmationBubbleView (Not to be confused with the omnibox icon). - waiter.WaitIfNeededAndGet(); - - EXPECT_TRUE( - web_app::WebAppInstallDialogCoordinator::GetOrCreateForBrowser(browser()) - ->IsShowing()); + // Wait for the PWA install dialog to show up. + views::Widget* widget = waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); } // Test that the Help App's `openUrlInBrowserAndTriggerInstallDialog` crashes diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index e494ebb8bde6aa..c0b1f254c20f55 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn @@ -6337,8 +6337,6 @@ static_library("ui") { "views/web_apps/web_app_identity_update_confirmation_view.h", "views/web_apps/web_app_info_image_source.cc", "views/web_apps/web_app_info_image_source.h", - "views/web_apps/web_app_install_dialog_coordinator.cc", - "views/web_apps/web_app_install_dialog_coordinator.h", "views/web_apps/web_app_install_dialog_delegate.cc", "views/web_apps/web_app_install_dialog_delegate.h", "views/web_apps/web_app_simple_install_dialog.cc", diff --git a/chrome/browser/ui/views/page_action/pwa_install_view.cc b/chrome/browser/ui/views/page_action/pwa_install_view.cc index 57f9a5ad823df8..095a4560902cc1 100644 --- a/chrome/browser/ui/views/page_action/pwa_install_view.cc +++ b/chrome/browser/ui/views/page_action/pwa_install_view.cc @@ -19,7 +19,6 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h" -#include "chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h" #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h" #include "chrome/browser/ui/web_applications/web_app_dialogs.h" #include "chrome/browser/web_applications/web_app_constants.h" @@ -31,6 +30,7 @@ #include "components/site_engagement/content/site_engagement_service.h" #include "components/user_education/common/feature_promo_controller.h" #include "components/user_education/common/feature_promo_specification.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/webapps/browser/banners/app_banner_manager.h" #include "components/webapps/browser/banners/web_app_banner_data.h" #include "components/webapps/browser/installable/installable_metrics.h" @@ -120,8 +120,6 @@ void PwaInstallView::UpdateImpl() { webapps::AppBannerManager::GetInstallableWebAppName(web_contents))); auto* manager = webapps::AppBannerManager::FromWebContents(web_contents); - auto* web_app_install_dialog_coordinator = - web_app::WebAppInstallDialogCoordinator::GetOrCreateForBrowser(browser); // May not be present e.g. in incognito mode. if (!manager) { @@ -141,8 +139,9 @@ void PwaInstallView::UpdateImpl() { ResetSlideAnimation(false); } - SetVisible(is_probably_promotable || - web_app_install_dialog_coordinator->IsShowing()); + // TODO(crbug.com/341254289): Cleanup after Universal Install has launched to + // 100% on Stable. + SetVisible(is_probably_promotable || PWAConfirmationBubbleView::IsShowing()); // See above about safety of this call. std::optional data = @@ -228,13 +227,9 @@ views::BubbleDialogDelegate* PwaInstallView::GetBubble() const { return nullptr; } - auto* dialog_coordinator = - web_app::WebAppInstallDialogCoordinator::GetOrCreateForBrowser(browser); - if (!dialog_coordinator) { - return nullptr; - } - - auto* bubble = dialog_coordinator->GetBubbleView(); + // TODO(crbug.com/341254289): Cleanup after Universal Install has launched to + // 100% on Stable. + auto* bubble = PWAConfirmationBubbleView::GetBubble(); // Only return the active bubble if it's anchored to `this`. (This check takes // the more generic approach of verifying that it's the same widget as to // avoid depending too heavily on the exact details of how anchoring works.) diff --git a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc index 8bd38a44e629a5..fa27f78af4a8ee 100644 --- a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc +++ b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc @@ -21,7 +21,6 @@ #include "chrome/browser/ui/views/location_bar/star_view.h" #include "chrome/browser/ui/views/page_action/page_action_icon_view.h" #include "chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h" -#include "chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h" #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h" #include "chrome/browser/ui/web_applications/web_app_dialogs.h" #include "chrome/browser/web_applications/install_bounce_metric.h" @@ -53,6 +52,7 @@ #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" #include "services/network/public/cpp/network_switches.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/color_utils.h" @@ -60,6 +60,7 @@ #include "ui/views/test/widget_test.h" #include "ui/views/view_observer.h" #include "ui/views/widget/any_widget_observer.h" +#include "ui/views/widget/widget.h" #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/components/arc/test/arc_util_test_support.h" @@ -332,19 +333,6 @@ class PwaInstallViewBrowserTest : public extensions::ExtensionBrowserTest, return pwa_confirmation_bubble_id_waiter.WaitIfNeededAndGet(); } - void AwaitPwaInstallDialogClosed() { - auto* install_dialog_coordinator = - web_app::WebAppInstallDialogCoordinator::GetOrCreateForBrowser( - browser()); - if (install_dialog_coordinator->IsShowing()) { - base::RunLoop run_loop; - install_dialog_coordinator->GetBubbleView() - ->RegisterDeleteDelegateCallback(run_loop.QuitClosure()); - install_dialog_coordinator->GetBubbleView()->GetWidget()->CloseWithReason( - views::Widget::ClosedReason::kEscKeyPressed); - run_loop.Run(); - } - } protected: bool IsUniversalInstallEnabled() { return GetParam(); } @@ -472,15 +460,16 @@ IN_PROC_BROWSER_TEST_P( ASSERT_EQ(installable_web_contents, GetCurrentTab()); EXPECT_TRUE(pwa_install_view_->GetVisible()); - EXPECT_NE(ClickPWAInstallIconAndWaitForBubbleShown(), nullptr); - + views::Widget* pwa_install_widget = + ClickPWAInstallIconAndWaitForBubbleShown(); + EXPECT_NE(pwa_install_widget, nullptr); chrome::SelectNextTab(browser()); - AwaitPwaInstallDialogClosed(); - ASSERT_EQ(non_installable_web_contents, GetCurrentTab()); + views::test::WidgetDestroyedWaiter destroy_waiter(pwa_install_widget); + pwa_install_widget->CloseWithReason( + views::Widget::ClosedReason::kEscKeyPressed); + destroy_waiter.Wait(); - EXPECT_FALSE( - web_app::WebAppInstallDialogCoordinator::GetOrCreateForBrowser(browser()) - ->IsShowing()); + ASSERT_EQ(non_installable_web_contents, GetCurrentTab()); EXPECT_FALSE(pwa_install_view_->GetVisible()); } diff --git a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc index 3314814ec6c7e2..dd17cb4fee387b 100644 --- a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc +++ b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc @@ -54,6 +54,8 @@ namespace { +PWAConfirmationBubbleView* g_bubble_ = nullptr; + // Returns an ImageView containing the app icon. std::unique_ptr CreateIconView( const web_app::WebAppInstallInfo& web_app_info) { @@ -82,10 +84,20 @@ DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(PWAConfirmationBubbleView, DEFINE_CLASS_CUSTOM_ELEMENT_EVENT_TYPE(PWAConfirmationBubbleView, kInstalledPWAEventId); +// static +bool PWAConfirmationBubbleView::IsShowing() { + return g_bubble_; +} + +// static +PWAConfirmationBubbleView* PWAConfirmationBubbleView::GetBubble() { + return g_bubble_; +} + PWAConfirmationBubbleView::PWAConfirmationBubbleView( views::View* anchor_view, base::WeakPtr web_contents, - PageActionIconView* highlight_icon_button, + PageActionIconView* pwa_install_icon_view, std::unique_ptr web_app_info, std::unique_ptr install_tracker, web_app::AppInstallationAcceptanceCallback callback, @@ -94,6 +106,7 @@ PWAConfirmationBubbleView::PWAConfirmationBubbleView( feature_engagement::Tracker* tracker) : LocationBarBubbleDelegateView(anchor_view, web_contents.get()), web_contents_(web_contents), + pwa_install_icon_view_(pwa_install_icon_view), web_app_info_(std::move(web_app_info)), install_tracker_(std::move(install_tracker)), callback_(std::move(callback)), @@ -160,7 +173,10 @@ PWAConfirmationBubbleView::PWAConfirmationBubbleView( SetDefaultButton(ui::DIALOG_BUTTON_CANCEL); - SetHighlightedButton(highlight_icon_button); + SetHighlightedButton(pwa_install_icon_view_); + + CHECK(!g_bubble_); + g_bubble_ = this; } PWAConfirmationBubbleView::~PWAConfirmationBubbleView() = default; @@ -175,6 +191,8 @@ void PWAConfirmationBubbleView::OnWidgetInitialized() { bool PWAConfirmationBubbleView::OnCloseRequested( views::Widget::ClosedReason close_reason) { + base::UmaHistogramEnumeration("WebApp.InstallConfirmation.CloseReason", + close_reason); webapps::MlInstallUserResponse response; switch (close_reason) { case views::Widget::ClosedReason::kAcceptButtonClicked: @@ -203,6 +221,13 @@ views::View* PWAConfirmationBubbleView::GetInitiallyFocusedView() { } void PWAConfirmationBubbleView::WindowClosing() { + DCHECK_EQ(g_bubble_, this); + g_bubble_ = nullptr; + + if (pwa_install_icon_view_) { + pwa_install_icon_view_->Update(); + } + // If |web_app_info_| is populated, then the bubble was not accepted. if (web_app_info_) { base::RecordAction(base::UserMetricsAction("WebAppInstallCancelled")); diff --git a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h index 34444e675a38b7..0adab4a194bf96 100644 --- a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h +++ b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h @@ -39,12 +39,14 @@ class MlInstallOperationTracker; // PWAConfirmationBubbleView provides a bubble dialog for accepting or rejecting // the installation of a PWA (Progressive Web App) anchored off the PWA install // icon in the omnibox. +// TODO(crbug.com/341254289): Completely remove after Universal Install has +// launched to 100% on Stable. class PWAConfirmationBubbleView : public LocationBarBubbleDelegateView { public: PWAConfirmationBubbleView( views::View* anchor_view, base::WeakPtr web_contents, - PageActionIconView* highlight_icon_button, + PageActionIconView* pwa_install_icon_view, std::unique_ptr web_app_info, std::unique_ptr install_tracker, web_app::AppInstallationAcceptanceCallback callback, @@ -62,6 +64,9 @@ class PWAConfirmationBubbleView : public LocationBarBubbleDelegateView { DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kInstallButton); DECLARE_CLASS_CUSTOM_ELEMENT_EVENT_TYPE(kInstalledPWAEventId); + static bool IsShowing(); + static PWAConfirmationBubbleView* GetBubble(); + // WidgetDelegate void OnWidgetInitialized() override; @@ -77,6 +82,7 @@ class PWAConfirmationBubbleView : public LocationBarBubbleDelegateView { private: base::WeakPtr web_contents_; + raw_ptr pwa_install_icon_view_ = nullptr; std::unique_ptr web_app_info_; std::unique_ptr install_tracker_; web_app::AppInstallationAcceptanceCallback callback_; diff --git a/chrome/browser/ui/views/web_apps/simple_install_dialog_bubble_view_browsertest.cc b/chrome/browser/ui/views/web_apps/simple_install_dialog_bubble_view_browsertest.cc index 3eef09673717c4..633f315161eddf 100644 --- a/chrome/browser/ui/views/web_apps/simple_install_dialog_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/web_apps/simple_install_dialog_bubble_view_browsertest.cc @@ -7,9 +7,9 @@ #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "base/test/test_future.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h" #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h" #include "chrome/browser/ui/web_applications/web_app_browsertest_base.h" #include "chrome/browser/ui/web_applications/web_app_dialogs.h" @@ -32,6 +32,7 @@ #include "components/webapps/common/web_app_id.h" #include "content/public/test/browser_test.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/views/test/dialog_test.h" #include "ui/views/test/widget_test.h" #include "ui/views/widget/any_widget_observer.h" #include "ui/views/widget/widget.h" @@ -78,12 +79,14 @@ class SimpleInstallDialogBubbleViewBrowserTest } protected: - views::BubbleDialogDelegate* GetBubbleView(Browser* browser) { - return WebAppInstallDialogCoordinator::GetOrCreateForBrowser(browser) - ->GetBubbleView(); - } - bool UniversalInstallEnabled() { return GetParam(); } + std::string GetBubbleName() { + if (UniversalInstallEnabled()) { + return "WebAppSimpleInstallDialog"; + } else { + return "PWAConfirmationBubbleView"; + } + } private: base::test::ScopedFeatureList scoped_feature_list_; @@ -99,7 +102,6 @@ IN_PROC_BROWSER_TEST_P(SimpleInstallDialogBubbleViewBrowserTest, Profile* profile = browser()->profile(); webapps::AppId app_id = test::InstallWebApp(profile, std::move(app_info)); Browser* browser = ::web_app::LaunchWebAppBrowser(profile, app_id); - app_info = GetAppInfo(); std::unique_ptr install_tracker = GetInstallTracker(browser); @@ -113,26 +115,28 @@ IN_PROC_BROWSER_TEST_P(SimpleInstallDialogBubbleViewBrowserTest, IN_PROC_BROWSER_TEST_P(SimpleInstallDialogBubbleViewBrowserTest, CancelledDialogReportsMetrics) { auto app_info = GetAppInfo(); - std::unique_ptr install_tracker = GetInstallTracker(browser()); - base::RunLoop loop; + views::NamedWidgetShownWaiter widget_waiter( + views::test::AnyWidgetTestPasskey{}, GetBubbleName()); + base::test::TestFuture> test_future; ShowSimpleInstallDialogForWebApps( browser()->tab_strip_model()->GetActiveWebContents(), std::move(app_info), - std::move(install_tracker), - base::BindLambdaForTesting( - [&](bool accepted, - std::unique_ptr app_info_callback) { - loop.Quit(); - })); + std::move(install_tracker), test_future.GetCallback()); + // Wait for the dialog to show up. + views::Widget* widget = widget_waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + EXPECT_FALSE(test_future.IsReady()); + + // Wait for the dialog to be destroyed post cancellation. base::HistogramTester histograms; - views::test::WidgetDestroyedWaiter destroyed_waiter( - GetBubbleView(browser())->GetWidget()); - GetBubbleView(browser())->CancelDialog(); - loop.Run(); + views::test::WidgetDestroyedWaiter destroyed_waiter(widget); + views::test::CancelDialog(widget); destroyed_waiter.Wait(); + ASSERT_TRUE(test_future.Wait()); + EXPECT_FALSE(test_future.Get()); histograms.ExpectUniqueSample( "WebApp.InstallConfirmation.CloseReason", @@ -142,26 +146,27 @@ IN_PROC_BROWSER_TEST_P(SimpleInstallDialogBubbleViewBrowserTest, IN_PROC_BROWSER_TEST_P(SimpleInstallDialogBubbleViewBrowserTest, AcceptDialogReportsMetrics) { auto app_info = GetAppInfo(); - std::unique_ptr install_tracker = GetInstallTracker(browser()); - base::RunLoop loop; + views::NamedWidgetShownWaiter widget_waiter( + views::test::AnyWidgetTestPasskey{}, GetBubbleName()); + base::test::TestFuture> test_future; ShowSimpleInstallDialogForWebApps( browser()->tab_strip_model()->GetActiveWebContents(), std::move(app_info), - std::move(install_tracker), - base::BindLambdaForTesting( - [&](bool accepted, - std::unique_ptr app_info_callback) { - loop.Quit(); - })); + std::move(install_tracker), test_future.GetCallback()); + views::Widget* widget = widget_waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + EXPECT_FALSE(test_future.IsReady()); + + // Wait for the dialog to be destroyed post acceptance. base::HistogramTester histogram_tester; - views::test::WidgetDestroyedWaiter destroyed_waiter( - GetBubbleView(browser())->GetWidget()); - GetBubbleView(browser())->AcceptDialog(); - loop.Run(); + views::test::WidgetDestroyedWaiter destroyed_waiter(widget); + views::test::AcceptDialog(widget); destroyed_waiter.Wait(); + ASSERT_TRUE(test_future.Wait()); + EXPECT_TRUE(test_future.Get()); histogram_tester.ExpectUniqueSample( "WebApp.InstallConfirmation.CloseReason", @@ -172,23 +177,27 @@ IN_PROC_BROWSER_TEST_P(SimpleInstallDialogBubbleViewBrowserTest, CancelledDialogReportsIphIgnored) { auto app_info = GetAppInfo(); GURL start_url = app_info->start_url; - - base::RunLoop loop; std::unique_ptr install_tracker = GetInstallTracker(browser()); content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); + + views::NamedWidgetShownWaiter widget_waiter( + views::test::AnyWidgetTestPasskey{}, GetBubbleName()); + base::test::TestFuture> test_future; ShowSimpleInstallDialogForWebApps( web_contents, std::move(app_info), std::move(install_tracker), - base::BindLambdaForTesting( - [&](bool accepted, - std::unique_ptr app_info_callback) { - loop.Quit(); - }), - PwaInProductHelpState::kShown); + test_future.GetCallback(), PwaInProductHelpState::kShown); + + views::Widget* widget = widget_waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + EXPECT_FALSE(test_future.IsReady()); + + base::HistogramTester histogram_tester; + views::test::WidgetDestroyedWaiter destroyed_waiter(widget); + views::test::CancelDialog(widget); + destroyed_waiter.Wait(); - GetBubbleView(browser())->CancelDialog(); - loop.Run(); PrefService* pref_service = Profile::FromBrowserContext(browser() ->tab_strip_model() @@ -226,25 +235,27 @@ IN_PROC_BROWSER_TEST_P(SimpleInstallDialogBubbleViewBrowserTest, ->GetActiveWebContents() ->GetBrowserContext()) ->GetPrefs(); - WebAppPrefGuardrails::GetForDesktopInstallIph(pref_service) .RecordIgnore(app_id, base::Time::Now()); - base::RunLoop loop; - // Show the PWA install dialog. + + views::NamedWidgetShownWaiter widget_waiter( + views::test::AnyWidgetTestPasskey{}, GetBubbleName()); + base::test::TestFuture> test_future; std::unique_ptr install_tracker = GetInstallTracker(browser()); ShowSimpleInstallDialogForWebApps( browser()->tab_strip_model()->GetActiveWebContents(), std::move(app_info), - std::move(install_tracker), - base::BindLambdaForTesting( - [&](bool accepted, - std::unique_ptr app_info_callback) { - loop.Quit(); - }), + std::move(install_tracker), test_future.GetCallback(), PwaInProductHelpState::kShown); - GetBubbleView(browser())->AcceptDialog(); - loop.Run(); + views::Widget* widget = widget_waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + EXPECT_FALSE(test_future.IsReady()); + + base::HistogramTester histogram_tester; + views::test::WidgetDestroyedWaiter destroyed_waiter(widget); + views::test::AcceptDialog(widget); + destroyed_waiter.Wait(); EXPECT_EQ(GetIntWebAppPref(pref_service, app_id, kIphPrefNames.not_accepted_count_name) @@ -260,40 +271,45 @@ IN_PROC_BROWSER_TEST_P(SimpleInstallDialogBubbleViewBrowserTest, IN_PROC_BROWSER_TEST_P(SimpleInstallDialogBubbleViewBrowserTest, CancelFromNavigation) { - std::optional dialog_accepted_ = std::nullopt; - std::unique_ptr install_tracker = GetInstallTracker(browser()); + + views::NamedWidgetShownWaiter widget_waiter( + views::test::AnyWidgetTestPasskey{}, GetBubbleName()); + base::test::TestFuture> test_future; ShowSimpleInstallDialogForWebApps( browser()->tab_strip_model()->GetActiveWebContents(), GetAppInfo(), - std::move(install_tracker), - base::BindLambdaForTesting( - [&](bool accepted, - std::unique_ptr app_info_callback) { - dialog_accepted_ = accepted; - })); + std::move(install_tracker), test_future.GetCallback()); + + views::Widget* widget = widget_waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + EXPECT_FALSE(test_future.IsReady()); base::HistogramTester histograms; - views::test::WidgetDestroyedWaiter destroy_waiter( - GetBubbleView(browser())->GetWidget()); + views::test::WidgetDestroyedWaiter destroy_waiter(widget); ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), GURL(url::kAboutBlankURL), /*number_of_navigations=*/1); - destroy_waiter.Wait(); - ASSERT_TRUE(dialog_accepted_); - ASSERT_FALSE(dialog_accepted_.value()); + ASSERT_TRUE(test_future.Wait()); + EXPECT_FALSE(test_future.Get()); + + if (UniversalInstallEnabled()) { + histograms.ExpectUniqueSample( + "WebApp.InstallConfirmation.CloseReason", + views::Widget::ClosedReason::kCloseButtonClicked, 1); + } else { histograms.ExpectUniqueSample("WebApp.InstallConfirmation.CloseReason", views::Widget::ClosedReason::kUnspecified, 1); + } } INSTANTIATE_TEST_SUITE_P(All, SimpleInstallDialogBubbleViewBrowserTest, testing::Bool(), [](const testing::TestParamInfo& info) { - return info.param - ? "WebAppSimpleInstallDialogUniversal" - : "PWAConfirmationBubbleView"; + return info.param ? "WebAppSimpleInstallDialog" + : "PWAConfirmationBubbleView"; }); } // namespace diff --git a/chrome/browser/ui/views/web_apps/web_app_detailed_install_dialog.cc b/chrome/browser/ui/views/web_apps/web_app_detailed_install_dialog.cc index b2ca026afcd8f0..aef6b4ca6decab 100644 --- a/chrome/browser/ui/views/web_apps/web_app_detailed_install_dialog.cc +++ b/chrome/browser/ui/views/web_apps/web_app_detailed_install_dialog.cc @@ -30,6 +30,7 @@ #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" #include "components/url_formatter/elide_url.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/webapps/browser/installable/installable_data.h" #include "components/webapps/browser/installable/ml_install_operation_tracker.h" #include "components/webapps/common/constants.h" @@ -365,6 +366,14 @@ void ShowWebAppDetailedInstallDialog( AppInstallationAcceptanceCallback callback, std::vector screenshots, PwaInProductHelpState iph_state) { + // Do not show the dialog if it is already being shown. + const web_modal::WebContentsModalDialogManager* manager = + web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); + if (!manager || manager->IsDialogActive()) { + std::move(callback).Run(/*is_accepted=*/false, nullptr); + return; + } + content::BrowserContext* browser_context = web_contents->GetBrowserContext(); PrefService* const prefs = Profile::FromBrowserContext(browser_context)->GetPrefs(); @@ -416,15 +425,17 @@ void ShowWebAppDetailedInstallDialog( &WebAppInstallDialogDelegate::OnCancel, delegate_weak_ptr)) .SetCloseActionCallback(base::BindOnce( &WebAppInstallDialogDelegate::OnClose, delegate_weak_ptr)) + .SetDialogDestroyingCallback(base::BindOnce( + &WebAppInstallDialogDelegate::OnDestroyed, delegate_weak_ptr)) .AddCustomField( std::make_unique( std::make_unique(screenshots), views::BubbleDialogModelHost::FieldType::kControl)) - .SetDialogDestroyingCallback(base::BindOnce( - &WebAppInstallDialogDelegate::OnClose, delegate_weak_ptr)) .OverrideDefaultButton(ui::DialogButton::DIALOG_BUTTON_NONE) .Build(); } else { + // TODO(crbug.com/341254289): Completely remove after Universal Install has + // launched to 100% on Stable. dialog_model = ui::DialogModel::Builder(std::move(delegate)) .SetInternalName("WebAppDetailedInstallDialog") @@ -441,14 +452,12 @@ void ShowWebAppDetailedInstallDialog( l10n_util::GetStringUTF16(IDS_INSTALL))) .AddCancelButton(base::BindOnce( &WebAppInstallDialogDelegate::OnCancel, delegate_weak_ptr)) - .SetCloseActionCallback(base::BindOnce( - &WebAppInstallDialogDelegate::OnClose, delegate_weak_ptr)) + .SetDialogDestroyingCallback(base::BindOnce( + &WebAppInstallDialogDelegate::OnDestroyed, delegate_weak_ptr)) .AddCustomField( std::make_unique( std::make_unique(screenshots), views::BubbleDialogModelHost::FieldType::kControl)) - .SetDialogDestroyingCallback(base::BindOnce( - &WebAppInstallDialogDelegate::OnClose, delegate_weak_ptr)) .OverrideDefaultButton(ui::DialogButton::DIALOG_BUTTON_CANCEL) .Build(); } diff --git a/chrome/browser/ui/views/web_apps/web_app_diy_install_dialog.cc b/chrome/browser/ui/views/web_apps/web_app_diy_install_dialog.cc index 049d2228ed413c..eccd168529cacf 100644 --- a/chrome/browser/ui/views/web_apps/web_app_diy_install_dialog.cc +++ b/chrome/browser/ui/views/web_apps/web_app_diy_install_dialog.cc @@ -17,7 +17,6 @@ #include "chrome/browser/ui/views/controls/site_icon_text_and_origin_view.h" #include "chrome/browser/ui/views/web_apps/web_app_icon_name_and_origin_view.h" #include "chrome/browser/ui/views/web_apps/web_app_info_image_source.h" -#include "chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h" #include "chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h" #include "chrome/browser/ui/views/web_apps/web_app_views_utils.h" #include "chrome/browser/ui/web_applications/web_app_dialogs.h" @@ -28,6 +27,7 @@ #include "components/constrained_window/constrained_window_views.h" #include "components/feature_engagement/public/tracker.h" #include "components/strings/grit/components_strings.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/webapps/browser/installable/ml_install_operation_tracker.h" #include "content/public/browser/web_contents.h" #include "ui/base/l10n/l10n_util.h" @@ -75,10 +75,11 @@ void ShowDiyAppInstallDialog( return; } - WebAppInstallDialogCoordinator* dialog_coordinator = - WebAppInstallDialogCoordinator::GetOrCreateForBrowser(browser); - if (dialog_coordinator->IsShowing()) { - std::move(callback).Run(false, nullptr); + // Do not show the dialog if it is already being shown. + const web_modal::WebContentsModalDialogManager* manager = + web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); + if (!manager || manager->IsDialogActive()) { + std::move(callback).Run(/*is_accepted=*/false, nullptr); return; } @@ -134,7 +135,7 @@ void ShowDiyAppInstallDialog( .SetCloseActionCallback(base::BindOnce( &WebAppInstallDialogDelegate::OnClose, delegate_weak_ptr)) .SetDialogDestroyingCallback(base::BindOnce( - &WebAppInstallDialogDelegate::OnClose, delegate_weak_ptr)) + &WebAppInstallDialogDelegate::OnDestroyed, delegate_weak_ptr)) .OverrideDefaultButton(ui::DialogButton::DIALOG_BUTTON_NONE) .Build(); @@ -155,7 +156,6 @@ void ShowDiyAppInstallDialog( views::BubbleDialogDelegate* dialog_delegate = dialog->AsBubbleDialogDelegate(); constrained_window::ShowWebModalDialogViews(dialog.release(), web_contents); - dialog_coordinator->StartTracking(dialog_delegate); base::RecordAction(base::UserMetricsAction("WebAppDiyInstallShown")); diff --git a/chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.cc b/chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.cc deleted file mode 100644 index ad6e9ca085bdb2..00000000000000 --- a/chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2024 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h" - -#include "base/memory/weak_ptr.h" -#include "base/metrics/histogram_functions.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_user_data.h" -#include "chrome/browser/ui/views/frame/browser_view.h" -#include "chrome/browser/ui/views/frame/toolbar_button_provider.h" -#include "chrome/browser/ui/views/page_action/page_action_icon_view.h" -#include "ui/views/bubble/bubble_dialog_delegate_view.h" - -namespace web_app { - -WebAppInstallDialogCoordinator::~WebAppInstallDialogCoordinator() { - if (IsShowing()) { - StopTracking(); - } -} - -bool WebAppInstallDialogCoordinator::IsShowing() { - return widget_observation_.IsObserving(); -} - -views::BubbleDialogDelegate* WebAppInstallDialogCoordinator::GetBubbleView() { - return IsShowing() ? dialog_delegate_ : nullptr; -} - -void WebAppInstallDialogCoordinator::StartTracking( - views::BubbleDialogDelegate* bubble_view) { - CHECK(!IsShowing()) << "Cannot track a new install dialog if an existing " - "one is already open"; - dialog_delegate_ = bubble_view; - auto* widget = bubble_view->GetWidget(); - widget_observation_.Observe(widget); -} - -void WebAppInstallDialogCoordinator::OnWidgetDestroying(views::Widget* widget) { - CHECK_EQ(widget, dialog_delegate_->GetWidget()); - base::UmaHistogramEnumeration("WebApp.InstallConfirmation.CloseReason", - widget->closed_reason()); - StopTracking(); -} - -void WebAppInstallDialogCoordinator::StopTracking() { - CHECK(IsShowing()) << "Cannot stop tracking install dialog when it was not " - "being tracked previously"; - widget_observation_.Reset(); - dialog_delegate_ = nullptr; - MaybeUpdatePwaAnchorViewIfNeeded(); -} - -void WebAppInstallDialogCoordinator::MaybeUpdatePwaAnchorViewIfNeeded() { - Browser* browser = &GetBrowser(); - if (!browser) { - return; - } - BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); - - if (browser_view && browser_view->toolbar_button_provider()) { - PageActionIconView* install_icon = - browser_view->toolbar_button_provider()->GetPageActionIconView( - PageActionIconType::kPwaInstall); - if (install_icon) { - // This ensures that quick navigations in between an installable and - // non-installable site hides the anchor view. See the test - // |IconVisibilityAfterTabSwitchingWhenPWAConfirmationBubbleViewShowing| - // for more information on why this was needed. - install_icon->Update(); - } - } -} - -WebAppInstallDialogCoordinator::WebAppInstallDialogCoordinator(Browser* browser) - : BrowserUserData(*browser) {} - -BROWSER_USER_DATA_KEY_IMPL(WebAppInstallDialogCoordinator); - -} // namespace web_app diff --git a/chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h b/chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h deleted file mode 100644 index bf843c065ad7bb..00000000000000 --- a/chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2024 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_INSTALL_DIALOG_COORDINATOR_H_ -#define CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_INSTALL_DIALOG_COORDINATOR_H_ - -#include "chrome/browser/ui/browser_user_data.h" -#include "ui/views/bubble/bubble_dialog_delegate_view.h" -#include "ui/views/widget/widget_observer.h" - -class Browser; - -namespace web_app { - -class WebAppInstallDialogCoordinator - : public BrowserUserData, - public views::WidgetObserver { - public: - ~WebAppInstallDialogCoordinator() override; - - bool IsShowing(); - views::BubbleDialogDelegate* GetBubbleView(); - void StartTracking(views::BubbleDialogDelegate* view); - - // WidgetObserver overrides: - void OnWidgetDestroying(views::Widget* widget) override; - - private: - explicit WebAppInstallDialogCoordinator(Browser* browser); - friend BrowserUserData; - - void StopTracking(); - void MaybeUpdatePwaAnchorViewIfNeeded(); - - raw_ptr dialog_delegate_ = nullptr; - base::ScopedObservation - widget_observation_{this}; - - BROWSER_USER_DATA_KEY_DECL(); -}; - -} // namespace web_app - -#endif // CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_INSTALL_DIALOG_COORDINATOR_H_ diff --git a/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.cc b/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.cc index e9895d42362548..4ec0bc80c6e4ff 100644 --- a/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.cc +++ b/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.cc @@ -6,6 +6,7 @@ #include +#include "base/metrics/histogram_functions.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "chrome/browser/ui/browser_finder.h" @@ -13,7 +14,6 @@ #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/toolbar_button_provider.h" #include "chrome/browser/ui/views/page_action/page_action_icon_view.h" -#include "chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h" #include "chrome/browser/ui/web_applications/web_app_dialogs.h" #include "chrome/browser/web_applications/web_app_helpers.h" #include "chrome/browser/web_applications/web_app_install_info.h" @@ -138,18 +138,48 @@ void WebAppInstallDialogDelegate::OnAccept() { CHECK(callback_); CHECK(install_tracker_); install_tracker_->ReportResult(webapps::MlInstallUserResponse::kAccepted); + received_user_response_ = true; + base::UmaHistogramEnumeration( + "WebApp.InstallConfirmation.CloseReason", + views::Widget::ClosedReason::kAcceptButtonClicked); std::move(callback_).Run(true, std::move(install_info_)); } void WebAppInstallDialogDelegate::OnCancel() { CHECK(install_tracker_); install_tracker_->ReportResult(webapps::MlInstallUserResponse::kCancelled); + received_user_response_ = true; + base::UmaHistogramEnumeration( + "WebApp.InstallConfirmation.CloseReason", + views::Widget::ClosedReason::kCancelButtonClicked); MeasureIphOnDialogClose(); } void WebAppInstallDialogDelegate::OnClose() { CHECK(install_tracker_); install_tracker_->ReportResult(webapps::MlInstallUserResponse::kIgnored); + received_user_response_ = true; + + // This could be hit by triggering the Esc key as well, unfortunately there is + // no way to listen to that without observing the low level widget. + base::UmaHistogramEnumeration( + "WebApp.InstallConfirmation.CloseReason", + views::Widget::ClosedReason::kCloseButtonClicked); + MeasureIphOnDialogClose(); +} + +void WebAppInstallDialogDelegate::OnDestroyed() { + // Only performs histogram measurement and other actions if the dialog was + // destroyed without user action, like a change in visibility or navigation to + // a different tab or destruction of the native widget that contains the + // dialog this delegate is assigned to. + if (received_user_response_) { + return; + } + + install_tracker_->ReportResult(webapps::MlInstallUserResponse::kIgnored); + base::UmaHistogramEnumeration("WebApp.InstallConfirmation.CloseReason", + views::Widget::ClosedReason::kUnspecified); MeasureIphOnDialogClose(); } diff --git a/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h b/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h index b3a60c307af0fc..4db6eb72c9c4cf 100644 --- a/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h +++ b/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h @@ -76,6 +76,10 @@ class WebAppInstallDialogDelegate : public ui::DialogModelDelegate, void OnCancel(); void OnClose(); + // This is called when the dialog has been either accepted, cancelled, closed + // or destroyed without an user-action. + void OnDestroyed(); + // Takes care of enabling or disabling the dialog model's OK button for DIY // apps based on changes in the text field, and also keeps track of the text // field's contents. @@ -106,6 +110,7 @@ class WebAppInstallDialogDelegate : public ui::DialogModelDelegate, raw_ptr tracker_; InstallDialogType dialog_type_; std::u16string text_field_contents_; + bool received_user_response_ = false; base::WeakPtrFactory weak_ptr_factory_{this}; }; diff --git a/chrome/browser/ui/views/web_apps/web_app_simple_install_dialog.cc b/chrome/browser/ui/views/web_apps/web_app_simple_install_dialog.cc index 2c0c66bcafdf07..57c2aa58bbdc43 100644 --- a/chrome/browser/ui/views/web_apps/web_app_simple_install_dialog.cc +++ b/chrome/browser/ui/views/web_apps/web_app_simple_install_dialog.cc @@ -15,7 +15,6 @@ #include "chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h" #include "chrome/browser/ui/views/web_apps/web_app_icon_name_and_origin_view.h" #include "chrome/browser/ui/views/web_apps/web_app_info_image_source.h" -#include "chrome/browser/ui/views/web_apps/web_app_install_dialog_coordinator.h" #include "chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h" #include "chrome/browser/ui/web_applications/web_app_dialogs.h" #include "chrome/browser/web_applications/web_app_constants.h" @@ -26,6 +25,7 @@ #include "components/feature_engagement/public/tracker.h" #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/webapps/browser/installable/ml_install_operation_tracker.h" #include "content/public/browser/web_contents.h" #include "ui/base/l10n/l10n_util.h" @@ -67,10 +67,11 @@ void ShowSimpleInstallDialogForWebApps( return; } - WebAppInstallDialogCoordinator* dialog_coordinator = - WebAppInstallDialogCoordinator::GetOrCreateForBrowser(browser); - if (dialog_coordinator->IsShowing()) { - std::move(callback).Run(false, nullptr); + // Do not show the dialog if it is already being shown. + const web_modal::WebContentsModalDialogManager* manager = + web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); + if (!manager || manager->IsDialogActive()) { + std::move(callback).Run(/*is_accepted=*/false, nullptr); return; } @@ -123,7 +124,7 @@ void ShowSimpleInstallDialogForWebApps( .SetCloseActionCallback(base::BindOnce( &WebAppInstallDialogDelegate::OnClose, delegate_weak_ptr)) .SetDialogDestroyingCallback(base::BindOnce( - &WebAppInstallDialogDelegate::OnClose, delegate_weak_ptr)) + &WebAppInstallDialogDelegate::OnDestroyed, delegate_weak_ptr)) .OverrideDefaultButton(ui::DialogButton::DIALOG_BUTTON_NONE) .AddCustomField( std::make_unique( @@ -141,9 +142,7 @@ void ShowSimpleInstallDialogForWebApps( if (icon) { dialog_delegate->SetAnchorView(icon); } - constrained_window::ShowWebModalDialogViews(dialog.release(), web_contents); - dialog_coordinator->StartTracking(dialog_delegate); } else { auto* dialog_view = new PWAConfirmationBubbleView( anchor_view, web_contents->GetWeakPtr(), icon, std::move(web_app_info), @@ -155,7 +154,6 @@ void ShowSimpleInstallDialogForWebApps( views::BubbleDialogDelegateView::CreateBubble(dialog_view)->Show(); dialog_delegate = dialog_view->AsBubbleDialogDelegate(); - dialog_coordinator->StartTracking(dialog_delegate); if (icon) { icon->Update(); DCHECK(icon->GetVisible()); From 462d8f1c7c1a931c10c9dfc8770548f6f5a8bf0c Mon Sep 17 00:00:00 2001 From: Min Qin Date: Tue, 21 May 2024 15:45:42 +0000 Subject: [PATCH 10/40] [Reland] use in memory download for pdf in incognito mode This is a reland of https://chromium-review.googlesource.com/c/chromium/src/+/5539855, the original CL is reverted due to a merge conflict in NOTREACHED() behavior as it will crash the app. Bug: 338466611 Low-Coverage-Reason: HARD_TO_TEST Change-Id: Ie3ad59717a96f55beffdf9191eba550be917a680 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5551581 Commit-Queue: Min Qin Reviewed-by: Shu Yang Cr-Commit-Position: refs/heads/main@{#1303793} --- .../chrome_download_manager_delegate.cc | 12 +- .../download/download_target_determiner.cc | 2 +- components/download/internal/common/BUILD.gn | 8 +- .../download/InMemoryDownloadFile.java | 91 ++++++++ .../internal/common/download_file_factory.cc | 17 +- .../internal/common/download_job_factory.cc | 5 + .../common/in_memory_download_file.cc | 213 ++++++++++++++++++ .../internal/common/in_memory_download_file.h | 86 +++++++ components/download/public/common/BUILD.gn | 1 + .../download/public/common/download_file.cc | 15 ++ .../download/public/common/download_file.h | 5 +- .../public/common/download_save_info.h | 3 + .../browser/download/download_manager_impl.cc | 50 ++-- 13 files changed, 477 insertions(+), 31 deletions(-) create mode 100644 components/download/internal/common/android/java/src/org/chromium/components/download/InMemoryDownloadFile.java create mode 100644 components/download/internal/common/in_memory_download_file.cc create mode 100644 components/download/internal/common/in_memory_download_file.h create mode 100644 components/download/public/common/download_file.cc diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc index 6c6d8667c3b413..927f55caf061ee 100644 --- a/chrome/browser/download/chrome_download_manager_delegate.cc +++ b/chrome/browser/download/chrome_download_manager_delegate.cc @@ -99,6 +99,7 @@ #include "base/android/build_info.h" #include "base/android/content_uri_utils.h" #include "base/android/path_utils.h" +#include "base/process/process_handle.h" #include "chrome/browser/android/tab_android.h" #include "chrome/browser/download/android/chrome_duplicate_download_infobar_delegate.h" #include "chrome/browser/download/android/download_controller.h" @@ -634,9 +635,14 @@ bool ChromeDownloadManagerDelegate::DetermineDownloadTarget( profile_->GetPrefs()->GetString(prefs::kDefaultCharset), download->GetSuggestedFilename(), download->GetMimeType(), l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME)); - base::FilePath cache_dir; - base::android::GetCacheDirectory(&cache_dir); - download_path = cache_dir.Append(kPdfDirName).Append(generated_filename); + if (profile_->IsOffTheRecord()) { + download_path = download->GetDownloadFile()->FullPath(); + } else { + base::FilePath cache_dir; + base::android::GetCacheDirectory(&cache_dir); + download_path = + cache_dir.Append(kPdfDirName).Append(generated_filename); + } action = DownloadPathReservationTracker::UNIQUIFY; } else { action = DownloadPathReservationTracker::OVERWRITE; diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc index c76967ddc10989..6148c043083155 100644 --- a/chrome/browser/download/download_target_determiner.cc +++ b/chrome/browser/download/download_target_determiner.cc @@ -606,7 +606,7 @@ DownloadTargetDeterminer::DoRequestConfirmation() { content::DownloadItemUtils::GetBrowserContext(download_); bool isOffTheRecord = Profile::FromBrowserContext(browser_context)->IsOffTheRecord(); - if (isOffTheRecord) { + if (isOffTheRecord && !download_->GetDownloadFile()->IsMemoryFile()) { delegate_->RequestIncognitoWarningConfirmation(base::BindOnce( &DownloadTargetDeterminer::RequestIncognitoWarningConfirmationDone, weak_ptr_factory_.GetWeakPtr())); diff --git a/components/download/internal/common/BUILD.gn b/components/download/internal/common/BUILD.gn index 5425fab170d9d0..d2d834a87e35c5 100644 --- a/components/download/internal/common/BUILD.gn +++ b/components/download/internal/common/BUILD.gn @@ -98,6 +98,8 @@ source_set("internal") { sources += [ "android/download_collection_bridge.cc", "android/download_collection_bridge.h", + "in_memory_download_file.cc", + "in_memory_download_file.h", ] deps += [ ":jni_headers" ] @@ -118,6 +120,7 @@ if (is_android) { sources = [ "android/java/src/org/chromium/components/download/DownloadCollectionBridge.java", "android/java/src/org/chromium/components/download/DownloadDelegate.java", + "android/java/src/org/chromium/components/download/InMemoryDownloadFile.java", ] deps = [ @@ -131,7 +134,10 @@ if (is_android) { generate_jni("jni_headers") { visibility = [ ":*" ] - sources = [ "android/java/src/org/chromium/components/download/DownloadCollectionBridge.java" ] + sources = [ + "android/java/src/org/chromium/components/download/DownloadCollectionBridge.java", + "android/java/src/org/chromium/components/download/InMemoryDownloadFile.java", + ] } } diff --git a/components/download/internal/common/android/java/src/org/chromium/components/download/InMemoryDownloadFile.java b/components/download/internal/common/android/java/src/org/chromium/components/download/InMemoryDownloadFile.java new file mode 100644 index 00000000000000..b1b0a4924c334d --- /dev/null +++ b/components/download/internal/common/android/java/src/org/chromium/components/download/InMemoryDownloadFile.java @@ -0,0 +1,91 @@ +// 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. + +package org.chromium.components.download; + +import android.os.Build; +import android.os.ParcelFileDescriptor; +import android.system.Os; + +import androidx.annotation.RequiresApi; + +import org.jni_zero.CalledByNative; +import org.jni_zero.JNINamespace; +import org.jni_zero.JniType; + +import org.chromium.base.Log; + +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; + +/** Helper class for publishing download files to the public download collection. */ +@JNINamespace("download") +public class InMemoryDownloadFile { + private static final String TAG = "InMemoryDownload"; + private FileOutputStream mFos; + private ParcelFileDescriptor mPfd; + + @CalledByNative + @RequiresApi(Build.VERSION_CODES.R) + private static InMemoryDownloadFile createFile(@JniType("std::string") String filename) { + try { + return new InMemoryDownloadFile(filename); + } catch (Exception e) { + return null; + } + } + + @RequiresApi(Build.VERSION_CODES.R) + private InMemoryDownloadFile(String filename) throws Exception { + FileDescriptor mFd = Os.memfd_create(filename, 0); + mPfd = ParcelFileDescriptor.dup(mFd); + mFos = new FileOutputStream(mFd); + } + + @CalledByNative + private void writeData(@JniType("std::vector") byte[] data) { + try { + mFos.write(data); + } catch (Exception e) { + Log.e(TAG, "failed to write data to file.", e); + } + } + + @CalledByNative + private void finish() { + try { + if (mFos != null) { + mFos.close(); + mFos = null; + } + // Detach the file descriptor, so native can use it even this + // class is destroyed. + if (mPfd != null) { + mPfd.detachFd(); + } + } catch (Exception e) { + Log.e(TAG, "failed to close output stream.", e); + } + } + + @CalledByNative + private int getFd() { + return mPfd != null ? mPfd.getFd() : 0; + } + + @CalledByNative + private void destroy() { + try { + if (mFos != null) { + mFos.close(); + } + if (mPfd != null) { + mPfd.close(); + } + } catch (IOException e) { + Log.e(TAG, "failed to close memory file.", e); + } + } +} diff --git a/components/download/internal/common/download_file_factory.cc b/components/download/internal/common/download_file_factory.cc index 924ef056cbf190..778084582f317f 100644 --- a/components/download/internal/common/download_file_factory.cc +++ b/components/download/internal/common/download_file_factory.cc @@ -9,6 +9,10 @@ #include "components/download/internal/common/download_file_with_copy.h" #include "components/download/public/common/download_file_impl.h" +#if BUILDFLAG(IS_ANDROID) +#include "components/download/internal/common/in_memory_download_file.h" +#endif // BUILDFLAG(IS_ANDROID) + namespace download { DownloadFileFactory::~DownloadFileFactory() {} @@ -20,11 +24,20 @@ DownloadFile* DownloadFileFactory::CreateFile( uint32_t download_id, const base::FilePath& duplicate_download_file_path, base::WeakPtr observer) { +#if BUILDFLAG(IS_ANDROID) + if (save_info->use_in_memory_file) { + return new InMemoryDownloadFile(std::move(save_info), std::move(stream), + observer); + } +#endif // BUILDFLAG(IS_ANDROID) + if (!duplicate_download_file_path.empty()) { return new DownloadFileWithCopy(duplicate_download_file_path, observer); + } else { + return new DownloadFileImpl(std::move(save_info), + default_downloads_directory, std::move(stream), + download_id, observer); } - return new DownloadFileImpl(std::move(save_info), default_downloads_directory, - std::move(stream), download_id, observer); } } // namespace download diff --git a/components/download/internal/common/download_job_factory.cc b/components/download/internal/common/download_job_factory.cc index c9ce5bee89cea2..acc7030159e37d 100644 --- a/components/download/internal/common/download_job_factory.cc +++ b/components/download/internal/common/download_job_factory.cc @@ -44,6 +44,11 @@ ConnectionType GetConnectionType(net::HttpConnectionInfo connection_info) { // Returns if the download can be parallelized. bool IsParallelizableDownload(const DownloadCreateInfo& create_info, DownloadItem* download_item) { + if (download_item->GetDownloadFile() && + download_item->GetDownloadFile()->IsMemoryFile()) { + return false; + } + // To enable parallel download, following conditions need to be satisfied. // 1. Feature |kParallelDownloading| enabled. // 2. Strong validators response headers. i.e. ETag and Last-Modified. diff --git a/components/download/internal/common/in_memory_download_file.cc b/components/download/internal/common/in_memory_download_file.cc new file mode 100644 index 00000000000000..e541019d357406 --- /dev/null +++ b/components/download/internal/common/in_memory_download_file.cc @@ -0,0 +1,213 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/internal/common/in_memory_download_file.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/files/file_util.h" +#include "base/functional/bind.h" +#include "base/process/process_handle.h" +#include "base/strings/stringprintf.h" +#include "base/task/sequenced_task_runner.h" +#include "components/download/internal/common/jni_headers/InMemoryDownloadFile_jni.h" +#include "components/download/public/common/download_destination_observer.h" +#include "crypto/secure_hash.h" + +using base::android::ConvertUTF8ToJavaString; + +namespace download { +namespace { +const char kDefaultFileName[] = "download"; + +void OnRenameComplete(const base::FilePath& file_path, + scoped_refptr task_runner, + DownloadFile::RenameCompletionCallback callback) { + task_runner->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), + DOWNLOAD_INTERRUPT_REASON_NONE, file_path)); +} +} // namespace + +InMemoryDownloadFile::InMemoryDownloadFile( + std::unique_ptr save_info, + std::unique_ptr stream, + base::WeakPtr observer) + : save_info_(std::move(save_info)), + input_stream_(std::move(stream)), + main_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()), + observer_(observer) {} + +InMemoryDownloadFile::~InMemoryDownloadFile() { + Cancel(); +} + +void InMemoryDownloadFile::Initialize( + InitializeCallback initialize_callback, + CancelRequestCallback cancel_request_callback, + const DownloadItem::ReceivedSlices& received_slices) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::FilePath filename = save_info_->file_path.BaseName(); + + java_ref_ = Java_InMemoryDownloadFile_createFile( + env, filename.empty() ? kDefaultFileName : filename.value()); + if (!java_ref_) { + main_task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(initialize_callback), + DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, + /*bytes_wasted=*/0)); + return; + } + + int fd = Java_InMemoryDownloadFile_getFd(env, java_ref_); + memory_file_path_ = base::FilePath(base::StringPrintf( + "/proc/%d/fd/%d", static_cast(base::GetCurrentProcId()), fd)); + + SendUpdate(); + + input_stream_->Initialize(); + + main_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(std::move(initialize_callback), + DOWNLOAD_INTERRUPT_REASON_NONE, /*bytes_wasted=*/0)); + + StreamActive(MOJO_RESULT_OK); +} + +void InMemoryDownloadFile::AddInputStream(std::unique_ptr stream, + int64_t offset) { + DCHECK(false) << "In memory file shouldn't have more than 1 input stream"; +} + +void InMemoryDownloadFile::RenameAndUniquify( + const base::FilePath& full_path, + RenameCompletionCallback callback) { + OnRenameComplete(memory_file_path_, main_task_runner_, std::move(callback)); +} + +void InMemoryDownloadFile::RenameAndAnnotate( + const base::FilePath& full_path, + const std::string& client_guid, + const GURL& source_url, + const GURL& referrer_url, + mojo::PendingRemote remote_quarantine, + RenameCompletionCallback callback) { + OnRenameComplete(memory_file_path_, main_task_runner_, std::move(callback)); +} + +void InMemoryDownloadFile::Detach() {} + +void InMemoryDownloadFile::Cancel() { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_InMemoryDownloadFile_destroy(env, java_ref_); +} + +void InMemoryDownloadFile::SetPotentialFileLength(int64_t length) {} + +const base::FilePath& InMemoryDownloadFile::FullPath() const { + return memory_file_path_; +} + +bool InMemoryDownloadFile::InProgress() const { + return true; +} + +void InMemoryDownloadFile::Pause() {} + +void InMemoryDownloadFile::Resume() {} + +void InMemoryDownloadFile::PublishDownload(RenameCompletionCallback callback) { + // This shouldn't get called. + DCHECK(false); +} + +void InMemoryDownloadFile::StreamActive(MojoResult result) { + JNIEnv* env = base::android::AttachCurrentThread(); + scoped_refptr incoming_data; + size_t incoming_data_size = 0; + InputStream::StreamState state(InputStream::EMPTY); + DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE; + // Take care of any file local activity required. + do { + state = input_stream_->Read(&incoming_data, &incoming_data_size); + switch (state) { + case InputStream::EMPTY: + break; + case InputStream::HAS_DATA: + Java_InMemoryDownloadFile_writeData( + env, java_ref_, + std::vector( + incoming_data->data(), + incoming_data->data() + incoming_data_size)); + total_bytes_ += incoming_data_size; + rate_estimator_.Increment(incoming_data_size); + break; + case InputStream::WAIT_FOR_COMPLETION: + input_stream_->RegisterCompletionCallback( + base::BindOnce(&InMemoryDownloadFile::OnStreamCompleted, + weak_factory_.GetWeakPtr())); + break; + case InputStream::COMPLETE: + break; + } + } while (state == InputStream::HAS_DATA && + reason == DOWNLOAD_INTERRUPT_REASON_NONE); + + if (state == InputStream::EMPTY) { + input_stream_->RegisterDataReadyCallback(base::BindRepeating( + &InMemoryDownloadFile::StreamActive, weak_factory_.GetWeakPtr())); + } + + if (state == InputStream::COMPLETE) { + OnStreamCompleted(); + } else if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { + NotifyObserver(reason, state); + } +} + +void InMemoryDownloadFile::SendUpdate() { + main_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&DownloadDestinationObserver::DestinationUpdate, observer_, + total_bytes_, rate_estimator_.GetCountPerSecond(), + std::vector())); +} + +void InMemoryDownloadFile::OnStreamCompleted() { + SendUpdate(); + input_stream_->ClearDataReadyCallback(); + weak_factory_.InvalidateWeakPtrs(); + + JNIEnv* env = base::android::AttachCurrentThread(); + Java_InMemoryDownloadFile_finish(env, java_ref_); + main_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&DownloadDestinationObserver::DestinationCompleted, + observer_, total_bytes_, + crypto::SecureHash::Create(crypto::SecureHash::SHA256))); +} + +void InMemoryDownloadFile::NotifyObserver( + DownloadInterruptReason reason, + InputStream::StreamState stream_state) { + input_stream_->ClearDataReadyCallback(); + SendUpdate(); // Make info up to date before error. + Cancel(); + // Error case for both upstream source and file write. + // Shut down processing and signal an error to our observer. + // Our observer will clean us up. + weak_factory_.InvalidateWeakPtrs(); + main_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&DownloadDestinationObserver::DestinationError, observer_, + reason, total_bytes_, + crypto::SecureHash::Create(crypto::SecureHash::SHA256))); +} + +bool InMemoryDownloadFile::IsMemoryFile() { + return true; +} + +} // namespace download diff --git a/components/download/internal/common/in_memory_download_file.h b/components/download/internal/common/in_memory_download_file.h new file mode 100644 index 00000000000000..d137a62a2ca47d --- /dev/null +++ b/components/download/internal/common/in_memory_download_file.h @@ -0,0 +1,86 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_COMMON_IN_MEMORY_DOWNLOAD_FILE_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_COMMON_IN_MEMORY_DOWNLOAD_FILE_H_ + +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "base/task/single_thread_task_runner.h" +#include "components/download/public/common/download_file.h" +#include "components/download/public/common/download_save_info.h" +#include "components/download/public/common/rate_estimator.h" + +namespace download { +class DownloadDestinationObserver; + +// Implementation of DownloadFile that stores data in memory. +class COMPONENTS_DOWNLOAD_EXPORT InMemoryDownloadFile : public DownloadFile { + public: + InMemoryDownloadFile(std::unique_ptr save_info, + std::unique_ptr stream, + base::WeakPtr observer); + InMemoryDownloadFile(const InMemoryDownloadFile&) = delete; + InMemoryDownloadFile& operator=(const InMemoryDownloadFile&) = delete; + ~InMemoryDownloadFile() override; + + // DownloadFile functions. + void Initialize(InitializeCallback initialize_callback, + CancelRequestCallback cancel_request_callback, + const DownloadItem::ReceivedSlices& received_slices) override; + void AddInputStream(std::unique_ptr stream, + int64_t offset) override; + void RenameAndUniquify(const base::FilePath& full_path, + RenameCompletionCallback callback) override; + void RenameAndAnnotate( + const base::FilePath& full_path, + const std::string& client_guid, + const GURL& source_url, + const GURL& referrer_url, + mojo::PendingRemote remote_quarantine, + RenameCompletionCallback callback) override; + void Detach() override; + void Cancel() override; + void SetPotentialFileLength(int64_t length) override; + const base::FilePath& FullPath() const override; + bool InProgress() const override; + void Pause() override; + void Resume() override; + void PublishDownload(RenameCompletionCallback callback) override; + bool IsMemoryFile() override; + + private: + void SendUpdate(); + void StreamActive(MojoResult result); + void OnStreamCompleted(); + void NotifyObserver(DownloadInterruptReason reason, + InputStream::StreamState stream_state); + + // DownloadSaveInfo provided during construction. Since the DownloadFileImpl + // can be created on any thread, this holds the save_info_ until it can be + // used to initialize file_ on the download sequence. + std::unique_ptr save_info_; + + std::unique_ptr input_stream_; + + // TaskRunner to post updates to the |observer_|. + scoped_refptr main_task_runner_; + + // Reference to the Java object. + base::android::ScopedJavaGlobalRef java_ref_; + + RateEstimator rate_estimator_; + + int64_t total_bytes_ = 0; + + // Path to the memory file. + base::FilePath memory_file_path_; + + base::WeakPtr observer_; + base::WeakPtrFactory weak_factory_{this}; +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_INTERNAL_COMMON_IN_MEMORY_DOWNLOAD_FILE_H_ diff --git a/components/download/public/common/BUILD.gn b/components/download/public/common/BUILD.gn index 10a1f72dee1f07..649571966bae05 100644 --- a/components/download/public/common/BUILD.gn +++ b/components/download/public/common/BUILD.gn @@ -26,6 +26,7 @@ component("public") { "download_destination_observer.h", "download_features.cc", "download_features.h", + "download_file.cc", "download_file.h", "download_file_factory.h", "download_file_impl.h", diff --git a/components/download/public/common/download_file.cc b/components/download/public/common/download_file.cc new file mode 100644 index 00000000000000..af4f0df364681f --- /dev/null +++ b/components/download/public/common/download_file.cc @@ -0,0 +1,15 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/public/common/download_file.h" + +namespace download { + +DownloadFile::~DownloadFile() = default; + +bool DownloadFile::IsMemoryFile() { + return false; +} + +} // namespace download diff --git a/components/download/public/common/download_file.h b/components/download/public/common/download_file.h index f59cd08aab81ca..c78d88aada271d 100644 --- a/components/download/public/common/download_file.h +++ b/components/download/public/common/download_file.h @@ -59,7 +59,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadFile { // download sequence. typedef base::RepeatingCallback CancelRequestCallback; - virtual ~DownloadFile() {} + virtual ~DownloadFile(); // Upon completion, |initialize_callback| will be called on the UI // thread as per the comment above, passing DOWNLOAD_INTERRUPT_REASON_NONE @@ -119,6 +119,9 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadFile { // the final content URI. virtual void PublishDownload(RenameCompletionCallback callback) = 0; #endif // BUILDFLAG(IS_ANDROID) + + // Whether the file is an in-memory file. + virtual bool IsMemoryFile(); }; } // namespace download diff --git a/components/download/public/common/download_save_info.h b/components/download/public/common/download_save_info.h index 0082f0ecfdd1c9..68bb67e888549f 100644 --- a/components/download/public/common/download_save_info.h +++ b/components/download/public/common/download_save_info.h @@ -89,6 +89,9 @@ struct COMPONENTS_DOWNLOAD_EXPORT DownloadSaveInfo { // the location will be determined automatically using |file_path| as a // basis if |file_path| is not empty. bool prompt_for_save_location = false; + + // Whether the file should be stored in memory. + bool use_in_memory_file = false; }; } // namespace download diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index 75760ca4bb2b2a..0b2e46af006d74 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc @@ -717,30 +717,34 @@ void DownloadManagerImpl::OnNewDownloadIdRetrieved( if (info->transient && !info->is_must_download && delegate_->ShouldOpenPdfInline() && base::EqualsCaseInsensitiveASCII(info->mime_type, kPdfMimeType)) { - for (const auto& iter : downloads_by_guid_) { - download::DownloadItem* item = iter.second; - if (item->GetFileExternallyRemoved() || - item->GetState() != download::DownloadItem::COMPLETE) { - continue; - } - - if (item->GetMimeType() != kPdfMimeType || - item->GetUrlChain() != info->url_chain) { - continue; - } - - if (!item->IsTransient() || item->IsMustDownload()) { - continue; + if (IsOffTheRecord()) { + info->save_info->use_in_memory_file = true; + } else { + for (const auto& iter : downloads_by_guid_) { + download::DownloadItem* item = iter.second; + if (item->GetFileExternallyRemoved() || + item->GetState() != download::DownloadItem::COMPLETE) { + continue; + } + + if (item->GetMimeType() != kPdfMimeType || + item->GetUrlChain() != info->url_chain) { + continue; + } + + if (!item->IsTransient() || item->IsMustDownload()) { + continue; + } + + disk_access_task_runner_->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&base::PathExists, item->GetTargetFilePath()), + base::BindOnce(&DownloadManagerImpl::CreateNewDownloadItemToStart, + weak_factory_.GetWeakPtr(), std::move(info), + std::move(on_started), std::move(callback), id, + item->GetTargetFilePath())); + return; } - - disk_access_task_runner_->PostTaskAndReplyWithResult( - FROM_HERE, - base::BindOnce(&base::PathExists, item->GetTargetFilePath()), - base::BindOnce(&DownloadManagerImpl::CreateNewDownloadItemToStart, - weak_factory_.GetWeakPtr(), std::move(info), - std::move(on_started), std::move(callback), id, - item->GetTargetFilePath())); - return; } } #endif // BUILDFLAG(IS_ANDROID) From cc4bae7524052670832b0aa58a3b335d0879d172 Mon Sep 17 00:00:00 2001 From: Ethan Jimenez Date: Tue, 21 May 2024 15:46:59 +0000 Subject: [PATCH 11/40] [Grid] Introduce dynamic-subgridded-item-height.html to WPT This test was discovered as a regression to recent changes in Blink's subgrid `MinMaxSizes` cache, which will be reintroduced later. Bug: 40946243 Change-Id: I6697f827b023c3a1483c002d94e511f20bbba75e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5551624 Commit-Queue: Ethan Jimenez Reviewed-by: Alison Maher Cr-Commit-Position: refs/heads/main@{#1303794} --- .../dynamic-subgridded-item-height.html | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/dynamic-subgridded-item-height.html diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/dynamic-subgridded-item-height.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/dynamic-subgridded-item-height.html new file mode 100644 index 00000000000000..46e41d233559af --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/dynamic-subgridded-item-height.html @@ -0,0 +1,37 @@ + + +CSS Grid Test: Subgridded item changing its height dynamically + + + + +

Test passes if there is a filled green square and no red.

+
+
+
+
+
+
+
+
+
+ From 08324578973fc4550b1fde3aeac15c690f008305 Mon Sep 17 00:00:00 2001 From: Maria Petrisor Date: Tue, 21 May 2024 15:48:30 +0000 Subject: [PATCH 12/40] Update Login screen APIs test extension to MV3 Bug: b:325482140 Change-Id: I70379b22d72396e604175c7bc7278e6c7cc14f27 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5542447 Reviewed-by: Andrey Davydov Commit-Queue: Maria Petrisor Cr-Commit-Position: refs/heads/main@{#1303795} --- .../api_test/login_screen_apis/extension.crx | Bin 5804 -> 6700 bytes .../login_screen_apis/extension/background.js | 110 +++++++----------- .../login_screen_apis/extension/manifest.json | 8 +- .../login_screen_apis/update_manifest.xml | 2 +- 4 files changed, 47 insertions(+), 73 deletions(-) diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/extension.crx b/chrome/test/data/extensions/api_test/login_screen_apis/extension.crx index 37e7431e08ad75a7694dee13621488f2671e9cd2..93345e73ff21fc7f54c2fb0049154221353da4b7 100644 GIT binary patch literal 6700 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 MMKIM&aP#iJ0BRfLrvLx| delta 4780 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 { - chrome.loginScreenUi.show({url: 'some/path.html'}, () => { - chrome.test.assertNoLastError(); - chrome.test.succeed(); - }); + 'LoginScreenUiCanOpenWindow': async () => { + await chrome.loginScreenUi.show({url: 'some/path.html'}); + chrome.test.succeed(); }, 'LoginScreenUiCannotOpenMultipleWindows': () => { chrome.loginScreenUi.show({url: 'some/path.html'}, () => { @@ -37,14 +35,10 @@ const tests = { }); }); }, - 'LoginScreenUiCanOpenAndCloseWindow': () => { - chrome.loginScreenUi.show({url: 'some/path.html'}, () => { - chrome.test.assertNoLastError(); - chrome.loginScreenUi.close(() => { - chrome.test.assertNoLastError(); - chrome.test.succeed(); - }); - }); + 'LoginScreenUiCanOpenAndCloseWindow': async () => { + await chrome.loginScreenUi.show({url: 'some/path.html'}); + await chrome.loginScreenUi.close(); + chrome.test.succeed(); }, 'LoginScreenUiCannotCloseNoWindow': () => { chrome.loginScreenUi.close(() => { @@ -52,19 +46,15 @@ const tests = { chrome.test.succeed(); }); }, - 'LoginScreenUiUserCanCloseWindow': () => { - chrome.loginScreenUi.show({url: 'some/path.html', - userCanClose: true}, () => { - chrome.test.assertNoLastError(); - chrome.test.succeed(); - }); + 'LoginScreenUiUserCanCloseWindow': async () => { + await chrome.loginScreenUi.show( + {url: 'some/path.html', userCanClose: true}); + chrome.test.succeed(); }, - 'LoginScreenUiUserCannotCloseWindow': () => { - chrome.loginScreenUi.show({url: 'some/path.html', - userCanClose: false}, () => { - chrome.test.assertNoLastError(); - chrome.test.succeed(); - }); + 'LoginScreenUiUserCannotCloseWindow': async () => { + await chrome.loginScreenUi.show( + {url: 'some/path.html', userCanClose: false}); + chrome.test.succeed(); }, /* Storage ******************************************************************/ @@ -86,27 +76,20 @@ const tests = { }); }); }, - 'StorageCanAccessManagedStorage': () => { - chrome.storage.managed.get(() => { - chrome.test.assertNoLastError(); - chrome.test.succeed(); - }); + 'StorageCanAccessManagedStorage': async () => { + await chrome.storage.managed.get(); + chrome.test.succeed(); }, /* Login ********************************************************************/ - 'LoginLaunchManagedGuestSession': () => { - chrome.login.launchManagedGuestSession(() => { - chrome.test.assertNoLastError(); - chrome.test.succeed(); - }); + 'LoginLaunchManagedGuestSession': async () => { + await chrome.login.launchManagedGuestSession(); + chrome.test.succeed(); }, - 'LoginLaunchManagedGuestSessionWithPassword': () => { - chrome.test.getConfig(config => { - chrome.login.launchManagedGuestSession(config.customArg, () => { - chrome.test.assertNoLastError(); - chrome.test.succeed(); - }); - }); + 'LoginLaunchManagedGuestSessionWithPassword': async () => { + const config = await chrome.test.getConfig(); + await chrome.login.launchManagedGuestSession(config.customArg); + chrome.test.succeed(); }, 'LoginLaunchManagedGuestSessionAlreadyExistsActiveSession': () => { chrome.login.launchManagedGuestSession(() => { @@ -120,20 +103,16 @@ const tests = { chrome.test.succeed(); }); }, - 'LoginExitCurrentSession': () => { - chrome.test.getConfig(config => { - chrome.login.exitCurrentSession(config.customArg); - // No check for success as browser process exits. - }); + 'LoginExitCurrentSession': async () => { + const config = await chrome.test.getConfig(); + await chrome.login.exitCurrentSession(config.customArg); + // No check for success as browser process exits. }, - 'LoginFetchDataForNextLoginAttempt': () => { - chrome.test.getConfig(config => { - chrome.login.fetchDataForNextLoginAttempt(data => { - chrome.test.assertNoLastError(); - chrome.test.assertEq(config.customArg, data); - chrome.test.succeed(); - }); - }); + 'LoginFetchDataForNextLoginAttempt': async () => { + const config = await chrome.test.getConfig(); + const data = await chrome.login.fetchDataForNextLoginAttempt(); + chrome.test.assertEq(config.customArg, data); + chrome.test.succeed(); }, 'LoginLockManagedGuestSessionNotActive': () => { chrome.login.lockManagedGuestSession(() => { @@ -141,11 +120,10 @@ const tests = { chrome.test.succeed(); }); }, - 'LoginUnlockManagedGuestSession': () => { - chrome.test.getConfig(config => { - chrome.login.unlockManagedGuestSession(config.customArg); - // No check for success as browser process exits. - }); + 'LoginUnlockManagedGuestSession': async () => { + const config = await chrome.test.getConfig(); + await chrome.login.unlockManagedGuestSession(config.customArg); + // No check for success as browser process exits. }, 'LoginUnlockManagedGuestSessionWrongPassword': () => { chrome.test.getConfig(config => { @@ -175,7 +153,6 @@ const tests = { }, 'LoginRequestExternalLogout': () => { chrome.login.requestExternalLogout(); - chrome.test.assertNoLastError(); chrome.test.succeed(); }, 'LoginOnExternalLogoutDone': () => { @@ -186,12 +163,11 @@ const tests = { chrome.test.sendMessage('onExternalLogoutDoneLoginScreenMessage'); }, /* I18n *********************************************************************/ - 'I18nGetMessage': () => { - chrome.test.getConfig(config => { - const message = chrome.i18n.getMessage(i18nMessageName); - chrome.test.assertEq(config.customArg, message); - chrome.test.succeed(); - }); + 'I18nGetMessage': async () => { + const config = await chrome.test.getConfig(); + const message = chrome.i18n.getMessage(i18nMessageName); + chrome.test.assertEq(config.customArg, message); + chrome.test.succeed(); }, }; diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/extension/manifest.json b/chrome/test/data/extensions/api_test/login_screen_apis/extension/manifest.json index 2e235efda3eb13..efe6b1c09ee17d 100644 --- a/chrome/test/data/extensions/api_test/login_screen_apis/extension/manifest.json +++ b/chrome/test/data/extensions/api_test/login_screen_apis/extension/manifest.json @@ -1,15 +1,13 @@ { "name": "Login screen APIs test extension", - "version": "1.27", - "manifest_version": 2, + "version": "1.28", + "manifest_version": 3, "description": "Login screen APIs test extension", "default_locale": "en", "background": { - "scripts": ["background.js"], - "persistent": false + "service_worker": "background.js" }, "permissions": [ - "i18n", "login", "loginScreenUi", "loginScreenStorage", diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/update_manifest.xml b/chrome/test/data/extensions/api_test/login_screen_apis/update_manifest.xml index c5f081e81752e4..8d97bb98beb801 100644 --- a/chrome/test/data/extensions/api_test/login_screen_apis/update_manifest.xml +++ b/chrome/test/data/extensions/api_test/login_screen_apis/update_manifest.xml @@ -8,7 +8,7 @@ + version='1.28' /> Date: Tue, 21 May 2024 15:49:00 +0000 Subject: [PATCH 13/40] Roll Perfetto from 3ce5202ceef9 to 9ac50d25a245 (14 revisions) https://android.googlesource.com/platform/external/perfetto.git/+log/3ce5202ceef9..9ac50d25a245 2024-05-21 khokhlov@google.com Merge "Fix Windows build" into main 2024-05-21 ddiproietto@google.com Merge "Add config java_proto build target for com.android.profiling" into main 2024-05-21 android-test-infra-autosubmit@system.gserviceaccount.com Merge "tp: update sqlite3_vtab_distinct handling based on latest documentation" into main 2024-05-21 ddiproietto@google.com Merge "tp: Add stat about packet loss per buffer" into main 2024-05-21 etiennep@google.com Merge "Reland "[counter] Filter out DynamicString for Track name."" into main 2024-05-21 carlscab@google.com Merge "Add counter names" into main 2024-05-21 stevegolton@google.com Merge "ui: Tidy up engine" into main 2024-05-21 stevegolton@google.com Merge "ui: Remove permalink controller" into main 2024-05-21 ddiproietto@google.com Merge "tp: Move ParseTraceStats before sorting" into main 2024-05-21 android-test-infra-autosubmit@system.gserviceaccount.com Merge "Use std::equal instead of memcmp in file_buffer_unittest.cc" into main 2024-05-20 sdiwas@google.com Merge "Add a dedicated Mainline Test Mapping group for ART" into main 2024-05-20 lalitm@google.com Merge "tp: hide contents of PerVtabState" into main 2024-05-20 carlscab@google.com Parse most common features 2024-05-20 carlscab@google.com Merge "Reapply "Refactor perf parsing"" into main If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/perfetto-chromium-autoroll Please CC perfetto-bugs@google.com,primiano@chromium.org on the revert to ensure that a human is aware of the problem. To file a bug in Chromium: https://bugs.chromium.org/p/chromium/issues/entry To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md Cq-Include-Trybots: luci.chromium.try:linux-perfetto-rel Bug: None Tbr: perfetto-bugs@google.com Change-Id: Iaf63f7deb84080d9813fc833b2da24912309d573 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5555182 Commit-Queue: chromium-autoroll Bot-Commit: chromium-autoroll Cr-Commit-Position: refs/heads/main@{#1303796} --- DEPS | 2 +- third_party/perfetto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6254bfb0439197..b52e7fd22859a7 100644 --- a/DEPS +++ b/DEPS @@ -1956,7 +1956,7 @@ deps = { Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '3ce5202ceef95d02a826c13c516a8485ef26237a', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '9ac50d25a24563cd24268c1a5c6561c8595b4647', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '8ef97ff3b7332e38e61b347a2fbed425a4617151', diff --git a/third_party/perfetto b/third_party/perfetto index 3ce5202ceef95d..9ac50d25a24563 160000 --- a/third_party/perfetto +++ b/third_party/perfetto @@ -1 +1 @@ -Subproject commit 3ce5202ceef95d02a826c13c516a8485ef26237a +Subproject commit 9ac50d25a24563cd24268c1a5c6561c8595b4647 From 3af809cea3b282c3d533478c65e018465caf59c4 Mon Sep 17 00:00:00 2001 From: Aaron Leventhal Date: Tue, 21 May 2024 15:49:39 +0000 Subject: [PATCH 14/40] Avoid 'IndexError: list index out of range' in a11y rebase script Bug: none Change-Id: I6189f3415ed2ae96dce0f24b97eaf1e1ec0417a5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5551472 Reviewed-by: Chris Harrelson Auto-Submit: Aaron Leventhal Commit-Queue: Chris Harrelson Cr-Commit-Position: refs/heads/main@{#1303797} --- tools/accessibility/rebase_dump_accessibility_tree_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/accessibility/rebase_dump_accessibility_tree_test.py b/tools/accessibility/rebase_dump_accessibility_tree_test.py index 5d5bc9f5495a2b..4436fa095ddd1f 100755 --- a/tools/accessibility/rebase_dump_accessibility_tree_test.py +++ b/tools/accessibility/rebase_dump_accessibility_tree_test.py @@ -94,7 +94,7 @@ def ParseLog(logdata): actual_text = '\n'.join(actual) # Make sure the text ends with a newline. - if actual[-1][-1] != '\n': + if len(actual) > 0 and actual[-1][-1] != '\n': actual_text += '\n' fp = open(dst_fullpath, 'w') From 1a9122b0bdb1a2cef8730260cd2a5b9663829e31 Mon Sep 17 00:00:00 2001 From: Tzarial Kuznia Date: Tue, 21 May 2024 15:50:08 +0000 Subject: [PATCH 15/40] [a11y] Put mouse keys reset logic into a helper function. BUG=b:259372916 TEST=ash_unittests --gtest_filter=MouseKeysTest.* Change-Id: I1acca1335b3d5a6034d47a15bfb3b066732cae9a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5552619 Auto-Submit: Tzarial Kuznia Reviewed-by: Akihiro Ota Commit-Queue: Akihiro Ota Cr-Commit-Position: refs/heads/main@{#1303798} --- .../mouse_keys/mouse_keys_controller.cc | 19 +++++++++---------- .../mouse_keys/mouse_keys_controller.h | 1 + 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ash/accessibility/mouse_keys/mouse_keys_controller.cc b/ash/accessibility/mouse_keys/mouse_keys_controller.cc index 441e5cf6ce028a..8a55df68ec265c 100644 --- a/ash/accessibility/mouse_keys/mouse_keys_controller.cc +++ b/ash/accessibility/mouse_keys/mouse_keys_controller.cc @@ -102,12 +102,8 @@ bool MouseKeysController::RewriteEvent(const ui::Event& event) { !(key_event->flags() & ui::EF_IS_REPEAT)) { paused_ = !paused_; if (paused_) { - // TODO(259372916): Move this to a helper function. // Reset everything when pausing. - speed_ = 0; - if (update_timer_.IsRunning()) { - update_timer_.Stop(); - } + Reset(); } return true; } @@ -332,12 +328,8 @@ void MouseKeysController::RefreshVelocity() { move_direction_ = gfx::Vector2d(x_direction, y_direction); if (x_direction == 0 && y_direction == 0) { - // TODO(259372916): Move this to a helper function. // Reset everything if there is no movement. - speed_ = 0; - if (update_timer_.IsRunning()) { - update_timer_.Stop(); - } + Reset(); return; } @@ -364,4 +356,11 @@ void MouseKeysController::UpdateState() { speed_ = std::clamp(speed_ + acceleration, 0.0, max_speed_); } +void MouseKeysController::Reset() { + speed_ = 0; + if (update_timer_.IsRunning()) { + update_timer_.Stop(); + } +} + } // namespace ash diff --git a/ash/accessibility/mouse_keys/mouse_keys_controller.h b/ash/accessibility/mouse_keys/mouse_keys_controller.h index 93a348bf06dbf2..e0dea0a9a73e74 100644 --- a/ash/accessibility/mouse_keys/mouse_keys_controller.h +++ b/ash/accessibility/mouse_keys/mouse_keys_controller.h @@ -104,6 +104,7 @@ class ASH_EXPORT MouseKeysController : public ui::EventHandler { void SelectNextButton(); void RefreshVelocity(); void UpdateState(); + void Reset(); bool enabled_ = false; bool paused_ = false; From 5116c37652339d4b9fcce14002427f69b75380e2 Mon Sep 17 00:00:00 2001 From: Colin Blundell Date: Tue, 21 May 2024 15:50:46 +0000 Subject: [PATCH 16/40] [//gpu] Kick off rename of Mailbox::GenerateForSharedImage() All Mailboxes now hold SharedImages \o/. This CL introduces Mailbox::Generate(), which will replace Mailbox::GenerateForSharedImage() once we sweep through the codebase converting all callers. Bug: 337538024 Change-Id: I1180a9c72ff89dd5b86d4c1aa47e6574918fcfaa Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5545623 Auto-Submit: Colin Blundell Commit-Queue: Colin Blundell Reviewed-by: Vasiliy Telezhnikov Cr-Commit-Position: refs/heads/main@{#1303799} --- gpu/command_buffer/common/mailbox.cc | 4 ++++ gpu/command_buffer/common/mailbox.h | 16 +++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/gpu/command_buffer/common/mailbox.cc b/gpu/command_buffer/common/mailbox.cc index 7e45c625d35300..ecc3778a616ca5 100644 --- a/gpu/command_buffer/common/mailbox.cc +++ b/gpu/command_buffer/common/mailbox.cc @@ -65,6 +65,10 @@ void Mailbox::SetName(const int8_t* n) { } Mailbox Mailbox::GenerateForSharedImage() { + return Generate(); +} + +Mailbox Mailbox::Generate() { return GenerateMailbox(); } diff --git a/gpu/command_buffer/common/mailbox.h b/gpu/command_buffer/common/mailbox.h index 2edd6916b25015..7ab49ecd9ad982 100644 --- a/gpu/command_buffer/common/mailbox.h +++ b/gpu/command_buffer/common/mailbox.h @@ -28,13 +28,11 @@ enum class TracingImportance : int { kClientOwner = 2, }; -// A mailbox is an unguessable name that references texture image data. -// This name can be passed across processes permitting one context to share -// texture image data with another. The mailbox name consists of a random +// A mailbox is an unguessable name that references a SharedImage. +// This name can be passed across processes permitting one process to share +// a SharedImage with another. The mailbox name consists of a random // set of bytes, optionally with a checksum (in debug mode) to verify the // name is valid. -// See src/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_mailbox.txt for more -// details. struct COMPONENT_EXPORT(GPU_MAILBOX) Mailbox { using Name = int8_t[GL_MAILBOX_SIZE_CHROMIUM]; @@ -49,8 +47,12 @@ struct COMPONENT_EXPORT(GPU_MAILBOX) Mailbox { void SetZero(); void SetName(const int8_t* name); - // Generate a unique unguessable mailbox name for use with the SharedImage - // system. + // Generate a unique unguessable mailbox name. + static Mailbox Generate(); + + // Generate a unique unguessable mailbox name. + // TODO(crbug.com/337538024): Remove this method once all callers have been + // ported. static Mailbox GenerateForSharedImage(); // Verify that the mailbox was created through Mailbox::Generate. This only From b2d3d274484794c0f253f7e58507e101af76eaff Mon Sep 17 00:00:00 2001 From: Miguel Casas Date: Tue, 21 May 2024 15:52:21 +0000 Subject: [PATCH 17/40] media/gpu/v4l2: move V4L2StatefulVideoDecoderBackend to legacy/ Since it's only used ATM for ARCVM on Trogdor; this is to avoid confusion by developers reading //media/gpu/v4l2. No functional changes. Done via > git mv media/gpu/v4l2/v4l2_video_decoder_backend_stateful.* media/gpu/v4l2/legacy/ > tools/git/mass-rename.py Bug: 333469457 Change-Id: Id4b3bb23c20bb4b1bebbfd54925a7df8cdeb8a90 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5546268 Commit-Queue: Miguel Casas-Sanchez Reviewed-by: Hang Nguyen Cr-Commit-Position: refs/heads/main@{#1303800} --- media/gpu/v4l2/BUILD.gn | 4 ++-- .../{ => legacy}/v4l2_video_decoder_backend_stateful.cc | 2 +- .../v4l2/{ => legacy}/v4l2_video_decoder_backend_stateful.h | 6 +++--- media/gpu/v4l2/v4l2_video_decoder.cc | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename media/gpu/v4l2/{ => legacy}/v4l2_video_decoder_backend_stateful.cc (99%) rename media/gpu/v4l2/{ => legacy}/v4l2_video_decoder_backend_stateful.h (96%) diff --git a/media/gpu/v4l2/BUILD.gn b/media/gpu/v4l2/BUILD.gn index cf469a68cd7ee4..ef788a2791d347 100644 --- a/media/gpu/v4l2/BUILD.gn +++ b/media/gpu/v4l2/BUILD.gn @@ -17,6 +17,8 @@ source_set("v4l2") { sources = [ "legacy/v4l2_video_decode_accelerator.cc", "legacy/v4l2_video_decode_accelerator.h", + "legacy/v4l2_video_decoder_backend_stateful.cc", + "legacy/v4l2_video_decoder_backend_stateful.h", "stateless/device.cc", "stateless/device.h", "stateless/h264_delegate.cc", @@ -57,8 +59,6 @@ source_set("v4l2") { "v4l2_video_decoder.h", "v4l2_video_decoder_backend.cc", "v4l2_video_decoder_backend.h", - "v4l2_video_decoder_backend_stateful.cc", - "v4l2_video_decoder_backend_stateful.h", "v4l2_video_decoder_backend_stateless.cc", "v4l2_video_decoder_backend_stateless.h", "v4l2_video_decoder_delegate_h264.cc", diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc b/media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.cc similarity index 99% rename from media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc rename to media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.cc index 68c84916606a81..8929feb42d89ce 100644 --- a/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc +++ b/media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h" +#include "media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.h" #include #include diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h b/media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.h similarity index 96% rename from media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h rename to media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.h index c33bf96ba3028b..39f28e0efe9dc8 100644 --- a/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h +++ b/media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_STATEFUL_H_ -#define MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_STATEFUL_H_ +#ifndef MEDIA_GPU_V4L2_LEGACY_V4L2_VIDEO_DECODER_BACKEND_STATEFUL_H_ +#define MEDIA_GPU_V4L2_LEGACY_V4L2_VIDEO_DECODER_BACKEND_STATEFUL_H_ #include #include @@ -178,4 +178,4 @@ class V4L2StatefulVideoDecoderBackend : public V4L2VideoDecoderBackend { } // namespace media -#endif // MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_STATEFUL_H_ +#endif // MEDIA_GPU_V4L2_LEGACY_V4L2_VIDEO_DECODER_BACKEND_STATEFUL_H_ diff --git a/media/gpu/v4l2/v4l2_video_decoder.cc b/media/gpu/v4l2/v4l2_video_decoder.cc index 424e95e5015bdb..afa05986a6e8ef 100644 --- a/media/gpu/v4l2/v4l2_video_decoder.cc +++ b/media/gpu/v4l2/v4l2_video_decoder.cc @@ -29,9 +29,9 @@ #include "media/gpu/chromeos/video_decoder_pipeline.h" #include "media/gpu/gpu_video_decode_accelerator_helpers.h" #include "media/gpu/macros.h" +#include "media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.h" #include "media/gpu/v4l2/v4l2_status.h" #include "media/gpu/v4l2/v4l2_utils.h" -#include "media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h" #include "media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h" #include "mojo/public/cpp/bindings/callback_helpers.h" From ffea9aceb99a98589a35baf31beeb2d0f89b872c Mon Sep 17 00:00:00 2001 From: Miguel Casas Date: Tue, 21 May 2024 15:52:59 +0000 Subject: [PATCH 18/40] media/gpu/V4L2StatefulVD: Handle unexpected number of CAPTURE buffers During |CAPTURE_queue_| configuration, a CHECK asserts that the number of buffers allocated is equal to or larger to the requested one. Field crashes tells us that this assertion doesn't hold; this CL handles it gracefully. Bug: 333882477 Change-Id: Ib185bf8f7679ee11eae15e568f8659164157162a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553491 Reviewed-by: Hang Nguyen Commit-Queue: Miguel Casas-Sanchez Cr-Commit-Position: refs/heads/main@{#1303801} --- media/gpu/v4l2/v4l2_stateful_video_decoder.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/media/gpu/v4l2/v4l2_stateful_video_decoder.cc b/media/gpu/v4l2/v4l2_stateful_video_decoder.cc index 8d9d1a516b3970..4ead8a2b7029e5 100644 --- a/media/gpu/v4l2/v4l2_stateful_video_decoder.cc +++ b/media/gpu/v4l2/v4l2_stateful_video_decoder.cc @@ -767,7 +767,11 @@ bool V4L2StatefulVideoDecoder::InitializeCAPTUREQueue() { const auto allocated_buffers = CAPTURE_queue_->AllocateBuffers( v4l2_num_buffers, buffer_type, /*incoherent=*/false); - CHECK_GE(allocated_buffers, v4l2_num_buffers); + if (allocated_buffers < v4l2_num_buffers) { + LOGF(ERROR) << "Failed to allocate enough CAPTURE buffers, requested= " + << v4l2_num_buffers << " actual= " << allocated_buffers; + return false; + } if (!CAPTURE_queue_->Streamon()) { return false; } From b2dfe87856206db3b6b99f9ff6dfe6d3cadf3980 Mon Sep 17 00:00:00 2001 From: Ian Clelland Date: Tue, 21 May 2024 15:57:10 +0000 Subject: [PATCH 19/40] Remove experimental unoptimized images policies. These document policies (previously feature policies): - lossless-images-max-bpp - lossless-images-strict-max-bpp - lossy-images-max-bpp have been in an experimental state for several years, and there are no current plans to ship them. Removing the feature to reduce the maintenance burden of unused code. Bug: 340920459 Change-Id: I27ad85fffa7d53821079a4fcbb37caf0fa8a8996 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5544759 Commit-Queue: Ian Clelland Reviewed-by: Joe Mason Reviewed-by: Chris Harrelson Cr-Commit-Position: refs/heads/main@{#1303802} --- .../document_policy_unittest.cc | 33 ++++++----- .../document_policy_feature.mojom | 6 +- .../renderer/core/loader/image_loader.cc | 27 +-------- .../loader/resource/image_resource_content.cc | 55 ------------------ .../loader/resource/image_resource_content.h | 7 --- .../document_policy_features.json5 | 21 ------- third_party/blink/web_tests/TestExpectations | 2 - ...es-max-bpp-reporting-onload-tentative.html | 26 --------- ...pp-reporting-onload-tentative.html.headers | 1 - ...sy-images-max-bpp-reporting-tentative.html | 27 --------- ...s-max-bpp-reporting-tentative.html.headers | 1 - .../reporting/unoptimized-image.jpg | Bin 43999 -> 0 bytes ...e-policies-with-border-radius-expected.txt | 1 - ...licy-image-policies-with-border-radius.php | 21 ------- ...olicy-lossless-images-max-bpp-expected.png | Bin 148171 -> 0 bytes ...olicy-lossless-images-max-bpp-expected.txt | 1 - ...ocument-policy-lossless-images-max-bpp.php | 16 ----- ...ossless-images-strict-max-bpp-expected.txt | 2 - ...-policy-lossless-images-strict-max-bpp.php | 21 ------- ...t-policy-lossy-images-max-bpp-expected.txt | 1 - .../document-policy-lossy-images-max-bpp.php | 21 ------- ...optimized-images-cached-image-expected.txt | 3 - ...olicy-unoptimized-images-cached-image.html | 11 ---- 23 files changed, 22 insertions(+), 282 deletions(-) delete mode 100644 third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-onload-tentative.html delete mode 100644 third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-onload-tentative.html.headers delete mode 100644 third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-tentative.html delete mode 100644 third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-tentative.html.headers delete mode 100644 third_party/blink/web_tests/external/wpt/document-policy/reporting/unoptimized-image.jpg delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-image-policies-with-border-radius-expected.txt delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-image-policies-with-border-radius.php delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp-expected.png delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp-expected.txt delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp.php delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-strict-max-bpp-expected.txt delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-strict-max-bpp.php delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-lossy-images-max-bpp-expected.txt delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-lossy-images-max-bpp.php delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-unoptimized-images-cached-image-expected.txt delete mode 100644 third_party/blink/web_tests/http/tests/images/document-policy-unoptimized-images-cached-image.html diff --git a/third_party/blink/common/permissions_policy/document_policy_unittest.cc b/third_party/blink/common/permissions_policy/document_policy_unittest.cc index fdaa90cd8d6d13..1f6990ccd1327b 100644 --- a/third_party/blink/common/permissions_policy/document_policy_unittest.cc +++ b/third_party/blink/common/permissions_policy/document_policy_unittest.cc @@ -70,22 +70,23 @@ TEST_F(DocumentPolicyTest, MergeFeatureState) { // IsPolicyCompatible should use default value for incoming policy when required // policy specifies a value for a feature and incoming policy is missing value // for that feature. -TEST_F(DocumentPolicyTest, IsPolicyCompatible) { - mojom::DocumentPolicyFeature feature = - mojom::DocumentPolicyFeature::kLosslessImagesMaxBpp; - double default_policy_value = - GetDocumentPolicyFeatureInfoMap().at(feature).default_value.DoubleValue(); - // Cap the default_policy_value, as it can be INF. - double strict_policy_value = - default_policy_value > 1.0 ? 1.0 : default_policy_value / 2; - - EXPECT_FALSE(DocumentPolicy::IsPolicyCompatible( - DocumentPolicyFeatureState{ - {feature, PolicyValue::CreateDecDouble( - strict_policy_value)}}, /* required policy */ - DocumentPolicyFeatureState{} /* incoming policy */ - )); -} +// TODO: This is not testable as only boolean features exist currently. +// TEST_F(DocumentPolicyTest, IsPolicyCompatible) { +// mojom::DocumentPolicyFeature feature = +// mojom::DocumentPolicyFeature::kLosslessImagesMaxBpp; +// double default_policy_value = +// GetDocumentPolicyFeatureInfoMap().at(feature).default_value.DoubleValue(); +// // Cap the default_policy_value, as it can be INF. +// double strict_policy_value = +// default_policy_value > 1.0 ? 1.0 : default_policy_value / 2; +// +// EXPECT_FALSE(DocumentPolicy::IsPolicyCompatible( +// DocumentPolicyFeatureState{ +// {feature, PolicyValue::CreateDecDouble( +// strict_policy_value)}}, /* required policy */ +// DocumentPolicyFeatureState{} /* incoming policy */ +// )); +// } } // namespace } // namespace blink diff --git a/third_party/blink/public/mojom/permissions_policy/document_policy_feature.mojom b/third_party/blink/public/mojom/permissions_policy/document_policy_feature.mojom index 053224b8b74b4b..82a16dcde80fe4 100644 --- a/third_party/blink/public/mojom/permissions_policy/document_policy_feature.mojom +++ b/third_party/blink/public/mojom/permissions_policy/document_policy_feature.mojom @@ -11,13 +11,13 @@ enum DocumentPolicyFeature { kFontDisplay = 1, // Takes a parameter, |bpp|, i.e. byte-per-pixel ratio, that images // needs to obey. - kLosslessImagesMaxBpp = 2, + // kLosslessImagesMaxBpp = 2, // Removed. // Controls whether the browser should allow navigations that cause the page to scroll. kForceLoadAtTop = 3, // Takes a parameter, |bpp|, i.e. byte-per-pixel ratio, that images // needs to obey. - kLosslessImagesStrictMaxBpp = 4, - kLossyImagesMaxBpp = 5, + // kLosslessImagesStrictMaxBpp = 4, // Removed. + // kLossyImagesMaxBpp = 5, // Removed. // Takes a parameter, |scale_ratio|, and restricts source image sizes to be // no more than |scale_ratio| x larger than the image's containing block. kOversizedImages = 6, diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc index 7fcc11e14c52b4..0094d36a83a256 100644 --- a/third_party/blink/renderer/core/loader/image_loader.cc +++ b/third_party/blink/renderer/core/loader/image_loader.cc @@ -82,22 +82,6 @@ namespace blink { namespace { -bool CheckForUnoptimizedImagePolicy(ExecutionContext* context, - ImageResourceContent* new_image) { - if (!context || !new_image) - return false; - - // Render the image as a placeholder image if the image is not sufficiently - // well-compressed, according to the unoptimized image policies on - // |document|. - if (RuntimeEnabledFeatures::ExperimentalPoliciesEnabled() && - !new_image->IsAcceptableCompressionRatio(*context)) { - return true; - } - - return false; -} - // This implements the HTML Standard's list of available images tuple-matching // logic [1]. In our implementation, it is only used to determine whether or not // we should skip queueing the microtask that continues the rest of the image @@ -817,19 +801,12 @@ void ImageLoader::ImageNotifyFinished(ImageResourceContent* content) { } } - // TODO(loonybear): support image policies on other images in addition to - // HTMLImageElement. - // crbug.com/930281 - auto* html_image_element = DynamicTo(element_.Get()); - if (CheckForUnoptimizedImagePolicy(element_->GetExecutionContext(), - image_content_) && - html_image_element) - html_image_element->SetImagePolicyViolated(); DispatchDecodeRequestsIfComplete(); - if (html_image_element) + if (auto* html_image_element = DynamicTo(element_.Get())) { LazyImageHelper::RecordMetricsOnLoadFinished(html_image_element); + } if (content->ErrorOccurred()) { pending_load_event_.Cancel(); diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc index 886a0812f1b279..0535c70be01797 100644 --- a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc +++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc @@ -10,10 +10,6 @@ #include "base/metrics/histogram_macros.h" #include "base/time/time.h" #include "third_party/blink/public/common/features.h" -#include "third_party/blink/public/common/permissions_policy/policy_value.h" -#include "third_party/blink/public/mojom/permissions_policy/document_policy_feature.mojom-blink.h" -#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-blink.h" -#include "third_party/blink/public/mojom/permissions_policy/policy_value.mojom-blink.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/loader/resource/image_resource.h" #include "third_party/blink/renderer/core/loader/resource/image_resource_info.h" @@ -542,57 +538,6 @@ uint64_t ImageResourceContent::ContentSizeForEntropy() const { return resource_length; } -bool ImageResourceContent::IsAcceptableCompressionRatio( - ExecutionContext& context) { - if (!image_) - return true; - - uint64_t pixels = image_->Size().Area64(); - if (!pixels) - return true; - - // Calculate the image's compression ratio (in bytes per pixel) with both 1k - // and 10k overhead. The constant overhead allowance is provided to allow room - // for headers and to account for small images (which are harder to compress). - double raw_bpp = static_cast(ContentSizeForEntropy()) / pixels; - double compression_ratio_1k = raw_bpp - (1024 / pixels); - double compression_ratio_10k = raw_bpp - (10240 / pixels); - - ImageDecoder::CompressionFormat compression_format = GetCompressionFormat(); - - // Pass image url to reporting API. - const String& image_url = Url().GetString(); - - const char* message_format = - "Image bpp (byte per pixel) exceeds max value set in %s."; - - if (compression_format == ImageDecoder::kLossyFormat) { - // Enforce the lossy image policy. - return context.IsFeatureEnabled( - mojom::blink::DocumentPolicyFeature::kLossyImagesMaxBpp, - PolicyValue::CreateDecDouble(compression_ratio_1k), - ReportOptions::kReportOnFailure, - String::Format(message_format, "lossy-images-max-bpp"), image_url); - } - if (compression_format == ImageDecoder::kLosslessFormat) { - // Enforce the lossless image policy. - bool enabled_by_10k_policy = context.IsFeatureEnabled( - mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp, - PolicyValue::CreateDecDouble(compression_ratio_10k), - ReportOptions::kReportOnFailure, - String::Format(message_format, "lossless-images-max-bpp"), image_url); - bool enabled_by_1k_policy = context.IsFeatureEnabled( - mojom::blink::DocumentPolicyFeature::kLosslessImagesStrictMaxBpp, - PolicyValue::CreateDecDouble(compression_ratio_1k), - ReportOptions::kReportOnFailure, - String::Format(message_format, "lossless-images-strict-max-bpp"), - image_url); - return enabled_by_10k_policy && enabled_by_1k_policy; - } - - return true; -} - void ImageResourceContent::DecodedSizeChangedTo(const blink::Image* image, size_t new_size) { if (!image || image != image_) diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.h b/third_party/blink/renderer/core/loader/resource/image_resource_content.h index 4b6ef53c3dba24..a10b5f01a24799 100644 --- a/third_party/blink/renderer/core/loader/resource/image_resource_content.h +++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.h @@ -28,7 +28,6 @@ class TimeTicks; namespace blink { -class ExecutionContext; class FetchParameters; class ImageResourceInfo; class KURL; @@ -222,12 +221,6 @@ class CORE_EXPORT ImageResourceContent final // rather than bytes. uint64_t ContentSizeForEntropy() const override; - // Returns true if the image content is well-compressed (and not full of - // extraneous metadata). "well-compressed" is determined by comparing the - // image's compression ratio against a specific value that is defined by an - // unoptimized image policy on |context|. - bool IsAcceptableCompressionRatio(ExecutionContext& context); - void LoadDeferredImage(ResourceFetcher* fetcher); // Returns whether the resource request has been tagged as an ad. diff --git a/third_party/blink/renderer/core/permissions_policy/document_policy_features.json5 b/third_party/blink/renderer/core/permissions_policy/document_policy_features.json5 index d5a8814c27828b..8c1d13c63e32a3 100644 --- a/third_party/blink/renderer/core/permissions_policy/document_policy_features.json5 +++ b/third_party/blink/renderer/core/permissions_policy/document_policy_features.json5 @@ -63,13 +63,6 @@ default_value: "true", depends_on: ["ExperimentalPolicies"], }, - { - name: "LosslessImagesMaxBpp", - document_policy_name: "lossless-images-max-bpp", - value_type: "DecDouble", - default_value: "max", - depends_on: ["ExperimentalPolicies"], - }, { // The ForceLoadAtTop policy lets pages opt-out of scrolling that // automatically happens on page load. This includes fragment scrolls, @@ -80,20 +73,6 @@ value_type: "Bool", default_value: "false", }, - { - name: "LosslessImagesStrictMaxBpp", - document_policy_name: "lossless-images-strict-max-bpp", - value_type: "DecDouble", - default_value: "max", - depends_on: ["ExperimentalPolicies"], - }, - { - name: "LossyImagesMaxBpp", - document_policy_name: "lossy-images-max-bpp", - value_type: "DecDouble", - default_value: "max", - depends_on: ["ExperimentalPolicies"], - }, { name: "OversizedImages", document_policy_name: "oversized-images", diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index a5bf0cf1259608..76dba9c99a7876 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations @@ -4976,8 +4976,6 @@ crbug.com/1450030 [ Mac13 ] http/tests/intersection-observer/cross-origin-iframe # Flaky tests in mac11-arm64 or mac12-arm64 or mac13-arm64 crbug.com/1249176 [ Mac11-arm64 ] transforms/3d/general/cssmatrix-3d-zoom.html [ Failure Pass ] -crbug.com/1249176 [ Mac11-arm64 ] http/tests/images/document-policy-lossy-images-max-bpp.php [ Failure Pass Timeout ] -crbug.com/1249176 [ Mac12-arm64 ] http/tests/images/document-policy-lossy-images-max-bpp.php [ Failure Pass Timeout ] crbug.com/1249176 [ Mac11-arm64 ] fast/forms/plaintext-mode-2.html [ Failure Pass ] crbug.com/1249176 [ Mac11-arm64 ] paint/markers/document-markers-font-8px.html [ Failure Pass ] crbug.com/1249176 [ Mac12-arm64 ] paint/markers/document-markers-font-8px.html [ Failure Pass ] diff --git a/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-onload-tentative.html b/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-onload-tentative.html deleted file mode 100644 index 85e1349a19f7b8..00000000000000 --- a/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-onload-tentative.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - diff --git a/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-onload-tentative.html.headers b/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-onload-tentative.html.headers deleted file mode 100644 index cb28d40ec15266..00000000000000 --- a/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-onload-tentative.html.headers +++ /dev/null @@ -1 +0,0 @@ -Document-Policy: lossy-images-max-bpp=0.5 diff --git a/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-tentative.html b/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-tentative.html deleted file mode 100644 index b6876f4880f4b9..00000000000000 --- a/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-tentative.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - diff --git a/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-tentative.html.headers b/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-tentative.html.headers deleted file mode 100644 index cb28d40ec15266..00000000000000 --- a/third_party/blink/web_tests/external/wpt/document-policy/reporting/lossy-images-max-bpp-reporting-tentative.html.headers +++ /dev/null @@ -1 +0,0 @@ -Document-Policy: lossy-images-max-bpp=0.5 diff --git a/third_party/blink/web_tests/external/wpt/document-policy/reporting/unoptimized-image.jpg b/third_party/blink/web_tests/external/wpt/document-policy/reporting/unoptimized-image.jpg deleted file mode 100644 index 599137a55d710fe6b8d3052c05c81915622ea0d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43999 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 diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-image-policies-with-border-radius-expected.txt b/third_party/blink/web_tests/http/tests/images/document-policy-image-policies-with-border-radius-expected.txt deleted file mode 100644 index 36c52e124c16dd..00000000000000 --- a/third_party/blink/web_tests/http/tests/images/document-policy-image-policies-with-border-radius-expected.txt +++ /dev/null @@ -1 +0,0 @@ -CONSOLE ERROR: Document policy violation: Image bpp (byte per pixel) exceeds max value set in lossy-images-max-bpp. diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-image-policies-with-border-radius.php b/third_party/blink/web_tests/http/tests/images/document-policy-image-policies-with-border-radius.php deleted file mode 100644 index 3c3a0675d0fdf5..00000000000000 --- a/third_party/blink/web_tests/http/tests/images/document-policy-image-policies-with-border-radius.php +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - -

- -
- diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp-expected.png b/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp-expected.png deleted file mode 100644 index 0bda061973285c1217a3e9d66fabb6b21b93affb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148171 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
?ses5j-qc9 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 diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp-expected.txt b/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp-expected.txt deleted file mode 100644 index 1ed32eb97db0b9..00000000000000 --- a/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp-expected.txt +++ /dev/null @@ -1 +0,0 @@ -CONSOLE ERROR: Document policy violation: Image bpp (byte per pixel) exceeds max value set in lossless-images-max-bpp. diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp.php b/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp.php deleted file mode 100644 index d9c78c0dd2e723..00000000000000 --- a/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-max-bpp.php +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-strict-max-bpp-expected.txt b/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-strict-max-bpp-expected.txt deleted file mode 100644 index 1af52c9a5d47b8..00000000000000 --- a/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-strict-max-bpp-expected.txt +++ /dev/null @@ -1,2 +0,0 @@ -CONSOLE ERROR: Document policy violation: Image bpp (byte per pixel) exceeds max value set in lossless-images-strict-max-bpp. -CONSOLE ERROR: Document policy violation: Image bpp (byte per pixel) exceeds max value set in lossless-images-strict-max-bpp. diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-strict-max-bpp.php b/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-strict-max-bpp.php deleted file mode 100644 index 12cbbbe56ee3ac..00000000000000 --- a/third_party/blink/web_tests/http/tests/images/document-policy-lossless-images-strict-max-bpp.php +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - -
- - - - - -
- diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-lossy-images-max-bpp-expected.txt b/third_party/blink/web_tests/http/tests/images/document-policy-lossy-images-max-bpp-expected.txt deleted file mode 100644 index 36c52e124c16dd..00000000000000 --- a/third_party/blink/web_tests/http/tests/images/document-policy-lossy-images-max-bpp-expected.txt +++ /dev/null @@ -1 +0,0 @@ -CONSOLE ERROR: Document policy violation: Image bpp (byte per pixel) exceeds max value set in lossy-images-max-bpp. diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-lossy-images-max-bpp.php b/third_party/blink/web_tests/http/tests/images/document-policy-lossy-images-max-bpp.php deleted file mode 100644 index e162083ee484c4..00000000000000 --- a/third_party/blink/web_tests/http/tests/images/document-policy-lossy-images-max-bpp.php +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - -
- - - - - -
- diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-unoptimized-images-cached-image-expected.txt b/third_party/blink/web_tests/http/tests/images/document-policy-unoptimized-images-cached-image-expected.txt deleted file mode 100644 index 704731631905df..00000000000000 --- a/third_party/blink/web_tests/http/tests/images/document-policy-unoptimized-images-cached-image-expected.txt +++ /dev/null @@ -1,3 +0,0 @@ -CONSOLE ERROR: Document policy violation: Image bpp (byte per pixel) exceeds max value set in lossy-images-max-bpp. -CONSOLE ERROR: Document policy violation: Image bpp (byte per pixel) exceeds max value set in lossy-images-max-bpp. -CONSOLE ERROR: Document policy violation: Image bpp (byte per pixel) exceeds max value set in lossy-images-max-bpp. diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-unoptimized-images-cached-image.html b/third_party/blink/web_tests/http/tests/images/document-policy-unoptimized-images-cached-image.html deleted file mode 100644 index eb0930f844f306..00000000000000 --- a/third_party/blink/web_tests/http/tests/images/document-policy-unoptimized-images-cached-image.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - From b421aea64b8c2abafa81a30197d7ba038c215693 Mon Sep 17 00:00:00 2001 From: chromium-internal-autoroll Date: Tue, 21 May 2024 15:57:40 +0000 Subject: [PATCH 20/40] Roll clank/internal/apps from b34fd76317a0 to 2cffdf40d097 (1 revision) https://chrome-internal.googlesource.com/clank/internal/apps.git/+log/b34fd76317a0..2cffdf40d097 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://skia-autoroll.corp.goog/r/clank-apps-chromium-autoroll Please CC atsvirchkova@google.com,chrome-brapp-engprod@google.com,sinansahin@google.com on the revert to ensure that a human is aware of the problem. To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md Bug: chromium:1491274 Tbr: atsvirchkova@google.com,sinansahin@google.com No-Try: true Change-Id: Ibf48e2a885a8ce5cd153ed29de6983e7994428a6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5555441 Commit-Queue: chromium-internal-autoroll Bot-Commit: chromium-internal-autoroll Cr-Commit-Position: refs/heads/main@{#1303803} --- DEPS | 2 +- clank | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b52e7fd22859a7..20c1ee171609ce 100644 --- a/DEPS +++ b/DEPS @@ -1004,7 +1004,7 @@ deps = { 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - 'b34fd76317a01da56fc86d37882ca27fe55859ca', + '2cffdf40d0973f4fad8cbe455e916c46f1ec64f5', 'condition': 'checkout_android and checkout_src_internal', }, diff --git a/clank b/clank index b34fd76317a01d..2cffdf40d0973f 160000 --- a/clank +++ b/clank @@ -1 +1 @@ -Subproject commit b34fd76317a01da56fc86d37882ca27fe55859ca +Subproject commit 2cffdf40d0973f4fad8cbe455e916c46f1ec64f5 From 20f5994905b26a69e1ba16b04c6c032c90b66f43 Mon Sep 17 00:00:00 2001 From: David Bertoni Date: Tue, 21 May 2024 15:59:21 +0000 Subject: [PATCH 21/40] [Code Health] Remove a use of base::SupportsWeakPtr. This replaces a use of this base class with a WeakPtrFactory and an accessor member function. Note this is a test-only class which does have 11 classes that derive from it, but it seems reasonable to avoid propagating changes into those classes and keep the factory in the base class. I'm happy to fix this hierarchy completely if there's disagreement. Bug: 40485134 Change-Id: Ib50f72b69470a66e307761254862dfce0c6ce3b4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5546297 Commit-Queue: danakj Auto-Submit: David Bertoni Reviewed-by: danakj Cr-Commit-Position: refs/heads/main@{#1303804} --- .../renderer/platform/testing/empty_web_media_player.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/third_party/blink/renderer/platform/testing/empty_web_media_player.h b/third_party/blink/renderer/platform/testing/empty_web_media_player.h index 13b3a561fb26fa..83c1086fa57c5a 100644 --- a/third_party/blink/renderer/platform/testing/empty_web_media_player.h +++ b/third_party/blink/renderer/platform/testing/empty_web_media_player.h @@ -19,8 +19,7 @@ namespace blink { // An empty WebMediaPlayer used only for tests. This class defines the methods // of WebMediaPlayer so that mock WebMediaPlayers don't need to redefine them if // they don't care their behavior. -class EmptyWebMediaPlayer : public WebMediaPlayer, - public base::SupportsWeakPtr { +class EmptyWebMediaPlayer : public WebMediaPlayer { public: ~EmptyWebMediaPlayer() override = default; @@ -74,11 +73,14 @@ class EmptyWebMediaPlayer : public WebMediaPlayer, bool HasAvailableVideoFrame() const override { return false; } bool HasReadableVideoFrame() const override { return false; } base::WeakPtr AsWeakPtr() override { - return base::SupportsWeakPtr::AsWeakPtr(); + return weak_ptr_factory_.GetWeakPtr(); } void RegisterFrameSinkHierarchy() override {} void UnregisterFrameSinkHierarchy() override {} bool PassedTimingAllowOriginCheck() const override { return true; } + + private: + base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace blink From 2eb8a65c5630c14063e880d94d1e2f277862e3ba Mon Sep 17 00:00:00 2001 From: chromium-autoroll Date: Tue, 21 May 2024 16:01:46 +0000 Subject: [PATCH 22/40] Roll Skia from e0881f06f94a to ca98796cc19e (3 revisions) https://skia.googlesource.com/skia.git/+log/e0881f06f94a..ca98796cc19e 2024-05-21 nathanasanchez@google.com Fold gradient matrix into parent local matrix data. 2024-05-21 kjlubick@google.com Fix visibility of shim alias 2024-05-21 3580430+namse@users.noreply.github.com Update skia download link If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-autoroll Please CC jlavrova@google.com,skiabot@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Chromium: https://bugs.chromium.org/p/chromium/issues/entry To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux-blink-rel;luci.chromium.try:linux-chromeos-compile-dbg;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel Cq-Do-Not-Cancel-Tryjobs: true Bug: None Tbr: jlavrova@google.com Change-Id: If33356f7e1d7225a3fa4dc19b7e8254f831c8049 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553394 Bot-Commit: chromium-autoroll Commit-Queue: chromium-autoroll Cr-Commit-Position: refs/heads/main@{#1303805} --- DEPS | 2 +- third_party/skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 20c1ee171609ce..c7c8ba3831b0fa 100644 --- a/DEPS +++ b/DEPS @@ -308,7 +308,7 @@ vars = { # 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': 'e0881f06f94a1bc31e0a5ecd4618090002f61c28', + 'skia_revision': 'ca98796cc19e4ea0ecc32914f2967f003046a282', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. diff --git a/third_party/skia b/third_party/skia index e0881f06f94a1b..ca98796cc19e4e 160000 --- a/third_party/skia +++ b/third_party/skia @@ -1 +1 @@ -Subproject commit e0881f06f94a1bc31e0a5ecd4618090002f61c28 +Subproject commit ca98796cc19e4ea0ecc32914f2967f003046a282 From 554bb020b1ef108d418c39304457f73415997603 Mon Sep 17 00:00:00 2001 From: Adem Derinel Date: Tue, 21 May 2024 16:02:33 +0000 Subject: [PATCH 23/40] [Android][WebAuthn] Check exception during Play Store availability check In public versions of WebView, the check throws an exception such as Play Store version is not available / wrong in the manifest. The app better not crash. Tested using `system_webview_apk` in the test app in google3/experimental/users/derinel/WebViewPasskeyDemo/ Change-Id: I60f865b2a2dc1a353128c4acf92ce654f0627947 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553591 Commit-Queue: Adem Derinel Reviewed-by: Adam Langley Code-Coverage: findit-for-me@appspot.gserviceaccount.com Cr-Commit-Position: refs/heads/main@{#1303806} --- .../components/webauthn/Fido2CredentialRequest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2CredentialRequest.java b/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2CredentialRequest.java index 8324c0fed0425e..37c65160a9f502 100644 --- a/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2CredentialRequest.java +++ b/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2CredentialRequest.java @@ -113,7 +113,13 @@ public enum ConditionalUiState { */ public Fido2CredentialRequest(AuthenticationContextProvider authenticationContextProvider) { mAuthenticationContextProvider = authenticationContextProvider; - mPlayServicesAvailable = Fido2ApiCallHelper.getInstance().arePlayServicesAvailable(); + boolean playServicesAvailable; + try { + playServicesAvailable = Fido2ApiCallHelper.getInstance().arePlayServicesAvailable(); + } catch (Exception e) { + playServicesAvailable = false; + } + mPlayServicesAvailable = playServicesAvailable; mCredManHelper = new CredManHelper(mAuthenticationContextProvider, this, mPlayServicesAvailable); mBarrier = new Barrier(this::returnErrorAndResetCallback); From fa6c3a46bb3f6ec181559ae402debb020075e19e Mon Sep 17 00:00:00 2001 From: Nate Chapin Date: Tue, 21 May 2024 16:05:32 +0000 Subject: [PATCH 24/40] Use new v8::Exception::CaptureStackTrace() API for DOMException stacks This allows us to put the stack directly on the DOMException's v8 wrapper object, instead of attaching a native data property with a dummy v8::Object to capture and retrieve the stack. It also produces a more descriptive error message. Change-Id: Ib60f4ee7232832348358a84681b8eaf137d8ab11 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5548666 Reviewed-by: Demetrios Papadopoulos Commit-Queue: Nate Chapin Reviewed-by: Andrey Kosyakov Reviewed-by: Cammie Smith Barnes Cr-Commit-Position: refs/heads/main@{#1303807} --- .../storage/shared_storage_browsertest.cc | 27 +++++----- .../shared_storage_browsertest.cc | 6 +-- content/browser/webui/web_ui_browsertest.cc | 20 ++++--- ...show-file-picker-interception-expected.txt | 3 -- .../bindings/core/v8/v8_initializer.cc | 14 ----- .../core/v8/v8_throw_dom_exception.cc | 52 ++----------------- .../bindings/core/v8/v8_throw_dom_exception.h | 2 - .../shared_storage_worklet_unittest.cc | 4 +- ...ror-stack-optional.sub.window-expected.txt | 8 +-- ...e-log-linkify-stack-in-errors-expected.txt | 2 +- 10 files changed, 39 insertions(+), 99 deletions(-) diff --git a/chrome/browser/storage/shared_storage_browsertest.cc b/chrome/browser/storage/shared_storage_browsertest.cc index 0183f278ccc241..a67939a5ff2d76 100644 --- a/chrome/browser/storage/shared_storage_browsertest.cc +++ b/chrome/browser/storage/shared_storage_browsertest.cc @@ -191,17 +191,17 @@ MakeFilter(std::vector possible_last_messages) { } std::string GetSharedStorageDisabledErrorMessage() { - return base::StrCat({"a JavaScript error: \"Error: ", + return base::StrCat({"a JavaScript error: \"OperationError: ", content::GetSharedStorageDisabledMessage()}); } std::string GetSharedStorageSelectURLDisabledErrorMessage() { - return base::StrCat({"a JavaScript error: \"Error: ", + return base::StrCat({"a JavaScript error: \"OperationError: ", content::GetSharedStorageSelectURLDisabledMessage()}); } std::string GetSharedStorageAddModuleDisabledErrorMessage() { - return base::StrCat({"a JavaScript error: \"Error: ", + return base::StrCat({"a JavaScript error: \"OperationError: ", content::GetSharedStorageAddModuleDisabledMessage()}); } @@ -738,7 +738,7 @@ class SharedStorageChromeBrowserTestBase : public PlatformBrowserTest { } std::string ExpectedSharedStorageDisabledMessage() { - return "Error: " + content::GetSharedStorageDisabledMessage(); + return "OperationError: " + content::GetSharedStorageDisabledMessage(); } protected: @@ -2229,11 +2229,11 @@ IN_PROC_BROWSER_TEST_P(SharedStorageChromeBrowserTest, content::JsReplace("sharedStorage.worklet.addModule($1)", invalid_url)); EXPECT_EQ( - base::StrCat( - {"a JavaScript error: \"Error: The module script url is invalid.\n", - " at __const_std::string&_script__:1:24):\n", - " {sharedStorage.worklet.addModule(\"", invalid_url, "\")\n", - " ^^^^^\n"}), + base::StrCat({"a JavaScript error: \"DataError: The module script url is " + "invalid.\n", + " at __const_std::string&_script__:1:24):\n", + " {sharedStorage.worklet.addModule(\"", invalid_url, + "\")\n", " ^^^^^\n"}), result.error); WaitForHistograms({kErrorTypeHistogram}); @@ -2253,7 +2253,7 @@ IN_PROC_BROWSER_TEST_P(SharedStorageChromeBrowserTest, content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)); EXPECT_EQ( - base::StrCat({"a JavaScript error: \"Error: Only same origin module ", + base::StrCat({"a JavaScript error: \"DataError: Only same origin module ", "script is allowed.", "\n at __const_std::string&_script__:1:24):\n ", "{sharedStorage.worklet.addModule(\"", @@ -2278,7 +2278,7 @@ IN_PROC_BROWSER_TEST_P(SharedStorageChromeBrowserTest, content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)); EXPECT_EQ( - base::StrCat({"a JavaScript error: \"Error: Failed to load ", + base::StrCat({"a JavaScript error: \"OperationError: Failed to load ", script_url.spec(), " HTTP status = 404 Not Found.\"\n"}), result.error); @@ -2299,8 +2299,9 @@ IN_PROC_BROWSER_TEST_P(SharedStorageChromeBrowserTest, content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)); EXPECT_EQ( - base::StrCat({"a JavaScript error: \"Error: Unexpected redirect on ", - script_url.spec(), ".\"\n"}), + base::StrCat( + {"a JavaScript error: \"OperationError: Unexpected redirect on ", + script_url.spec(), ".\"\n"}), result.error); WaitForHistograms({kErrorTypeHistogram}); diff --git a/content/browser/shared_storage/shared_storage_browsertest.cc b/content/browser/shared_storage/shared_storage_browsertest.cc index 16852fb6e8daab..9827e61d3e801e 100644 --- a/content/browser/shared_storage/shared_storage_browsertest.cc +++ b/content/browser/shared_storage/shared_storage_browsertest.cc @@ -1319,7 +1319,7 @@ IN_PROC_BROWSER_TEST_P(SharedStorageBrowserTest, AddModule_ScriptNotFound) { WebContentsConsoleObserver console_observer(shell()->web_contents()); std::string expected_error = base::StrCat( - {"a JavaScript error: \"Error: Failed to load ", + {"a JavaScript error: \"OperationError: Failed to load ", https_server() ->GetURL("a.test", "/shared_storage/nonexistent_module.js") .spec(), @@ -1349,7 +1349,7 @@ IN_PROC_BROWSER_TEST_P(SharedStorageBrowserTest, AddModule_RedirectNotAllowed) { WebContentsConsoleObserver console_observer(shell()->web_contents()); std::string expected_error = base::StrCat( - {"a JavaScript error: \"Error: Unexpected redirect on ", + {"a JavaScript error: \"OperationError: Unexpected redirect on ", https_server() ->GetURL("a.test", "/server-redirect?shared_storage/simple_module.js") @@ -6538,7 +6538,7 @@ IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest, // `selectURL()` fails when map is full. std::string expected_error = base::StrCat( - {"a JavaScript error: \"Error: ", + {"a JavaScript error: \"OperationError: ", "sharedStorage.selectURL() failed because number of urn::uuid to url ", "mappings has reached the limit.\"\n"}); EXPECT_EQ(expected_error, extra_result.error); diff --git a/content/browser/webui/web_ui_browsertest.cc b/content/browser/webui/web_ui_browsertest.cc index 5d749ea58d3f65..68db55eea3b651 100644 --- a/content/browser/webui/web_ui_browsertest.cc +++ b/content/browser/webui/web_ui_browsertest.cc @@ -1117,7 +1117,7 @@ IN_PROC_BROWSER_TEST_F(WebUIWorkerTest, kLoadSharedWorkerScript); std::string expected_failure = - "a JavaScript error: \"Error: Failed to construct 'SharedWorker'"; + "a JavaScript error: \"SecurityError: Failed to construct 'SharedWorker'"; EXPECT_THAT(result.error, ::testing::StartsWith(expected_failure)); } @@ -1191,7 +1191,8 @@ IN_PROC_BROWSER_TEST_F(WebUIWorkerTest, kLoadSharedWorkerScript); std::string expected_failure = - "a JavaScript error: \"Error: Failed to construct 'SharedWorker': " + "a JavaScript error: \"SecurityError: Failed to construct " + "'SharedWorker': " "Script at 'chrome-untrusted://untrusted/web_ui_shared_worker.js' cannot " "be accessed from origin 'chrome://trusted'"; EXPECT_THAT(result.error, ::testing::StartsWith(expected_failure)); @@ -1209,7 +1210,8 @@ IN_PROC_BROWSER_TEST_F(WebUIWorkerTest, kLoadSharedWorkerScript); std::string expected_failure = - "a JavaScript error: \"Error: Failed to construct 'SharedWorker': " + "a JavaScript error: \"SecurityError: Failed to construct " + "'SharedWorker': " "Script at 'chrome-untrusted://untrusted/web_ui_shared_worker.js' cannot " "be accessed from origin 'http://localhost"; EXPECT_THAT(result.error, ::testing::StartsWith(expected_failure)); @@ -1226,7 +1228,8 @@ IN_PROC_BROWSER_TEST_F(WebUIWorkerTest, GetWebUIURL("trusted/web_ui_shared_worker.js"), kLoadSharedWorkerScript); std::string expected_failure = - "a JavaScript error: \"Error: Failed to construct 'SharedWorker': Script " + "a JavaScript error: \"SecurityError: Failed to construct " + "'SharedWorker': Script " "at 'chrome://trusted/web_ui_shared_worker.js' cannot be accessed from " "origin 'chrome-untrusted://untrusted'."; EXPECT_THAT(result.error, ::testing::StartsWith(expected_failure)); @@ -1256,7 +1259,7 @@ IN_PROC_BROWSER_TEST_P(WebUIDedicatedWorkerTest, kLoadDedicatedWorkerScript); std::string expected_failure = - "a JavaScript error: \"Error: Failed to construct 'Worker'"; + "a JavaScript error: \"SecurityError: Failed to construct 'Worker'"; EXPECT_THAT(result.error, ::testing::StartsWith(expected_failure)); } @@ -1328,7 +1331,7 @@ IN_PROC_BROWSER_TEST_P( kLoadDedicatedWorkerScript); std::string expected_failure = - "a JavaScript error: \"Error: Failed to construct 'Worker': " + "a JavaScript error: \"SecurityError: Failed to construct 'Worker': " "Script at 'chrome-untrusted://untrusted/web_ui_dedicated_worker.js' " "cannot be accessed from origin 'chrome://trusted'"; EXPECT_THAT(result.error, ::testing::StartsWith(expected_failure)); @@ -1346,7 +1349,7 @@ IN_PROC_BROWSER_TEST_P(WebUIDedicatedWorkerTest, kLoadDedicatedWorkerScript); std::string expected_failure = - "a JavaScript error: \"Error: Failed to construct 'Worker': " + "a JavaScript error: \"SecurityError: Failed to construct 'Worker': " "Script at 'chrome-untrusted://untrusted/web_ui_dedicated_worker.js' " "cannot be accessed from origin 'http://localhost"; EXPECT_THAT(result.error, ::testing::StartsWith(expected_failure)); @@ -1365,7 +1368,8 @@ IN_PROC_BROWSER_TEST_P(WebUIDedicatedWorkerTest, kLoadDedicatedWorkerScript); std::string expected_failure = - "a JavaScript error: \"Error: Failed to construct 'Worker': Script " + "a JavaScript error: \"SecurityError: Failed to construct 'Worker': " + "Script " "at 'chrome://trusted/web_ui_dedicated_worker.js' cannot be accessed " "from origin 'chrome-untrusted://untrusted'."; EXPECT_THAT(result.error, ::testing::StartsWith(expected_failure)); diff --git a/headless/test/data/protocol/sanity/show-file-picker-interception-expected.txt b/headless/test/data/protocol/sanity/show-file-picker-interception-expected.txt index 6e675e7fe81bc6..af8e06ef0dd709 100644 --- a/headless/test/data/protocol/sanity/show-file-picker-interception-expected.txt +++ b/headless/test/data/protocol/sanity/show-file-picker-interception-expected.txt @@ -1,11 +1,8 @@ Tests that file picker interception works as expected { - stack : Error: Failed to execute 'showOpenFilePicker' on 'Window': Intercepted by Page.setInterceptFileChooserDialog(). at :2:12 } { - stack : Error: Failed to execute 'showSaveFilePicker' on 'Window': Intercepted by Page.setInterceptFileChooserDialog(). at :2:12 } { - stack : Error: Failed to execute 'showDirectoryPicker' on 'Window': Intercepted by Page.setInterceptFileChooserDialog(). at :2:12 } Intercepted file chooser mode: selectSingle \ No newline at end of file diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc index b4af8b62a25cbe..a445d416190aed 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc @@ -263,20 +263,6 @@ static void PromiseRejectHandler(v8::PromiseRejectMessage data, ExecutionContext* context = ExecutionContext::From(script_state); v8::Local exception = data.GetValue(); - if (V8PerIsolateData::From(isolate)->HasInstance( - DOMException::GetStaticWrapperTypeInfo(), exception)) { - // Try to get the stack & location from a wrapped DOMException object. - CHECK(exception->IsObject()); - auto private_error = V8PrivateProperty::GetSymbol( - isolate, kPrivatePropertyDOMExceptionError); - v8::Local error; - if (private_error.GetOrUndefined(exception.As()) - .ToLocal(&error) && - !error->IsUndefined()) { - exception = error; - } - } - String error_message; SanitizeScriptErrors sanitize_script_errors = SanitizeScriptErrors::kSanitize; std::unique_ptr location; diff --git a/third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.cc b/third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.cc index 5ae18ae63f6034..17ed149b0b1b52 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.cc @@ -13,39 +13,12 @@ namespace blink { -// extern -const V8PrivateProperty::SymbolKey kPrivatePropertyDOMExceptionError; - // static void V8ThrowDOMException::Init() { ExceptionState::SetCreateDOMExceptionFunction( V8ThrowDOMException::CreateOrEmpty); } -namespace { - -void DomExceptionStackGetter(v8::Local name, - const v8::PropertyCallbackInfo& info) { - v8::Isolate* isolate = info.GetIsolate(); - v8::Local value; - if (info.Data() - .As() - ->Get(isolate->GetCurrentContext(), V8AtomicString(isolate, "stack")) - .ToLocal(&value)) { - bindings::V8SetReturnValue(info, value); - } -} - -void DomExceptionStackSetter(v8::Local name, - v8::Local value, - const v8::PropertyCallbackInfo& info) { - [[maybe_unused]] v8::Maybe unused = info.Data().As()->Set( - info.GetIsolate()->GetCurrentContext(), - V8AtomicString(info.GetIsolate(), "stack"), value); -} - -} // namespace - v8::Local V8ThrowDOMException::CreateOrEmpty( v8::Isolate* isolate, DOMExceptionCode exception_code, @@ -80,32 +53,13 @@ v8::Local V8ThrowDOMException::AttachStackProperty( if (isolate->IsExecutionTerminating()) return v8::Local(); - auto current_context = isolate->GetCurrentContext(); - // We use the isolate's current context here because we are creating an // exception object. + auto current_context = isolate->GetCurrentContext(); v8::Local exception_obj = - ToV8Traits::ToV8( - ScriptState::From(isolate, current_context), dom_exception) + dom_exception->ToV8(ScriptState::From(isolate, current_context)) .As(); - - // Attach an Error object to the DOMException. This is then lazily used to get - // the stack value. - v8::Local error = - v8::Exception::Error(V8String(isolate, dom_exception->message())); - - // The context passed to SetNativeDataProperty is used to create an error - // object if needed, and so should be the isolate's current context. - exception_obj - ->SetNativeDataProperty(current_context, V8AtomicString(isolate, "stack"), - DomExceptionStackGetter, DomExceptionStackSetter, - error) - .ToChecked(); - - auto private_error = - V8PrivateProperty::GetSymbol(isolate, kPrivatePropertyDOMExceptionError); - private_error.Set(exception_obj, error); - + v8::Exception::CaptureStackTrace(current_context, exception_obj); return exception_obj; } diff --git a/third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h b/third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h index 78e90b256c82bc..c2c320223ede44 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h +++ b/third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h @@ -50,8 +50,6 @@ class CORE_EXPORT V8ThrowDOMException { static v8::Local AttachStackProperty(v8::Isolate*, DOMException*); }; -extern const V8PrivateProperty::SymbolKey kPrivatePropertyDOMExceptionError; - } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_THROW_DOM_EXCEPTION_H_ diff --git a/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_unittest.cc b/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_unittest.cc index c48ad1a6dc2678..9b72a6adc84bfa 100644 --- a/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_unittest.cc +++ b/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_unittest.cc @@ -2567,7 +2567,7 @@ TEST_F(SharedStorageWorkletTest, Entries_FirstBatchError_Failure) { RunResult run_result{run_future.Get<0>(), run_future.Get<1>()}; EXPECT_FALSE(run_result.success); - EXPECT_EQ(run_result.error_message, "Error: Internal error 12345"); + EXPECT_EQ(run_result.error_message, "OperationError: Internal error 12345"); EXPECT_EQ(test_client_->observed_console_log_messages_.size(), 0u); } @@ -2660,7 +2660,7 @@ TEST_F(SharedStorageWorkletTest, Entries_SecondBatchError_Failure) { RunResult run_result{run_future.Get<0>(), run_future.Get<1>()}; EXPECT_FALSE(run_result.success); - EXPECT_EQ(run_result.error_message, "Error: Internal error 12345"); + EXPECT_EQ(run_result.error_message, "OperationError: Internal error 12345"); EXPECT_EQ(test_client_->observed_console_log_messages_.size(), 1u); } diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt index 3cc0dba1f7478d..9a732a9a5d6366 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt @@ -1,11 +1,11 @@ This is a testharness.js-based test. [FAIL] web API-created DOMException (structuredClone()) - assert_equals: expected (string) "Error: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at Test. (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:41:19)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2622:25)\\n at test (http://web-platform.test:8001/resources/testharness.js:633:30)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:40:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined + assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at Test. (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:41:19)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2622:25)\\n at test (http://web-platform.test:8001/resources/testharness.js:633:30)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:40:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined [FAIL] web API-created DOMException (worker) - assert_equals: expected (string) "Error: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at Test. (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:53:19)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2622:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:52:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined + assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at Test. (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:53:19)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2622:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:52:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined [FAIL] web API-created DOMException (cross-site iframe) - assert_equals: expected (string) "Error: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at iframeTest (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:72:19)\\n at Test. (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:99:5)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2622:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:96:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined + assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at iframeTest (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:72:19)\\n at Test. (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:99:5)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2622:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:96:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined [FAIL] web API-created DOMException (same-origin iframe) - assert_equals: expected (string) "Error: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at iframeTest (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:72:19)\\n at Test. (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:104:5)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2622:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:102:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined + assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at iframeTest (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:72:19)\\n at Test. (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:104:5)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2622:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:102:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined Harness: the test ran to completion. diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors-expected.txt index 2d3d8869e7da23..26f708b1ce9e58 100644 --- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors-expected.txt @@ -7,7 +7,7 @@ console-log-linkify-…ack-in-errors.js:17 Error: line break at forStack (console-log-linkify-…-in-errors.js:17:23) at console-log-linkify-…k-in-errors.js:20:7 -console-log-linkify-…ack-in-errors.js:36 Error: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node. +console-log-linkify-…ack-in-errors.js:36 NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node. at domError (console-log-linkify-…-in-errors.js:34:29) at console-log-linkify-…k-in-errors.js:40:7 console-log-linkify-…ack-in-errors.js:47 Error: some error From 5519ce81d25994e3790a6d7733f740019b140bab Mon Sep 17 00:00:00 2001 From: Maria Petrisor Date: Tue, 21 May 2024 16:07:02 +0000 Subject: [PATCH 25/40] Update Login screen APIs in-session test extension to MV3 Bug: b:325490004 Change-Id: Ida86cff8c23620b879abcd50184b74a33756c647 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5542035 Reviewed-by: Andrey Davydov Commit-Queue: Maria Petrisor Cr-Commit-Position: refs/heads/main@{#1303808} --- .../in_session_extension.crx | Bin 4013 -> 4364 bytes .../in_session_extension/background.js | 55 +++++++----------- .../in_session_extension/manifest.json | 6 +- .../login_screen_apis/update_manifest.xml | 2 +- 4 files changed, 26 insertions(+), 37 deletions(-) diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/in_session_extension.crx b/chrome/test/data/extensions/api_test/login_screen_apis/in_session_extension.crx index 1c0b2e0c20c1c80a9b1c9e0704cdcf95cf727751..07034f688cf752c1266316cbd39329a8eeb4ac11 100644 GIT binary patch delta 3637 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 aobZ2yYXbx!(f1|57e~c~9jv6^@BRguf9bpc delta 3292 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 P3W!z?X>AbG>F9p|PyVLZ diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/in_session_extension/background.js b/chrome/test/data/extensions/api_test/login_screen_apis/in_session_extension/background.js index 659f9f8946dbb5..b2b43527f0b8a5 100644 --- a/chrome/test/data/extensions/api_test/login_screen_apis/in_session_extension/background.js +++ b/chrome/test/data/extensions/api_test/login_screen_apis/in_session_extension/background.js @@ -20,11 +20,9 @@ const noPermissionToUnlockErrorMessage = 'The extension does not have permission to unlock this session'; const tests = { - 'InSessionLoginLockManagedGuestSession': () => { - chrome.login.lockManagedGuestSession(() => { - chrome.test.assertNoLastError(); - chrome.test.succeed(); - }); + 'InSessionLoginLockManagedGuestSession': async () => { + await chrome.login.lockManagedGuestSession(); + chrome.test.succeed(); }, 'InSessionLoginLockManagedGuestSessionNoPermission': () => { chrome.login.lockManagedGuestSession(() => { @@ -40,7 +38,6 @@ const tests = { }, 'InSessionLoginNotifyExternalLogoutDone': () => { chrome.login.notifyExternalLogoutDone(); - chrome.test.assertNoLastError(); chrome.test.succeed(); }, 'InSessionLoginOnRequestExternalLogout': () => { @@ -50,38 +47,30 @@ const tests = { }); chrome.test.sendMessage('onRequestExternalLogoutInSessionMessage'); }, - 'InSessionLoginScreenStorageStorePersistentData': () => { - chrome.loginScreenStorage.storePersistentData( - [extensionId1, extensionId2], data, () => { - chrome.test.assertNoLastError(); - chrome.test.succeed(); - }); + 'InSessionLoginScreenStorageStorePersistentData': async () => { + await chrome.loginScreenStorage.storePersistentData( + [extensionId1, extensionId2], data); + chrome.test.succeed(); }, - 'InSessionLoginScreenStorageRetrievePersistentData': () => { - chrome.loginScreenStorage.retrievePersistentData(extensionId, data => { - chrome.test.assertNoLastError(); - chrome.test.assertEq(loginScreenStorageResult, data); - chrome.test.succeed(); - }); + 'InSessionLoginScreenStorageRetrievePersistentData': async () => { + const data = + await chrome.loginScreenStorage.retrievePersistentData(extensionId); + chrome.test.assertEq(loginScreenStorageResult, data); + chrome.test.succeed(); }, - 'InSessionLoginScreenStorageStoreCredentials': () => { - chrome.loginScreenStorage.storeCredentials( - extensionId, credentials, () => { - chrome.test.assertNoLastError(); - chrome.test.succeed(); - }); + 'InSessionLoginScreenStorageStoreCredentials': async () => { + await chrome.loginScreenStorage.storeCredentials(extensionId, credentials); + chrome.test.succeed(); }, - 'InSessionLoginScreenStorageRetrieveCredentials': () => { - chrome.loginScreenStorage.retrieveCredentials(credentials => { - chrome.test.assertNoLastError(); - chrome.test.assertEq(loginScreenStorageResult, credentials); - chrome.test.succeed(); - }); + 'InSessionLoginScreenStorageRetrieveCredentials': async () => { + const credentials = await chrome.loginScreenStorage.retrieveCredentials(); + chrome.test.assertEq(loginScreenStorageResult, credentials); + chrome.test.succeed(); } -} +}; -// |waitForTestName()| waits for the browser test to reply with a test name and -// runs the specified test. The browser test logic can be found at +// |waitForTestName()| waits for the browser test to reply with a test name +// and runs the specified test. The browser test logic can be found at // chrome/browser/chromeos/extensions/login_screen/login_screen_apitest_base.cc function waitForTestName(testName) { if (!tests.hasOwnProperty(testName) || diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/in_session_extension/manifest.json b/chrome/test/data/extensions/api_test/login_screen_apis/in_session_extension/manifest.json index d0a8391043b34c..81d858e595e42a 100644 --- a/chrome/test/data/extensions/api_test/login_screen_apis/in_session_extension/manifest.json +++ b/chrome/test/data/extensions/api_test/login_screen_apis/in_session_extension/manifest.json @@ -1,10 +1,10 @@ { "name": "Login screen APIs in-session test extension", - "version": "0.7", - "manifest_version": 2, + "version": "0.8", + "manifest_version": 3, "description": "In session extension for testing the chrome.login extension API", "background": { - "scripts": ["background.js"] + "service_worker": "background.js" }, "permissions": [ "login", diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/update_manifest.xml b/chrome/test/data/extensions/api_test/login_screen_apis/update_manifest.xml index 8d97bb98beb801..a4279c08b371c3 100644 --- a/chrome/test/data/extensions/api_test/login_screen_apis/update_manifest.xml +++ b/chrome/test/data/extensions/api_test/login_screen_apis/update_manifest.xml @@ -13,6 +13,6 @@ + version='0.8' /> From 4bfcab51c9e72a7bdc1abb6c436a8e6b93dc1689 Mon Sep 17 00:00:00 2001 From: Avi Drissman Date: Tue, 21 May 2024 16:07:29 +0000 Subject: [PATCH 26/40] Do minor clean-up on base::ScopedFD. Bug: none Change-Id: I73e903ba36f11d0f7cc3f8d01c81b3a26fa001b2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5545932 Reviewed-by: danakj Auto-Submit: Avi Drissman Commit-Queue: danakj Code-Coverage: findit-for-me@appspot.gserviceaccount.com Cr-Commit-Position: refs/heads/main@{#1303809} --- base/files/scoped_file.cc | 13 +++++------ base/files/scoped_file.h | 45 +++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/base/files/scoped_file.cc b/base/files/scoped_file.cc index 7ff0c17b90b836..7094e212e0b03a 100644 --- a/base/files/scoped_file.cc +++ b/base/files/scoped_file.cc @@ -14,18 +14,19 @@ #include "base/posix/eintr_wrapper.h" #endif -namespace base { -namespace internal { +namespace base::internal { #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) // static void ScopedFDCloseTraits::Free(int fd) { - // It's important to crash here. + // It's important to crash here if something goes wrong. + // // There are security implications to not closing a file descriptor // properly. As file descriptors are "capabilities", keeping them open // would make the current process keep access to a resource. Much of // Chrome relies on being able to "drop" such access. + // // It's especially problematic on Linux with the setuid sandbox, where // a single open directory would bypass the entire security model. int ret = IGNORE_EINTR(close(fd)); @@ -36,8 +37,9 @@ void ScopedFDCloseTraits::Free(int fd) { // filesystems such as NFS and Linux input devices. On Linux, macOS, and // Fuchsia's POSIX layer, errors from close other than EBADF do not indicate // failure to actually close the fd. - if (ret != 0 && errno != EBADF) + if (ret != 0 && errno != EBADF) { ret = 0; + } #endif PCHECK(0 == ret); @@ -45,5 +47,4 @@ void ScopedFDCloseTraits::Free(int fd) { #endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) -} // namespace internal -} // namespace base +} // namespace base::internal diff --git a/base/files/scoped_file.h b/base/files/scoped_file.h index 23180de58a3956..181d821001d3bc 100644 --- a/base/files/scoped_file.h +++ b/base/files/scoped_file.h @@ -17,38 +17,37 @@ namespace base { namespace internal { -#if BUILDFLAG(IS_ANDROID) -// Use fdsan on android. +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) +// Platforms for which it is possible to track ownership of file descriptors. +// +// On Android, fdsan is used. +// +// On ChromeOS and Linux, file descriptor lifetime is guarded with a global +// table and a hook into libc close(). struct BASE_EXPORT ScopedFDCloseTraits : public ScopedGenericOwnershipTracking { static int InvalidValue() { return -1; } - static void Free(int); - static void Acquire(const ScopedGeneric&, int); - static void Release(const ScopedGeneric&, int); + static void Free(int fd); + static void Acquire(const ScopedGeneric& owner, + int fd); + static void Release(const ScopedGeneric& owner, + int fd); }; + #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) -#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) -// On ChromeOS and Linux we guard FD lifetime with a global table and hook into -// libc close() to perform checks. -struct BASE_EXPORT ScopedFDCloseTraits : public ScopedGenericOwnershipTracking { -#else + struct BASE_EXPORT ScopedFDCloseTraits { -#endif - static int InvalidValue() { - return -1; - } + static int InvalidValue() { return -1; } static void Free(int fd); -#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) - static void Acquire(const ScopedGeneric&, int); - static void Release(const ScopedGeneric&, int); -#endif }; + #endif -// Functor for |ScopedFILE| (below). +// Functor for `ScopedFILE` (below). struct ScopedFILECloser { inline void operator()(FILE* x) const { - if (x) + if (x) { fclose(x); + } } }; @@ -98,11 +97,11 @@ void BASE_EXPORT ResetFDOwnership(); // should generally use base::File instead which can be constructed with a // handle, and in addition to handling ownership, has convenient cross-platform // file manipulation functions on it. -typedef ScopedGeneric ScopedFD; +using ScopedFD = ScopedGeneric; #endif -// Automatically closes |FILE*|s. -typedef std::unique_ptr ScopedFILE; +// Automatically closes `FILE*`s. +using ScopedFILE = std::unique_ptr; #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) // Queries the ownership status of an FD, i.e. whether it is currently owned by From f3829f670b012ea2c95f8849f375e4f778cf448d Mon Sep 17 00:00:00 2001 From: Maria Petrisor Date: Tue, 21 May 2024 16:08:10 +0000 Subject: [PATCH 27/40] Update chrome.loginState test extensions to MV3 Bug: b:341051510 Change-Id: I645f97bd222afa1e42300d52eb2facb36af32980 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5544477 Reviewed-by: Andrey Davydov Commit-Queue: Maria Petrisor Cr-Commit-Position: refs/heads/main@{#1303810} --- .../login_state/get_profile_type/manifest.json | 6 +++--- .../login_state/get_session_state/manifest.json | 6 +++--- .../login_state/on_session_state_changed/manifest.json | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_profile_type/manifest.json b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_profile_type/manifest.json index bdd9ebb46f02f3..fd0b1fb74c8687 100644 --- a/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_profile_type/manifest.json +++ b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_profile_type/manifest.json @@ -1,10 +1,10 @@ { "name": "Get Profile Type", - "version": "0.1", - "manifest_version": 2, + "version": "2.0", + "manifest_version": 3, "description": "Browser test for chrome.loginState.getProfileType()", "background": { - "scripts": ["test.js"] + "service_worker": "test.js" }, "permissions": [ "loginState" diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_session_state/manifest.json b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_session_state/manifest.json index 870f1008cf7d69..93350cce04dd59 100644 --- a/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_session_state/manifest.json +++ b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_session_state/manifest.json @@ -1,10 +1,10 @@ { "name": "Get Session State", - "version": "1.0", - "manifest_version": 2, + "version": "2.0", + "manifest_version": 3, "description": "Browser test for chrome.loginState.getSessionState()", "background": { - "scripts": ["test.js"] + "service_worker": "test.js" }, "permissions": [ "loginState" diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/login_state/on_session_state_changed/manifest.json b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/on_session_state_changed/manifest.json index f299e1a9391e24..b8ebe600e4dfe9 100644 --- a/chrome/test/data/extensions/api_test/login_screen_apis/login_state/on_session_state_changed/manifest.json +++ b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/on_session_state_changed/manifest.json @@ -1,10 +1,10 @@ { "name": "On Session State Changed", - "version": "0.1", - "manifest_version": 2, + "version": "2.0", + "manifest_version": 3, "description": "Browser test for chrome.loginState.onSessionStateChanged()", "background": { - "scripts": ["test.js"] + "service_worker": "test.js" }, "permissions": [ "loginState" From 425f7ad52df155f5d1e1a8e5f406a6371f315984 Mon Sep 17 00:00:00 2001 From: chromium-autoroll Date: Tue, 21 May 2024 16:09:50 +0000 Subject: [PATCH 28/40] Roll V8 from 54fbb5fc84ec to 7d50244cc4fd (9 revisions) https://chromium.googlesource.com/v8/v8.git/+log/54fbb5fc84ec..7d50244cc4fd 2024-05-21 v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com Version 12.7.90 2024-05-21 dinfuehr@chromium.org [heap] Verify shared trusted spaces as well in the heap verifier 2024-05-21 olivf@chromium.org [maglev] Statically fold TestTypeOf 2024-05-21 mlippautz@chromium.org [heap] Disable HWASAN for stack scanning 2024-05-21 victorgomes@chromium.org [maglev] Consider number values in BranchBuildIfRootConstant 2024-05-21 machenbach@chromium.org [infra] Add drumbrake builders on Windows 2024-05-21 verwaest@chromium.org [maglev] Refine element feedback 2024-05-21 mliedtke@chromium.org [deoptimizer][wasm] Correct handling of inlined parameter stack slots 2024-05-21 dmercadier@chromium.org [turboshaft] Maglev-to-ts: support CheckedSmiTagFloat64 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/v8-chromium-autoroll Please CC liviurau@google.com,machenbach@google.com,v8-waterfall-gardener@grotations.appspotmail.com on the revert to ensure that a human is aware of the problem. To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md Cq-Include-Trybots: luci.chromium.try:linux-blink-rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel;luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:dawn-linux-x64-deps-rel Change-Id: If44b2df72f3398e1e8587b248409c38ae8c2adfb Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5555321 Commit-Queue: chromium-autoroll Bot-Commit: chromium-autoroll Cr-Commit-Position: refs/heads/main@{#1303811} --- DEPS | 2 +- v8 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c7c8ba3831b0fa..8289be54832a74 100644 --- a/DEPS +++ b/DEPS @@ -312,7 +312,7 @@ vars = { # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '54fbb5fc84ec83a32b25e6746db942e0aaca02af', + 'v8_revision': '7d50244cc4fdf617bf0a940830b92146c8afc711', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. diff --git a/v8 b/v8 index 54fbb5fc84ec83..7d50244cc4fdf6 160000 --- a/v8 +++ b/v8 @@ -1 +1 @@ -Subproject commit 54fbb5fc84ec83a32b25e6746db942e0aaca02af +Subproject commit 7d50244cc4fdf617bf0a940830b92146c8afc711 From 1ec7d38818fe3677c1d0392b96575895313f0298 Mon Sep 17 00:00:00 2001 From: Fiona Macintosh Date: Tue, 21 May 2024 16:10:26 +0000 Subject: [PATCH 29/40] [TP] Add Tracking Protection exceptions list to settings page This just adds the component, content based on user state (i.e. pre-3PC with ACT vs. TP) will be sent as a followup Bug: b:334970346 Change-Id: I181443847df3192953b5200e9133833e10b49d31 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5463519 Auto-Submit: Fiona Macintosh Reviewed-by: Kevin Graney Commit-Queue: Kevin Graney Commit-Queue: Fiona Macintosh Cr-Commit-Position: refs/heads/main@{#1303812} --- .../settings/privacy_page/cookies_page.html | 38 +++++++++++++------ .../settings/privacy_page/cookies_page.ts | 13 +++++++ .../data/webui/settings/cookies_page_test.ts | 37 +++++++++++++++++- .../webui/settings/settings_browsertest.cc | 6 +++ 4 files changed, 80 insertions(+), 14 deletions(-) diff --git a/chrome/browser/resources/settings/privacy_page/cookies_page.html b/chrome/browser/resources/settings/privacy_page/cookies_page.html index 3277fc7e98c3cc..f1c515d7bf1b3d 100644 --- a/chrome/browser/resources/settings/privacy_page/cookies_page.html +++ b/chrome/browser/resources/settings/privacy_page/cookies_page.html @@ -9,7 +9,8 @@ padding: 0 var(--cr-section-padding); } - #exceptionHeader3pcd { + #exceptionHeader3pcd, + #exceptionHeaderTrackingProtection { padding: 0 var(--cr-section-padding); margin-bottom: -32px; } @@ -267,17 +268,30 @@

on-click="onSiteDataClick_" label="$i18n{cookiePageAllSitesLink}" role-description="$i18n{subpageArrowRoleDescription}"> -
-

$i18n{trackingProtectionSitesAllowedCookiesTitle}

-
- - + +
$i18n{privacySandboxCookiesDialog}
diff --git a/chrome/browser/resources/settings/privacy_page/cookies_page.ts b/chrome/browser/resources/settings/privacy_page/cookies_page.ts index 185ef60bbd89f4..a37ac5ebbef228 100644 --- a/chrome/browser/resources/settings/privacy_page/cookies_page.ts +++ b/chrome/browser/resources/settings/privacy_page/cookies_page.ts @@ -94,6 +94,11 @@ export class SettingsCookiesPageElement extends SettingsCookiesPageElementBase { value: ContentSettingsTypes.COOKIES, }, + trackingProtectionContentSettingType_: { + type: String, + value: ContentSettingsTypes.TRACKING_PROTECTION, + }, + exceptionListsReadOnly_: { type: Boolean, value: false, @@ -116,6 +121,12 @@ export class SettingsCookiesPageElement extends SettingsCookiesPageElementBase { value: () => loadTimeData.getBoolean('firstPartySetsUIEnabled'), }, + enableTrackingProtectionRolloutUx_: { + type: Boolean, + value: () => + loadTimeData.getBoolean('enableTrackingProtectionRolloutUx'), + }, + is3pcdRedesignEnabled_: { type: Boolean, value: () => @@ -149,10 +160,12 @@ export class SettingsCookiesPageElement extends SettingsCookiesPageElementBase { searchTerm: string; private cookiesContentSettingType_: ContentSettingsTypes; + private trackingProtectionContentSettingType_: ContentSettingsTypes; private exceptionListsReadOnly_: boolean; private blockAllPref_: chrome.settingsPrivate.PrefObject; focusConfig: FocusConfig; private enableFirstPartySetsUI_: boolean; + private enableTrackingProtectionRolloutUx_: boolean; private is3pcdRedesignEnabled_: boolean; private isIpProtectionAvailable_: boolean; private isFingerprintingProtectionAvailable_: boolean; diff --git a/chrome/test/data/webui/settings/cookies_page_test.ts b/chrome/test/data/webui/settings/cookies_page_test.ts index 8e12b7d77bc39b..e51b3f55e53c64 100644 --- a/chrome/test/data/webui/settings/cookies_page_test.ts +++ b/chrome/test/data/webui/settings/cookies_page_test.ts @@ -84,10 +84,13 @@ suite('CookiesPageTest', function() { assertTrue(isChildVisible(page, '#generalControls')); assertTrue(isChildVisible(page, '#advancedHeader')); assertTrue(isChildVisible(page, '#exceptionHeader3pcd')); - assertTrue(isChildVisible(page, '#allowExceptionsList')); + assertTrue(isChildVisible(page, '#allow3pcExceptionsList')); // To be removed with old UI. assertFalse(isChildVisible(page, '#exceptionHeader')); assertFalse(isChildVisible(page, '#exceptionHeaderSubLabel')); + // Will only be shown in the TP rollout. + assertFalse(isChildVisible(page, '#exceptionHeaderTrackingProtection')); + assertFalse(isChildVisible(page, '#trackingProtectionExceptionsList')); // Settings assertTrue(isChildVisible(page, '#doNotTrack')); @@ -425,7 +428,7 @@ suite('TrackingProtectionSettings', function() { assertFalse(isChildVisible(page, '#exceptionHeader')); assertFalse(isChildVisible(page, '#exceptionHeaderSubLabel')); assertTrue(isChildVisible(page, '#exceptionHeader3pcd')); - assertTrue(isChildVisible(page, '#allowExceptionsList')); + assertTrue(isChildVisible(page, '#allow3pcExceptionsList')); }); test('BlockAll3pcToggle', async function() { @@ -549,6 +552,36 @@ suite('FingerprintingProtectionToggle', function() { }); }); +suite('TrackingProtectionRolloutUx', function() { + let page: SettingsCookiesPageElement; + let settingsPrefs: SettingsPrefsElement; + + suiteSetup(function() { + loadTimeData.overrideValues({ + enableTrackingProtectionRolloutUx: true, + }); + settingsPrefs = document.createElement('settings-prefs'); + return CrSettingsPrefs.initialized; + }); + + setup(function() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + page = document.createElement('settings-cookies-page'); + page.prefs = settingsPrefs.prefs!; + document.body.appendChild(page); + flush(); + }); + + test('TrackingProtectionExceptionsListDisplayed', function() { + // Tracking Protection elements are shown + assertTrue(isChildVisible(page, '#exceptionHeaderTrackingProtection')); + assertTrue(isChildVisible(page, '#trackingProtectionExceptionsList')); + // 3PC elements are hidden + assertFalse(isChildVisible(page, '#exceptionHeader3pcd')); + assertFalse(isChildVisible(page, '#allow3pcExceptionsList')); + }); +}); + suite('TrackingProtectionSettingsRollbackNotice', function() { let page: SettingsCookiesPageElement; let settingsPrefs: SettingsPrefsElement; diff --git a/chrome/test/data/webui/settings/settings_browsertest.cc b/chrome/test/data/webui/settings/settings_browsertest.cc index 9bcf2325638069..8710c090f6b691 100644 --- a/chrome/test/data/webui/settings/settings_browsertest.cc +++ b/chrome/test/data/webui/settings/settings_browsertest.cc @@ -627,6 +627,12 @@ IN_PROC_BROWSER_TEST_F(SettingsCookiesPageTest, TrackingProtectionSettings) { "runMochaSuite('TrackingProtectionSettings')"); } +IN_PROC_BROWSER_TEST_F(SettingsCookiesPageTest, + TrackingProtectionRolloutUx) { + RunTest("settings/cookies_page_test.js", + "runMochaSuite('TrackingProtectionRolloutUx')"); +} + IN_PROC_BROWSER_TEST_F(SettingsCookiesPageTest, TrackingProtectionSettingsRollbackNotice) { RunTest("settings/cookies_page_test.js", From f0e1437513ed45f4d01bfd230b96f57d760c1ff5 Mon Sep 17 00:00:00 2001 From: Ahmed Mehfooz Date: Tue, 21 May 2024 16:12:15 +0000 Subject: [PATCH 30/40] Fix Track pad swipe gestures in SlideOutController SlideOutController::OnScrollEvent has been rewritten to process trackpad scroll events until they are completed. This will ensure all trackpad swipes are completely consumed by the `SlideOutController` when it is active. Bug: b/333750690 Change-Id: Ib6d738389c7e10fc1e98bc4a1c7df3b14902561c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5550759 Commit-Queue: Ahmed Mehfooz Reviewed-by: Mitsuru Oshima Cr-Commit-Position: refs/heads/main@{#1303813} --- .../arc_notification_view_unittest.cc | 2 +- .../views/notification_view_base_unittest.cc | 6 ++- ui/views/animation/slide_out_controller.cc | 49 ++++++++++++------- .../slide_out_controller_unittest.cc | 34 ++++++++----- 4 files changed, 57 insertions(+), 34 deletions(-) diff --git a/ash/public/cpp/external_arc/message_center/arc_notification_view_unittest.cc b/ash/public/cpp/external_arc/message_center/arc_notification_view_unittest.cc index d4461e8aa274d8..40ffc79cbfe568 100644 --- a/ash/public/cpp/external_arc/message_center/arc_notification_view_unittest.cc +++ b/ash/public/cpp/external_arc/message_center/arc_notification_view_unittest.cc @@ -423,7 +423,7 @@ TEST_F(NotificationGestureUpdateTest, TrackPadGestureSlideOut) { ui::test::EventGenerator generator( (notification_view()->GetWidget()->GetNativeWindow()->GetRootWindow())); - generator.ScrollSequence(gfx::Point(), base::TimeDelta(), /*x_offset=*/20, + generator.ScrollSequence(gfx::Point(), base::TimeDelta(), /*x_offset=*/200, /*y_offset=*/0, /*steps=*/1, /*num_fingers=*/2); EXPECT_TRUE(IsPopupRemovedAfterIdle(kDefaultNotificationId)); } diff --git a/ui/message_center/views/notification_view_base_unittest.cc b/ui/message_center/views/notification_view_base_unittest.cc index 871ca196d5fc78..433f3b0120186c 100644 --- a/ui/message_center/views/notification_view_base_unittest.cc +++ b/ui/message_center/views/notification_view_base_unittest.cc @@ -1244,8 +1244,10 @@ TEST_F(NotificationViewBaseWithNotificationGestureUpdateTest, ui::test::EventGenerator generator( GetRootWindow(notification_view()->GetWidget())); - generator.ScrollSequence(gfx::Point(), base::TimeDelta(), /*x_offset=*/20, - /*y_offset=*/0, /*steps=*/1, /*num_fingers=*/2); + generator.ScrollSequence( + gfx::Point(), base::TimeDelta(), + /*x_offset=*/notification_view()->bounds().width() + 1, + /*y_offset=*/0, /*steps=*/1, /*num_fingers=*/2); EXPECT_TRUE(IsPopupRemovedAfterIdle(kDefaultNotificationId)); } diff --git a/ui/views/animation/slide_out_controller.cc b/ui/views/animation/slide_out_controller.cc index d41a778b38560f..8bbd2a408461bc 100644 --- a/ui/views/animation/slide_out_controller.cc +++ b/ui/views/animation/slide_out_controller.cc @@ -13,6 +13,7 @@ #include "ui/compositor/layer.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/events/event.h" +#include "ui/events/types/event_type.h" #include "ui/gfx/geometry/transform.h" #include "ui/views/animation/animation_builder.h" #include "ui/views/animation/slide_out_controller_delegate.h" @@ -139,33 +140,43 @@ void SlideOutController::OnGestureEvent(ui::GestureEvent* event) { } void SlideOutController::OnScrollEvent(ui::ScrollEvent* event) { - if (!trackpad_gestures_enabled_) { + // Ignore events if slide out by trackpad is not available. + if (!trackpad_gestures_enabled_ || mode_ != SlideMode::kFull) { return; } - // This threshold has been set to 20.f to stay consistent with the trackpad - // scroll threshold used to determine if the app list should be opened when - // scrolling on the shelf in ChromeOS. - constexpr float kScrollOffsetThreshold = 20.f; - if (abs(event->x_offset()) < kScrollOffsetThreshold || - event->finger_count() != 2) { + // Ignore events where vertical offset is greater than horizontal (likely not + // a slide-out gesture). + if (abs(event->x_offset()) < abs(event->y_offset())) { return; } - if (mode_ == SlideMode::kFull) { + if (event->type() == ui::EventType::ET_SCROLL_FLING_CANCEL) { + gesture_amount_ = 0; + } else if (event->type() == ui::EventType::ET_SCROLL) { + if (event->finger_count() == 2) { + gesture_amount_ += event->x_offset(); + } + } else if (event->type() == ui::EventType::ET_SCROLL_FLING_START) { auto* layer = delegate_->GetSlideOutLayer(); - gfx::Transform transform; - transform.Translate(layer->bounds().width(), 0); - AnimationBuilder() - .OnEnded(base::BindOnce(&SlideOutController::OnSlideOut, - weak_ptr_factory_.GetWeakPtr())) - .Once() - .SetDuration(base::Milliseconds(kSwipeOutTotalDurationMs)) - .SetTransform(layer, transform, kSwipeTweenType) - .SetOpacity(layer, 0.f); - event->SetHandled(); - return; + int width = layer->bounds().width(); + if (abs(gesture_amount_) > width) { + int direction = gesture_amount_ > 0 ? -1 : 1; + gfx::Transform transform; + transform.Translate(direction * width, 0); + + AnimationBuilder() + .OnEnded(base::BindOnce(&SlideOutController::OnSlideOut, + weak_ptr_factory_.GetWeakPtr())) + .Once() + .SetDuration(base::Milliseconds(kSwipeOutTotalDurationMs)) + .SetTransform(layer, transform, kSwipeTweenType) + .SetOpacity(layer, 0.f); + } + gesture_amount_ = 0; } + + event->SetHandled(); } void SlideOutController::RestoreVisualState() { diff --git a/ui/views/animation/slide_out_controller_unittest.cc b/ui/views/animation/slide_out_controller_unittest.cc index 96407fd70eb408..3d6c55a8a50b4e 100644 --- a/ui/views/animation/slide_out_controller_unittest.cc +++ b/ui/views/animation/slide_out_controller_unittest.cc @@ -15,6 +15,7 @@ #include "ui/compositor/layer.h" #include "ui/events/event.h" #include "ui/events/test/event_generator.h" +#include "ui/events/types/event_type.h" #include "ui/views/animation/slide_out_controller_delegate.h" #include "ui/views/test/views_test_base.h" #include "ui/views/view.h" @@ -24,7 +25,6 @@ namespace views { namespace { constexpr int kSwipeControlWidth = 30; // px constexpr int kTargetWidth = 200; // px -constexpr int kScrollOffsetThreshold = 20; } // namespace class TestSlideOutControllerDelegate : public SlideOutControllerDelegate { @@ -123,10 +123,12 @@ class SlideOutControllerTest : public ViewsTestBase { ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); } - void PostTrackPadSwipeEvent(int swipe_amount, int finger_count) { - auto scroll_event = ui::ScrollEvent(ui::ET_SCROLL, gfx::PointF(), - gfx::PointF(), base::TimeTicks(), 0, - swipe_amount, 0, 0, 0, finger_count); + void PostTrackPadSwipeEvent(ui::EventType type, + int swipe_amount, + int finger_count) { + auto scroll_event = + ui::ScrollEvent(type, gfx::PointF(), gfx::PointF(), base::TimeTicks(), + 0, swipe_amount, 0, 0, 0, finger_count); slide_out_controller()->OnScrollEvent(&scroll_event); } @@ -575,20 +577,28 @@ class TrackPadGestureTest : public SlideOutControllerTest { }; TEST_F(TrackPadGestureTest, SlideOut) { - // A slide out should not be triggered if the scroll offset is below - // `kScrollOffsetThreshold`. - PostTrackPadSwipeEvent(kScrollOffsetThreshold - 1, /*finger_count=*/2); + int width = delegate()->GetSlideOutLayer()->bounds().width(); + // A slide out should not be triggered if the scroll offset isn't less greater + // than the view's width. + PostTrackPadSwipeEvent(ui::EventType::ET_SCROLL, width, + /*finger_count=*/2); + PostTrackPadSwipeEvent(ui::EventType::ET_SCROLL_FLING_START, 0, 2); EXPECT_EQ(0, delegate()->slide_out_count_); // A slide out should not be triggered if the finger count is not equal to 2. - PostTrackPadSwipeEvent(kScrollOffsetThreshold, + PostTrackPadSwipeEvent(ui::EventType::ET_SCROLL, width + 1, + /*finger_count=*/3); + PostTrackPadSwipeEvent(ui::EventType::ET_SCROLL_FLING_START, 0, /*finger_count=*/3); EXPECT_EQ(0, delegate()->slide_out_count_); - // A slide out should be triggered with both of the conditions above being - // met. - PostTrackPadSwipeEvent(kScrollOffsetThreshold, + PostTrackPadSwipeEvent(ui::EventType::ET_SCROLL, width + 1, /*finger_count=*/2); + // A slide out should not be triggered until the `ET_SCROLL_FLING_START` is + // posted. + EXPECT_EQ(0, delegate()->slide_out_count_); + + PostTrackPadSwipeEvent(ui::EventType::ET_SCROLL_FLING_START, 0, 2); EXPECT_EQ(1, delegate()->slide_out_count_); } From 9da3d712ed0d32ddd56ff82c47cb28a24975b9b5 Mon Sep 17 00:00:00 2001 From: Amelie Schneider Date: Tue, 21 May 2024 16:12:42 +0000 Subject: [PATCH 31/40] [UNO] Use AccessPoint as source for Reauth Through this CL, the `AccessPoint` is now set every time the exchange of an OAuth 2.0 authorization code was successful. This implies that the `AccessPoint` in the `AccountInfo` now reflects the last reauth, rather than the original sign in. This is done in order to ensure that a piece of autofill data should be moved after a reauth with a specific `AccessPoint`, which implies that the reauth originated from a sign-in promo. Bug: b:339157240 Change-Id: I6ed9ef38ba405fea71108d874bd98db1c146ecc4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5554372 Commit-Queue: Amelie Schneider Reviewed-by: Ryan Sultanem Reviewed-by: Alex Ilin Code-Coverage: findit-for-me@appspot.gserviceaccount.com Cr-Commit-Position: refs/heads/main@{#1303814} --- .../browser/signin/dice_response_handler.cc | 24 ++++--------------- chrome/browser/signin/signin_manager.cc | 6 ++--- .../autofill_signin_promo_tab_helper.cc | 6 ++--- ..._bubble_signin_promo_interactive_uitest.cc | 2 +- .../profile_oauth2_token_service_delegate.cc | 4 ---- .../signin/public/base/signin_metrics.h | 5 ++-- .../public/identity_manager/account_info.h | 5 ++-- .../histograms/metadata/signin/enums.xml | 2 +- 8 files changed, 18 insertions(+), 36 deletions(-) diff --git a/chrome/browser/signin/dice_response_handler.cc b/chrome/browser/signin/dice_response_handler.cc index 0fcb1cf3174566..ea53cd6fa9d4e7 100644 --- a/chrome/browser/signin/dice_response_handler.cc +++ b/chrome/browser/signin/dice_response_handler.cc @@ -551,27 +551,11 @@ void DiceResponseHandler::OnTokenExchangeSuccess( bool is_new_account = !identity_manager_->HasAccountWithRefreshToken(account_id); - // If this is a reauth, do not update the access point. - signin_metrics::AccessPoint access_point = - is_new_account ? token_fetcher->delegate()->GetAccessPoint() - : signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN; - // Specifically set the token operation source in case the error was updated - // through a sign in from a password sign in promo, as this will indicate - // whether to move the password to account storage or not. - // TODO(crbug.com/339157240): Change the way this is implemented to not use - // SourceForRefreshTokenOperation as an indicator of the reauthentication - // source. - signin_metrics::SourceForRefreshTokenOperation token_operation_source = - token_fetcher->delegate()->GetAccessPoint() == - signin_metrics::AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE - ? signin_metrics::SourceForRefreshTokenOperation:: - kDiceResponseHandler_PasswordPromoSignin - : signin_metrics::SourceForRefreshTokenOperation:: - kDiceResponseHandler_Signin; - identity_manager_->GetAccountsMutator()->AddOrUpdateAccount( - gaia_id, email, refresh_token, is_under_advanced_protection, access_point, - token_operation_source + gaia_id, email, refresh_token, is_under_advanced_protection, + token_fetcher->delegate()->GetAccessPoint(), + signin_metrics::SourceForRefreshTokenOperation:: + kDiceResponseHandler_Signin #if BUILDFLAG(ENABLE_BOUND_SESSION_CREDENTIALS) , wrapped_binding_key diff --git a/chrome/browser/signin/signin_manager.cc b/chrome/browser/signin/signin_manager.cc index 15748349f7a200..f92b84f0d78c99 100644 --- a/chrome/browser/signin/signin_manager.cc +++ b/chrome/browser/signin/signin_manager.cc @@ -133,9 +133,9 @@ void SigninManager::UpdateUnconsentedPrimaryAccount() { signin::ConsentLevel::kSignin) != account) { DCHECK( !identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSync)); - // The access point is the same as the access point that added the - // account. If it is unknown, report `ACCESS_POINT_DESKTOP_SIGNIN_MANAGER` - // instead. + // The access point is the point from where the last authentication + // happened, either through adding the account or a reauth. If it is + // unknown, report `ACCESS_POINT_DESKTOP_SIGNIN_MANAGER` instead. signin_metrics::AccessPoint access_point = identity_manager_->FindExtendedAccountInfo(account).access_point; if (access_point == signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN) { diff --git a/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.cc b/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.cc index a763ece7148384..fa4c2ef470f6fa 100644 --- a/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.cc +++ b/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.cc @@ -130,10 +130,10 @@ void AutofillSigninPromoTabHelper::OnErrorStateOfRefreshTokenUpdatedForAccount( } // We only want to move the data if the sign in event has the correct - // operation source, so if it was performed from the tab that was opened after + // access point, so if it was performed from the tab that was opened after // clicking the sign in promo. - if (token_operation_source != signin_metrics::SourceForRefreshTokenOperation:: - kDiceResponseHandler_PasswordPromoSignin) { + if (identity_manager->FindExtendedAccountInfo(account_info).access_point != + state_->access_point_) { Reset(); return; } diff --git a/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_interactive_uitest.cc b/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_interactive_uitest.cc index 43a47f5136bc6d..f4bd63efb02503 100644 --- a/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_interactive_uitest.cc +++ b/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_interactive_uitest.cc @@ -311,7 +311,7 @@ IN_PROC_BROWSER_TEST_F(AutofillBubbleSignInPromoInteractiveUITest, /*is_under_advanced_protection=*/false, signin_metrics::AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE, signin_metrics::SourceForRefreshTokenOperation:: - kDiceResponseHandler_PasswordPromoSignin); + kDiceResponseHandler_Signin); account_store_waiter.WaitOrReturn(); // Check that the sign in was successful. diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.cc index aaaf9a31c199e7..24a5a480fbe372 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.cc +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.cc @@ -70,10 +70,6 @@ std::string SourceToString(SourceForRefreshTokenOperation source) { case SourceForRefreshTokenOperation:: kAccountReconcilor_RevokeTokensNotInCookies: return "AccountReconcilor::RevokeTokensNotInCookies"; - case SourceForRefreshTokenOperation:: - kDiceResponseHandler_PasswordPromoSignin: - return "DiceResponseHandler::Signin from sign in promo after password " - "save"; } } diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h index 74c88095364bba..37ee72a20b4d05 100644 --- a/components/signin/public/base/signin_metrics.h +++ b/components/signin/public/base/signin_metrics.h @@ -457,9 +457,10 @@ enum class SourceForRefreshTokenOperation { kLogoutTabHelper_PrimaryPageChanged = 19, kForceSigninReauthWithDifferentAccount = 20, kAccountReconcilor_RevokeTokensNotInCookies = 21, - kDiceResponseHandler_PasswordPromoSignin = 22, + // DEPRECATED on 05/2024 + // kDiceResponseHandler_PasswordPromoSignin = 22, - kMaxValue = kDiceResponseHandler_PasswordPromoSignin, + kMaxValue = kAccountReconcilor_RevokeTokensNotInCookies, }; // Different types of reporting. This is used as a histogram suffix. diff --git a/components/signin/public/identity_manager/account_info.h b/components/signin/public/identity_manager/account_info.h index fab0bab36ffce4..facdc80d740a97 100644 --- a/components/signin/public/identity_manager/account_info.h +++ b/components/signin/public/identity_manager/account_info.h @@ -73,8 +73,9 @@ struct AccountInfo : public CoreAccountInfo { std::string last_downloaded_image_url_with_size; gfx::Image account_image; - // For metrics. This field is not consistently set on all platforms. - // Not persisted to disk. Resets to `ACCESS_POINT_UNKNOWN` on restart. + // Access point used to add the account, is also updated on reauth. + // This field is not consistently set on all platforms. + // Not persisted to disk: resets to `ACCESS_POINT_UNKNOWN` on restart. signin_metrics::AccessPoint access_point = signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN; diff --git a/tools/metrics/histograms/metadata/signin/enums.xml b/tools/metrics/histograms/metadata/signin/enums.xml index a77ad9a0fdd476..8c05b2a4cc7313 100644 --- a/tools/metrics/histograms/metadata/signin/enums.xml +++ b/tools/metrics/histograms/metadata/signin/enums.xml @@ -833,7 +833,7 @@ chromium-metrics-reviews@google.com. + save (obsolete)"/> From f0bbfdfc54fc79ca1e9bbe716cdfcc89113c1c72 Mon Sep 17 00:00:00 2001 From: Anthony Garant Date: Tue, 21 May 2024 16:13:22 +0000 Subject: [PATCH 32/40] Revert "Log audit issues upon receiving duplicate web ARA registration headers" This reverts commit 86f842e68a04dce46c23355944bfd70764fef824. Reason for revert: Non-coalescing ARA headers will be reverted. As such, we must revert this change first. Some WPT covering the status quo behavior will be re-added in a follow up CL. Original change's description: > Log audit issues upon receiving duplicate web ARA registration headers > > The issue description will be updated in this CL: > https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5544984 > > Change-Id: Ie0de73c368bcaff61b98054ea32dd8ffb514d334 > Bug: 40242261 > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5544682 > Reviewed-by: Andrew Paseltiner > Commit-Queue: Anthony Garant > Cr-Commit-Position: refs/heads/main@{#1302546} Bug: 40242261 Change-Id: Ic9466c3b5a185bfdf048a0c01b07eef9f3f18d8a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5552872 Commit-Queue: Anthony Garant Bot-Commit: Rubber Stamper Reviewed-by: Andrew Paseltiner Cr-Commit-Position: refs/heads/main@{#1303815} --- .../attribution_data_host_manager_impl.cc | 10 ++---- ...ltiple-source-headers-ignored-expected.txt | 11 ------- .../multiple-source-headers-ignored.js | 25 --------------- ...tiple-trigger-headers-ignored-expected.txt | 11 ------- .../multiple-trigger-headers-ignored.js | 31 ------------------- .../resources/register-multiple-sources.php | 4 --- .../resources/register-multiple-triggers.php | 4 --- 7 files changed, 2 insertions(+), 94 deletions(-) delete mode 100644 third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-source-headers-ignored-expected.txt delete mode 100644 third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-source-headers-ignored.js delete mode 100644 third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-trigger-headers-ignored-expected.txt delete mode 100644 third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-trigger-headers-ignored.js delete mode 100644 third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-multiple-sources.php delete mode 100644 third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-multiple-triggers.php diff --git a/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc b/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc index 24599486a0f1e4..282ec1f901bdb0 100644 --- a/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc +++ b/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc @@ -767,10 +767,7 @@ struct AttributionDataHostManagerImpl::RegistrationDataHeaders { attribution_reporting::kAttributionReportingRegisterSourceHeader, &value)) { if (web_source_header.has_value()) { - MaybeLogAuditIssue(registrations.render_frame_id(), reporting_url, - registrations.devtools_request_id(), - /*invalid_parameter=*/std::nullopt, - AttributionReportingIssueType::kSourceIgnored); + // TODO(https://crbug.com/40242261): Log an audit issue. return std::nullopt; } web_source_header = std::move(value); @@ -786,10 +783,7 @@ struct AttributionDataHostManagerImpl::RegistrationDataHeaders { attribution_reporting::kAttributionReportingRegisterTriggerHeader, &value)) { if (web_trigger_header.has_value()) { - MaybeLogAuditIssue(registrations.render_frame_id(), reporting_url, - registrations.devtools_request_id(), - /*invalid_parameter=*/std::nullopt, - AttributionReportingIssueType::kTriggerIgnored); + // TODO(https://crbug.com/40242261): Log an audit issue. return std::nullopt; } web_trigger_header = std::move(value); diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-source-headers-ignored-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-source-headers-ignored-expected.txt deleted file mode 100644 index a2d5201241e7cf..00000000000000 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-source-headers-ignored-expected.txt +++ /dev/null @@ -1,11 +0,0 @@ -Test that clicking an attributionsrc anchor which returns multiple Attribution-Reporting-Register-Source headers triggers an issue. -Issue reported: { - code : AttributionReportingIssue - details : { - attributionReportingIssueDetails : { - request : - violationType : SourceIgnored - } - } -} - diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-source-headers-ignored.js b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-source-headers-ignored.js deleted file mode 100644 index 143239a9ef747b..00000000000000 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-source-headers-ignored.js +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2024 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -(async function(/** @type {import('test_runner').TestRunner} */ testRunner) { - const { dp } = await testRunner.startHTML( - 'Link', - "Test that clicking an attributionsrc anchor which returns multiple Attribution-Reporting-Register-Source headers triggers an issue." - ); - - await dp.Audits.enable(); - - const issue = dp.Audits.onceIssueAdded(); - - await dp.Runtime.evaluate({ - expression: `document.querySelector('a').click()`, - userGesture: true, - }); - - testRunner.log((await issue).params.issue, "Issue reported: ", [ - "request", - ]); - - testRunner.completeTest(); -}); diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-trigger-headers-ignored-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-trigger-headers-ignored-expected.txt deleted file mode 100644 index 7c98e325c4843d..00000000000000 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-trigger-headers-ignored-expected.txt +++ /dev/null @@ -1,11 +0,0 @@ -Test that clicking an attributionsrc anchor which returns multiple Attribution-Reporting-Register-Trigger headers triggers an issue. -Issue reported: { - code : AttributionReportingIssue - details : { - attributionReportingIssueDetails : { - request : - violationType : TriggerIgnored - } - } -} - diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-trigger-headers-ignored.js b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-trigger-headers-ignored.js deleted file mode 100644 index bd63c9dff24b34..00000000000000 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/multiple-trigger-headers-ignored.js +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2024 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// TODO(@anthonygarant): Update to be a background ping instead of a navigation -// the keepalive in-browser migration is enabled in the main -// attribution-reporting WPT suite. With a navigation, the trigger registration -// would be ignored regardless of the fact that there are multiple headers since -// the eligibility is source only. - -(async function(/** @type {import('test_runner').TestRunner} */ testRunner) { - const { dp } = await testRunner.startHTML( - 'Link', - "Test that clicking an attributionsrc anchor which returns multiple Attribution-Reporting-Register-Trigger headers triggers an issue." - ); - - await dp.Audits.enable(); - - const issue = dp.Audits.onceIssueAdded(); - - await dp.Runtime.evaluate({ - expression: `document.querySelector('a').click()`, - userGesture: true, - }); - - testRunner.log((await issue).params.issue, "Issue reported: ", [ - "request", - ]); - - testRunner.completeTest(); -}); diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-multiple-sources.php b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-multiple-sources.php deleted file mode 100644 index 5766df49d75c58..00000000000000 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-multiple-sources.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-multiple-triggers.php b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-multiple-triggers.php deleted file mode 100644 index a4152bdb3999f7..00000000000000 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-multiple-triggers.php +++ /dev/null @@ -1,4 +0,0 @@ - From 37c0dc38809ac061c55272043a00ce695cdda296 Mon Sep 17 00:00:00 2001 From: Dibyajyoti Pal Date: Tue, 21 May 2024 16:13:49 +0000 Subject: [PATCH 33/40] [Shortcuts] DocumentIconFetcher runs a single task to fetch icons This CL is essentially a no-op, and has been confirmed with manual testing and by running the existing browser tests (thanks for those!). The DocumentIconFetcher was initially built with the assumption that it can trigger multiple icon downloading tasks. Now that the entire system has been built, there can be only a single document icon download call triggered for the current document. As a result, it does not need the multiple task architecture. This CL cleans up the old code, and makes the DocumentIconFetcher perform the icon fetching itself. The old contract of the task being self destructed and any pending callbacks run asynchronously during destruction are still maintained. Bug: 333024272 Change-Id: Iba5bd8573a84bfdc2b1dbc6d18ec72182fe835b8 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5546540 Reviewed-by: Daniel Murphy Commit-Queue: Dibyajyoti Pal Cr-Commit-Position: refs/heads/main@{#1303816} --- chrome/browser/shortcuts/BUILD.gn | 6 +- ..._shortcut_for_current_web_contents_task.cc | 7 +- ...e_shortcut_for_current_web_contents_task.h | 5 +- .../shortcuts/document_icon_fetcher.cc | 90 ---------------- .../browser/shortcuts/document_icon_fetcher.h | 61 ----------- .../document_icon_fetcher_browsertest.cc | 64 ++++++----- ..._task.cc => document_icon_fetcher_task.cc} | 87 ++++++++------- .../shortcuts/document_icon_fetcher_task.h | 87 +++++++++++++++ .../fetch_icons_from_document_task.h | 101 ------------------ 9 files changed, 179 insertions(+), 329 deletions(-) delete mode 100644 chrome/browser/shortcuts/document_icon_fetcher.cc delete mode 100644 chrome/browser/shortcuts/document_icon_fetcher.h rename chrome/browser/shortcuts/{fetch_icons_from_document_task.cc => document_icon_fetcher_task.cc} (53%) create mode 100644 chrome/browser/shortcuts/document_icon_fetcher_task.h delete mode 100644 chrome/browser/shortcuts/fetch_icons_from_document_task.h diff --git a/chrome/browser/shortcuts/BUILD.gn b/chrome/browser/shortcuts/BUILD.gn index b0a2a71ccf07b5..237a695346e4a1 100644 --- a/chrome/browser/shortcuts/BUILD.gn +++ b/chrome/browser/shortcuts/BUILD.gn @@ -22,10 +22,8 @@ source_set("shortcuts") { sources += [ "create_shortcut_for_current_web_contents_task.cc", - "document_icon_fetcher.cc", - "document_icon_fetcher.h", - "fetch_icons_from_document_task.cc", - "fetch_icons_from_document_task.h", + "document_icon_fetcher_task.cc", + "document_icon_fetcher_task.h", "icon_badging.cc", "icon_badging.h", "shortcut_creator.cc", diff --git a/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.cc b/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.cc index f38e3ee2a45d63..835082c6c9aa01 100644 --- a/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.cc +++ b/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.cc @@ -10,7 +10,7 @@ #include "base/task/bind_post_task.h" #include "chrome/browser/platform_util.h" // nogncheck (crbug.com/335727004) #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/shortcuts/document_icon_fetcher.h" +#include "chrome/browser/shortcuts/document_icon_fetcher_task.h" #include "chrome/browser/shortcuts/icon_badging.h" #include "chrome/browser/shortcuts/shortcut_creator.h" #include "chrome/common/chrome_features.h" @@ -101,15 +101,18 @@ void CreateShortcutForCurrentWebContentsTask::FetchIcons( callback_ = std::move(callback); Observe(&web_contents); - DocumentIconFetcher::FetchIcons( + icon_fetcher_task_ = std::make_unique( web_contents, base::BindOnce(&CreateShortcutForCurrentWebContentsTask:: OnIconsFetchedStartBadgingAndShowDialog, weak_ptr_factory_.GetWeakPtr())); + icon_fetcher_task_->StartIconFetching(); } void CreateShortcutForCurrentWebContentsTask:: OnIconsFetchedStartBadgingAndShowDialog( FetchIconsFromDocumentResult result) { + CHECK(icon_fetcher_task_); + icon_fetcher_task_.reset(); if (!result.has_value()) { OnMetadataFetchCompleteSelfDestruct( base::unexpected(ShortcutCreationTaskResult::kIconFetchingFailed)); diff --git a/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.h b/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.h index 7f964c2bf3f672..ac0d6a168ff5d5 100644 --- a/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.h +++ b/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.h @@ -5,9 +5,11 @@ #ifndef CHROME_BROWSER_SHORTCUTS_CREATE_SHORTCUT_FOR_CURRENT_WEB_CONTENTS_TASK_H_ #define CHROME_BROWSER_SHORTCUTS_CREATE_SHORTCUT_FOR_CURRENT_WEB_CONTENTS_TASK_H_ +#include + #include "base/functional/callback.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/shortcuts/fetch_icons_from_document_task.h" +#include "chrome/browser/shortcuts/document_icon_fetcher_task.h" #include "chrome/browser/shortcuts/shortcut_creator.h" #include "content/public/browser/document_user_data.h" #include "content/public/browser/web_contents_observer.h" @@ -94,6 +96,7 @@ class CreateShortcutForCurrentWebContentsTask ShortcutsDialogCallback dialog_callback_; base::OnceCallback callback_; + std::unique_ptr icon_fetcher_task_; base::WeakPtrFactory weak_ptr_factory_{this}; }; diff --git a/chrome/browser/shortcuts/document_icon_fetcher.cc b/chrome/browser/shortcuts/document_icon_fetcher.cc deleted file mode 100644 index b75fdc81d3d3a2..00000000000000 --- a/chrome/browser/shortcuts/document_icon_fetcher.cc +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2024 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/shortcuts/document_icon_fetcher.h" - -#include -#include - -#include "base/containers/flat_map.h" -#include "base/functional/bind.h" -#include "base/functional/callback.h" -#include "base/functional/callback_forward.h" -#include "base/location.h" -#include "base/memory/weak_ptr.h" -#include "base/task/sequenced_task_runner.h" -#include "base/types/expected.h" -#include "base/types/pass_key.h" -#include "chrome/browser/shortcuts/fetch_icons_from_document_task.h" -#include "chrome/browser/shortcuts/shortcut_icon_generator.h" -#include "content/public/browser/document_user_data.h" -#include "content/public/browser/web_contents.h" -#include "third_party/skia/include/core/SkBitmap.h" - -namespace shortcuts { - -// static -void DocumentIconFetcher::FetchIcons(content::WebContents& web_contents, - FetchIconsFromDocumentCallback callback) { - DocumentIconFetcher* fetch_manager = - DocumentIconFetcher::GetOrCreateForCurrentDocument( - web_contents.GetPrimaryMainFrame()); - fetch_manager->RunTask(GenerateIconLetterFromName(web_contents.GetTitle()), - std::move(callback)); -} - -DocumentIconFetcher::~DocumentIconFetcher() { - in_destruction_ = true; - // All of the tasks callbacks call `DocumentIconFetcher::OnTaskComplete` below - // directly. Save them & call them synchronously after the tasks are - // destroyed to prevent map modification during iteration. - std::vector pending_callbacks; - for (const auto& [id, task] : fetch_tasks_) { - pending_callbacks.push_back(task->TakeCallback()); - } - fetch_tasks_.clear(); - for (FetchIconsFromDocumentCallback& callback : pending_callbacks) { - CHECK(callback); - // This calls `DocumentIconFetcher::OnTaskComplete` below. - std::move(callback).Run( - base::unexpected(FetchIconsForDocumentError::kDocumentDestroyed)); - } -} - -DOCUMENT_USER_DATA_KEY_IMPL(DocumentIconFetcher); - -DocumentIconFetcher::DocumentIconFetcher(content::RenderFrameHost* rfh) - : content::DocumentUserData(rfh) {} - -void DocumentIconFetcher::RunTask(char32_t fallback_letter, - FetchIconsFromDocumentCallback callback) { - std::unique_ptr task = - std::make_unique( - base::PassKey(), render_frame_host()); - int task_id = next_task_id_; - next_task_id_++; - const auto& [iter, _] = fetch_tasks_.emplace(task_id, std::move(task)); - // Note: the callback may be called synchronously. - iter->second->Start(base::BindOnce(&DocumentIconFetcher::OnTaskComplete, - weak_factory_.GetWeakPtr(), task_id, - fallback_letter, std::move(callback))); -} - -void DocumentIconFetcher::OnTaskComplete( - int id, - char32_t fallback_letter, - FetchIconsFromDocumentCallback original_callback, - FetchIconsFromDocumentResult result) { - int num_erased = fetch_tasks_.erase(id); - CHECK(num_erased > 0 || in_destruction_); - - if (result.has_value() && result->empty()) { - result->push_back(GenerateBitmap(128, fallback_letter)); - } - - base::SequencedTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, base::BindOnce(std::move(original_callback), result)); -} - -} // namespace shortcuts diff --git a/chrome/browser/shortcuts/document_icon_fetcher.h b/chrome/browser/shortcuts/document_icon_fetcher.h deleted file mode 100644 index 543fe8f595de54..00000000000000 --- a/chrome/browser/shortcuts/document_icon_fetcher.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2024 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SHORTCUTS_DOCUMENT_ICON_FETCHER_H_ -#define CHROME_BROWSER_SHORTCUTS_DOCUMENT_ICON_FETCHER_H_ - -#include - -#include "base/containers/flat_map.h" -#include "base/functional/callback_forward.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/shortcuts/fetch_icons_from_document_task.h" -#include "content/public/browser/document_user_data.h" - -namespace content { -class WebContents; -} - -namespace shortcuts { - -// This object is responsible for fetching all available icons from a given -// document. -class DocumentIconFetcher - : public content::DocumentUserData { - public: - // Fetches all icons for the top level primary frame of the given web - // contents. `callback` will always be called (even on document destruction), - // and always called asynchronously. If the callback is not called with an - // error, it is guaranteed to include at least one icon (i.e. it is not - // possible for fetching to succeed but not return any icons. If no icons - // were found, a fallback icon is generated). - static void FetchIcons(content::WebContents& web_contents, - FetchIconsFromDocumentCallback callback); - - ~DocumentIconFetcher() override; - - private: - friend DocumentUserData; - DOCUMENT_USER_DATA_KEY_DECL(); - - explicit DocumentIconFetcher(content::RenderFrameHost* rfh); - - void RunTask(char32_t fallback_letter, - FetchIconsFromDocumentCallback callback); - - void OnTaskComplete(int id, - char32_t fallback_letter, - FetchIconsFromDocumentCallback original_callback, - FetchIconsFromDocumentResult result); - - bool in_destruction_ = false; - int next_task_id_ = 0; - base::flat_map> fetch_tasks_; - - base::WeakPtrFactory weak_factory_{this}; -}; - -} // namespace shortcuts - -#endif // CHROME_BROWSER_SHORTCUTS_DOCUMENT_ICON_FETCHER_H_ diff --git a/chrome/browser/shortcuts/document_icon_fetcher_browsertest.cc b/chrome/browser/shortcuts/document_icon_fetcher_browsertest.cc index 2080e45ea97fba..a570be0eaeadf7 100644 --- a/chrome/browser/shortcuts/document_icon_fetcher_browsertest.cc +++ b/chrome/browser/shortcuts/document_icon_fetcher_browsertest.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/shortcuts/document_icon_fetcher.h" - #include #include "base/base_paths.h" @@ -12,11 +10,10 @@ #include "base/test/gmock_expected_support.h" #include "base/test/test_future.h" #include "base/types/expected.h" -#include "chrome/browser/shortcuts/fetch_icons_from_document_task.h" +#include "chrome/browser/shortcuts/document_icon_fetcher_task.h" #include "chrome/browser/shortcuts/image_test_utils.h" #include "chrome/browser/shortcuts/shortcut_icon_generator.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_commands.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/test/browser_test.h" @@ -45,6 +42,16 @@ class DocumentIconFetcherTest : public InProcessBrowserTest { return default_favicon_server_.GetURL("/index.html"); } + FetchIconsFromDocumentResult RunIconFetchingTaskForCurrentWebContents() { + base::test::TestFuture future; + DocumentIconFetcherTask icon_fetcher_task( + *browser()->tab_strip_model()->GetActiveWebContents(), + future.GetCallback()); + icon_fetcher_task.StartIconFetching(); + EXPECT_TRUE(future.Wait()); + return future.Get(); + } + private: net::EmbeddedTestServer default_favicon_server_{ net::EmbeddedTestServer::TYPE_HTTPS}; @@ -54,14 +61,11 @@ IN_PROC_BROWSER_TEST_F(DocumentIconFetcherTest, PageNoIcons) { ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), embedded_https_test_server().GetURL(kPageNoIcons))); - base::test::TestFuture future; - DocumentIconFetcher::FetchIcons( - *browser()->tab_strip_model()->GetActiveWebContents(), - future.GetCallback()); - ASSERT_TRUE(future.Wait()); - EXPECT_TRUE(future.Get().has_value()); + FetchIconsFromDocumentResult result = + RunIconFetchingTaskForCurrentWebContents(); + ASSERT_TRUE(result.has_value()); EXPECT_THAT( - future.Get().value(), + result.value(), testing::ElementsAre(gfx::test::EqualsBitmap(GenerateBitmap(128, U'P')))); } @@ -69,14 +73,10 @@ IN_PROC_BROWSER_TEST_F(DocumentIconFetcherTest, IconMetadata) { ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), embedded_https_test_server().GetURL(kPageWithIcons))); - base::test::TestFuture future; - - DocumentIconFetcher::FetchIcons( - *browser()->tab_strip_model()->GetActiveWebContents(), - future.GetCallback()); - ASSERT_TRUE(future.Wait()); - ASSERT_TRUE(future.Get().has_value()); - std::vector images = future.Get().value(); + FetchIconsFromDocumentResult result = + RunIconFetchingTaskForCurrentWebContents(); + ASSERT_TRUE(result.has_value()); + std::vector images = result.value(); SkBitmap expected_green; ASSERT_OK_AND_ASSIGN(expected_green, @@ -95,13 +95,10 @@ IN_PROC_BROWSER_TEST_F(DocumentIconFetcherTest, DefaultFavicon) { ASSERT_TRUE( ui_test_utils::NavigateToURL(browser(), GetPageWithDefaultFavicon())); - base::test::TestFuture future; - DocumentIconFetcher::FetchIcons( - *browser()->tab_strip_model()->GetActiveWebContents(), - future.GetCallback()); - ASSERT_TRUE(future.Wait()); - EXPECT_TRUE(future.Get().has_value()); - std::vector images = future.Get().value(); + FetchIconsFromDocumentResult result = + RunIconFetchingTaskForCurrentWebContents(); + ASSERT_TRUE(result.has_value()); + std::vector images = result.value(); SkBitmap expected_16; ASSERT_OK_AND_ASSIGN( expected_16, LoadImageFromTestFile(base::FilePath(FILE_PATH_LITERAL( @@ -115,19 +112,20 @@ IN_PROC_BROWSER_TEST_F(DocumentIconFetcherTest, DefaultFavicon) { gfx::test::EqualsBitmap(expected_32))); } -IN_PROC_BROWSER_TEST_F(DocumentIconFetcherTest, WebContentsClosed) { +IN_PROC_BROWSER_TEST_F(DocumentIconFetcherTest, + TaskDestroyedDoesNotDropCallback) { base::test::TestFuture future; - chrome::NewTab(browser()); ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), embedded_https_test_server().GetURL(kPageWithIcons))); - DocumentIconFetcher::FetchIcons( + auto icon_fetcher_task = std::make_unique( *browser()->tab_strip_model()->GetActiveWebContents(), future.GetCallback()); - chrome::CloseTab(browser()); + + // Task destruction should not drop the callback. + icon_fetcher_task.reset(); ASSERT_TRUE(future.Wait()); - EXPECT_THAT( - future.Get(), - base::test::ErrorIs(FetchIconsForDocumentError::kDocumentDestroyed)); + EXPECT_THAT(future.Get(), + base::test::ErrorIs(FetchIconsForDocumentError::kTaskDestroyed)); } } // namespace diff --git a/chrome/browser/shortcuts/fetch_icons_from_document_task.cc b/chrome/browser/shortcuts/document_icon_fetcher_task.cc similarity index 53% rename from chrome/browser/shortcuts/fetch_icons_from_document_task.cc rename to chrome/browser/shortcuts/document_icon_fetcher_task.cc index 653a96e1be1184..2296225d63ffb4 100644 --- a/chrome/browser/shortcuts/fetch_icons_from_document_task.cc +++ b/chrome/browser/shortcuts/document_icon_fetcher_task.cc @@ -2,16 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/shortcuts/fetch_icons_from_document_task.h" +#include "chrome/browser/shortcuts/document_icon_fetcher_task.h" +#include +#include +#include + +#include "base/containers/flat_map.h" +#include "base/containers/flat_set.h" #include "base/functional/bind.h" #include "base/functional/callback.h" +#include "base/functional/callback_forward.h" #include "base/location.h" -#include "base/memory/raw_ref.h" +#include "base/memory/weak_ptr.h" +#include "base/task/sequenced_task_runner.h" #include "base/types/expected.h" +#include "chrome/browser/shortcuts/shortcut_icon_generator.h" #include "components/webapps/common/web_page_metadata.mojom.h" #include "components/webapps/common/web_page_metadata_agent.mojom.h" -#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" @@ -21,41 +29,51 @@ namespace shortcuts { -FetchIconsFromDocumentTask::FetchIconsFromDocumentTask( - base::PassKey, - content::RenderFrameHost& rfh) - : frame_host_(rfh) { - CHECK(frame_host_->IsInPrimaryMainFrame()); +DocumentIconFetcherTask::DocumentIconFetcherTask( + content::WebContents& web_contents, + FetchIconsFromDocumentCallback callback) + : web_contents_(web_contents.GetWeakPtr()), + fallback_letter_(GenerateIconLetterFromName(web_contents.GetTitle())), + final_callback_(std::move(callback)) {} + +DocumentIconFetcherTask::~DocumentIconFetcherTask() { + // If the final_callback_ has not been run yet, prevent that from hanging by + // returning an error message. Although this function calls + // `OnIconFetchingCompleteSelfDestruct()`, for this use-case, self-destruction + // will not occur since this is being triggered as part of destruction itself. + if (!final_callback_.is_null()) { + OnIconFetchingCompleteSelfDestruct( + base::unexpected(FetchIconsForDocumentError::kTaskDestroyed)); + } } -FetchIconsFromDocumentTask::~FetchIconsFromDocumentTask() = default; - -void FetchIconsFromDocumentTask::Start( - FetchIconsFromDocumentCallback callback) { - callback_ = std::move(callback); +void DocumentIconFetcherTask::StartIconFetching() { mojo::AssociatedRemote metadata_agent; - frame_host_->GetRemoteAssociatedInterfaces()->GetInterface(&metadata_agent); + web_contents_->GetPrimaryMainFrame() + ->GetRemoteAssociatedInterfaces() + ->GetInterface(&metadata_agent); // Set the error handler so that we can run abort this task if the WebContents // or the RenderFrameHost are destroyed and the connection to // ChromeRenderFrame is lost. metadata_agent.set_disconnect_handler( - base::BindOnce(&FetchIconsFromDocumentTask::OnMetadataFetchError, + base::BindOnce(&DocumentIconFetcherTask::OnMetadataFetchError, weak_factory_.GetWeakPtr())); // Bind the InterfacePtr into the callback so that it's kept alive // until there's either a connection error or a response. auto* web_page_metadata_proxy = metadata_agent.get(); web_page_metadata_proxy->GetWebPageMetadata( - base::BindOnce(&FetchIconsFromDocumentTask::OnWebPageMetadataObtained, + base::BindOnce(&DocumentIconFetcherTask::OnWebPageMetadataObtained, weak_factory_.GetWeakPtr(), std::move(metadata_agent))); } -FetchIconsFromDocumentCallback FetchIconsFromDocumentTask::TakeCallback() { - return std::move(callback_); +void DocumentIconFetcherTask::OnMetadataFetchError() { + OnIconFetchingCompleteSelfDestruct( + base::unexpected(FetchIconsForDocumentError::kMetadataFetchFailed)); } -void FetchIconsFromDocumentTask::OnWebPageMetadataObtained( +void DocumentIconFetcherTask::OnWebPageMetadataObtained( mojo::AssociatedRemote metadata_agent, webapps::mojom::WebPageMetadataPtr web_page_metadata) { metadata_fetch_complete_ = true; @@ -63,7 +81,7 @@ void FetchIconsFromDocumentTask::OnWebPageMetadataObtained( for (const auto& icon_info : web_page_metadata->icons) { icons.push_back(icon_info->url); } - for (const auto& favicon_url : frame_host_->FaviconURLs()) { + for (const auto& favicon_url : web_contents_->GetFaviconURLs()) { icons.push_back(favicon_url->icon_url); } @@ -71,20 +89,18 @@ void FetchIconsFromDocumentTask::OnWebPageMetadataObtained( base::flat_set icon_set(std::move(icons)); num_pending_image_requests_ = icon_set.size(); - content::WebContents* web_contents = - content::WebContents::FromRenderFrameHost(&frame_host_.get()); for (const GURL& url : icon_set) { - web_contents->DownloadImageInFrame( - frame_host_->GetGlobalId(), url, /*is_favicon=*/true, + web_contents_->DownloadImage( + url, /*is_favicon=*/true, /*preferred_size=*/gfx::Size(), /*max_bitmap_size=*/0, /*bypass_cache=*/false, - base::BindOnce(&FetchIconsFromDocumentTask::DidDownloadFavicon, + base::BindOnce(&DocumentIconFetcherTask::DidDownloadFavicon, weak_factory_.GetWeakPtr())); } MaybeCompleteImageDownloadAndSelfDestruct(); } -void FetchIconsFromDocumentTask::DidDownloadFavicon( +void DocumentIconFetcherTask::DidDownloadFavicon( int id, int http_status_code, const GURL& image_url, @@ -101,24 +117,21 @@ void FetchIconsFromDocumentTask::DidDownloadFavicon( MaybeCompleteImageDownloadAndSelfDestruct(); } -void FetchIconsFromDocumentTask::MaybeCompleteImageDownloadAndSelfDestruct() { +void DocumentIconFetcherTask::MaybeCompleteImageDownloadAndSelfDestruct() { if (!metadata_fetch_complete_ || num_pending_image_requests_ > 0) { return; } - OnCompleteSelfDestruct(base::ok(std::move(icons_))); + OnIconFetchingCompleteSelfDestruct(base::ok(std::move(icons_))); } -void FetchIconsFromDocumentTask::OnCompleteSelfDestruct(Result result, - base::Location here) { - if (!callback_) { - return; +void DocumentIconFetcherTask::OnIconFetchingCompleteSelfDestruct( + FetchIconsFromDocumentResult result) { + if (result.has_value() && result->empty()) { + result->push_back(GenerateBitmap(128, fallback_letter_)); } - std::move(callback_).Run(std::move(result)); -} -void FetchIconsFromDocumentTask::OnMetadataFetchError() { - OnCompleteSelfDestruct( - base::unexpected(FetchIconsForDocumentError::kMetadataFetchFailed)); + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, base::BindOnce(std::move(final_callback_), result)); } } // namespace shortcuts diff --git a/chrome/browser/shortcuts/document_icon_fetcher_task.h b/chrome/browser/shortcuts/document_icon_fetcher_task.h new file mode 100644 index 00000000000000..741ad6adb62c69 --- /dev/null +++ b/chrome/browser/shortcuts/document_icon_fetcher_task.h @@ -0,0 +1,87 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SHORTCUTS_DOCUMENT_ICON_FETCHER_TASK_H_ +#define CHROME_BROWSER_SHORTCUTS_DOCUMENT_ICON_FETCHER_TASK_H_ + +#include +#include + +#include "base/containers/flat_map.h" +#include "base/functional/callback_forward.h" +#include "base/memory/weak_ptr.h" +#include "base/types/expected.h" +#include "components/webapps/common/web_page_metadata.mojom-forward.h" +#include "components/webapps/common/web_page_metadata_agent.mojom-forward.h" +#include "content/public/browser/document_user_data.h" +#include "mojo/public/cpp/bindings/associated_remote.h" + +namespace content { +class WebContents; +} // namespace content + +class GURL; +class SkBitmap; + +namespace gfx { +class Size; +} + +namespace shortcuts { + +enum class FetchIconsForDocumentError { kTaskDestroyed, kMetadataFetchFailed }; + +using FetchIconsFromDocumentResult = + base::expected, FetchIconsForDocumentError>; + +using FetchIconsFromDocumentCallback = + base::OnceCallback; + +// This object is responsible for fetching all available icons from a given +// document. +class DocumentIconFetcherTask { + public: + // Creates a task that fetches all icons for the top level primary frame of + // the given web contents. `callback` will always be called (even on document + // destruction), and always called asynchronously. If the callback is not + // called with an error, it is guaranteed to include at least one icon (i.e. + // it is not possible for fetching to succeed but not return any icons. If no + // icons were found, a fallback icon is generated). + DocumentIconFetcherTask(content::WebContents& web_contents, + FetchIconsFromDocumentCallback callback); + ~DocumentIconFetcherTask(); + + void StartIconFetching(); + + private: + void OnMetadataFetchError(); + + void OnWebPageMetadataObtained( + mojo::AssociatedRemote + metadata_agent, + webapps::mojom::WebPageMetadataPtr web_page_metadata); + + void DidDownloadFavicon(int id, + int http_status_code, + const GURL& image_url, + const std::vector& bitmaps, + const std::vector& sizes); + + void MaybeCompleteImageDownloadAndSelfDestruct(); + + void OnIconFetchingCompleteSelfDestruct(FetchIconsFromDocumentResult result); + + base::WeakPtr web_contents_; + char32_t fallback_letter_; + FetchIconsFromDocumentCallback final_callback_; + bool metadata_fetch_complete_ = false; + int num_pending_image_requests_ = 0; + std::vector icons_; + + base::WeakPtrFactory weak_factory_{this}; +}; + +} // namespace shortcuts + +#endif // CHROME_BROWSER_SHORTCUTS_DOCUMENT_ICON_FETCHER_TASK_H_ diff --git a/chrome/browser/shortcuts/fetch_icons_from_document_task.h b/chrome/browser/shortcuts/fetch_icons_from_document_task.h deleted file mode 100644 index 7ef5b9a53130af..00000000000000 --- a/chrome/browser/shortcuts/fetch_icons_from_document_task.h +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2024 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SHORTCUTS_FETCH_ICONS_FROM_DOCUMENT_TASK_H_ -#define CHROME_BROWSER_SHORTCUTS_FETCH_ICONS_FROM_DOCUMENT_TASK_H_ - -#include - -#include "base/functional/callback_forward.h" -#include "base/memory/raw_ref.h" -#include "base/memory/weak_ptr.h" -#include "base/types/expected.h" -#include "base/types/pass_key.h" -#include "base/values.h" -#include "components/webapps/common/web_page_metadata.mojom-forward.h" -#include "components/webapps/common/web_page_metadata_agent.mojom-forward.h" -#include "mojo/public/cpp/bindings/associated_remote.h" - -class SkBitmap; -class GURL; - -namespace base { -class Location; -} - -namespace content { -class RenderFrameHost; -} - -namespace gfx { -class Size; -} - -namespace shortcuts { -class DocumentIconFetcher; - -enum class FetchIconsForDocumentError { - kDocumentDestroyed, - kMetadataFetchFailed -}; -using FetchIconsFromDocumentResult = - base::expected, FetchIconsForDocumentError>; -using FetchIconsFromDocumentCallback = - base::OnceCallback; - -// Fetch all icons for the current RenderFrameHost document. -// Invariants: -// - The `frame_host_` provided to this class must be alive for the lifetime of -// this class. -// - The `callback` may be called synchronously. -// - The `callback` will be NOT be called on destruction. To handle that, the -// user -// of this class must use the `TakeCallback()` method to extract the callback. -class FetchIconsFromDocumentTask { - public: - using Result = FetchIconsFromDocumentResult; - - // `rfh` must be the primary main frame. - FetchIconsFromDocumentTask(base::PassKey, - content::RenderFrameHost& rfh); - ~FetchIconsFromDocumentTask(); - - // The `callback` may be called synchronously. - void Start(FetchIconsFromDocumentCallback callback); - - FetchIconsFromDocumentCallback TakeCallback(); - - private: - void OnWebPageMetadataObtained( - mojo::AssociatedRemote - metadata_agent, - webapps::mojom::WebPageMetadataPtr web_page_metadata); - - void DownloadIcon(const GURL& url); - - void DidDownloadFavicon(int id, - int http_status_code, - const GURL& image_url, - const std::vector& bitmaps, - const std::vector& sizes); - - void MaybeCompleteImageDownloadAndSelfDestruct(); - - void OnCompleteSelfDestruct(Result result, base::Location here = FROM_HERE); - - void OnMetadataFetchError(); - - base::raw_ref frame_host_; - FetchIconsFromDocumentCallback callback_; - - bool metadata_fetch_complete_ = false; - int num_pending_image_requests_ = 0; - std::vector icons_; - - base::WeakPtrFactory weak_factory_{this}; -}; - -} // namespace shortcuts - -#endif // CHROME_BROWSER_SHORTCUTS_FETCH_ICONS_FROM_DOCUMENT_TASK_H_ From a4df02a35582143bf3ef1adc5eaa0ae6e25f3167 Mon Sep 17 00:00:00 2001 From: chromium-internal-autoroll Date: Tue, 21 May 2024 16:14:35 +0000 Subject: [PATCH 34/40] Roll Help App from 6FwohtL9JxTjoHpDq... to 3S_vch9BVEqwxlGe0... Release_Notes: http://go/help_app-x20/relnotes/Main/help_app_nightly_202405210800_RC00.html https://chrome-infra-packages.appspot.com/p/chromeos_internal/apps/help_app/app/+/3S_vch9BVEqwxlGe0IC6rd6LBxn7XN9zQENaXTo-30QC If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://skia-autoroll.corp.goog/r/help-app-chromium-autoroll Please CC cros-essential-apps-dev@chromium.org,help-app@grotations.appspotmail.com,jomag@google.com on the revert to ensure that a human is aware of the problem. To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md Cq-Include-Trybots: luci.chrome.try:linux-chromeos-chrome Bug: None Tbr: help-app@grotations.appspotmail.com Change-Id: I6c1d8949a5b1d012b1009e3a725a01f2694d4c33 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553396 Commit-Queue: chromium-internal-autoroll Bot-Commit: chromium-internal-autoroll Cr-Commit-Position: refs/heads/main@{#1303817} --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 8289be54832a74..fb30cc0ea93d08 100644 --- a/DEPS +++ b/DEPS @@ -2296,7 +2296,7 @@ deps = { 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': '6FwohtL9JxTjoHpDqhB1LFIzwbcPwzcwKsPQrs3kRBEC', + 'version': '3S_vch9BVEqwxlGe0IC6rd6LBxn7XN9zQENaXTo-30QC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', From 21d8ad487d4b6b70019af565e1aa115249e7636b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9mie=20St-Onge?= Date: Tue, 21 May 2024 16:15:00 +0000 Subject: [PATCH 35/40] [iOS] Fix VoiceOver shift when switching toggle in payment settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When switching the "Save and Fill Payment Methods" toggle in payment settings, the VoiceOver focus would temporarily move to the below table view cell, before going back to its original position. When toggling the switch, the "AutofillPaymentMethodsEnabled" pref is also updated, ultimately triggering a data reload of the table view. It seems that VoiceOver wasn't able to properly process the simultaneous UI updates of updating the toggle state and reloading the table view, causing it to move its focus when it shouldn't have. This CL resolves the issue by slightly delaying updating the pref when VoiceOver is running. The delay is small enough to not be noticeable. Fixed: 326923292 Change-Id: I9d22cfe20883cc52ff8530a076b24d5602d7021c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5544692 Reviewed-by: Vidhan Jain Commit-Queue: Noémie St-Onge Code-Coverage: findit-for-me@appspot.gserviceaccount.com Cr-Commit-Position: refs/heads/main@{#1303818} --- ...ofill_credit_card_table_view_controller.mm | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm index e91322aaf26a33..a1a31382db8312 100644 --- a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm @@ -52,6 +52,8 @@ namespace { +constexpr base::TimeDelta kUpdatePrefDelay = base::Seconds(0.3); + enum SectionIdentifier : NSInteger { SectionIdentifierAutofillCardSwitch = kSectionIdentifierEnumZero, SectionIdentifierMandatoryReauthSwitch, @@ -507,8 +509,20 @@ - (void)autofillCardSwitchChanged:(UISwitch*)switchView { [self setSwitchItemOn:[switchView isOn] itemType:ItemTypeAutofillCardSwitch sectionIdentifier:SectionIdentifierAutofillCardSwitch]; - [self setAutofillCreditCardEnabled:[switchView isOn]]; - self.addButtonInToolbar.enabled = [self isAutofillCreditCardEnabled]; + + // Delay updating the pref when VoiceOver is running to prevent a temporary + // focus shift due to simultaneous UI updates, see crbug.com/326923292. + if (UIAccessibilityIsVoiceOverRunning()) { + __weak __typeof(self) weakSelf = self; + base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, base::BindOnce(^{ + [weakSelf + updateAutofillCreditCardPrefAndToolbarForState:[switchView isOn]]; + }), + kUpdatePrefDelay); + } else { + [self updateAutofillCreditCardPrefAndToolbarForState:[switchView isOn]]; + } } - (void)mandatoryReauthSwitchChanged:(UISwitch*)switchView { @@ -856,6 +870,13 @@ - (void)handleReauthenticationResult:(ReauthenticationResult)result { /*opt_in=*/!mandatoryReauthEnabled, flow_event); } +// Updates the Autofill Credit Card pref and the view controller's toolbar +// according to the provided `enabled` state. +- (void)updateAutofillCreditCardPrefAndToolbarForState:(BOOL)enabled { + [self setAutofillCreditCardEnabled:enabled]; + self.addButtonInToolbar.enabled = [self isAutofillCreditCardEnabled]; +} + #pragma mark - AutofillAddCreditCardCoordinatorDelegate - (void)autofillAddCreditCardCoordinatorWantsToBeStopped: From 53ebf61540484423df7f20a2a5d7f53864146a9f Mon Sep 17 00:00:00 2001 From: Aliona DANGLA Date: Tue, 21 May 2024 16:15:54 +0000 Subject: [PATCH 36/40] [iOS] Remove space in tab group header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove space as it shift the view instead of creating more space. See screenshot: https://drive.google.com/file/d/1NSNNw0P-SgcFbFQtSnkrezHDn410ho_k/view?usp=drive_link Bug: 1501837 Change-Id: I8c4fb663676cb9d1092e4ffb5c0cfb5a837341f9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5533218 Reviewed-by: Ewann Pellé Auto-Submit: Aliona Dangla Commit-Queue: Gauthier Ambard Reviewed-by: Gauthier Ambard Cr-Commit-Position: refs/heads/main@{#1303819} --- .../tab_grid/grid/tab_groups/tab_group_header.mm | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_group_header.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_group_header.mm index 0ee97624e05a04..f747aa4fa230a8 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_group_header.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_group_header.mm @@ -5,7 +5,6 @@ #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_group_header.h" namespace { -constexpr CGFloat kTitleVerticalMargin = 10; constexpr CGFloat kDotTitleSeparationMargin = 8; constexpr CGFloat kColoredDotSize = 20; } // namespace @@ -35,10 +34,8 @@ - (instancetype)initWithFrame:(CGRect)frame { [_coloredDotView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], [_titleView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], - [_titleView.topAnchor constraintEqualToAnchor:self.topAnchor - constant:kTitleVerticalMargin], - [_titleView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor - constant:kTitleVerticalMargin], + [_titleView.topAnchor constraintEqualToAnchor:self.topAnchor], + [_titleView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], ]]; } return self; From 21a1b1a2a7847588a82b9dccae366096a20258d1 Mon Sep 17 00:00:00 2001 From: Akihiro Ota Date: Tue, 21 May 2024 16:16:45 +0000 Subject: [PATCH 37/40] FaceGaze: Implement more key press macros This change implements two new key press macros that will be used from FaceGaze. These are both marked as essential for the MVP in the FaceGaze PRD (go/facegaze-prd). These will be added to the FaceGaze settings page in a follow-up CL. Bug: b:330766904 Change-Id: Ie1118095ba9f91cb7edcf3db01ae9d7bd8c4b896 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5540029 Commit-Queue: Akihiro Ota Reviewed-by: Katie Dektar Cr-Commit-Position: refs/heads/main@{#1303820} --- .../resources/accessibility/macro_names.ts | 6 +++ .../facegaze/facegaze_test.js | 49 +++++++++++++++++-- .../facegaze/gesture_handler.ts | 2 + .../macros/key_press_macro.ts | 8 +++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/ash/webui/common/resources/accessibility/macro_names.ts b/ash/webui/common/resources/accessibility/macro_names.ts index cd1091bc2d2af6..e919dbabe2e059 100644 --- a/ash/webui/common/resources/accessibility/macro_names.ts +++ b/ash/webui/common/resources/accessibility/macro_names.ts @@ -152,6 +152,12 @@ export enum MacroName { // Generates a synthetic down arrow key event. KEY_PRESS_DOWN = 42, + // Shows/hides the overview of the user's active desktops. + KEY_PRESS_TOGGLE_OVERVIEW = 43, + + // Pauses/plays active media. + KEY_PRESS_MEDIA_PLAY_PAUSE = 44, + // Any new actions should match with Voice Access's semantic tags where // possible. } diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/facegaze/facegaze_test.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/facegaze/facegaze_test.js index 726f58b52a9468..8d33c2f00ad623 100644 --- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/facegaze/facegaze_test.js +++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/facegaze/facegaze_test.js @@ -662,13 +662,18 @@ AX_TEST_F('FaceGazeTest', 'KeyEvents', async function() { .set(FacialGesture.EYE_SQUINT_RIGHT, MacroName.KEY_PRESS_UP) .set(FacialGesture.MOUTH_SMILE, MacroName.KEY_PRESS_DOWN) .set(FacialGesture.MOUTH_UPPER_UP, MacroName.KEY_PRESS_LEFT) - .set(FacialGesture.EYES_BLINK, MacroName.KEY_PRESS_RIGHT); + .set(FacialGesture.EYES_BLINK, MacroName.KEY_PRESS_RIGHT) + .set(FacialGesture.JAW_OPEN, MacroName.KEY_PRESS_TOGGLE_OVERVIEW) + .set( + FacialGesture.MOUTH_PUCKER, MacroName.KEY_PRESS_MEDIA_PLAY_PAUSE); const gestureToConfidence = new Map() .set(FacialGesture.EYE_SQUINT_LEFT, 0.7) .set(FacialGesture.EYE_SQUINT_RIGHT, 0.7) .set(FacialGesture.MOUTH_SMILE, 0.7) .set(FacialGesture.MOUTH_UPPER_UP, 0.7) - .set(FacialGesture.EYES_BLINK, 0.7); + .set(FacialGesture.EYES_BLINK, 0.7) + .set(FacialGesture.JAW_OPEN, 0.7) + .set(FacialGesture.MOUTH_PUCKER, 0.7); const config = new Config() .withMouseLocation({x: 600, y: 400}) .withGestureToMacroName(gestureToMacroName) @@ -701,7 +706,13 @@ AX_TEST_F('FaceGazeTest', 'KeyEvents', async function() { gestures.blinkLeft ? gestures.blinkLeft : 0.3) .addGestureWithConfidence( MediapipeFacialGesture.EYE_BLINK_RIGHT, - gestures.blinkRight ? gestures.blinkRight : 0.3); + gestures.blinkRight ? gestures.blinkRight : 0.3) + .addGestureWithConfidence( + MediapipeFacialGesture.JAW_OPEN, + gestures.jawOpen ? gestures.jawOpen : 0.3) + .addGestureWithConfidence( + MediapipeFacialGesture.MOUTH_PUCKER, + gestures.mouthPucker ? gestures.mouthPucker : 0.3); this.processFaceLandmarkerResult( result, /*triggerMouseControllerInterval=*/ true); return this.mockAccessibilityPrivate.syntheticKeyEvents_; @@ -792,4 +803,36 @@ AX_TEST_F('FaceGazeTest', 'KeyEvents', async function() { chrome.accessibilityPrivate.SyntheticKeyboardEventType.KEYUP, keyEvents[9].type); assertEquals(KeyCode.LEFT, keyEvents[9].keyCode); + + // Jaw open for toggle overview key press. + keyEvents = makeResultAndProcess({jawOpen: .75}); + assertEquals(11, keyEvents.length); + assertEquals( + chrome.accessibilityPrivate.SyntheticKeyboardEventType.KEYDOWN, + keyEvents[10].type); + assertEquals(KeyCode.MEDIA_LAUNCH_APP1, keyEvents[10].keyCode); + + // Jaw close for toggle overview key release. + keyEvents = makeResultAndProcess({}); + assertEquals(12, keyEvents.length); + assertEquals( + chrome.accessibilityPrivate.SyntheticKeyboardEventType.KEYUP, + keyEvents[11].type); + assertEquals(KeyCode.MEDIA_LAUNCH_APP1, keyEvents[11].keyCode); + + // Mouth pucker for media play/pause key press. + keyEvents = makeResultAndProcess({mouthPucker: .75}); + assertEquals(13, keyEvents.length); + assertEquals( + chrome.accessibilityPrivate.SyntheticKeyboardEventType.KEYDOWN, + keyEvents[12].type); + assertEquals(KeyCode.MEDIA_PLAY_PAUSE, keyEvents[12].keyCode); + + // Stop mouth pucker for media play/pause key release. + keyEvents = makeResultAndProcess({}); + assertEquals(14, keyEvents.length); + assertEquals( + chrome.accessibilityPrivate.SyntheticKeyboardEventType.KEYUP, + keyEvents[13].type); + assertEquals(KeyCode.MEDIA_PLAY_PAUSE, keyEvents[13].keyCode); }); diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/facegaze/gesture_handler.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/facegaze/gesture_handler.ts index 484f82de42abfe..3a203668681a6c 100644 --- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/facegaze/gesture_handler.ts +++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/facegaze/gesture_handler.ts @@ -176,6 +176,8 @@ export class GestureHandler { case MacroName.KEY_PRESS_LEFT: case MacroName.KEY_PRESS_RIGHT: case MacroName.KEY_PRESS_UP: + case MacroName.KEY_PRESS_TOGGLE_OVERVIEW: + case MacroName.KEY_PRESS_MEDIA_PLAY_PAUSE: return new KeyPressMacro(name); default: return; diff --git a/chrome/browser/resources/chromeos/accessibility/common/action_fulfillment/macros/key_press_macro.ts b/chrome/browser/resources/chromeos/accessibility/common/action_fulfillment/macros/key_press_macro.ts index 8b52cd2dbc7025..010830eb01f295 100644 --- a/chrome/browser/resources/chromeos/accessibility/common/action_fulfillment/macros/key_press_macro.ts +++ b/chrome/browser/resources/chromeos/accessibility/common/action_fulfillment/macros/key_press_macro.ts @@ -36,6 +36,14 @@ export class KeyPressMacro extends Macro { case MacroName.KEY_PRESS_UP: this.key_ = KeyCode.UP; break; + case MacroName.KEY_PRESS_TOGGLE_OVERVIEW: + // The MEDIA_LAUNCH_APP1 key is bound to the kToggleOverview accelerator + // action in accelerators.cc. + this.key_ = KeyCode.MEDIA_LAUNCH_APP1; + break; + case MacroName.KEY_PRESS_MEDIA_PLAY_PAUSE: + this.key_ = KeyCode.MEDIA_PLAY_PAUSE; + break; default: console.error('Macro ' + macroName + ' is not a key press macro.'); } From e984bc99012e507d3ac538a54285b1a003c0d306 Mon Sep 17 00:00:00 2001 From: Aida Zolic Date: Tue, 21 May 2024 16:18:16 +0000 Subject: [PATCH 38/40] [skyvault] Block all VMs when local files are disabled Blocks all VMs, not just arc, if local files are disabled. Ideally, the admins should configure the policies so that the VMs are already also disabled, but this is not guaranteed, so this ensures that there aren't local volumes (like Linux Files). Fixed: b/329206976 Change-Id: I9b282214af163777a7f0204fb3c62feaeafcdc81 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5546418 Reviewed-by: Joel Hockey Commit-Queue: Aida Zolic Reviewed-by: Sergey Poromov Cr-Commit-Position: refs/heads/main@{#1303821} --- chrome/browser/ash/guest_os/public/DEPS | 1 + .../public/guest_os_mount_provider.cc | 25 ++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/chrome/browser/ash/guest_os/public/DEPS b/chrome/browser/ash/guest_os/public/DEPS index 7bb540d012125f..074bb43a8d064a 100644 --- a/chrome/browser/ash/guest_os/public/DEPS +++ b/chrome/browser/ash/guest_os/public/DEPS @@ -24,4 +24,5 @@ include_rules = [ "+chrome/browser/extensions/api/terminal", "+chrome/browser/profiles", "+chrome/test/base", + "+chrome/common/chrome_features.h", ] diff --git a/chrome/browser/ash/guest_os/public/guest_os_mount_provider.cc b/chrome/browser/ash/guest_os/public/guest_os_mount_provider.cc index e73d54cb72cd4f..c96b0259cd1491 100644 --- a/chrome/browser/ash/guest_os/public/guest_os_mount_provider.cc +++ b/chrome/browser/ash/guest_os/public/guest_os_mount_provider.cc @@ -6,6 +6,7 @@ #include +#include "base/feature_list.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/functional/callback_forward.h" @@ -15,9 +16,12 @@ #include "base/strings/stringprintf.h" #include "chrome/browser/ash/file_manager/path_util.h" #include "chrome/browser/ash/file_manager/volume_manager.h" +#include "chrome/browser/ash/guest_os/guest_id.h" #include "chrome/browser/ash/guest_os/infra/cached_callback.h" +#include "chrome/browser/ash/guest_os/public/types.h" #include "chrome/browser/ash/policy/skyvault/policy_utils.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/common/chrome_features.h" #include "chromeos/ash/components/disks/disk_mount_manager.h" #include "storage/browser/file_system/external_mount_points.h" @@ -169,10 +173,23 @@ class GuestOsMountProviderInner : public CachedCallback { }; void GuestOsMountProvider::Mount(base::OnceCallback callback) { - if (!policy::local_user_files::LocalUserFilesAllowed() && - vm_type() == VmType::ARCVM) { - LOG(ERROR) - << "Error mounting ARCVM container: local user files are disabled"; + const bool local_files_allowed = + policy::local_user_files::LocalUserFilesAllowed(); + + // If SkyVaultV2 is enabled (GA version), block all VMs regardless of the + // type. + if (!local_files_allowed && + base::FeatureList::IsEnabled(features::kSkyVaultV2)) { + LOG(ERROR) << "Error mounting Guest OS container with guest id=" + << this->GuestId() << ": local user files are disabled"; + std::move(callback).Run(false); + return; + } + + // If SkyVaultV2 is disabled (TT version), only block ARC. + if (!local_files_allowed && vm_type() == VmType::ARCVM) { + LOG(ERROR) << "Error mounting Guest OS container with guest id=" + << this->GuestId() << ": local user files are disabled"; std::move(callback).Run(false); return; } From fc79321cc2c09f7cd3f5bb8989eb64a853841407 Mon Sep 17 00:00:00 2001 From: Tina Wang Date: Tue, 21 May 2024 16:21:50 +0000 Subject: [PATCH 39/40] [Notif] Update feature flag check in PushNotificationClientManager The PushNotificationClientManager is used when receiving notification. It routes each notification to its appropriate PushNotificationClient. We'll init the ContentNotificationClient for users that enable the content notification experiments. More context: the original plan is to replace IsContentPushNotificationsEnabled() with IsContentNotificationEnabled(is_user_signed_in, is_default_search_engine, pref_service), which ensures only users in the "enabled" experiment groups will have ContentNotificationClient initiated, but by doing that we'll need to get a browserState object for the eligibility check, and the test will be much more complex. So to make the check light-weighted, we check the overall experiment feature flag. It won't affect any user visible UI, nor the registration flow, but guarantees that ContentPushNotificationsEnabled flag won't be checked before eligibility check. It's unrelated to Chime registration flow, so users won't be overly registered. TODO: Since this cl needs to be merged in M126, so I'll keep it small. There is a typo in the feature flag checking method. I'll correct it in the follow up cl. Bug: b/338254318 Change-Id: I32723c2bf89caf0861078f5d57dac28263826a72 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5546980 Commit-Queue: Tina Wang Code-Coverage: findit-for-me@appspot.gserviceaccount.com Reviewed-by: Guillem Perez Cr-Commit-Position: refs/heads/main@{#1303822} --- .../model/push_notification_client_manager.mm | 4 ++-- .../model/push_notification_settings_util_unittest.mm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/chrome/browser/push_notification/model/push_notification_client_manager.mm b/ios/chrome/browser/push_notification/model/push_notification_client_manager.mm index aa802942941bfb..be5a23c868f973 100644 --- a/ios/chrome/browser/push_notification/model/push_notification_client_manager.mm +++ b/ios/chrome/browser/push_notification/model/push_notification_client_manager.mm @@ -28,7 +28,7 @@ AddPushNotificationClient(std::make_unique()); } - if (IsContentPushNotificationsEnabled()) { + if (IsContentNotificationExperimentEnalbed()) { AddPushNotificationClient(std::make_unique()); } } @@ -98,7 +98,7 @@ PushNotificationClientManager::GetClients() { std::vector client_ids = { PushNotificationClientId::kCommerce}; - if (IsContentPushNotificationsEnabled()) { + if (IsContentNotificationExperimentEnalbed()) { client_ids.push_back(PushNotificationClientId::kContent); client_ids.push_back(PushNotificationClientId::kSports); } diff --git a/ios/chrome/browser/push_notification/model/push_notification_settings_util_unittest.mm b/ios/chrome/browser/push_notification/model/push_notification_settings_util_unittest.mm index 2e98c47668f19e..26fa28c0d3e8f1 100644 --- a/ios/chrome/browser/push_notification/model/push_notification_settings_util_unittest.mm +++ b/ios/chrome/browser/push_notification/model/push_notification_settings_util_unittest.mm @@ -49,7 +49,7 @@ fake_id_ = [FakeSystemIdentity fakeIdentity1]; // TODO(b/318863934): Remove flag when enabled by default. feature_list_.InitWithFeatures( - {/*enabled=*/kContentPushNotifications, kIOSTipsNotifications}, + {/*enabled=*/kContentNotificationExperiment, kIOSTipsNotifications}, {/*disabled=*/}); AddTestCasesToManager(manager_, browser_state_info(), base::SysNSStringToUTF8(fake_id_.gaiaID), From bead720c07bfebff9a2601e1bcca70dc63b89e65 Mon Sep 17 00:00:00 2001 From: Maggie Chen Date: Tue, 21 May 2024 16:25:23 +0000 Subject: [PATCH 40/40] Remove the feature flag CALayerTreeOptimization CALayerTreeOptimization has been enabled by default since M107 Bug: 40214116 Change-Id: Ib538dbd48097d56328134acf9242088eb0bb81f8 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5549057 Reviewed-by: ccameron chromium Commit-Queue: Maggie Chen Cr-Commit-Position: refs/heads/main@{#1303823} --- .../ca_renderer_layer_tree.h | 6 ---- .../ca_renderer_layer_tree.mm | 30 ++----------------- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h index 275d50b4accab4..621864905bbc11 100644 --- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h +++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h @@ -35,7 +35,6 @@ namespace ui { ACCELERATED_WIDGET_MAC_EXPORT BASE_DECLARE_FEATURE( kFullscreenLowPowerBackdropMac); -ACCELERATED_WIDGET_MAC_EXPORT BASE_DECLARE_FEATURE(kCALayerTreeOptimization); struct CARendererLayerParams; @@ -101,7 +100,6 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree { using CALayerMap = std::unordered_map>; - void MatchLayersToOldTreeDefault(CARendererLayerTree* old_tree); void MatchLayersToOldTree(CARendererLayerTree* old_tree); class RootLayer { @@ -321,10 +319,6 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree { const bool allow_solid_color_layers_ = true; id __strong metal_device_ = nil; - // Enable CALayerTree optimization that will try to reuse the CALayer with a - // matched CALayer from the old CALayerTree in the previous frame. - const bool ca_layer_tree_optimization_; - // Map of content IOSurface. CALayerMap ca_layer_map_; }; diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm index 75b82e349154be..6511c75637b20b 100644 --- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm +++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm @@ -38,10 +38,6 @@ "FullscreenLowPowerBackdropMac", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kCALayerTreeOptimization, - "CALayerTreeOptimization", - base::FEATURE_ENABLED_BY_DEFAULT); - #if BUILDFLAG(IS_MAC) // Show borders around RenderPassDrawQuad CALayers. which is the output of a // non-root render pass. @@ -315,9 +311,7 @@ CATransform3D ToCATransform3D(const gfx::Transform& t) { bool allow_solid_color_layers) : allow_av_sample_buffer_display_layer_( allow_av_sample_buffer_display_layer), - allow_solid_color_layers_(allow_solid_color_layers), - ca_layer_tree_optimization_( - base::FeatureList::IsEnabled(kCALayerTreeOptimization)) {} + allow_solid_color_layers_(allow_solid_color_layers) {} CARendererLayerTree::~CARendererLayerTree() = default; bool CARendererLayerTree::ScheduleCALayer(const CARendererLayerParams& params) { @@ -336,10 +330,8 @@ CATransform3D ToCATransform3D(const gfx::Transform& t) { TRACE_EVENT0("gpu", "CARendererLayerTree::CommitScheduledCALayers"); scale_factor_ = scale_factor; - if (ca_layer_tree_optimization_) - MatchLayersToOldTree(old_tree.get()); - else - MatchLayersToOldTreeDefault(old_tree.get()); + // The CALayerTree optimization reuses the matched CALayer from the previous. + MatchLayersToOldTree(old_tree.get()); root_layer_.CommitToCA(superlayer, pixel_size); // If there are any extra CALayers in |old_tree| that were not stolen by this @@ -348,22 +340,6 @@ CATransform3D ToCATransform3D(const gfx::Transform& t) { has_committed_ = true; } -void CARendererLayerTree::MatchLayersToOldTreeDefault( - CARendererLayerTree* old_tree) { - if (!old_tree) - return; - DCHECK(old_tree->has_committed_); - - // Match the root layer. - if (old_tree->scale_factor_ != scale_factor_) - return; - - root_layer_.old_layer_ = - old_tree->root_layer_.weak_factory_for_new_layer_.GetWeakPtr(); - - root_layer_.CALayerFallBack(); -} - void CARendererLayerTree::MatchLayersToOldTree(CARendererLayerTree* old_tree) { if (!old_tree) return;