diff --git a/DEPS b/DEPS index c441185..2ee5d13 100644 --- a/DEPS +++ b/DEPS
@@ -211,7 +211,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '29eeb610bd49e80a8109a6b42f2c95adcc619099', + 'angle_revision': 'd2e76b73efc2c16d7c4a2cddbef4965deeb2f1c9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -246,7 +246,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': 'd28e6c52e05ea2f1b3231de473b6dbfce59bce40', + 'nacl_revision': 'cb31feffa500401c95c6c44d88b7c358236bca36', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -266,7 +266,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'b2af2da3481cd7a14c8ff6c9edf98164d8fad009', + 'catapult_revision': 'f46e9e72306f00405741ac4abd146cf904aabe3e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -274,7 +274,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '57654f96e343a4fe2bf29f28a770b5c4f391f759', + 'devtools_frontend_revision': '3100aca993ac2fc227ed4a29c855c8302e0cff0d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -318,7 +318,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': 'e84d83393be4536291ce719787f6a275db07b733', + 'quiche_revision': '9aef115356ce48848790dd64a0f2d2ed9f55149b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -873,7 +873,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '628b7f61f813da6b7e44a31e34a6c51f041bcf68', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '5fcf0fa9382ef09d010f2ffdcb1ee90dce670efc', 'condition': 'checkout_chromeos', }, @@ -893,7 +893,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '091f5ac0a64ce66b75c185eb0ee698ef4e837145', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '428143ee24c5f084c8dfb38cd17f07b4f7ba9bf7', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1391,7 +1391,7 @@ 'packages': [ { 'package': 'chromium/third_party/r8', - 'version': 'DR3nwJggFDcmTDz7P8fJQCtRLO1nxDt26czkOqhtZJ8C', + 'version': 'F8cKQoSai0fZxFRJVRZnoWeS-oVyp53L7bpuVq9t44AC', }, ], 'condition': 'checkout_android', @@ -1588,7 +1588,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'bx6pXjyY-3vkrBjpqnuCDbusE-Ui_g3xSzSffOHHktoC', + 'version': 'BhbSyh4bjbYmwfA5WJTXzE9uMvDFyyviZuft_yjZ8ZgC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1599,7 +1599,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'DYU_0-Aok5UvqgV35z_dEgBIqBP98Ypx98hUZ8a8NcoC', + 'version': 'xO6b6gm3QxUDRY3PGCD_ON0uPe2bjwP9ftauSv0ar3cC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 92d6310..cc832089 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -2059,7 +2059,8 @@ } // If we are reloading the same url, then set transition type as reload. - if (params.getUrl() != null && params.getUrl().equals(mWebContents.getLastCommittedUrl()) + if (params.getUrl() != null + && params.getUrl().equals(mWebContents.getLastCommittedUrl().getSpec()) && params.getTransitionType() == PageTransition.TYPED) { params.setTransitionType(PageTransition.RELOAD); } @@ -2131,9 +2132,9 @@ */ public String getLastCommittedUrl() { if (isDestroyed(NO_WARN)) return null; - String url = mWebContents.getLastCommittedUrl(); - if (url == null || url.trim().isEmpty()) return null; - return url; + GURL url = mWebContents.getLastCommittedUrl(); + if (url == null || url.isEmpty()) return null; + return url.getSpec(); } public void requestFocus() {
diff --git a/ash/touch/touch_hud_renderer.cc b/ash/touch/touch_hud_renderer.cc index e8c3c85..c2390745 100644 --- a/ash/touch/touch_hud_renderer.cc +++ b/ash/touch/touch_hud_renderer.cc
@@ -4,6 +4,7 @@ #include "ash/touch/touch_hud_renderer.h" +#include "base/scoped_observer.h" #include "base/time/time.h" #include "third_party/skia/include/effects/SkGradientShader.h" #include "ui/compositor/layer.h"
diff --git a/ash/wm/desks/desk_name_view.cc b/ash/wm/desks/desk_name_view.cc index 5cf6e16..69b0ea09 100644 --- a/ash/wm/desks/desk_name_view.cc +++ b/ash/wm/desks/desk_name_view.cc
@@ -117,7 +117,7 @@ } void DeskNameView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ax::mojom::Role::kTextField; + Textfield::GetAccessibleNodeData(node_data); // When Bento is enabled and the user creates a new desk, |full_text_| will be // empty but the accesssible name for |this| will be the default desk name. node_data->SetName(full_text_.empty() ? GetAccessibleName() : full_text_);
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn index c01a56e..9348e2dc7 100644 --- a/base/allocator/BUILD.gn +++ b/base/allocator/BUILD.gn
@@ -320,5 +320,9 @@ # <unistd.h> functions "-Wl,-wrap,getcwd", + + # <stdio.h> functions + "-Wl,-wrap,asprintf", + "-Wl,-wrap,vasprintf", ] }
diff --git a/base/allocator/allocator.gni b/base/allocator/allocator.gni index e15c2216..d15ff97 100644 --- a/base/allocator/allocator.gni +++ b/base/allocator/allocator.gni
@@ -8,6 +8,12 @@ # Sanitizers replace the allocator, don't use our own. _is_using_sanitizers = is_asan || is_hwasan || is_lsan || is_tsan || is_msan +# - Windows: shims don't work for component builds and debug CRT is not +# compatible, see below. +# - Android: symbol wrapping is not universal for component builds. +_disable_partition_alloc = (is_win && (is_component_build || is_debug)) || + (is_android && is_component_build) + # The debug CRT on Windows has some debug features that are incompatible with # the shim. NaCl in particular does seem to link some binaries statically # against the debug CRT with "is_nacl=false". @@ -18,9 +24,8 @@ _default_use_allocator_shim = false } -# TODO(https://crbug.com/1166748): android/x86 is temporarily disabled. -if (_default_use_allocator_shim && - (is_win || (is_android && target_cpu != "x86"))) { +if (_default_use_allocator_shim && (is_win || is_android) && + !_disable_partition_alloc) { _default_allocator = "partition" } else if (is_android || is_apple || _is_using_sanitizers || is_win || is_fuchsia || ((is_linux || is_chromeos) && target_cpu == "arm64") ||
diff --git a/base/allocator/allocator_shim_override_linker_wrapped_symbols.h b/base/allocator/allocator_shim_override_linker_wrapped_symbols.h index e2c6a68..04103f9 100644 --- a/base/allocator/allocator_shim_override_linker_wrapped_symbols.h +++ b/base/allocator/allocator_shim_override_linker_wrapped_symbols.h
@@ -110,4 +110,38 @@ return __wrap_strdup(local_buffer); } +// Override stdio.h + +// This is non-standard (_GNU_SOURCE only), but implemented by Bionic on +// Android, and used by libc++. +SHIM_ALWAYS_EXPORT int __wrap_vasprintf(char** strp, + const char* fmt, + va_list va_args) { + constexpr int kInitialSize = 128; + *strp = static_cast<char*>( + malloc(kInitialSize)); // Our malloc() doesn't return nullptr. + + int actual_size = vsnprintf(*strp, kInitialSize, fmt, va_args); + *strp = static_cast<char*>(realloc(*strp, actual_size + 1)); + + // Now we know the size. This is not very efficient, but we cannot really do + // better without accessing internal libc functions, or reimplementing + // *printf(). + // + // This is very lightly used in Chromium in practice, see crbug.com/116558 for + // details. + if (actual_size >= kInitialSize) + return vsnprintf(*strp, actual_size + 1, fmt, va_args); + + return actual_size; +} + +SHIM_ALWAYS_EXPORT int __wrap_asprintf(char** strp, const char* fmt, ...) { + va_list va_args; + va_start(va_args, fmt); + int retval = vasprintf(strp, fmt, va_args); + va_end(va_args); + return retval; +} + } // extern "C"
diff --git a/base/allocator/allocator_shim_unittest.cc b/base/allocator/allocator_shim_unittest.cc index 41d9568..9a8fb841 100644 --- a/base/allocator/allocator_shim_unittest.cc +++ b/base/allocator/allocator_shim_unittest.cc
@@ -8,8 +8,10 @@ #include <string.h> #include <atomic> +#include <iomanip> #include <memory> #include <new> +#include <sstream> #include <vector> #include "base/allocator/buildflags.h" @@ -685,8 +687,29 @@ counts_after = total_counts(allocs_intercepted_by_size); EXPECT_GT(counts_after, counts_before); + // Calls vasprintf() indirectly, see below. + counts_before = counts_after; + std::stringstream stream; + stream << std::setprecision(1) << std::showpoint << std::fixed << 1.e38; + EXPECT_GT(stream.str().size(), 30u); + counts_after = total_counts(allocs_intercepted_by_size); + EXPECT_GT(counts_after, counts_before); + RemoveAllocatorDispatchForTesting(&g_mock_dispatch); } + +#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) +// Non-regression test for crbug.com/1166558. +TEST_F(AllocatorShimTest, InterceptVasprintf) { + // Printing a float which expands to >=30 characters calls vasprintf() in + // libc, which we should intercept. + std::stringstream stream; + stream << std::setprecision(1) << std::showpoint << std::fixed << 1.e38; + EXPECT_GT(stream.str().size(), 30u); + // Should not crash. +} +#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) + #endif // defined(OS_ANDROID) } // namespace
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h index c594eb05..dd0f164 100644 --- a/base/allocator/partition_allocator/partition_root.h +++ b/base/allocator/partition_allocator/partition_root.h
@@ -803,6 +803,24 @@ if (UNLIKELY(!ptr)) return; + // On Android, malloc() interception is more fragile than on other + // platforms, as we use wrapped symbols. However, the GigaCage allows us to + // quickly tell that a pointer was allocated with PartitionAlloc. GigaCage + // is unfortunately not used for the aligned partition when BackupRefPtr is + // enabled, yielding the set of conditions below. + // + // This is a crash to detect imperfect symbol interception. However, we can + // forward allocations we don't own to the system malloc() implementation in + // these rare cases, assuming that some remain. + // + // TODO(lizeb): Make this a PA_CHECK() at least temporarily to detect + // potential issues in the wild as well. +#if defined(OS_ANDROID) && BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \ + !ENABLE_REF_COUNT_FOR_BACKUP_REF_PTR + PA_DCHECK(IsManagedByPartitionAllocNormalBuckets(ptr) || + IsManagedByPartitionAllocDirectMap(ptr)); +#endif + // No check as the pointer hasn't been adjusted yet. SlotSpan* slot_span = SlotSpan::FromPointerNoAlignmentCheck(ptr); // TODO(palmer): See if we can afford to make this a CHECK.
diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc index c085f5e..0a74e4c7 100644 --- a/base/i18n/time_formatting.cc +++ b/base/i18n/time_formatting.cc
@@ -154,11 +154,22 @@ return TimeFormat(formatter.get(), time); } +#if defined(OS_CHROMEOS) +string16 TimeFormatMonthAndYear(const Time& time, + const icu::TimeZone* time_zone) { + icu::SimpleDateFormat formatter = + CreateSimpleDateFormatter(DateFormatToString(DATE_FORMAT_YEAR_MONTH)); + if (time_zone) + formatter.setTimeZone(*time_zone); + return TimeFormat(&formatter, time); +} +#else string16 TimeFormatMonthAndYear(const Time& time) { icu::SimpleDateFormat formatter = CreateSimpleDateFormatter(DateFormatToString(DATE_FORMAT_YEAR_MONTH)); return TimeFormat(&formatter, time); } +#endif // defined(OS_CHROMEOS) string16 TimeFormatFriendlyDateAndTime(const Time& time) { std::unique_ptr<icu::DateFormat> formatter(
diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h index 64b09964..1063f6e6 100644 --- a/base/i18n/time_formatting.h +++ b/base/i18n/time_formatting.h
@@ -11,6 +11,11 @@ #include "base/compiler_specific.h" #include "base/i18n/base_i18n_export.h" #include "base/strings/string16.h" +#include "build/build_config.h" + +#if defined(OS_CHROMEOS) +#include "third_party/icu/source/i18n/unicode/timezone.h" +#endif // defined(OS_CHROMEOS) namespace base { @@ -72,8 +77,17 @@ // Returns a numeric date and time such as "12/13/52 2:44:30 PM". BASE_I18N_EXPORT string16 TimeFormatShortDateAndTime(const Time& time); +#if defined(OS_CHROMEOS) +// Returns a month and year, e.g. "November 2007" +// Note: If `time_zone` is non-null, the time will be formatted in the provided +// time zone. Otherwise, it will default to local time. +BASE_I18N_EXPORT string16 +TimeFormatMonthAndYear(const Time& time, + const icu::TimeZone* time_zone = nullptr); +#else // Returns a month and year, e.g. "November 2007" BASE_I18N_EXPORT string16 TimeFormatMonthAndYear(const Time& time); +#endif // defined(OS_CHROMEOS) // Returns a numeric date and time with time zone such as // "12/13/52 2:44:30 PM PST".
diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc index 824b9b9..701370a 100644 --- a/base/i18n/time_formatting_unittest.cc +++ b/base/i18n/time_formatting_unittest.cc
@@ -11,6 +11,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/icu_test_util.h" #include "base/time/time.h" +#include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/icu/source/common/unicode/uversion.h" #include "third_party/icu/source/i18n/unicode/calendar.h" @@ -203,6 +204,36 @@ kDropAmPm)); } +#if defined(OS_CHROMEOS) +TEST(TimeFormattingTest, TimeMonthYearInUTC) { + // See third_party/icu/source/data/locales/en.txt. + // The date patterns are "EEEE, MMMM d, y", "MMM d, y", and "M/d/yy". + test::ScopedRestoreICUDefaultLocale restore_locale; + i18n::SetICUDefaultLocale("en_US"); + test::ScopedRestoreDefaultTimezone la_time("America/Los_Angeles"); + + Time time; + EXPECT_TRUE(Time::FromUTCExploded(kTestDateTimeExploded, &time)); + EXPECT_EQ( + ASCIIToUTF16("April 2011"), + TimeFormatMonthAndYear(time, /*time_zone=*/icu::TimeZone::getGMT())); + EXPECT_EQ(ASCIIToUTF16("April 2011"), + TimeFormatMonthAndYear(time, /*time_zone=*/nullptr)); + + const Time::Exploded kDiffMonthsForDiffTzTime = { + 2011, 4, 5, 1, // Fri, Apr 1, 2011 UTC = Thurs, March 31, 2011 US PDT. + 0, 0, 0, 0 // 00:00:00.000 UTC = 05:00:00 previous day US PDT. + }; + + EXPECT_TRUE(Time::FromUTCExploded(kDiffMonthsForDiffTzTime, &time)); + EXPECT_EQ( + ASCIIToUTF16("April 2011"), + TimeFormatMonthAndYear(time, /*time_zone=*/icu::TimeZone::getGMT())); + EXPECT_EQ(ASCIIToUTF16("March 2011"), + TimeFormatMonthAndYear(time, /*time_zone=*/nullptr)); +} +#endif // defined(OS_CHROMEOS) + TEST(TimeFormattingTest, TimeFormatDateUS) { // See third_party/icu/source/data/locales/en.txt. // The date patterns are "EEEE, MMMM d, y", "MMM d, y", and "M/d/yy".
diff --git a/base/power_monitor/power_monitor_device_source.h b/base/power_monitor/power_monitor_device_source.h index c09a6a4..937f418 100644 --- a/base/power_monitor/power_monitor_device_source.h +++ b/base/power_monitor/power_monitor_device_source.h
@@ -130,7 +130,7 @@ PowerMessageWindow power_message_window_; #endif -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) PowerObserver::DeviceThermalState current_thermal_state_ = PowerObserver::DeviceThermalState::kUnknown; #endif
diff --git a/build/config/chromeos/rules.gni b/build/config/chromeos/rules.gni index 9e61743..d8d5025 100644 --- a/build/config/chromeos/rules.gni +++ b/build/config/chromeos/rules.gni
@@ -8,56 +8,90 @@ import("//build/config/gclient_args.gni") import("//build/config/python.gni") -assert(is_chromeos_ash) +assert(is_chromeos_ash || is_chromeos_lacros) # Determine the real paths for various items in the SDK, which may be used # in the 'generate_runner_script' template below. We do so outside the template # to confine exec_script to a single invocation. -cros_is_vm = false if (is_chromeos_device && cros_sdk_version != "") { - _cache_path_prefix = - "//build/cros_cache/chrome-sdk/symlinks/${cros_board}+${cros_sdk_version}" + # Ideally these should be maps, however, gn doesn't support map, so using a + # list of list to simulate a map: + # [key1, [value1, value2, ...]], [key2, [value1, value2, ...]], where + # the keys are boards and values are symlinks or symlink targets, and the + # mapping shouldn't be used for anything else. + # + # A sample usage is: + # foreach(m, _symlink_targets_map) { + # if(m[0] == target_key) { + # target_value = m[1] + # } + # } + # + _symlink_map = [] + _symlink_targets_map = [] + _boards = [] - foreach(b, string_split(cros_boards_with_qemu_images, ":")) { - if (cros_board == b) { - cros_is_vm = true + if (cros_boards != "") { + _boards += string_split(cros_boards, ":") + } + if (cros_boards_with_qemu_images != "") { + _boards += string_split(cros_boards_with_qemu_images, ":") + } + + foreach(b, _boards) { + _cache_path_prefix = + "//build/cros_cache/chrome-sdk/symlinks/${b}+${cros_sdk_version}" + + cros_is_vm = false + foreach(b1, string_split(cros_boards_with_qemu_images, ":")) { + if (b == b1) { + cros_is_vm = true + } } + + _symlinks = [] + _symlinks = [ + # Tast harness & test data. + rebase_path("${_cache_path_prefix}+chromeos-base/tast-cmd"), + rebase_path("${_cache_path_prefix}+chromeos-base/tast-remote-tests-cros"), + + # Binutils (and other toolchain tools) used to deploy Chrome to the device. + rebase_path( + "${_cache_path_prefix}+environment_chromeos-base_chromeos-chrome.tar.xz"), + rebase_path("${_cache_path_prefix}+target_toolchain"), + ] + if (cros_is_vm) { + # VM-related tools. + _symlinks += [ + rebase_path("${_cache_path_prefix}+sys-firmware/seabios"), + rebase_path("${_cache_path_prefix}+chromiumos_qemu_image.tar.xz"), + rebase_path("${_cache_path_prefix}+app-emulation/qemu"), + ] + } + _symlink_map += [ [ + b, + _symlinks, + ] ] } - _symlinks = [ - # Tast harness & test data. - rebase_path("${_cache_path_prefix}+chromeos-base/tast-cmd"), - rebase_path("${_cache_path_prefix}+chromeos-base/tast-remote-tests-cros"), - - # Binutils (and other toolchain tools) used to deploy Chrome to the device. - rebase_path( - "${_cache_path_prefix}+environment_chromeos-base_chromeos-chrome.tar.xz"), - rebase_path("${_cache_path_prefix}+target_toolchain"), - ] - if (cros_is_vm) { - # VM-related tools. - _symlinks += [ - rebase_path("${_cache_path_prefix}+sys-firmware/seabios"), - rebase_path("${_cache_path_prefix}+chromiumos_qemu_image.tar.xz"), - rebase_path("${_cache_path_prefix}+app-emulation/qemu"), - ] + _all_symlinks = [] + foreach(m, _symlink_map) { + _all_symlinks += m[1] } - _symlink_targets = - exec_script("//build/get_symlink_targets.py", _symlinks, "list lines") - tast_sdk_items = [ - _symlink_targets[0], - _symlink_targets[1], - ] - toolchain_sdk_items = [ - _symlink_targets[2], - _symlink_targets[3], - ] - if (cros_is_vm) { - vm_sdk_items = [ - _symlink_targets[4], - _symlink_targets[5], - _symlink_targets[6], - ] + _all_symlink_targets = + exec_script("//build/get_symlink_targets.py", _all_symlinks, "list lines") + _index = 0 + foreach(m, _symlink_map) { + _symlink_targets = [] + foreach(_, m[1]) { + _symlink_targets += [ _all_symlink_targets[_index] ] + _index += 1 + } + + _symlink_targets_map += [ [ + m[0], + _symlink_targets, + ] ] } } @@ -76,28 +110,86 @@ # build dir to the VM after launching it. # runtime_deps_file: Path to file listing runtime deps for the test. If set, # all files listed will be copied to the VM before testing. +# override_board: "cros_board" variable was used to decide both the toolchain +# to build Chrome and the DUTs to test the binary, however, with the +# introduction of Lacros, this is not true anymore: a Lacros chrome can be +# built by an amd64-generic toolchain, but tested on eve devices, and to +# accommondate the use case, this variable is introduced to allow +# overriding the board to test the built binary. +# tast_vars: A list of "key=value" runtime variable pairs to pass to invoke +# the Tast tests. For more details, please see: +# https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#Runtime-variables template("generate_runner_script") { forward_variables_from(invoker, [ + "override_board", "deploy_chrome", "generated_script", "runtime_deps_file", "tast_attr_expr", "tast_tests", + "tast_vars", "testonly", "test_exe", ]) - if (!defined(deploy_chrome)) { - deploy_chrome = false + + if (defined(override_board)) { + cros_board = override_board } - assert(defined(generated_script), - "Must specify where to place generated test launcher script via " + - "'generated_script'") - is_tast = defined(tast_attr_expr) || defined(tast_tests) - assert(!(is_tast && defined(test_exe)), - "Tast tests are invoked from binaries shipped with the VM image. " + - "There should be no locally built binary needed.") + if (is_chromeos_device && cros_sdk_version != "") { + assert(defined(generated_script), + "Must specify where to place generated test launcher script via " + + "'generated_script'") + is_tast = defined(tast_attr_expr) || defined(tast_tests) + assert(!(is_tast && defined(test_exe)), + "Tast tests are invoked from binaries shipped with the VM image. " + + "There should be no locally built binary needed.") + assert(is_tast || !defined(tast_vars), + "tast_vars is only support for Tast tests") + + # Determine the real paths for various items in the SDK, which may be used + # in the 'generate_runner_script' template below. + cros_is_vm = false + foreach(b, string_split(cros_boards_with_qemu_images, ":")) { + if (cros_board == b) { + cros_is_vm = true + } + } + + if (!defined(deploy_chrome)) { + deploy_chrome = false + } + + if (is_tast || cros_is_vm || deploy_chrome) { + foreach(m, _symlink_targets_map) { + if (cros_board == m[0]) { + _symlink_targets = [] + _symlink_targets = m[1] + } + } + + if (is_tast) { + _tast_sdk_items = [ + _symlink_targets[0], + _symlink_targets[1], + ] + } + if (deploy_chrome) { + _toolchain_sdk_items = [ + _symlink_targets[2], + _symlink_targets[3], + ] + } + if (cros_is_vm) { + _vm_sdk_items = [ + _symlink_targets[4], + _symlink_targets[5], + _symlink_targets[6], + ] + } + } + } # TODO(crbug.com/1112471): Get this to run cleanly under Python 3. python2_action(target_name) { @@ -171,21 +263,25 @@ args += [ "--deploy-chrome" ] } + if (is_chromeos_lacros) { + args += [ "--deploy-lacros" ] + } + # If we're in the cros chrome-sdk (and not the raw ebuild), the test will # need some additional runtime data located in the SDK cache. if (cros_sdk_version != "") { # Add the VM/QEMU-launching bits if needed. if (cros_is_vm) { - data += vm_sdk_items + data += _vm_sdk_items } if (is_tast) { - data += tast_sdk_items + data += _tast_sdk_items } if (deploy_chrome) { # To deploy chrome to the VM, it needs to be stripped down to fit into # the VM. This is done by using binutils in the toolchain. So add the # toolchain to the data. - data += toolchain_sdk_items + data += _toolchain_sdk_items } } @@ -223,6 +319,14 @@ ] } } + if (defined(tast_vars)) { + foreach(var, tast_vars) { + args += [ + "--tast-var", + var, + ] + } + } } } } @@ -278,6 +382,39 @@ "//third_party/breakpad:minidump_dump", "//third_party/breakpad:minidump_stackwalk", ] + + data = [ "//components/crash/content/tools/generate_breakpad_symbols.py" ] + } +} + +template("lacros_tast_test") { + forward_variables_from(invoker, + [ + "override_board", + "tast_tests", + ]) + generate_runner_script(target_name) { + testonly = true + generated_script = "$root_build_dir/bin/run_${target_name}" + runtime_deps_file = "$root_out_dir/${target_name}.runtime_deps" + + # By default, tast tests download a lacros-chrome from a gcs location and + # use it for testing. To support running lacros tast tests from Chromium CI, + # a Var is added to support pointing the tast tests to use a specified + # pre-deployed lacros-chrome. The location is decided by: + # https://source.chromium.org/chromium/chromium/src/+/master:third_party/chromite/scripts/deploy_chrome.py;l=80;drc=86f1234a4be8e9574442e076cdc835897f7bea61 + tast_vars = [ "lacrosDeployedBinary=/usr/local/lacros-chrome" ] + data_deps = [ + "//chrome", # Builds the browser. + + # Tools used to symbolize Chrome crash dumps. + # TODO(crbug.com/1156772): Remove these if/when all tests pick them up by + # default. + "//third_party/breakpad:dump_syms", + "//third_party/breakpad:minidump_dump", + "//third_party/breakpad:minidump_stackwalk", + ] + data = [ "//components/crash/content/tools/generate_breakpad_symbols.py" ] } }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 61486b9b..55b0b0b 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -0.20210114.3.1 +0.20210115.0.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 61486b9b..55b0b0b 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -0.20210114.3.1 +0.20210115.0.1
diff --git a/cc/OWNERS b/cc/OWNERS index 3eec17e2..3b3a9427 100644 --- a/cc/OWNERS +++ b/cc/OWNERS
@@ -36,7 +36,6 @@ smcgruer@chromium.org # images -khushalsagar@chromium.org vmpstr@chromium.org # surfaces
diff --git a/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/cc/mojo_embedder/async_layer_tree_frame_sink.cc index 452bb737..0a09747 100644 --- a/cc/mojo_embedder/async_layer_tree_frame_sink.cc +++ b/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -275,9 +275,10 @@ DCHECK(compositor_frame_sink_ptr_); if (needs_begin_frames_ != needs_begin_frames) { if (needs_begin_frames_) { - TRACE_EVENT_ASYNC_END0("cc,benchmark", "NeedsBeginFrames", this); + TRACE_EVENT_NESTABLE_ASYNC_END0("cc,benchmark", "NeedsBeginFrames", this); } else { - TRACE_EVENT_ASYNC_BEGIN0("cc,benchmark", "NeedsBeginFrames", this); + TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc,benchmark", "NeedsBeginFrames", + this); } } needs_begin_frames_ = needs_begin_frames;
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 47056c31..d70a3bf 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -3441,6 +3441,7 @@ "java/src/org/chromium/chrome/browser/sharing/SharingServiceProxy.java", "java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java", "java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java", + "java/src/org/chromium/chrome/browser/signin/SigninBridge.java", "java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java", "java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java", "java/src/org/chromium/chrome/browser/signin/SigninUtils.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index c537050..4029085 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -84,11 +84,8 @@ "java/src/org/chromium/chrome/browser/app/tabmodel/AsyncTabParamsManagerSingleton.java", "java/src/org/chromium/chrome/browser/app/tabmodel/ChromeNextTabPolicySupplier.java", "java/src/org/chromium/chrome/browser/app/tabmodel/ChromeTabModelFilterFactory.java", - "java/src/org/chromium/chrome/browser/app/tabmodel/CustomTabsTabModelOrchestrator.java", "java/src/org/chromium/chrome/browser/app/tabmodel/DefaultTabModelSelectorFactory.java", - "java/src/org/chromium/chrome/browser/app/tabmodel/TabModelOrchestrator.java", "java/src/org/chromium/chrome/browser/app/tabmodel/TabWindowManagerSingleton.java", - "java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java", "java/src/org/chromium/chrome/browser/app/video_tutorials/ChromeLanguageInfoProvider.java", "java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java", "java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java", @@ -1243,6 +1240,7 @@ "java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardShareActivity.java", "java/src/org/chromium/chrome/browser/signin/SigninActivity.java", "java/src/org/chromium/chrome/browser/signin/SigninActivityLauncherImpl.java", + "java/src/org/chromium/chrome/browser/signin/SigninBridge.java", "java/src/org/chromium/chrome/browser/signin/SigninFragment.java", "java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java", "java/src/org/chromium/chrome/browser/signin/SigninHelperProvider.java",
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java index 90a43500..a661385 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java
@@ -110,12 +110,13 @@ } @Override - public void getModuleEntry(Tab tab, Callback<AutofillAssistantModuleEntry> callback) { + public void getModuleEntry( + Tab tab, Callback<AutofillAssistantModuleEntry> callback, boolean showUi) { if (mCannotInstall) { callback.onResult(null); return; } mNotInstalled = false; - super.getModuleEntry(tab, callback); + super.getModuleEntry(tab, callback, showUi); } }
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java index 934a8da7..91c3e79 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java
@@ -216,7 +216,7 @@ mModuleEntryProvider.getModuleEntry(tab, (entry) -> { mDelegate = createDelegate(entry); callback.onResult(mDelegate); - }); + }, /* showUi = */ true); } /** Creates a delegate from the given {@link AutofillAssistantModuleEntry}, if possible. */
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java index 754ec9f1..db5d89d9 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -133,36 +133,45 @@ } if (AutofillAssistantModuleEntryProvider.INSTANCE.getModuleEntryIfInstalled() - == null) { - // Opt-out users who don't have DFM installed. - AutofillAssistantMetrics.recordLiteScriptStarted( - tab.getWebContents(), LiteScriptStarted.LITE_SCRIPT_DFM_UNAVAILABLE); + == null + && arguments.containsTriggerScript() + && !ChromeFeatureList.isEnabled( + ChromeFeatureList + .AUTOFILL_ASSISTANT_LOAD_DFM_FOR_TRIGGER_SCRIPTS)) { return; } } - AutofillAssistantModuleEntryProvider.INSTANCE.getModuleEntry( - tab, (moduleEntry) -> { - if (moduleEntry == null || activity.isActivityFinishingOrDestroyed()) { - AutofillAssistantMetrics.recordDropOut( - DropOutReason.DFM_INSTALL_FAILED); - return; + if (AutofillAssistantModuleEntryProvider.INSTANCE.getModuleEntryIfInstalled() == null) { + AutofillAssistantModuleEntryProvider.INSTANCE.getModuleEntry(tab, (moduleEntry) -> { + if (moduleEntry == null || activity.isActivityFinishingOrDestroyed()) { + AutofillAssistantMetrics.recordDropOut(DropOutReason.DFM_INSTALL_FAILED); + if (arguments.containsTriggerScript()) { + AutofillAssistantMetrics.recordLiteScriptFinished(tab.getWebContents(), + LiteScriptStarted.LITE_SCRIPT_DFM_UNAVAILABLE); } - - moduleEntry.start( - BottomSheetControllerProvider.from(activity.getWindowAndroid()), - activity.getBrowserControlsManager(), - activity.getCompositorViewHolder(), activity, tab.getWebContents(), - activity.getWindowAndroid().getKeyboardDelegate(), - activity.getWindowAndroid().getApplicationBottomInsetProvider(), - activity.getActivityTabProvider(), - activity instanceof CustomTabActivity, arguments.getInitialUrl(), - arguments.getParameters(), arguments.getExperimentIds(), - arguments.getCallerAccount(), arguments.getUserName()); - }); + return; + } + start(activity, arguments, moduleEntry); + }, /* showUi = */ !arguments.containsTriggerScript()); + } else { + start(activity, arguments, + AutofillAssistantModuleEntryProvider.INSTANCE.getModuleEntryIfInstalled()); + } }); } + private static void start(ChromeActivity activity, AutofillAssistantArguments arguments, + AutofillAssistantModuleEntry module) { + module.start(BottomSheetControllerProvider.from(activity.getWindowAndroid()), + activity.getBrowserControlsManager(), activity.getCompositorViewHolder(), activity, + activity.getCurrentWebContents(), activity.getWindowAndroid().getKeyboardDelegate(), + activity.getWindowAndroid().getApplicationBottomInsetProvider(), + activity.getActivityTabProvider(), activity instanceof CustomTabActivity, + arguments.getInitialUrl(), arguments.getParameters(), arguments.getExperimentIds(), + arguments.getCallerAccount(), arguments.getUserName()); + } + /** * Checks whether direct actions provided by Autofill Assistant should be available - assuming * that direct actions are available at all.
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java index d536aa8..29d84e0 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java
@@ -42,7 +42,7 @@ /** Gets the AA module entry, installing it if necessary. */ /* package */ - void getModuleEntry(Tab tab, Callback<AutofillAssistantModuleEntry> callback) { + void getModuleEntry(Tab tab, Callback<AutofillAssistantModuleEntry> callback, boolean showUi) { AutofillAssistantModuleEntry entry = getModuleEntryIfInstalled(); if (entry != null) { AutofillAssistantMetrics.recordFeatureModuleInstallation( @@ -50,7 +50,7 @@ callback.onResult(entry); return; } - loadDynamicModuleWithUi(tab, callback); + loadDynamicModule(tab, callback, showUi); } /** @@ -83,14 +83,14 @@ AutofillAssistantModule.installDeferred(); } - private static void loadDynamicModuleWithUi( - Tab tab, Callback<AutofillAssistantModuleEntry> callback) { + private static void loadDynamicModule( + Tab tab, Callback<AutofillAssistantModuleEntry> callback, boolean showUi) { ModuleInstallUi ui = new ModuleInstallUi(tab, R.string.autofill_assistant_module_title, new ModuleInstallUi.FailureUiListener() { @Override public void onFailureUiResponse(boolean retry) { if (retry) { - loadDynamicModuleWithUi(tab, callback); + loadDynamicModule(tab, callback, showUi); } else { AutofillAssistantMetrics.recordFeatureModuleInstallation( FeatureModuleInstallation.DFM_FOREGROUND_INSTALLATION_FAILED); @@ -98,8 +98,11 @@ } } }); - // Shows toast informing user about install start. - ui.showInstallStartUi(); + if (showUi) { + // Shows toast informing user about install start. + ui.showInstallStartUi(); + } + AutofillAssistantModule.install((success) -> { if (success) { // Don't show success UI from DFM, transition to Autofill Assistant UI directly. @@ -107,9 +110,12 @@ FeatureModuleInstallation.DFM_FOREGROUND_INSTALLATION_SUCCEEDED); callback.onResult(AutofillAssistantModule.getImpl()); return; + } else if (showUi) { + // Show inforbar to ask user if they want to retry or cancel. + ui.showInstallFailureUi(); + } else { + callback.onResult(null); } - // Show inforbar to ask user if they want to retry or cancel. - ui.showInstallFailureUi(); }); } }
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java index d346ec3e..033b89e 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
@@ -57,7 +57,6 @@ import android.os.Build; import android.support.test.InstrumentationRegistry; import android.support.test.uiautomator.UiDevice; -import android.text.TextUtils; import android.view.View; import android.widget.ImageView; @@ -135,6 +134,7 @@ import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; +import org.chromium.components.embedder_support.util.UrlUtilities; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.WebContentsUtils; @@ -587,10 +587,9 @@ }, "Overview not hidden yet"); int delta; if (switchToAnotherTab - && !TextUtils.equals(mActivityTestRule.getActivity() - .getCurrentWebContents() - .getLastCommittedUrl(), - NTP_URL)) { + && !UrlUtilities.isNTPUrl(mActivityTestRule.getActivity() + .getCurrentWebContents() + .getLastCommittedUrl())) { // Capture the original tab. delta = 1; } else { @@ -2130,9 +2129,9 @@ // Make sure the fading animation is done. int delta; - if (TextUtils.equals( - mActivityTestRule.getActivity().getCurrentWebContents().getLastCommittedUrl(), - NTP_URL)) { + if (UrlUtilities.isNTPUrl(mActivityTestRule.getActivity() + .getCurrentWebContents() + .getLastCommittedUrl())) { // NTP is not invalidated, so no new captures. delta = 0; } else { @@ -2187,9 +2186,9 @@ private void checkFinalCaptureCount(boolean switchToAnotherTab, int initCount) { int expected; - if (TextUtils.equals( - mActivityTestRule.getActivity().getCurrentWebContents().getLastCommittedUrl(), - NTP_URL)) { + if (UrlUtilities.isNTPUrl(mActivityTestRule.getActivity() + .getCurrentWebContents() + .getLastCommittedUrl())) { expected = 0; } else { expected = mRepeat;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index e668a43..7372a35 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -60,9 +60,7 @@ import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton; import org.chromium.chrome.browser.app.tabmodel.ChromeNextTabPolicySupplier; -import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator; import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton; -import org.chromium.chrome.browser.app.tabmodel.TabbedModeTabModelOrchestrator; import org.chromium.chrome.browser.bookmarks.BookmarkUtils; import org.chromium.chrome.browser.compositor.CompositorViewHolder; import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCoordinator; @@ -249,7 +247,6 @@ private ToolbarControlContainer mControlContainer; - private TabbedModeTabModelOrchestrator mTabModelOrchestrator; private TabModelSelectorImpl mTabModelSelectorImpl; private TabModelSelectorTabObserver mTabModelSelectorTabObserver; private TabModelSelectorTabModelObserver mTabModelObserver; @@ -1626,13 +1623,7 @@ } @Override - protected TabModelOrchestrator createTabModelOrchestrator() { - mTabModelOrchestrator = new TabbedModeTabModelOrchestrator(); - return mTabModelOrchestrator; - } - - @Override - protected void createTabModels() { + protected TabModelSelector createTabModelSelector() { assert mTabModelSelectorImpl == null; Bundle savedInstanceState = getSavedInstanceState(); @@ -1643,15 +1634,17 @@ int index = savedInstanceState != null ? savedInstanceState.getInt(WINDOW_INDEX, 0) : 0; mNextTabPolicySupplier = new ChromeNextTabPolicySupplier(mOverviewModeBehaviorSupplier); - - boolean tabModelWasCreated = - mTabModelOrchestrator.createTabModels(this, this, mNextTabPolicySupplier, index); - if (!tabModelWasCreated) { + mTabModelSelectorImpl = + (TabModelSelectorImpl) TabWindowManagerSingleton.getInstance().requestSelector( + this, this, mNextTabPolicySupplier, index); + if (mTabModelSelectorImpl == null) { + Toast.makeText( + this, getString(R.string.unsupported_number_of_windows), Toast.LENGTH_LONG) + .show(); finish(); - return; + return null; } - mTabModelSelectorImpl = mTabModelOrchestrator.getTabModelSelector(); mTabModelSelectorImpl.addObserver(new EmptyTabModelSelectorObserver() { @Override public void onTabStateInitialized() { @@ -1675,6 +1668,8 @@ mAppIndexingUtil = new AppIndexingUtil(mTabModelSelectorImpl); if (startIncognito) mTabModelSelectorImpl.selectModel(true); + + return mTabModelSelectorImpl; } @Override @@ -2224,13 +2219,6 @@ } @Override - protected void destroyTabModels() { - if (mTabModelOrchestrator != null) { - mTabModelOrchestrator.destroy(); - } - } - - @Override public void onTrimMemory(int level) { super.onTrimMemory(level); if (ChromeApplication.isSevereMemorySignal(level)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java index afa7f5d..706fc1f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -71,7 +71,6 @@ import org.chromium.chrome.browser.app.tab_activity_glue.ReparentingDelegateFactory; import org.chromium.chrome.browser.app.tab_activity_glue.TabReparentingController; import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton; -import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator; import org.chromium.chrome.browser.bookmarks.BookmarkBridge; import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem; import org.chromium.chrome.browser.bookmarks.BookmarkModel; @@ -242,7 +241,7 @@ new TabModelSelectorProfileSupplier(mTabModelSelectorSupplier); protected ObservableSupplierImpl<BookmarkBridge> mBookmarkBridgeSupplier = new ObservableSupplierImpl<>(); - private TabModelOrchestrator mTabModelOrchestrator; + private TabModelSelector mTabModelSelector; private TabModelSelectorTabObserver mTabModelSelectorTabObserver; private TabCreator mRegularTabCreator; private TabCreator mIncognitoTabCreator; @@ -264,6 +263,7 @@ /** Whether or not {@link #postDeferredStartupIfNeeded()} has already successfully run. */ private boolean mDeferredStartupPosted; + private boolean mTabModelsInitialized; private boolean mNativeInitialized; private boolean mRemoveWindowBackgroundDone; protected AccessibilityVisibilityHandler mAccessibilityVisibilityHandler; @@ -358,9 +358,6 @@ // onPreInflationStartup event. mComponent = createComponent(); - // Create the orchestrator that manages Tab models and persistence - mTabModelOrchestrator = createTabModelOrchestrator(); - // There's no corresponding call to removeObserver() for this addObserver() because // mTabModelProfileSupplier has the same lifecycle as this activity. mTabModelProfileSupplier.addObserver((profile) -> { @@ -491,10 +488,9 @@ mCompositorViewHolder.getCompositorView()); initializeTabModels(); - TabModelSelector tabModelSelector = mTabModelOrchestrator.getTabModelSelector(); setTabContentManager(new TabContentManager(this, getContentOffsetProvider(), !SysUtils.isLowEndDevice(), - tabModelSelector != null ? tabModelSelector::getTabById : null)); + mTabModelSelector != null ? mTabModelSelector::getTabById : null)); if (!isFinishing()) { getBrowserControlsManager().initialize( @@ -656,28 +652,28 @@ * this activity. */ public final void initializeTabModels() { - if (mTabModelOrchestrator.areTabModelsInitialized()) return; + if (mTabModelsInitialized) return; - createTabModels(); - TabModelSelector tabModelSelector = mTabModelOrchestrator.getTabModelSelector(); + mTabModelSelector = createTabModelSelector(); - if (tabModelSelector == null) { + if (mTabModelSelector == null) { assert isFinishing(); + mTabModelsInitialized = true; return; } - mTabModelSelectorSupplier.set(tabModelSelector); - mActivityTabProvider.setTabModelSelector(tabModelSelector); - getStatusBarColorController().setTabModelSelector(tabModelSelector); + mTabModelSelectorSupplier.set(mTabModelSelector); + mActivityTabProvider.setTabModelSelector(mTabModelSelector); + getStatusBarColorController().setTabModelSelector(mTabModelSelector); Pair<? extends TabCreator, ? extends TabCreator> tabCreators = createTabCreators(); mRegularTabCreator = tabCreators.first; mIncognitoTabCreator = tabCreators.second; - OfflinePageUtils.observeTabModelSelector(this, tabModelSelector); + OfflinePageUtils.observeTabModelSelector(this, mTabModelSelector); if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.destroy(); - mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(tabModelSelector) { + mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(mTabModelSelector) { @Override public void onLoadStopped(Tab tab, boolean toDifferentDocument) { postDeferredStartupIfNeeded(); @@ -694,6 +690,8 @@ postDeferredStartupIfNeeded(); } }; + + mTabModelsInitialized = true; } /** @@ -709,19 +707,9 @@ } /** - * @return The {@link TabModelOrchestrator} owned by this {@link ChromeActivity}. + * @return The {@link TabModelSelector} owned by this {@link ChromeActivity}. */ - protected abstract TabModelOrchestrator createTabModelOrchestrator(); - - /** - * Call the {@link TabModelOrchestrator} to initialize its members. - */ - protected abstract void createTabModels(); - - /** - * Call the {@link TabModelOrchestrator} to destroy its members. - */ - protected abstract void destroyTabModels(); + protected abstract TabModelSelector createTabModelSelector(); /** * @return The {@link TabCreator}s owned @@ -860,8 +848,7 @@ VrModuleProvider.getDelegate().onActivityHidden(this); Tab tab = getActivityTab(); - TabModelSelector tabModelSelector = mTabModelOrchestrator.getTabModelSelector(); - if (tabModelSelector != null && !tabModelSelector.isReparentingInProgress() + if (mTabModelSelector != null && !mTabModelSelector.isReparentingInProgress() && tab != null) { tab.hide(TabHidingType.ACTIVITY_HIDDEN); } @@ -1325,7 +1312,10 @@ mActivityTabStartupMetricsTracker = null; } - destroyTabModels(); + if (mTabModelsInitialized) { + TabModelSelector selector = getTabModelSelector(); + if (selector != null) selector.destroy(); + } if (mBookmarkBridgeSupplier != null) { BookmarkBridge bookmarkBridge = mBookmarkBridgeSupplier.get(); @@ -1601,7 +1591,7 @@ * @return Whether the tab models have been fully initialized. */ public boolean areTabModelsInitialized() { - return mTabModelOrchestrator.areTabModelsInitialized(); + return mTabModelsInitialized; } /** @@ -1610,11 +1600,11 @@ * @return The {@link TabModelSelector}, possibly null. */ public TabModelSelector getTabModelSelector() { - if (!mTabModelOrchestrator.areTabModelsInitialized()) { + if (!mTabModelsInitialized) { throw new IllegalStateException( "Attempting to access TabModelSelector before initialization"); } - return mTabModelOrchestrator.getTabModelSelector(); + return mTabModelSelector; } /** @@ -1635,7 +1625,7 @@ @Override public TabCreator getTabCreator(boolean incognito) { - if (!mTabModelOrchestrator.areTabModelsInitialized()) { + if (!mTabModelsInitialized) { throw new IllegalStateException( "Attempting to access TabCreator before initialization"); } @@ -1702,7 +1692,7 @@ * null if the Tab does not exist or the system is not initialized. */ public Tab getActivityTab() { - if (!mTabModelOrchestrator.areTabModelsInitialized()) { + if (!mTabModelsInitialized) { return null; } return TabModelUtils.getCurrentTab(getCurrentTabModel()); @@ -1713,7 +1703,7 @@ * WebContents. */ public WebContents getCurrentWebContents() { - if (!mTabModelOrchestrator.areTabModelsInitialized()) { + if (!mTabModelsInitialized) { return null; } return TabModelUtils.getCurrentWebContents(getCurrentTabModel()); @@ -2037,7 +2027,7 @@ if (id == R.id.help_id) { String url = currentTab != null ? currentTab.getUrlString() : ""; - Profile profile = getTabModelSelector().isIncognitoSelected() + Profile profile = mTabModelSelector.isIncognitoSelected() ? Profile.getLastUsedRegularProfile().getPrimaryOTRProfile() : Profile.getLastUsedRegularProfile(); startHelpAndFeedback(url, "MobileMenuFeedback", profile);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CustomTabsTabModelOrchestrator.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CustomTabsTabModelOrchestrator.java deleted file mode 100644 index b319dbb..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CustomTabsTabModelOrchestrator.java +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.app.tabmodel; - -import androidx.annotation.Nullable; - -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.dependency_injection.ActivityScope; -import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager; -import org.chromium.chrome.browser.tabmodel.NextTabPolicy; -import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier; -import org.chromium.chrome.browser.tabmodel.TabCreatorManager; -import org.chromium.chrome.browser.tabmodel.TabModelFilterFactory; -import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; -import org.chromium.chrome.browser.tabmodel.TabPersistencePolicy; -import org.chromium.chrome.browser.tabmodel.TabPersistentStore; -import org.chromium.ui.base.WindowAndroid; - -import javax.inject.Inject; - -/** - * Glue-level class that manages lifetime of root .tabmodel objects: {@link TabPersistentStore} and - * {@link TabModelSelectorImpl} for custom tabs. - */ -@ActivityScope -public class CustomTabsTabModelOrchestrator extends TabModelOrchestrator { - @Inject - public CustomTabsTabModelOrchestrator() {} - - /** - * Creates the TabModelSelector and the TabPersistentStore. - */ - public void createTabModels(@Nullable Supplier<WindowAndroid> windowAndroidSupplier, - TabCreatorManager tabCreatorManager, TabModelFilterFactory tabModelFilterFactory, - TabPersistencePolicy persistencePolicy, AsyncTabParamsManager asyncTabParamsManager) { - // Instantiate TabModelSelectorImpl - NextTabPolicySupplier nextTabPolicySupplier = () -> NextTabPolicy.LOCATIONAL; - mTabModelSelector = new TabModelSelectorImpl(windowAndroidSupplier, tabCreatorManager, - tabModelFilterFactory, nextTabPolicySupplier, asyncTabParamsManager, false, false, - false); - - // Instantiate TabPersistentStore - mTabPersistentStore = - new TabPersistentStore(persistencePolicy, mTabModelSelector, tabCreatorManager); - - wireSelectorAndStore(); - markTabModelsInitialized(); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/DefaultTabModelSelectorFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/DefaultTabModelSelectorFactory.java index 41f14d8..9a4f7363 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/DefaultTabModelSelectorFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/DefaultTabModelSelectorFactory.java
@@ -5,15 +5,19 @@ package org.chromium.chrome.browser.app.tabmodel; import android.app.Activity; +import android.os.Build; import org.chromium.base.annotations.VerifiesOnN; -import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager; +import org.chromium.chrome.browser.multiwindow.MultiInstanceManager; +import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; import org.chromium.chrome.browser.tabmodel.TabModelFilterFactory; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorFactory; import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; +import org.chromium.chrome.browser.tabmodel.TabPersistencePolicy; +import org.chromium.chrome.browser.tabmodel.TabbedModeTabPersistencePolicy; /** * Default {@link TabModelSelectorFactory} for Chrome. @@ -25,11 +29,32 @@ @Override public TabModelSelector buildSelector(Activity activity, TabCreatorManager tabCreatorManager, NextTabPolicySupplier nextTabPolicySupplier, int selectorIndex) { + // Merge tabs if this TabModelSelector is for a ChromeTabbedActivity created in + // fullscreen mode and there are no TabModelSelector's currently alive. This indicates + // that it is a cold start or process restart in fullscreen mode. + boolean mergeTabs = Build.VERSION.SDK_INT > Build.VERSION_CODES.M + && MultiInstanceManager.isTabModelMergingEnabled() + && !activity.isInMultiWindowMode(); + if (MultiInstanceManager.shouldMergeOnStartup(activity)) { + mergeTabs = mergeTabs + && (!MultiWindowUtils.getInstance().isInMultiDisplayMode(activity) + || TabWindowManagerSingleton.getInstance() + .getNumberOfAssignedTabModelSelectors() + == 0); + } else { + mergeTabs = mergeTabs + && TabWindowManagerSingleton.getInstance() + .getNumberOfAssignedTabModelSelectors() + == 0; + } + if (mergeTabs) { + MultiInstanceManager.mergedOnStartup(); + } + TabPersistencePolicy persistencePolicy = + new TabbedModeTabPersistencePolicy(selectorIndex, mergeTabs); TabModelFilterFactory tabModelFilterFactory = new ChromeTabModelFilterFactory(); - AsyncTabParamsManager asyncTabParamsManager = AsyncTabParamsManagerSingleton.getInstance(); - - return new TabModelSelectorImpl(/*windowAndroidSupplier=*/null, tabCreatorManager, - tabModelFilterFactory, nextTabPolicySupplier, asyncTabParamsManager, true, true, - false); + return new TabModelSelectorImpl(activity, /*windowAndroidSupplier=*/null, tabCreatorManager, + persistencePolicy, tabModelFilterFactory, nextTabPolicySupplier, + AsyncTabParamsManagerSingleton.getInstance(), true, true, false); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabModelOrchestrator.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabModelOrchestrator.java deleted file mode 100644 index e91d8cc..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabModelOrchestrator.java +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.app.tabmodel; - -import org.chromium.base.supplier.ObservableSupplierImpl; -import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; -import org.chromium.chrome.browser.tabmodel.TabPersistentStore; -import org.chromium.chrome.browser.tabmodel.TabPersistentStore.TabPersistentStoreObserver; - -/** - * Implementers are glue-level objects that manage lifetime of root .tabmodel objects: {@link - * TabPersistentStore} and {@link TabModelSelectorImpl}. - */ -public abstract class TabModelOrchestrator { - protected TabPersistentStore mTabPersistentStore; - protected TabModelSelectorImpl mTabModelSelector; - private boolean mTabModelsInitialized; - - /** - * @return Whether the tab models have been fully initialized. - */ - public boolean areTabModelsInitialized() { - return mTabModelsInitialized; - } - - /** - * @return The {@link TabModelSelectorImpl} managed by this orchestrator. - */ - public TabModelSelectorImpl getTabModelSelector() { - return mTabModelSelector; - } - - /** - * Destroy the {@link TabPersistentStore} and {@link TabModelSelectorImpl} members. - */ - public void destroy() { - if (!mTabModelsInitialized) { - return; - } - - if (mTabPersistentStore != null) { - mTabPersistentStore.destroy(); - mTabPersistentStore = null; - } - - if (mTabModelSelector != null) { - mTabModelSelector.destroy(); - mTabModelSelector = null; - } - - mTabModelsInitialized = false; - } - - protected void wireSelectorAndStore() { - // Supply TabModelSelectorImpl with TabPersistentStore. - // - // TODO(crbug.com/1138561): Remove this dependency by making TabModelSelectorImpl emit - // events and TabPersistentStore react to them as an observer. - ObservableSupplierImpl<TabPersistentStore> tabPersistentStoreSupplier = - new ObservableSupplierImpl<>(); - tabPersistentStoreSupplier.set(mTabPersistentStore); - mTabModelSelector.setTabPersistentStoreSupplier(tabPersistentStoreSupplier); - - // Notify TabModelSelectorImpl when TabPersistentStore initializes tab state - final TabPersistentStoreObserver persistentStoreObserver = - new TabPersistentStoreObserver() { - @Override - public void onStateLoaded() { - mTabModelSelector.markTabStateInitialized(); - } - }; - mTabPersistentStore.addObserver(persistentStoreObserver); - } - - protected void markTabModelsInitialized() { - mTabModelsInitialized = true; - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java deleted file mode 100644 index 11fe7e67..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java +++ /dev/null
@@ -1,90 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.app.tabmodel; - -import android.app.Activity; -import android.os.Build; -import android.util.Pair; - -import org.chromium.chrome.browser.multiwindow.MultiInstanceManager; -import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; -import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier; -import org.chromium.chrome.browser.tabmodel.TabCreatorManager; -import org.chromium.chrome.browser.tabmodel.TabModelSelector; -import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; -import org.chromium.chrome.browser.tabmodel.TabPersistencePolicy; -import org.chromium.chrome.browser.tabmodel.TabPersistentStore; -import org.chromium.chrome.browser.tabmodel.TabbedModeTabPersistencePolicy; -import org.chromium.ui.widget.Toast; - -/** - * Glue-level class that manages lifetime of root .tabmodel objects: {@link TabPersistentStore} and - * {@link TabModelSelectorImpl} for tabbed mode. - */ -public class TabbedModeTabModelOrchestrator extends TabModelOrchestrator { - public TabbedModeTabModelOrchestrator() {} - - /** - * Creates the TabModelSelector and the TabPersistentStore. - * - * @return Whether the creation was successful. It may fail is we reached the limit of number of - * windows. - */ - public boolean createTabModels(Activity activity, TabCreatorManager tabCreatorManager, - NextTabPolicySupplier nextTabPolicySupplier, int selectorIndex) { - boolean mergeTabs = shouldMergeTabs(activity); - if (mergeTabs) { - MultiInstanceManager.mergedOnStartup(); - } - - // Instantiate TabModelSelectorImpl - Pair<Integer, TabModelSelector> selectorAssignment = - TabWindowManagerSingleton.getInstance().requestSelector( - activity, tabCreatorManager, nextTabPolicySupplier, selectorIndex); - int assignedIndex = selectorAssignment.first; - mTabModelSelector = (TabModelSelectorImpl) selectorAssignment.second; - if (mTabModelSelector == null) { - markTabModelsInitialized(); - Toast.makeText(activity, - activity.getString( - org.chromium.chrome.R.string.unsupported_number_of_windows), - Toast.LENGTH_LONG) - .show(); - return false; - } - - // Instantiate TabPersistentStore - TabPersistencePolicy tabPersistencePolicy = - new TabbedModeTabPersistencePolicy(assignedIndex, mergeTabs); - mTabPersistentStore = - new TabPersistentStore(tabPersistencePolicy, mTabModelSelector, tabCreatorManager); - - wireSelectorAndStore(); - markTabModelsInitialized(); - return true; - } - - private boolean shouldMergeTabs(Activity activity) { - // Merge tabs if this TabModelSelector is for a ChromeTabbedActivity created in - // fullscreen mode and there are no TabModelSelector's currently alive. This indicates - // that it is a cold start or process restart in fullscreen mode. - boolean mergeTabs = Build.VERSION.SDK_INT > Build.VERSION_CODES.M - && MultiInstanceManager.isTabModelMergingEnabled() - && !activity.isInMultiWindowMode(); - if (MultiInstanceManager.shouldMergeOnStartup(activity)) { - mergeTabs = mergeTabs - && (!MultiWindowUtils.getInstance().isInMultiDisplayMode(activity) - || TabWindowManagerSingleton.getInstance() - .getNumberOfAssignedTabModelSelectors() - == 0); - } else { - mergeTabs = mergeTabs - && TabWindowManagerSingleton.getInstance() - .getNumberOfAssignedTabModelSelectors() - == 0; - } - return mergeTabs; - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java index 8166ec2..2ad2546 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -11,11 +11,9 @@ import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnGlobalFocusChangeListener; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; - import org.chromium.base.Log; import org.chromium.base.ObserverList; import org.chromium.base.SysUtils; @@ -70,9 +68,6 @@ import org.chromium.ui.touch_selection.SelectionEventType; import org.chromium.url.GURL; -import java.net.MalformedURLException; -import java.net.URL; - /** * Manages the Contextual Search feature. This class keeps track of the status of Contextual * Search and coordinates the control with the layout. @@ -378,16 +373,12 @@ return mSelectionController.getBaseWebContents(); } - /** @return The Base Page's {@link URL}. */ + /** @return The Base Page's {@link GURL}. */ @Nullable - private URL getBasePageURL() { + private GURL getBasePageURL() { WebContents baseWebContents = mSelectionController.getBaseWebContents(); if (baseWebContents == null) return null; - try { - return new URL(baseWebContents.getVisibleUrl().getSpec()); - } catch (MalformedURLException e) { - return null; - } + return baseWebContents.getVisibleUrl(); } /** Notifies that the base page has started loading a page. */ @@ -539,15 +530,10 @@ @Override @Nullable - public URL getBasePageUrl() { + public GURL getBasePageUrl() { WebContents baseWebContents = getBaseWebContents(); if (baseWebContents == null) return null; - - try { - return new URL(baseWebContents.getLastCommittedUrl()); - } catch (MalformedURLException e) { - return null; - } + return baseWebContents.getLastCommittedUrl(); } /** Accessor for the {@code InfoBarContainer} currently attached to the {@code Tab}. */ @@ -1232,7 +1218,9 @@ // this problem, we are ignoring tap gestures in the Search Bar if we don't know what // to search for. if (mSearchRequest != null && getSearchPanelWebContents() != null) { - String url = getContentViewUrl(getSearchPanelWebContents()); + GURL gurl = getContentViewUrl(getSearchPanelWebContents()); + // TODO(yfriedman): crbug/783819 - Finish ContextualSearch migration to gurl. + String url = gurl.getSpec(); // If it's a search URL, format it so the SearchBox becomes visible. if (mSearchRequest.isContextualSearchUrl(url)) { @@ -1253,11 +1241,11 @@ * @param searchWebContents The given WebContents. * @return The current loaded URL. */ - private String getContentViewUrl(WebContents searchWebContents) { + private GURL getContentViewUrl(WebContents searchWebContents) { // First, check the pending navigation entry, because there might be an navigation // not yet committed being processed. Otherwise, get the URL from the WebContents. NavigationEntry entry = searchWebContents.getNavigationController().getPendingEntry(); - return entry != null ? entry.getUrl().getSpec() : searchWebContents.getLastCommittedUrl(); + return entry != null ? entry.getUrl() : searchWebContents.getLastCommittedUrl(); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java index 31d2ea6..9dd4977 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java
@@ -6,7 +6,7 @@ import androidx.annotation.Nullable; -import java.net.URL; +import org.chromium.url.GURL; /** * An interface for network communication between the Contextual Search client and server. @@ -50,5 +50,6 @@ * This is needed to stub out for testing, but has nothing to do with networking. * @return The URL of the base page (needed for testing purposes). */ - @Nullable URL getBasePageUrl(); + @Nullable + GURL getBasePageUrl(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java index 07d93a9..0ae2a66 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -28,8 +28,9 @@ import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge; import org.chromium.chrome.browser.version.ChromeVersionInfo; import org.chromium.components.embedder_support.util.UrlConstants; +import org.chromium.components.embedder_support.util.UrlUtilities; +import org.chromium.url.GURL; -import java.net.URL; import java.util.HashSet; import java.util.regex.Pattern; @@ -349,7 +350,7 @@ // and it's also possible that public pages, e.g. news, have more searches for multi-word // entities like people. if (!isUserUndecided()) { - URL url = mNetworkCommunicator.getBasePageUrl(); + GURL url = mNetworkCommunicator.getBasePageUrl(); ContextualSearchUma.logBasePageProtocol(isBasePageHTTP(url)); boolean isSingleWord = !CONTAINS_WHITESPACE_PATTERN.matcher(searchTerm.trim()).find(); ContextualSearchUma.logSearchTermResolvedWords(isSingleWord); @@ -388,10 +389,9 @@ if (!TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle()) return false; // Only allow HTTP or HTTPS URLs. - URL url = mNetworkCommunicator.getBasePageUrl(); - String urlProtocol = url != null ? url.getProtocol() : ""; - if (!(urlProtocol.equals(UrlConstants.HTTP_SCHEME) - || urlProtocol.equals(UrlConstants.HTTPS_SCHEME))) { + GURL url = mNetworkCommunicator.getBasePageUrl(); + + if (url == null || !UrlUtilities.isHttpOrHttps(url)) { return false; } @@ -523,8 +523,8 @@ * @param url The URL of the base page. * @return Whether the given content view is for an HTTP page. */ - boolean isBasePageHTTP(@Nullable URL url) { - return url != null && UrlConstants.HTTP_SCHEME.equals(url.getProtocol()); + boolean isBasePageHTTP(@Nullable GURL url) { + return url != null && UrlConstants.HTTP_SCHEME.equals(url.getScheme()); } // --------------------------------------------------------------------------------------------
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java index cac448e..f7e9b23a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -24,7 +24,6 @@ import org.chromium.chrome.browser.ChromeApplication; import org.chromium.chrome.browser.KeyboardShortcuts; import org.chromium.chrome.browser.app.ChromeActivity; -import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator; import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.ui.controller.Verifier; import org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityCoordinator; @@ -46,6 +45,7 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabState; import org.chromium.chrome.browser.tabmodel.ChromeTabCreator; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; import org.chromium.chrome.browser.theme.TopUiThemeColorProvider; import org.chromium.chrome.browser.ui.RootUiCoordinator; @@ -293,20 +293,8 @@ } @Override - protected TabModelOrchestrator createTabModelOrchestrator() { - return mTabFactory.createTabModelOrchestrator(); - } - - @Override - protected void destroyTabModels() { - if (mTabFactory != null) { - mTabFactory.destroyTabModelOrchestrator(); - } - } - - @Override - protected void createTabModels() { - mTabFactory.createTabModels(); + protected TabModelSelector createTabModelSelector() { + return mTabFactory.createTabModelSelector(); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java index d2427843..26188ed 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java
@@ -15,8 +15,6 @@ import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton; import org.chromium.chrome.browser.app.tabmodel.ChromeTabModelFilterFactory; -import org.chromium.chrome.browser.app.tabmodel.CustomTabsTabModelOrchestrator; -import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator; import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory; import org.chromium.chrome.browser.customtabs.CustomTabTabPersistencePolicy; @@ -28,6 +26,7 @@ import org.chromium.chrome.browser.tab.TabLaunchType; import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager; import org.chromium.chrome.browser.tabmodel.ChromeTabCreator; +import org.chromium.chrome.browser.tabmodel.NextTabPolicy; import org.chromium.chrome.browser.tabmodel.TabModelFilterFactory; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; @@ -57,7 +56,7 @@ private final Lazy<AsyncTabParamsManager> mAsyncTabParamsManager; @Nullable - private CustomTabsTabModelOrchestrator mTabModelOrchestrator; + private TabModelSelectorImpl mTabModelSelector; @Inject public CustomTabActivityTabFactory(ChromeActivity<?> activity, @@ -78,35 +77,21 @@ mAsyncTabParamsManager = asyncTabParamsManager; } - /** Creates a {@link TabModelOrchestrator} for the custom tab. */ - public TabModelOrchestrator createTabModelOrchestrator() { - mTabModelOrchestrator = new CustomTabsTabModelOrchestrator(); - return mTabModelOrchestrator; - } - - public void destroyTabModelOrchestrator() { - if (mTabModelOrchestrator != null) { - mTabModelOrchestrator.destroy(); - } - } - - /** Calls the {@link TabModelOrchestrator} to create TabModels and TabPersistentStore. */ - public void createTabModels() { - mTabModelOrchestrator.createTabModels(mActivityWindowAndroid::get, mActivity, - mTabModelFilterFactory, mPersistencePolicy, mAsyncTabParamsManager.get()); + /** Creates a {@link TabModelSelector} for the custom tab. */ + public TabModelSelectorImpl createTabModelSelector() { + mTabModelSelector = new TabModelSelectorImpl(mActivity, mActivityWindowAndroid::get, + mActivity, mPersistencePolicy, mTabModelFilterFactory, + () -> NextTabPolicy.LOCATIONAL, mAsyncTabParamsManager.get(), false, false, false); + return mTabModelSelector; } /** Returns the previously created {@link TabModelSelector}. */ public TabModelSelectorImpl getTabModelSelector() { - if (mTabModelOrchestrator == null) { + if (mTabModelSelector == null) { assert false; - createTabModelOrchestrator(); + return createTabModelSelector(); } - if (mTabModelOrchestrator.getTabModelSelector() == null) { - assert false; - createTabModels(); - } - return mTabModelOrchestrator.getTabModelSelector(); + return mTabModelSelector; } /** Creates a {@link ChromeTabCreator}s for the custom tab. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java index 521f9f8..968264e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
@@ -45,6 +45,7 @@ import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.ui.util.ColorUtils; +import org.chromium.url.GURL; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -423,8 +424,7 @@ WebContents webContents = mTab.getWebContents(); if (webContents == null) return; - String url = webContents.getLastCommittedUrl(); - if (url == null) return; + GURL url = webContents.getLastCommittedUrl(); onStartedReaderMode(); @@ -461,15 +461,14 @@ WebContents webContents = mTab.getWebContents(); if (webContents == null) return; - String url = webContents.getLastCommittedUrl(); - if (url == null) return; + GURL url = webContents.getLastCommittedUrl(); onStartedReaderMode(); DomDistillerTabUtils.distillCurrentPage(webContents); String distillerUrl = DomDistillerUrlUtils.getDistillerViewUrlFromUrl( - DOM_DISTILLER_SCHEME, url, webContents.getTitle()); + DOM_DISTILLER_SCHEME, url.getSpec(), webContents.getTitle()); CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); builder.setShowTitle(true);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java index 6e24417..f598c13 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java
@@ -10,6 +10,7 @@ import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantArguments; import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantFacade; import org.chromium.ui.base.WindowAndroid; +import org.chromium.url.GURL; /** Class for starting a password change flow in Autofill Assistant. */ public class PasswordChangeLauncher { @@ -26,7 +27,7 @@ private static final String INTENT = "PASSWORD_CHANGE"; @CalledByNative - public static void start(WindowAndroid windowAndroid, String origin, String username) { + public static void start(WindowAndroid windowAndroid, GURL origin, String username) { ChromeActivity activity = (ChromeActivity) windowAndroid.getActivity().get(); if (activity == null) { Log.v(TAG, "Failed to retrieve ChromeActivity."); @@ -34,7 +35,7 @@ } AutofillAssistantFacade.start(activity, AutofillAssistantArguments.newBuilder() - .withInitialUrl(origin) + .withInitialUrl(origin.getSpec()) .addParameter(PASSWORD_CHANGE_USERNAME_PARAMETER, username) .addParameter(INTENT_PARAMETER, INTENT) .addParameter(AutofillAssistantArguments.PARAMETER_START_IMMEDIATELY, true)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUiService.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUiService.java index c123e2f4..6866be1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUiService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUiService.java
@@ -1270,7 +1270,7 @@ final FaviconHelper faviconHelper = new FaviconHelper(); faviconHelper.getLocalFaviconImageForURL(Profile.fromWebContents(mWebContents), - mWebContents.getLastCommittedUrl(), + mWebContents.getLastCommittedUrl().getSpec(), activity.getResources().getDimensionPixelSize(R.dimen.payments_favicon_size), (bitmap, iconUrl) -> { if (bitmap == null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninBridge.java new file mode 100644 index 0000000..a51d859 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninBridge.java
@@ -0,0 +1,33 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.signin; + +import android.content.Context; + +import org.chromium.base.ThreadUtils; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.chrome.browser.sync.settings.AccountManagementFragment; +import org.chromium.components.signin.GAIAServiceType; +import org.chromium.ui.base.WindowAndroid; + +/** + * The bridge regroups methods invoked by native code to interact with Android Signin UI. + */ +final class SigninBridge { + /** + * Opens account management screen. + */ + @CalledByNative + private static void openAccountManagementScreen( + WindowAndroid windowAndroid, @GAIAServiceType int gaiaServiceType) { + ThreadUtils.assertOnUiThread(); + final Context context = windowAndroid.getContext().get(); + if (context != null) { + AccountManagementFragment.openAccountManagementScreen(context, gaiaServiceType); + } + } + + private SigninBridge() {} +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java index d6da252b..aee18a9a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
@@ -10,7 +10,6 @@ import android.os.Build; import android.provider.Settings; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.chromium.base.IntentUtils; @@ -25,13 +24,11 @@ import org.chromium.chrome.browser.signin.services.SigninMetricsUtils; import org.chromium.chrome.browser.signin.services.WebSigninBridge; import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerBottomSheetCoordinator; -import org.chromium.chrome.browser.sync.settings.AccountManagementFragment; import org.chromium.chrome.browser.tabmodel.TabCreator; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider; import org.chromium.components.signin.AccountManagerFacadeProvider; -import org.chromium.components.signin.GAIAServiceType; import org.chromium.components.signin.metrics.AccountConsistencyPromoAction; import org.chromium.ui.base.WindowAndroid; @@ -69,13 +66,9 @@ return IntentUtils.safeStartActivity(activity, new Intent(Settings.ACTION_SYNC_SETTINGS)); } - @CalledByNative - private static void openAccountManagementScreen(WindowAndroid windowAndroid, - @GAIAServiceType int gaiaServiceType, @Nullable String email) { - ThreadUtils.assertOnUiThread(); - AccountManagementFragment.openAccountManagementScreen(gaiaServiceType); - } - + /** + * TODO(crbug/1165772): Move this method to SigninBridge. + */ @CalledByNative @VisibleForTesting static void openAccountPickerBottomSheet(WindowAndroid windowAndroid, String continueUrl) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java index 8d1b68f..66e9629 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
@@ -21,7 +21,6 @@ import androidx.preference.PreferenceScreen; import org.chromium.base.ApiCompatibilityUtils; -import org.chromium.base.ContextUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.preferences.Pref; @@ -449,11 +448,12 @@ * Open the account management UI. * @param serviceType A signin::GAIAServiceType that triggered the dialog. */ - public static void openAccountManagementScreen(@GAIAServiceType int serviceType) { + public static void openAccountManagementScreen( + Context context, @GAIAServiceType int serviceType) { Bundle arguments = new Bundle(); arguments.putInt(SHOW_GAIA_SERVICE_TYPE_EXTRA, serviceType); SettingsLauncher settingsLauncher = new SettingsLauncherImpl(); settingsLauncher.launchSettingsActivity( - ContextUtils.getApplicationContext(), AccountManagementFragment.class, arguments); + context, AccountManagementFragment.class, arguments); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabIdManager.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabIdManager.java index 272f200..0362697 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabIdManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabIdManager.java
@@ -95,4 +95,9 @@ mPreferences = SharedPreferencesManager.getInstance(); mIdCounter.set(mPreferences.readInt(ChromePreferenceKeys.TAB_ID_MANAGER_NEXT_ID)); } + + @VisibleForTesting + static void resetInstanceForTesting() { + sInstance = null; + } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java index b036ac1..82ad191 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.tabmodel; +import android.app.Activity; import android.os.Handler; import androidx.annotation.Nullable; @@ -19,6 +20,7 @@ import org.chromium.chrome.browser.tab.TabLaunchType; import org.chromium.chrome.browser.tab.TabSelectionType; import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier; +import org.chromium.chrome.browser.tabmodel.TabPersistentStore.TabPersistentStoreObserver; import org.chromium.ui.base.WindowAndroid; import org.chromium.url.GURL; @@ -35,6 +37,7 @@ /** Flag set to false when the asynchronous loading of tabs is finished. */ private final AtomicBoolean mSessionRestoreInProgress = new AtomicBoolean(true); + private final TabPersistentStore mTabSaver; private boolean mIsUndoSupported; @@ -44,10 +47,6 @@ private final TabModelOrderController mOrderController; - // TODO(crbug.com/1138561): Remove the dependency from TabModelSelectorImpl to - // TabPersistentStore. - private Supplier<TabPersistentStore> mTabSaver; - private final AsyncTabParamsManager mAsyncTabParamsManager; private NextTabPolicySupplier mNextTabPolicySupplier; @@ -62,41 +61,41 @@ /** * Builds a {@link TabModelSelectorImpl} instance. + * @param activity An {@link Activity} instance. * @param windowAndroidSupplier A supplier of {@link WindowAndroid} instance which is passed * down to {@link IncognitoTabModelImplCreator} for creating {@link IncognitoTabModel}. * @param tabCreatorManager A {@link TabCreatorManager} instance. + * @param persistencePolicy A {@link TabPersistencePolicy} instance. * @param tabModelFilterFactory * @param nextTabPolicySupplier * @param asyncTabParamsManager * @param supportUndo Whether a tab closure can be undone. */ - public TabModelSelectorImpl(@Nullable Supplier<WindowAndroid> windowAndroidSupplier, - TabCreatorManager tabCreatorManager, TabModelFilterFactory tabModelFilterFactory, + public TabModelSelectorImpl(Activity activity, + @Nullable Supplier<WindowAndroid> windowAndroidSupplier, + TabCreatorManager tabCreatorManager, TabPersistencePolicy persistencePolicy, + TabModelFilterFactory tabModelFilterFactory, NextTabPolicySupplier nextTabPolicySupplier, AsyncTabParamsManager asyncTabParamsManager, boolean supportUndo, boolean isTabbedActivity, boolean startIncognito) { super(tabCreatorManager, tabModelFilterFactory, startIncognito); mWindowAndroidSupplier = windowAndroidSupplier; + final TabPersistentStoreObserver persistentStoreObserver = + new TabPersistentStoreObserver() { + @Override + public void onStateLoaded() { + markTabStateInitialized(); + } + }; mIsUndoSupported = supportUndo; mIsTabbedActivityForSync = isTabbedActivity; + mTabSaver = new TabPersistentStore(persistencePolicy, this, tabCreatorManager); + mTabSaver.addObserver(persistentStoreObserver); mOrderController = new TabModelOrderControllerImpl(this); mNextTabPolicySupplier = nextTabPolicySupplier; mAsyncTabParamsManager = asyncTabParamsManager; } - /** - * TODO(crbug.com/1138561): Do not add more parameters here. This is temporary while the - * dependency from TabModelSelectorImpl to TabPersistentStore is removed. - * - * This must be called after the constructor; NPEs are expected, otherwise. - * A Supplier that supplies null can be passed in tests. - */ - public void setTabPersistentStoreSupplier( - Supplier<TabPersistentStore> tabPersistentStoreSupplier) { - assert mTabSaver == null; - mTabSaver = tabPersistentStoreSupplier; - } - @Override public void markTabStateInitialized() { super.markTabStateInitialized(); @@ -114,9 +113,7 @@ } private void handleOnPageLoadStopped(Tab tab) { - if (tab != null && mTabSaver.get() != null) { - mTabSaver.get().addTabToSaveQueue(tab); - } + if (tab != null) mTabSaver.addTabToSaveQueue(tab); } /** @@ -139,13 +136,13 @@ (ChromeTabCreator) getTabCreatorManager().getTabCreator(true); TabModelImpl normalModel = new TabModelImpl(Profile.getLastUsedRegularProfile(), mIsTabbedActivityForSync, regularTabCreator, incognitoTabCreator, mOrderController, - mTabContentManager, mTabSaver.get(), mNextTabPolicySupplier, mAsyncTabParamsManager, - this, mIsUndoSupported); + mTabContentManager, mTabSaver, mNextTabPolicySupplier, mAsyncTabParamsManager, this, + mIsUndoSupported); regularTabCreator.setTabModel(normalModel, mOrderController); IncognitoTabModel incognitoModel = new IncognitoTabModelImpl( new IncognitoTabModelImplCreator(mWindowAndroidSupplier, regularTabCreator, - incognitoTabCreator, mOrderController, mTabContentManager, mTabSaver.get(), + incognitoTabCreator, mOrderController, mTabContentManager, mTabSaver, mNextTabPolicySupplier, mAsyncTabParamsManager, this)); incognitoTabCreator.setTabModel(incognitoModel, mOrderController); onNativeLibraryReadyInternal(tabContentProvider, normalModel, incognitoModel); @@ -156,9 +153,7 @@ IncognitoTabModel incognitoModel) { mTabContentManager = tabContentProvider; initialize(normalModel, incognitoModel); - if (mTabSaver.get() != null) { - mTabSaver.get().setTabContentManager(mTabContentManager); - } + mTabSaver.setTabContentManager(mTabContentManager); addObserver(new EmptyTabModelSelectorObserver() { @Override @@ -168,9 +163,8 @@ mTabContentManager.invalidateIfChanged(tab.getId(), tab.getUrlString()); } - if (mTabSaver.get() != null - && creationState == TabCreationState.FROZEN_FOR_LAZY_LOAD) { - mTabSaver.get().addTabToSaveQueue(tab); + if (creationState == TabCreationState.FROZEN_FOR_LAZY_LOAD) { + mTabSaver.addTabToSaveQueue(tab); } } }); @@ -213,9 +207,7 @@ @Override public void onNavigationEntriesDeleted(Tab tab) { - if (mTabSaver.get() != null) { - mTabSaver.get().addTabToSaveQueue(tab); - } + mTabSaver.addTabToSaveQueue(tab); } @Override @@ -232,9 +224,7 @@ @Override public void onRootIdChanged(Tab tab, int newRootId) { - if (mTabSaver.get() != null) { - mTabSaver.get().addTabToSaveQueue(tab); - } + mTabSaver.addTabToSaveQueue(tab); } }; } @@ -295,9 +285,7 @@ */ public void saveState() { commitAllTabClosures(); - if (mTabSaver.get() != null) { - mTabSaver.get().saveState(); - } + mTabSaver.saveState(); } /** @@ -306,16 +294,12 @@ * @param ignoreIncognitoFiles Whether to skip loading incognito tabs. */ public void loadState(boolean ignoreIncognitoFiles) { - if (mTabSaver.get() != null) { - mTabSaver.get().loadState(ignoreIncognitoFiles); - } + mTabSaver.loadState(ignoreIncognitoFiles); } @Override public void mergeState() { - if (mTabSaver.get() != null) { - mTabSaver.get().mergeState(); - } + mTabSaver.mergeState(); } /** @@ -325,9 +309,7 @@ * active tab. */ public void restoreTabs(boolean setActiveTab) { - if (mTabSaver.get() != null) { - mTabSaver.get().restoreTabs(setActiveTab); - } + mTabSaver.restoreTabs(setActiveTab); } /** @@ -336,9 +318,7 @@ * there isn't a tab being restored with this url, or the tab has already been restored. */ public void tryToRestoreTabStateForUrl(String url) { - if (mTabSaver.get() != null && isSessionRestoreInProgress()) { - mTabSaver.get().restoreTabStateForUrl(url); - } + if (isSessionRestoreInProgress()) mTabSaver.restoreTabStateForUrl(url); } /** @@ -347,26 +327,24 @@ * there isn't a tab being restored with this id, or the tab has already been restored. */ public void tryToRestoreTabStateForId(int id) { - if (isSessionRestoreInProgress()) { - mTabSaver.get().restoreTabStateForId(id); - } + if (isSessionRestoreInProgress()) mTabSaver.restoreTabStateForId(id); } public void clearState() { - if (mTabSaver.get() != null) { - mTabSaver.get().clearState(); - } + mTabSaver.clearState(); + } + + @Override + public void destroy() { + mTabSaver.destroy(); + super.destroy(); } /** * @return Number of restored tabs on cold startup. */ public int getRestoredTabCount() { - if (mTabSaver.get() != null) { - return mTabSaver.get().getRestoredTabCount(); - } else { - return 0; - } + return mTabSaver.getRestoredTabCount(); } @Override @@ -388,9 +366,7 @@ cacheTabBitmap(mVisibleTab); } mVisibleTab.hide(TabHidingType.CHANGED_TABS); - if (mTabSaver.get() != null) { - mTabSaver.get().addTabToSaveQueue(mVisibleTab); - } + mTabSaver.addTabToSaveQueue(mVisibleTab); } mVisibleTab = null; } @@ -439,6 +415,6 @@ @VisibleForTesting public TabPersistentStore getTabPersistentStoreForTesting() { - return mTabSaver.get(); + return mTabSaver; } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java index 70c5bed..7b944408 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
@@ -16,9 +16,8 @@ import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelContentFactory; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContentsObserver; +import org.chromium.url.GURL; -import java.net.MalformedURLException; -import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -558,17 +557,12 @@ @Override @Nullable - public URL getBasePageUrl() { - URL baseUrl = mBaseManager.getBasePageUrl(); + public GURL getBasePageUrl() { + GURL baseUrl = mBaseManager.getBasePageUrl(); if (baseUrl != null) { - try { - // Return plain HTTP URLs so we can test that we don't give them our legacy privacy - // exceptions. - return new URL(baseUrl.toString().replace("https://", "http://")); - } catch (MalformedURLException e) { - // TODO(donnd): Replace Auto-generated catch block - e.printStackTrace(); - } + // Return plain HTTP URLs so we can test that we don't give them our legacy privacy + // exceptions. + return new GURL(baseUrl.getSpec().replace("https://", "http://")); } return baseUrl; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicyTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicyTest.java index 6b29fda6..6858b8e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicyTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicyTest.java
@@ -27,8 +27,7 @@ import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.content_public.browser.test.util.TestThreadUtils; - -import java.net.URL; +import org.chromium.url.GURL; /** * Tests for the ContextualSearchPolicy class. @@ -58,7 +57,7 @@ UnifiedConsentServiceBridge.setUrlKeyedAnonymizedDataCollectionEnabled( Profile.getLastUsedRegularProfile(), true); try { - when(mMockServer.getBasePageUrl()).thenReturn(new URL("https://someUrl")); + when(mMockServer.getBasePageUrl()).thenReturn(new GURL("https://someUrl")); } catch (Exception e) { Assert.fail("Exception raised building a sample URL"); } @@ -114,7 +113,7 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { setupAllConditionsToSendUrl(); try { - when(mMockServer.getBasePageUrl()).thenReturn(new URL("ftp://someSource")); + when(mMockServer.getBasePageUrl()).thenReturn(new GURL("ftp://someSource")); } catch (Exception e) { Assert.fail("Exception building FTP Uri"); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicyTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicyTest.java index 6dbff08..ca857638 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicyTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicyTest.java
@@ -34,11 +34,12 @@ import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton; import org.chromium.chrome.browser.app.tabmodel.ChromeTabModelFilterFactory; -import org.chromium.chrome.browser.app.tabmodel.CustomTabsTabModelOrchestrator; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; import org.chromium.chrome.browser.tab.MockTab; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabStateFileManager; +import org.chromium.chrome.browser.tabmodel.NextTabPolicy; +import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; import org.chromium.chrome.browser.tabmodel.TabPersistencePolicy; @@ -455,11 +456,12 @@ CustomTabActivity activity = new CustomTabActivity(); ApplicationStatus.onStateChangeForTesting(activity, ActivityState.CREATED); - CustomTabsTabModelOrchestrator orchestrator = new CustomTabsTabModelOrchestrator(); - orchestrator.createTabModels(activity::getWindowAndroid, activity, - new ChromeTabModelFilterFactory(), buildTestPersistencePolicy(), - AsyncTabParamsManagerSingleton.getInstance()); - TabModelSelectorImpl selector = orchestrator.getTabModelSelector(); + NextTabPolicySupplier nextTabPolicySupplier = () -> NextTabPolicy.LOCATIONAL; + + TabModelSelectorImpl selector = new TabModelSelectorImpl(activity, + activity::getWindowAndroid, activity, buildTestPersistencePolicy(), + new ChromeTabModelFilterFactory(), nextTabPolicySupplier, + AsyncTabParamsManagerSingleton.getInstance(), false, false, false); selector.initializeForTesting(normalTabModel, incognitoTabModel); ApplicationStatus.onStateChangeForTesting(activity, ActivityState.DESTROYED); return selector;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/directactions/DirectActionTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/directactions/DirectActionTestUtils.java index a92462c..2a8c791 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/directactions/DirectActionTestUtils.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/directactions/DirectActionTestUtils.java
@@ -71,7 +71,7 @@ static void allowGoForward(ChromeActivityTestRule<?> rule) throws Exception { ChromeActivity activity = rule.getActivity(); String initialUrl = TestThreadUtils.runOnUiThreadBlocking( - () -> activity.getCurrentWebContents().getLastCommittedUrl()); + () -> activity.getCurrentWebContents().getLastCommittedUrl().getSpec()); // Any built-in page that is not about:blank and is reasonably cheap to render will do, // here.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java index 3ce506d..5d16f57 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java
@@ -85,7 +85,10 @@ onView(withText(R.string.cancel)).perform(click()); Assert.assertEquals(BEFORE_UNLOAD_URL, - mActivityTestRule.getActivity().getCurrentWebContents().getLastCommittedUrl()); + mActivityTestRule.getActivity() + .getCurrentWebContents() + .getLastCommittedUrl() + .getSpec()); executeJavaScriptAndWaitForDialog("history.back();"); jsDialog = getCurrentDialog(); @@ -98,7 +101,10 @@ onView(withText(R.string.leave)).perform(click()); onPageLoaded.waitForCallback(callCount); Assert.assertEquals(EMPTY_PAGE, - mActivityTestRule.getActivity().getCurrentWebContents().getLastCommittedUrl()); + mActivityTestRule.getActivity() + .getCurrentWebContents() + .getLastCommittedUrl() + .getSpec()); } /** @@ -165,7 +171,10 @@ Assert.assertNotNull("No dialog showing.", jsDialog); onView(withText(R.string.cancel)).perform(click()); Assert.assertEquals(BEFORE_UNLOAD_URL, - mActivityTestRule.getActivity().getCurrentWebContents().getLastCommittedUrl()); + mActivityTestRule.getActivity() + .getCurrentWebContents() + .getLastCommittedUrl() + .getSpec()); // Show it again, it should have the option to suppress subsequent dialogs. OnEvaluateJavaScriptResultHelper resultHelper = @@ -178,7 +187,10 @@ .check(matches(isChecked())); onView(withText(R.string.cancel)).perform(click()); Assert.assertEquals(BEFORE_UNLOAD_URL, - mActivityTestRule.getActivity().getCurrentWebContents().getLastCommittedUrl()); + mActivityTestRule.getActivity() + .getCurrentWebContents() + .getLastCommittedUrl() + .getSpec()); // Try showing a dialog again and verify it is not shown. resultHelper.evaluateJavaScriptForTests(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/RepostFormWarningTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/RepostFormWarningTest.java index d279e96..2615084 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/RepostFormWarningTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/RepostFormWarningTest.java
@@ -10,13 +10,14 @@ import androidx.test.filters.SmallTest; import org.hamcrest.Matchers; -import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; @@ -25,6 +26,7 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer; import org.chromium.content_public.browser.test.util.TestThreadUtils; @@ -40,11 +42,17 @@ */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +@Batch(Batch.PER_CLASS) public class RepostFormWarningTest { // Active tab. + @ClassRule + public static ChromeTabbedActivityTestRule sActivityTestRule = + new ChromeTabbedActivityTestRule(); + @Rule - public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + public BlankCTATabInitialStateRule mInitialStateRule = + new BlankCTATabInitialStateRule(sActivityTestRule, false); private Tab mTab; // Callback helper that manages waiting for pageloads to finish. @@ -54,16 +62,9 @@ @Before public void setUp() throws Exception { - mActivityTestRule.startMainActivityOnBlankPage(); - - mTab = mActivityTestRule.getActivity().getActivityTab(); + mTab = sActivityTestRule.getActivity().getActivityTab(); mCallbackHelper = new TestCallbackHelperContainer(mTab.getWebContents()); - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); - } - - @After - public void tearDown() { - mTestServer.stopAndDestroyServer(); + mTestServer = sActivityTestRule.getTestServer(); } /** Verifies that the form resubmission warning is not displayed upon first POST navigation. */ @@ -148,7 +149,8 @@ waitForRepostFormWarningDialog(); TestThreadUtils.runOnUiThreadBlocking( - (Runnable) () -> mActivityTestRule.getActivity().getCurrentTabModel().closeTab(mTab)); + (Runnable) () + -> sActivityTestRule.getActivity().getCurrentTabModel().closeTab(mTab)); waitForNoReportFormWarningDialog(); } @@ -156,7 +158,7 @@ private PropertyModel getCurrentModalDialog() { return TestThreadUtils.runOnUiThreadBlockingNoException( () - -> mActivityTestRule.getActivity() + -> sActivityTestRule.getActivity() .getModalDialogManager() .getCurrentDialogForTest()); } @@ -174,7 +176,7 @@ Criteria.checkThat("No modal dialog shown", dialogModel, Matchers.notNullValue()); Criteria.checkThat("Modal dialog is not a HTTP post dialog", dialogModel.get(ModalDialogProperties.TITLE), - Matchers.is(mActivityTestRule.getActivity().getString( + Matchers.is(sActivityTestRule.getActivity().getString( R.string.http_post_warning_title))); }); return getCurrentModalDialog();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabIdManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabIdManagerTest.java index 6352b8a..1cbc521c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabIdManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabIdManagerTest.java
@@ -16,18 +16,21 @@ import org.chromium.base.test.UiThreadTest; import org.chromium.base.test.util.AdvancedMockContext; +import org.chromium.base.test.util.Batch; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; /** Tests for the TabIdManager. */ @RunWith(ChromeJUnit4ClassRunner.class) +@Batch(Batch.UNIT_TESTS) public class TabIdManagerTest { Context mContext; @Before public void setUp() { mContext = new AdvancedMockContext(InstrumentationRegistry.getTargetContext()); + TabIdManager.resetInstanceForTesting(); } /** Tests that IDs are stored and generated properly. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java index c4be5334..817a66c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java
@@ -74,7 +74,8 @@ public RecordingTabModelSelector(Activity activity, TabCreatorManager tabCreatorManager, TabModelFilterFactory tabModelFilterFactory, int selectorIndex) { - super(null, tabCreatorManager, tabModelFilterFactory, + super(activity, null, tabCreatorManager, + new TabbedModeTabPersistencePolicy(selectorIndex, false), tabModelFilterFactory, () -> NextTabPolicy.HIERARCHICAL, AsyncTabParamsManagerSingleton.getInstance(), false, false, false);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java index 5111d77..45471592 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java
@@ -361,9 +361,7 @@ MockTabPersistentStoreObserver mockObserver = new MockTabPersistentStoreObserver(); TabModelSelectorImpl tabModelSelector = (TabModelSelectorImpl) mActivity2.getTabModelSelector(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - tabModelSelector.getTabPersistentStoreForTesting().addObserver(mockObserver); - }); + tabModelSelector.getTabPersistentStoreForTesting().addObserver(mockObserver); // Merge tabs into ChromeTabbedActivity2. Wait for the merge to finish, ensuring the // tab metadata file for ChromeTabbedActivity gets deleted before attempting to merge
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java index 5b514bf..3f21e37 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
@@ -32,7 +32,6 @@ import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton; import org.chromium.chrome.browser.app.tabmodel.ChromeTabModelFilterFactory; -import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator; import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton; import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelper; import org.chromium.chrome.browser.flags.ActivityType; @@ -247,17 +246,11 @@ } @Override - protected TabModelOrchestrator createTabModelOrchestrator() { + protected TabModelSelector createTabModelSelector() { return null; } @Override - protected void createTabModels() {} - - @Override - protected void destroyTabModels() {} - - @Override protected BrowserControlsManager createBrowserControlsManager() { return null; } @@ -728,9 +721,8 @@ // createAndRestoreRealTabModelImpls is called multiple times in one test). sTabWindowManager.onActivityStateChange( mChromeActivity, ActivityState.DESTROYED); - return (TestTabModelSelector) sTabWindowManager - .requestSelector(mChromeActivity, mChromeActivity, null, 0) - .second; + return (TestTabModelSelector) sTabWindowManager.requestSelector( + mChromeActivity, mChromeActivity, null, 0); } });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerTest.java index 5cc728a9..9864a32 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerTest.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.tabmodel; import android.app.Activity; -import android.util.Pair; import androidx.test.filters.SmallTest; @@ -72,10 +71,9 @@ ApplicationStatus.onStateChangeForTesting(a, ActivityState.DESTROYED); } - private Pair<Integer, TabModelSelector> requestSelector( - ChromeActivity activity, int requestedIndex) { + private MockTabModelSelector requestSelector(ChromeActivity activity, int requestedIndex) { final TabWindowManager manager = TabWindowManagerSingleton.getInstance(); - return manager.requestSelector( + return (MockTabModelSelector) manager.requestSelector( activity, activity, () -> NextTabPolicy.HIERARCHICAL, requestedIndex); } @@ -100,10 +98,8 @@ final TabWindowManager manager = TabWindowManagerSingleton.getInstance(); ChromeActivity activity0 = buildActivity(); - Pair<Integer, TabModelSelector> assignment0 = requestSelector(activity0, 0); + TabModelSelector selector0 = requestSelector(activity0, 0); - Assert.assertEquals(0, assignment0.first.intValue()); - TabModelSelector selector0 = assignment0.second; Assert.assertNotNull("Was not able to build the TabModelSelector", selector0); Assert.assertEquals("Unexpected model index", 0, manager.getIndexForWindow(activity0)); } @@ -121,13 +117,11 @@ ChromeActivity activity0 = buildActivity(); ChromeActivity activity1 = buildActivity(); - Pair<Integer, TabModelSelector> assignment0 = requestSelector(activity0, 0); - Pair<Integer, TabModelSelector> assignment1 = requestSelector(activity1, 1); + TabModelSelector selector0 = requestSelector(activity0, 0); + TabModelSelector selector1 = requestSelector(activity1, 1); - Assert.assertEquals(0, assignment0.first.intValue()); - Assert.assertEquals(1, assignment1.first.intValue()); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment0.second); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment1.second); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector0); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector1); Assert.assertEquals("Unexpected model index", 0, manager.getIndexForWindow(activity0)); Assert.assertEquals("Unexpected model index", 1, manager.getIndexForWindow(activity1)); } @@ -166,14 +160,12 @@ ChromeActivity activity0 = buildActivity(); ChromeActivity activity1 = buildActivity(); - Pair<Integer, TabModelSelector> assignment0 = requestSelector(activity0, 0); + TabModelSelector selector0 = requestSelector(activity0, 0); // Request 0 again, but should get 1 instead. - Pair<Integer, TabModelSelector> assignment1 = requestSelector(activity1, 0); + TabModelSelector selector1 = requestSelector(activity1, 0); - Assert.assertEquals(0, assignment0.first.intValue()); - Assert.assertEquals(1, assignment1.first.intValue()); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment0.second); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment1.second); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector0); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector1); Assert.assertEquals("Unexpected model index", 0, manager.getIndexForWindow(activity0)); Assert.assertEquals("Unexpected model index", 1, manager.getIndexForWindow(activity1)); } @@ -193,14 +185,12 @@ ChromeActivity activity0 = buildActivity(); ChromeActivity activity1 = buildActivity(); - Pair<Integer, TabModelSelector> assignment0 = requestSelector(activity0, 2); + TabModelSelector selector0 = requestSelector(activity0, 2); // Request 2 again, but should get 0 instead. - Pair<Integer, TabModelSelector> assignment1 = requestSelector(activity1, 2); + TabModelSelector selector1 = requestSelector(activity1, 2); - Assert.assertEquals(2, assignment0.first.intValue()); - Assert.assertEquals(0, assignment1.first.intValue()); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment0.second); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment1.second); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector0); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector1); Assert.assertEquals("Unexpected model index", 2, manager.getIndexForWindow(activity0)); Assert.assertEquals("Unexpected model index", 0, manager.getIndexForWindow(activity1)); } @@ -217,10 +207,9 @@ final TabWindowManager manager = TabWindowManagerSingleton.getInstance(); ChromeActivity activity0 = buildActivity(); - Pair<Integer, TabModelSelector> assignment0 = requestSelector(activity0, 0); + TabModelSelector selector0 = requestSelector(activity0, 0); - Assert.assertEquals(0, assignment0.first.intValue()); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment0.second); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector0); Assert.assertEquals("Unexpected model index", 0, manager.getIndexForWindow(activity0)); destroyActivity(activity0); @@ -241,10 +230,9 @@ final TabWindowManager manager = TabWindowManagerSingleton.getInstance(); ChromeActivity activity0 = buildActivity(); - Pair<Integer, TabModelSelector> assignment0 = requestSelector(activity0, 0); + TabModelSelector selector0 = requestSelector(activity0, 0); - Assert.assertEquals(0, assignment0.first.intValue()); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment0.second); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector0); Assert.assertEquals("Unexpected model index", 0, manager.getIndexForWindow(activity0)); destroyActivity(activity0); @@ -253,10 +241,9 @@ manager.getIndexForWindow(activity0)); ChromeActivity activity1 = buildActivity(); - Pair<Integer, TabModelSelector> assignment1 = requestSelector(activity1, 0); + TabModelSelector selector1 = requestSelector(activity1, 0); - Assert.assertEquals(0, assignment1.first.intValue()); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment1.second); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector1); Assert.assertEquals("Unexpected model index", 0, manager.getIndexForWindow(activity1)); } @@ -276,13 +263,11 @@ ChromeActivity activity0 = buildActivity(); ChromeActivity activity1 = buildActivity(); - Pair<Integer, TabModelSelector> assignment0 = requestSelector(activity0, 0); - Pair<Integer, TabModelSelector> assignment1 = requestSelector(activity1, 1); + TabModelSelector selector0 = requestSelector(activity0, 0); + TabModelSelector selector1 = requestSelector(activity1, 1); - Assert.assertEquals(0, assignment0.first.intValue()); - Assert.assertEquals(1, assignment1.first.intValue()); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment0.second); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment1.second); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector0); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector1); Assert.assertEquals("Unexpected model index", 0, manager.getIndexForWindow(activity0)); Assert.assertEquals("Unexpected model index", 1, manager.getIndexForWindow(activity1)); @@ -292,10 +277,9 @@ manager.getIndexForWindow(activity1)); ChromeActivity activity2 = buildActivity(); - Pair<Integer, TabModelSelector> assignment2 = requestSelector(activity2, 1); + TabModelSelector selector2 = requestSelector(activity2, 1); - Assert.assertEquals(1, assignment2.first.intValue()); - Assert.assertNotNull("Was not able to build the TabModelSelector", assignment2.second); + Assert.assertNotNull("Was not able to build the TabModelSelector", selector2); Assert.assertEquals("Unexpected model index", 0, manager.getIndexForWindow(activity0)); Assert.assertEquals("Unexpected model index", 1, manager.getIndexForWindow(activity2)); } @@ -312,10 +296,8 @@ ChromeActivity activity0 = buildActivity(); ChromeActivity activity1 = buildActivity(); - Pair<Integer, TabModelSelector> assignment0 = requestSelector(activity0, 0); - Pair<Integer, TabModelSelector> assignment1 = requestSelector(activity1, 1); - MockTabModelSelector selector0 = (MockTabModelSelector) assignment0.second; - MockTabModelSelector selector1 = (MockTabModelSelector) assignment1.second; + MockTabModelSelector selector0 = requestSelector(activity0, 0); + MockTabModelSelector selector1 = requestSelector(activity1, 1); Tab tab1 = selector0.addMockTab(); Tab tab2 = selector1.addMockIncognitoTab(); @@ -350,10 +332,8 @@ ChromeActivity activity0 = buildActivity(); ChromeActivity activity1 = buildActivity(); - Pair<Integer, TabModelSelector> assignment0 = requestSelector(activity0, 0); - Pair<Integer, TabModelSelector> assignment1 = requestSelector(activity1, 1); - MockTabModelSelector selector0 = (MockTabModelSelector) assignment0.second; - MockTabModelSelector selector1 = (MockTabModelSelector) assignment1.second; + MockTabModelSelector selector0 = requestSelector(activity0, 0); + MockTabModelSelector selector1 = requestSelector(activity1, 1); Tab tab1 = selector0.addMockTab(); Tab tab2 = selector1.addMockIncognitoTab(); @@ -388,10 +368,8 @@ ChromeActivity activity0 = buildActivity(); ChromeActivity activity1 = buildActivity(); - Pair<Integer, TabModelSelector> assignment0 = requestSelector(activity0, 0); - Pair<Integer, TabModelSelector> assignment1 = requestSelector(activity1, 1); - MockTabModelSelector selector0 = (MockTabModelSelector) assignment0.second; - MockTabModelSelector selector1 = (MockTabModelSelector) assignment1.second; + MockTabModelSelector selector0 = requestSelector(activity0, 0); + MockTabModelSelector selector1 = requestSelector(activity1, 1); Tab tab1 = selector0.addMockTab(); Tab tab2 = selector1.addMockTab(); Tab tab3 = selector0.addMockIncognitoTab();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationFaviconTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationFaviconTest.java index 9fbb186..f0405bf 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationFaviconTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationFaviconTest.java
@@ -29,6 +29,7 @@ import org.chromium.components.browser_ui.media.MediaNotificationInfo; import org.chromium.components.favicon.IconType; import org.chromium.components.favicon.LargeIconBridge; +import org.chromium.url.GURL; /** * Test of media notifications to ensure that the favicon is displayed on normal devices and @@ -57,8 +58,8 @@ } @Override - public boolean getLargeIconForStringUrl( - final String pageUrl, int desiredSizePx, final LargeIconCallback callback) { + public boolean getLargeIconForUrl( + final GURL pageUrl, int desiredSizePx, final LargeIconCallback callback) { mGetIconCalledAtLeastOnce = true; mCallback = callback; return true;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/payments/PaymentRequestParamsBuilder.java b/chrome/android/junit/src/org/chromium/chrome/browser/payments/PaymentRequestParamsBuilder.java index a0a87f7..f607aaa 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/payments/PaymentRequestParamsBuilder.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/payments/PaymentRequestParamsBuilder.java
@@ -36,6 +36,8 @@ import org.chromium.payments.mojom.PaymentRequest; import org.chromium.payments.mojom.PaymentRequestClient; import org.chromium.ui.base.WindowAndroid; +import org.chromium.url.GURL; +import org.chromium.url.JUnitTestGURLs; import org.chromium.url.Origin; import java.lang.ref.WeakReference; @@ -69,7 +71,9 @@ mPaymentUiService = paymentUiService; mJourneyLogger = Mockito.mock(JourneyLogger.class); mWebContents = Mockito.mock(WebContents.class); - Mockito.doReturn("https://top.level.origin").when(mWebContents).getLastCommittedUrl(); + Mockito.doReturn(JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_1)) + .when(mWebContents) + .getLastCommittedUrl(); mRenderFrameHost = Mockito.mock(RenderFrameHost.class); Mockito.doReturn("https://frame.origin").when(mRenderFrameHost).getLastCommittedURL(); Origin origin = Mockito.mock(Origin.class); @@ -144,7 +148,7 @@ } @Override - public boolean isOriginSecure(String url) { + public boolean isOriginSecure(GURL url) { return true; } @@ -164,7 +168,7 @@ } @Override - public boolean isOriginAllowedToUseWebPaymentApis(String url) { + public boolean isOriginAllowedToUseWebPaymentApis(GURL url) { return true; }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImplTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImplTest.java index c2d7144..da7027d 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImplTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImplTest.java
@@ -8,6 +8,8 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import android.app.Activity; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -15,6 +17,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; import org.robolectric.annotation.Config; import org.chromium.base.test.BaseRobolectricTestRunner; @@ -35,6 +38,8 @@ @Config(manifest = Config.NONE) public class TabModelSelectorImplTest { @Mock + TabPersistencePolicy mMockTabPersistencePolicy; + @Mock TabModelFilterFactory mMockTabModelFilterFactory; @Mock TabContentManager mMockTabContentManager; @@ -45,22 +50,27 @@ private TabModelSelectorImpl mTabModelSelector; private MockTabCreatorManager mTabCreatorManager; + private Activity mActivity; @Before public void setUp() { + mActivity = Robolectric.buildActivity(Activity.class).setup().get(); MockitoAnnotations.initMocks(this); + doReturn(TabPersistentStore.SAVED_STATE_FILE_PREFIX) + .when(mMockTabPersistencePolicy) + .getStateFileName(); + doReturn(mock(TabModelFilter.class)) .when(mMockTabModelFilterFactory) .createTabModelFilter(any()); mTabCreatorManager = new MockTabCreatorManager(); AsyncTabParamsManager realAsyncTabParamsManager = AsyncTabParamsManagerFactory.createAsyncTabParamsManager(); - mTabModelSelector = new TabModelSelectorImpl(null, mTabCreatorManager, - mMockTabModelFilterFactory, mNextTabPolicySupplier, realAsyncTabParamsManager, - /*supportUndo=*/false, + mTabModelSelector = new TabModelSelectorImpl(mActivity, null, mTabCreatorManager, + mMockTabPersistencePolicy, mMockTabModelFilterFactory, mNextTabPolicySupplier, + realAsyncTabParamsManager, /*supportUndo=*/false, /*isTabbedActivity=*/false, /*startIncognito=*/false); - mTabModelSelector.setTabPersistentStoreSupplier(() -> null); mTabCreatorManager.initialize(mTabModelSelector); mTabModelSelector.onNativeLibraryReadyInternal(mMockTabContentManager, new MockTabModel(false, null), new MockTabModel(true, null));
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index b755688a..68079aa3 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2888,13 +2888,13 @@ "android/service_tab_launcher.h", "android/shortcut_helper.cc", "android/shortcut_helper.h", + "android/signin/signin_bridge.cc", + "android/signin/signin_bridge.h", "android/signin/signin_manager_android.cc", "android/signin/signin_manager_android.h", "android/signin/signin_metrics_utils.cc", "android/signin/signin_promo_util_android.cc", "android/signin/signin_promo_util_android.h", - "android/signin/signin_utils.cc", - "android/signin/signin_utils.h", "android/signin/unified_consent_service_bridge.cc", "android/signin/web_signin_bridge.cc", "android/signin/web_signin_bridge.h",
diff --git a/chrome/browser/android/signin/signin_utils.cc b/chrome/browser/android/signin/signin_bridge.cc similarity index 65% rename from chrome/browser/android/signin/signin_utils.cc rename to chrome/browser/android/signin/signin_bridge.cc index e1f6d9f..b5b1f5a 100644 --- a/chrome/browser/android/signin/signin_utils.cc +++ b/chrome/browser/android/signin/signin_bridge.cc
@@ -2,30 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/android/signin/signin_utils.h" +#include "chrome/browser/android/signin/signin_bridge.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" +#include "chrome/android/chrome_jni_headers/SigninBridge_jni.h" #include "chrome/android/chrome_jni_headers/SigninUtils_jni.h" #include "ui/android/window_android.h" using base::android::JavaParamRef; // static -void SigninUtils::OpenAccountManagementScreen( +void SigninBridge::OpenAccountManagementScreen( ui::WindowAndroid* window, - signin::GAIAServiceType service_type, - const std::string& email) { + signin::GAIAServiceType service_type) { DCHECK(window); JNIEnv* env = base::android::AttachCurrentThread(); - Java_SigninUtils_openAccountManagementScreen( - env, window->GetJavaObject(), static_cast<int>(service_type), - email.empty() ? nullptr - : base::android::ConvertUTF8ToJavaString(env, email)); + Java_SigninBridge_openAccountManagementScreen(env, window->GetJavaObject(), + static_cast<int>(service_type)); } -void SigninUtils::OpenAccountPickerBottomSheet( +void SigninBridge::OpenAccountPickerBottomSheet( ui::WindowAndroid* window, const std::string& continue_url) { DCHECK(window);
diff --git a/chrome/browser/android/signin/signin_utils.h b/chrome/browser/android/signin/signin_bridge.h similarity index 62% rename from chrome/browser/android/signin/signin_utils.h rename to chrome/browser/android/signin/signin_bridge.h index e18d35e..75fd461 100644 --- a/chrome/browser/android/signin/signin_utils.h +++ b/chrome/browser/android/signin/signin_bridge.h
@@ -2,32 +2,29 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_ANDROID_SIGNIN_SIGNIN_UTILS_H_ -#define CHROME_BROWSER_ANDROID_SIGNIN_SIGNIN_UTILS_H_ +#ifndef CHROME_BROWSER_ANDROID_SIGNIN_SIGNIN_BRIDGE_H_ +#define CHROME_BROWSER_ANDROID_SIGNIN_SIGNIN_BRIDGE_H_ #include <string> -#include "base/macros.h" #include "components/signin/core/browser/signin_header_helper.h" namespace ui { class WindowAndroid; } -// The glue for Java-side implementation of SigninUtils. -class SigninUtils { +// The glue for Java-side implementation of SigninBridge. +class SigninBridge { public: // Opens the account management screen. static void OpenAccountManagementScreen(ui::WindowAndroid* profile, - signin::GAIAServiceType service_type, - const std::string& email); + signin::GAIAServiceType service_type); // Opens the account picker bottomsheet static void OpenAccountPickerBottomSheet(ui::WindowAndroid* window, const std::string& continue_url); - private: - DISALLOW_COPY_AND_ASSIGN(SigninUtils); + SigninBridge() = delete; }; -#endif // CHROME_BROWSER_ANDROID_SIGNIN_SIGNIN_UTILS_H_ +#endif // CHROME_BROWSER_ANDROID_SIGNIN_SIGNIN_BRIDGE_H_
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index e2eb5c2..b60f2d38 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -1422,6 +1422,7 @@ return profile_manager->GetProfile( GetStartupProfilePath(profile_manager->user_data_dir(), + /*current_directory=*/base::FilePath(), *base::CommandLine::ForCurrentProcess())); }
diff --git a/chrome/browser/apps/app_service/extension_apps_chromeos.cc b/chrome/browser/apps/app_service/extension_apps_chromeos.cc index ab3648b6..ea440ea1 100644 --- a/chrome/browser/apps/app_service/extension_apps_chromeos.cc +++ b/chrome/browser/apps/app_service/extension_apps_chromeos.cc
@@ -173,6 +173,10 @@ policy::policy_prefs::kSystemFeaturesDisableList, base::BindRepeating(&ExtensionAppsBase::OnSystemFeaturesPrefChanged, GetWeakPtr())); + local_state_pref_change_registrar_.Add( + policy::policy_prefs::kSystemFeaturesDisableMode, + base::BindRepeating(&ExtensionAppsBase::OnSystemFeaturesPrefChanged, + GetWeakPtr())); OnSystemFeaturesPrefChanged(); } } @@ -504,13 +508,21 @@ return; } - UpdateAppDisabledState(disabled_system_features_pref, - policy::SystemFeature::kCamera, - extension_misc::kCameraAppId); + const bool is_pref_disabled_mode_hidden = + local_state->GetString( + policy::policy_prefs::kSystemFeaturesDisableMode) == + policy::kHiddenDisableMode; + const bool is_disabled_mode_changed = + (is_pref_disabled_mode_hidden != is_disabled_apps_mode_hidden_); + is_disabled_apps_mode_hidden_ = is_pref_disabled_mode_hidden; + + UpdateAppDisabledState( + disabled_system_features_pref, policy::SystemFeature::kCamera, + extension_misc::kCameraAppId, is_disabled_mode_changed); UpdateAppDisabledState(disabled_system_features_pref, policy::SystemFeature::kWebStore, - extensions::kWebStoreAppId); + extensions::kWebStoreAppId, is_disabled_mode_changed); } bool ExtensionAppsChromeOs::Accepts(const extensions::Extension* extension) { @@ -529,10 +541,10 @@ apps::mojom::AppPtr ExtensionAppsChromeOs::Convert( const extensions::Extension* extension, apps::mojom::Readiness readiness) { - apps::mojom::AppPtr app = - ConvertImpl(extension, base::Contains(disabled_apps_, extension->id()) - ? apps::mojom::Readiness::kDisabledByPolicy - : readiness); + const bool is_app_disabled = base::Contains(disabled_apps_, extension->id()); + apps::mojom::AppPtr app = ConvertImpl( + extension, + is_app_disabled ? apps::mojom::Readiness::kDisabledByPolicy : readiness); bool paused = paused_apps_.IsPaused(extension->id()); app->icon_key = icon_key_factory().MakeIconKey(GetIconEffects(extension, paused)); @@ -543,6 +555,12 @@ app->paused = paused ? apps::mojom::OptionalBool::kTrue : apps::mojom::OptionalBool::kFalse; + if (is_app_disabled && is_disabled_apps_mode_hidden_) { + app->show_in_launcher = apps::mojom::OptionalBool::kFalse; + app->show_in_search = apps::mojom::OptionalBool::kFalse; + app->show_in_shelf = apps::mojom::OptionalBool::kFalse; + } + return app; } @@ -712,7 +730,8 @@ void ExtensionAppsChromeOs::UpdateAppDisabledState( const base::ListValue* disabled_system_features_pref, int feature, - const std::string& app_id) { + const std::string& app_id, + bool is_disabled_mode_changed) { const bool is_disabled = base::Contains(*disabled_system_features_pref, base::Value(feature)); // Sometimes the policy is updated before the app is installed, so this way @@ -720,7 +739,8 @@ // and the app will be published with the correct readiness upon its // installation. const bool should_publish = - (base::Contains(disabled_apps_, app_id) != is_disabled); + (base::Contains(disabled_apps_, app_id) != is_disabled) || + is_disabled_mode_changed; if (is_disabled) { disabled_apps_.insert(app_id);
diff --git a/chrome/browser/apps/app_service/extension_apps_chromeos.h b/chrome/browser/apps/app_service/extension_apps_chromeos.h index 371a45b..72f26d87 100644 --- a/chrome/browser/apps/app_service/extension_apps_chromeos.h +++ b/chrome/browser/apps/app_service/extension_apps_chromeos.h
@@ -153,7 +153,8 @@ void UpdateAppDisabledState( const base::ListValue* disabled_system_features_pref, int feature, - const std::string& app_id); + const std::string& app_id, + bool is_disabled_mode_changed); apps::InstanceRegistry* instance_registry_; ScopedObserver<extensions::AppWindowRegistry, @@ -164,6 +165,11 @@ std::set<std::string> disabled_apps_; + // Boolean signifying whether the preferred user experience mode of disabled + // apps is hidden (true) or blocked (false). The value comes from user pref + // and is set by updating SystemDisabledMode policy. + bool is_disabled_apps_mode_hidden_ = false; + std::map<extensions::AppWindow*, aura::Window*> app_window_to_aura_window_; ArcAppListPrefs* arc_prefs_ = nullptr;
diff --git a/chrome/browser/autofill/autofill_server_browsertest.cc b/chrome/browser/autofill/autofill_server_browsertest.cc index 9b6a0aa2..973c059f5 100644 --- a/chrome/browser/autofill/autofill_server_browsertest.cc +++ b/chrome/browser/autofill/autofill_server_browsertest.cc
@@ -152,12 +152,6 @@ WaitForPersonalDataManagerToBeLoaded(browser()->profile()); } - void SetUpCommandLine(base::CommandLine* command_line) override { - // Enable finch experiment for sending field metadata. - command_line->AppendSwitchASCII(::switches::kForceFieldTrials, - "AutofillFieldMetadata/Enabled/"); - } - private: base::test::ScopedFeatureList scoped_feature_list_; }; @@ -194,10 +188,10 @@ auto* query_form = query.add_forms(); query_form->set_signature(15916856893790176210U); - test::FillQueryField(query_form->add_fields(), 2594484045U, "one", "text"); - test::FillQueryField(query_form->add_fields(), 2750915947U, "two", "text"); - test::FillQueryField(query_form->add_fields(), 3494787134U, "three", "text"); - test::FillQueryField(query_form->add_fields(), 1236501728U, "four", "text"); + query_form->add_fields()->set_signature(2594484045U); + query_form->add_fields()->set_signature(2750915947U); + query_form->add_fields()->set_signature(3494787134U); + query_form->add_fields()->set_signature(1236501728U); std::string expected_query_string; ASSERT_TRUE(query.SerializeToString(&expected_query_string)); @@ -226,21 +220,21 @@ } else { upload->set_data_present("1f7e0003780000080004"); } - upload->set_action_signature(15724779818122431245U); - upload->set_form_name("test_form"); upload->set_passwords_revealed(false); upload->set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_HTML_FORM_SUBMISSION); upload->set_has_form_tag(true); - test::FillUploadField(upload->add_field(), 2594484045U, "one", "text", + // Enabling raw form data uploading (e.g., field name) is too complicated in + // this test. So, don't expect it in the upload. + test::FillUploadField(upload->add_field(), 2594484045U, nullptr, nullptr, nullptr, 2U); - test::FillUploadField(upload->add_field(), 2750915947U, "two", "text", "off", - 2U); - test::FillUploadField(upload->add_field(), 3494787134U, "three", "text", + test::FillUploadField(upload->add_field(), 2750915947U, nullptr, nullptr, nullptr, 2U); - test::FillUploadField(upload->add_field(), 1236501728U, "four", "text", "off", - 2U); + test::FillUploadField(upload->add_field(), 3494787134U, nullptr, nullptr, + nullptr, 2U); + test::FillUploadField(upload->add_field(), 1236501728U, nullptr, nullptr, + nullptr, 2U); std::string expected_upload_string; ASSERT_TRUE(request.SerializeToString(&expected_upload_string)); @@ -271,10 +265,9 @@ auto* query_form = query.add_forms(); query_form->set_signature(8900697631820480876U); - test::FillQueryField(query_form->add_fields(), 2594484045U, "one", "text"); - test::FillQueryField(query_form->add_fields(), 2750915947U, "two", "text"); - test::FillQueryField(query_form->add_fields(), 116843943U, "three", - "password"); + query_form->add_fields()->set_signature(2594484045U); + query_form->add_fields()->set_signature(2750915947U); + query_form->add_fields()->set_signature(116843943U); std::string expected_query_string; ASSERT_TRUE(query.SerializeToString(&expected_query_string));
diff --git a/chrome/browser/background_fetch/background_fetch_browsertest.cc b/chrome/browser/background_fetch/background_fetch_browsertest.cc index 7d5ef476..e4b82d5 100644 --- a/chrome/browser/background_fetch/background_fetch_browsertest.cc +++ b/chrome/browser/background_fetch/background_fetch_browsertest.cc
@@ -601,7 +601,7 @@ IN_PROC_BROWSER_TEST_F( BackgroundFetchBrowserTest, - OfflineItemCollection_VerifyResourceDownloadedWhenDownloadTotalLargerThanActualSize) { + DISABLED_OfflineItemCollection_VerifyResourceDownloadedWhenDownloadTotalLargerThanActualSize) { // Starts a Background Fetch for a single to-be-downloaded file and waits for // the fetch to be registered with the offline items collection. std::vector<OfflineItem> items;
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index fee4d5f..48ac613 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -446,7 +446,7 @@ base::FilePath user_data_dir = g_browser_process->profile_manager()->user_data_dir(); base::FilePath startup_profile_dir = - GetStartupProfilePath(user_data_dir, command_line); + GetStartupProfilePath(user_data_dir, current_directory, command_line); StartupBrowserCreator::ProcessCommandLineAlreadyRunning( command_line, current_directory, startup_profile_dir);
diff --git a/chrome/browser/chromeos/eol_notification.cc b/chrome/browser/chromeos/eol_notification.cc index b82489f..426e189 100644 --- a/chrome/browser/chromeos/eol_notification.cc +++ b/chrome/browser/chromeos/eol_notification.cc
@@ -46,29 +46,6 @@ return eol_date - base::TimeDelta::FromDays(kSecondWarningDaysInAdvance); } -base::string16 FormatMonthAndYearWithOffset(base::Time eol_date) { - // TODO(crbug/998983): This is not the ideal way to correct months shifts. - // A follow up CL will modify base/i18n/time_formatting.h so that - // setting the time can be formatted based off UTC rather than only local. - // - // If the EOL date is on the first day of the month, then notifications with - // different month names may be shown to different users by - // base::TimeFormatMonthAndYear(), depending on their time zone. There are - // devices in Goldeneye with EOL dates on the first and last day of the month. - // Since only the month is shown, the day is set to the 15th to prevent any - // forward or backward month shifts. - constexpr int kApproxMidPointDayInMonth = 15; - - base::Time adjusted_date; - base::Time::Exploded exploded; - eol_date.UTCExplode(&exploded); - exploded.day_of_month = kApproxMidPointDayInMonth; - if (!base::Time::FromUTCExploded(exploded, &adjusted_date)) { - return base::TimeFormatMonthAndYear(eol_date); - } - return base::TimeFormatMonthAndYear(adjusted_date); -} - } // namespace // static @@ -150,8 +127,10 @@ // Notifies user that updates will stop occurring at a month and year. notification = ash::CreateSystemNotification( message_center::NOTIFICATION_TYPE_SIMPLE, kEolNotificationId, - l10n_util::GetStringFUTF16(IDS_PENDING_EOL_NOTIFICATION_TITLE, - FormatMonthAndYearWithOffset(eol_date)), + l10n_util::GetStringFUTF16( + IDS_PENDING_EOL_NOTIFICATION_TITLE, + TimeFormatMonthAndYear(eol_date, + /*time_zone=*/icu::TimeZone::getGMT())), l10n_util::GetStringFUTF16(IDS_PENDING_EOL_NOTIFICATION_MESSAGE, ui::GetChromeOSDeviceName()), base::string16() /* display_source */, GURL(kEolNotificationId),
diff --git a/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc b/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc deleted file mode 100644 index bc7a2e3..0000000 --- a/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc +++ /dev/null
@@ -1,300 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/full_restore/app_launch_handler.h" - -#include "ash/public/cpp/ash_features.h" -#include "base/test/scoped_feature_list.h" -#include "base/timer/timer.h" -#include "chrome/browser/apps/app_service/app_service_proxy.h" -#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_list.h" -#include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h" -#include "chrome/browser/web_applications/components/web_app_id.h" -#include "chrome/browser/web_applications/components/web_application_info.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "components/full_restore/app_launch_info.h" -#include "components/full_restore/full_restore_read_handler.h" -#include "components/full_restore/full_restore_save_handler.h" -#include "components/full_restore/full_restore_utils.h" -#include "components/services/app_service/public/mojom/types.mojom.h" -#include "content/public/test/browser_test.h" -#include "content/public/test/test_utils.h" -#include "ui/aura/window.h" -#include "ui/base/window_open_disposition.h" -#include "ui/display/types/display_constants.h" - -namespace chromeos { -namespace full_restore { - -namespace { - -const char kAppId[] = "mldnpnnoiloahfhddhobgjeophloidmo"; -const int32_t kId = 100; - -} // namespace - -class AppLaunchHandlerBrowserTest : public InProcessBrowserTest { - public: - AppLaunchHandlerBrowserTest() { - scoped_feature_list_.InitAndEnableFeature(ash::features::kFullRestore); - } - ~AppLaunchHandlerBrowserTest() override = default; - - void WaitForAppLaunchInfoSaved() { - ::full_restore::FullRestoreSaveHandler* save_handler = - ::full_restore::FullRestoreSaveHandler::GetInstance(); - base::OneShotTimer* timer = save_handler->GetTimerForTesting(); - EXPECT_TRUE(timer->IsRunning()); - - // Simulate timeout, and the launch info is saved. - timer->FireNow(); - content::RunAllTasksUntilIdle(); - } - - void CreateWebApp() { - auto web_application_info = std::make_unique<WebApplicationInfo>(); - web_application_info->start_url = GURL("https://example.org"); - web_app::AppId app_id = - web_app::InstallWebApp(profile(), std::move(web_application_info)); - - // Wait for app service to see the newly installed app. - auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile()); - proxy->FlushMojoCallsForTesting(); - } - - bool FindWebAppWindow() { - for (auto* browser : *BrowserList::GetInstance()) { - aura::Window* window = browser->window()->GetNativeWindow(); - if (window->GetProperty(::full_restore::kRestoreWindowIdKey) == kId) - return true; - } - return false; - } - - Profile* profile() { return browser()->profile(); } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -IN_PROC_BROWSER_TEST_F(AppLaunchHandlerBrowserTest, NotLaunchBrowser) { - // Add app launch info. - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), std::make_unique<::full_restore::AppLaunchInfo>( - extension_misc::kChromeAppId, kId)); - - WaitForAppLaunchInfoSaved(); - - size_t count = BrowserList::GetInstance()->size(); - - // Create AppLaunchHandler, and set should restore. - auto app_launch_handler = std::make_unique<AppLaunchHandler>(profile()); - app_launch_handler->SetShouldRestore(); - - content::RunAllTasksUntilIdle(); - - // Verify there is no new browser launched. - EXPECT_EQ(count, BrowserList::GetInstance()->size()); -} - -IN_PROC_BROWSER_TEST_F(AppLaunchHandlerBrowserTest, RestoreAndAddApp) { - // Add app launch info. - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), - std::make_unique<::full_restore::AppLaunchInfo>( - kAppId, kId, apps::mojom::LaunchContainer::kLaunchContainerWindow, - WindowOpenDisposition::NEW_WINDOW, display::kDefaultDisplayId, - std::vector<base::FilePath>{}, nullptr)); - - WaitForAppLaunchInfoSaved(); - - // Create AppLaunchHandler, and set should restore. - auto app_launch_handler = std::make_unique<AppLaunchHandler>(profile()); - app_launch_handler->SetShouldRestore(); - - CreateWebApp(); - - content::RunAllTasksUntilIdle(); - - EXPECT_TRUE(FindWebAppWindow()); -} - -IN_PROC_BROWSER_TEST_F(AppLaunchHandlerBrowserTest, AddAppAndRestore) { - // Add app launch info. - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), - std::make_unique<::full_restore::AppLaunchInfo>( - kAppId, kId, apps::mojom::LaunchContainer::kLaunchContainerWindow, - WindowOpenDisposition::NEW_WINDOW, display::kDefaultDisplayId, - std::vector<base::FilePath>{}, nullptr)); - - WaitForAppLaunchInfoSaved(); - - // Create AppLaunchHandler. - auto app_launch_handler = std::make_unique<AppLaunchHandler>(profile()); - - CreateWebApp(); - - // Set should restore - app_launch_handler->SetShouldRestore(); - - content::RunAllTasksUntilIdle(); - - EXPECT_TRUE(FindWebAppWindow()); -} - -IN_PROC_BROWSER_TEST_F(AppLaunchHandlerBrowserTest, NotRestore) { - // Add app launch infos. - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), std::make_unique<::full_restore::AppLaunchInfo>( - extension_misc::kChromeAppId, kId)); - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), - std::make_unique<::full_restore::AppLaunchInfo>( - kAppId, kId, apps::mojom::LaunchContainer::kLaunchContainerWindow, - WindowOpenDisposition::NEW_WINDOW, display::kDefaultDisplayId, - std::vector<base::FilePath>{}, nullptr)); - - WaitForAppLaunchInfoSaved(); - - size_t count = BrowserList::GetInstance()->size(); - - // Create AppLaunchHandler. - auto app_launch_handler = std::make_unique<AppLaunchHandler>(profile()); - app_launch_handler->LauncherBrowserWhenReady(); - - CreateWebApp(); - - content::RunAllTasksUntilIdle(); - - // Verify there is no new browser launched. - EXPECT_EQ(count, BrowserList::GetInstance()->size()); - EXPECT_FALSE(FindWebAppWindow()); -} - -IN_PROC_BROWSER_TEST_F(AppLaunchHandlerBrowserTest, RestoreAndLaunchBrowser) { - size_t count = BrowserList::GetInstance()->size(); - - // Add the chrome browser launch info. - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), std::make_unique<::full_restore::AppLaunchInfo>( - extension_misc::kChromeAppId, kId)); - - WaitForAppLaunchInfoSaved(); - - // Create AppLaunchHandler. - auto app_launch_handler = std::make_unique<AppLaunchHandler>(profile()); - - // Set should restore - app_launch_handler->SetShouldRestore(); - content::RunAllTasksUntilIdle(); - - app_launch_handler->LauncherBrowserWhenReady(); - content::RunAllTasksUntilIdle(); - - // Verify there is new browser launched. - EXPECT_EQ(count + 1, BrowserList::GetInstance()->size()); -} - -IN_PROC_BROWSER_TEST_F(AppLaunchHandlerBrowserTest, LaunchBrowserAndRestore) { - size_t count = BrowserList::GetInstance()->size(); - - // Add the chrome browser launch info. - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), std::make_unique<::full_restore::AppLaunchInfo>( - extension_misc::kChromeAppId, kId)); - - WaitForAppLaunchInfoSaved(); - - // Create AppLaunchHandler. - auto app_launch_handler = std::make_unique<AppLaunchHandler>(profile()); - - app_launch_handler->LauncherBrowserWhenReady(); - content::RunAllTasksUntilIdle(); - - // Verify there is no new browser launched. - EXPECT_EQ(count, BrowserList::GetInstance()->size()); - - // Set should restore - app_launch_handler->SetShouldRestore(); - content::RunAllTasksUntilIdle(); - - // Verify there is new browser launched. - EXPECT_EQ(count + 1, BrowserList::GetInstance()->size()); -} - -IN_PROC_BROWSER_TEST_F(AppLaunchHandlerBrowserTest, - RestoreAndLaunchBrowserAndAddApp) { - size_t count = BrowserList::GetInstance()->size(); - - // Add app launch infos. - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), std::make_unique<::full_restore::AppLaunchInfo>( - extension_misc::kChromeAppId, kId)); - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), - std::make_unique<::full_restore::AppLaunchInfo>( - kAppId, kId, apps::mojom::LaunchContainer::kLaunchContainerWindow, - WindowOpenDisposition::NEW_WINDOW, display::kDefaultDisplayId, - std::vector<base::FilePath>{}, nullptr)); - - WaitForAppLaunchInfoSaved(); - - // Create AppLaunchHandler, and set should restore. - auto app_launch_handler = std::make_unique<AppLaunchHandler>(profile()); - app_launch_handler->SetShouldRestore(); - content::RunAllTasksUntilIdle(); - - app_launch_handler->LauncherBrowserWhenReady(); - content::RunAllTasksUntilIdle(); - - CreateWebApp(); - content::RunAllTasksUntilIdle(); - - // Verify there is new browser launched. - EXPECT_EQ(count + 2, BrowserList::GetInstance()->size()); - EXPECT_TRUE(FindWebAppWindow()); -} - -IN_PROC_BROWSER_TEST_F(AppLaunchHandlerBrowserTest, - LaunchBrowserAndAddAppAndRestore) { - size_t count = BrowserList::GetInstance()->size(); - - // Add app launch infos. - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), std::make_unique<::full_restore::AppLaunchInfo>( - extension_misc::kChromeAppId, kId)); - ::full_restore::SaveAppLaunchInfo( - profile()->GetPath(), - std::make_unique<::full_restore::AppLaunchInfo>( - kAppId, kId, apps::mojom::LaunchContainer::kLaunchContainerWindow, - WindowOpenDisposition::NEW_WINDOW, display::kDefaultDisplayId, - std::vector<base::FilePath>{}, nullptr)); - - WaitForAppLaunchInfoSaved(); - - // Create AppLaunchHandler. - auto app_launch_handler = std::make_unique<AppLaunchHandler>(profile()); - - app_launch_handler->LauncherBrowserWhenReady(); - content::RunAllTasksUntilIdle(); - - CreateWebApp(); - content::RunAllTasksUntilIdle(); - - // Set should restore - app_launch_handler->SetShouldRestore(); - content::RunAllTasksUntilIdle(); - - // Verify there is new browser launched. - EXPECT_EQ(count + 2, BrowserList::GetInstance()->size()); - EXPECT_TRUE(FindWebAppWindow()); -} - -} // namespace full_restore -} // namespace chromeos
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc index 4b7891c..69ea9c7e 100644 --- a/chrome/browser/devtools/devtools_sanity_browsertest.cc +++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -1863,7 +1863,13 @@ std::unique_ptr<DevToolsWindowCreationObserver> observer_; }; -IN_PROC_BROWSER_TEST_F(DevToolsAutoOpenerTest, TestAutoOpenForTabs) { +// TODO(https://crbug.com/1167158): Flaky on debug builds. +#if defined(NDEBUG) +#define MAYBE_TestAutoOpenForTabs DISABLED_TestAutoOpenForTabs +#else +#define MAYBE_TestAutoOpenForTabs TestAutoOpenForTabs +#endif +IN_PROC_BROWSER_TEST_F(DevToolsAutoOpenerTest, MAYBE_TestAutoOpenForTabs) { { DevToolsWindowCreationObserver observer; AddTabAtIndexToBrowser(browser(), 0, GURL("about:blank"),
diff --git a/chrome/browser/extensions/activity_log/activity_log_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_unittest.cc index 954b28c..8baedd9 100644 --- a/chrome/browser/extensions/activity_log/activity_log_unittest.cc +++ b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
@@ -85,6 +85,8 @@ bool is_lock_screen_context) override {} void SetSystemFont(const std::string& font_family, const std::string& font_size) override {} + void SetWebViewPartitionID(const std::string& partition_id) override {} + mojo::AssociatedReceiverSet<mojom::Renderer> receivers_; };
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc index 2ec2412..c0cd4bdb 100644 --- a/chrome/browser/extensions/api/automation/automation_apitest.cc +++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -292,6 +292,12 @@ } #endif +IN_PROC_BROWSER_TEST_F(AutomationApiTest, IframeNav) { + StartEmbeddedTestServer(); + ASSERT_TRUE(RunExtensionSubtest("automation/tests/desktop", "iframenav.html")) + << message_; +} + IN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopNotRequested) { ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "desktop_not_requested.html")) << message_;
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc index 37c4ffb..9cf97e7 100644 --- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc +++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc
@@ -9,6 +9,7 @@ #include "base/files/scoped_temp_dir.h" #include "base/macros.h" #include "base/threading/thread_restrictions.h" +#include "build/build_config.h" #include "components/version_info/version_info.h" #include "content/public/test/browser_test.h" #include "extensions/common/features/feature_channel.h" @@ -73,7 +74,13 @@ DeclarativeNetRequestLazyAPItest, ::testing::Values(ContextType::kServiceWorker)); -IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestLazyAPItest, DynamicRules) { +// Flaky on MSAN: https://crbug.com/1167168 +#if defined(MEMORY_SANITIZER) +#define MAYBE_DynamicRules DISABLED_DynamicRules +#else +#define MAYBE_DynamicRules DynamicRules +#endif +IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestLazyAPItest, MAYBE_DynamicRules) { ASSERT_TRUE(RunTest("dynamic_rules")) << message_; }
diff --git a/chrome/browser/extensions/autoplay_browsertest.cc b/chrome/browser/extensions/autoplay_browsertest.cc index ec3492ab..ec4f662e 100644 --- a/chrome/browser/extensions/autoplay_browsertest.cc +++ b/chrome/browser/extensions/autoplay_browsertest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/ui/extensions/extension_action_test_helper.h" #include "chrome/test/base/ui_test_utils.h" @@ -29,6 +30,13 @@ ASSERT_TRUE(RunExtensionTest("autoplay")) << message_; } +// TODO(crbug.com/1166927): AutoplayAllowedInIframe sporadically (~10%?) times +// out on Linux. +#if defined(OS_LINUX) +#define MAYBE_AutoplayAllowedInIframe DISABLED_AutoplayAllowedInIframe +#else +#define MAYBE_AutoplayAllowedInIframe AutoplayAllowedInIframe +#endif // defined(OS_LINUX) IN_PROC_BROWSER_TEST_F(AutoplayExtensionBrowserTest, AutoplayAllowedInIframe) { ASSERT_TRUE(StartEmbeddedTestServer());
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 23c72e0..d0dda089 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -84,6 +84,7 @@ &autofill_assistant::features::kAutofillAssistantChromeEntry, &autofill_assistant::features::kAutofillAssistantDirectActions, &autofill_assistant::features::kAutofillAssistantDisableOnboardingFlow, + &autofill_assistant::features::kAutofillAssistantLoadDFMForTriggerScripts, &autofill_assistant::features::kAutofillAssistantProactiveHelp, &autofill_assistant::features:: kAutofillAssistantDisableProactiveHelpTiedToMSBB,
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 523da9ad..0406c31 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -225,6 +225,8 @@ public static final String AUTOFILL_ASSISTANT_DIRECT_ACTIONS = "AutofillAssistantDirectActions"; public static final String AUTOFILL_ASSISTANT_DISABLE_ONBOARDING_FLOW = "AutofillAssistantDisableOnboardingFlow"; + public static final String AUTOFILL_ASSISTANT_LOAD_DFM_FOR_TRIGGER_SCRIPTS = + "AutofillAssistantLoadDFMForTriggerScripts"; public static final String AUTOFILL_ASSISTANT_PROACTIVE_HELP = "AutofillAssistantProactiveHelp"; public static final String AUTOFILL_ASSISTANT_DISABLE_PROACTIVE_HELP_TIED_TO_MSBB = "AutofillAssistantDisableProactiveHelpTiedToMSBB";
diff --git a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc index 884a1c71..e7da47a 100644 --- a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc +++ b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc
@@ -12,6 +12,7 @@ #include "base/test/test_timeouts.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "build/buildflag.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/ui/browser.h" @@ -46,6 +47,7 @@ #include "net/dns/mock_host_resolver.h" #include "net/http/http_response_headers.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "printing/buildflags/buildflags.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/view.h" @@ -54,6 +56,9 @@ #if defined(USE_AURA) #include "ui/aura/window.h" #endif +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) +#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" +#endif using extensions::ExtensionsAPIClient; using extensions::MimeHandlerViewGuest; @@ -184,6 +189,42 @@ base::span<const uint8_t> message) override {} }; +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) +class PrintPreviewDelegate : printing::PrintPreviewUI::TestDelegate { + public: + PrintPreviewDelegate() { + printing::PrintPreviewUI::SetDelegateForTesting(this); + } + PrintPreviewDelegate(const PrintPreviewDelegate&) = delete; + PrintPreviewDelegate& operator=(const PrintPreviewDelegate&) = delete; + ~PrintPreviewDelegate() override { + printing::PrintPreviewUI::SetDelegateForTesting(nullptr); + } + + void WaitUntilPreviewIsReady() { + if (total_page_count_ > 0) + return; + + base::RunLoop run_loop; + quit_callback_ = run_loop.QuitClosure(); + run_loop.Run(); + } + + private: + // PrintPreviewUI::TestDelegate: + void DidGetPreviewPageCount(uint32_t page_count) override { + EXPECT_GE(page_count, 1u); + total_page_count_ = page_count; + if (quit_callback_) + std::move(quit_callback_).Run(); + } + void DidRenderPreviewPage(content::WebContents* preview_dialog) override {} + + uint32_t total_page_count_ = 0; + base::OnceClosure quit_callback_; +}; +#endif + } // namespace // Flaky (https://crbug.com/1033009) @@ -229,3 +270,23 @@ ui_test_utils::NavigateToURL(browser(), data_url); ASSERT_TRUE(GetGuestViewManager()->WaitForSingleGuestCreated()); } + +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) +IN_PROC_BROWSER_TEST_F(ChromeMimeHandlerViewTest, EmbeddedThenPrint) { + PrintPreviewDelegate print_preview_delegate; + InitializeTestPage(embedded_test_server()->GetURL("/test_embedded.html")); + ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)); + auto* gv_manager = GetGuestViewManager(); + gv_manager->WaitForAllGuestsDeleted(); + EXPECT_EQ(1U, gv_manager->num_guests_created()); + + // Verify that print dialog comes up. + auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); + auto* main_frame = web_contents->GetMainFrame(); + // Use setTimeout() to prevent ExecuteScript() from blocking on the print + // dialog. + ASSERT_TRUE(content::ExecuteScript( + main_frame, "setTimeout(function() { window.print(); }, 0)")); + print_preview_delegate.WaitUntilPreviewIsReady(); +} +#endif
diff --git a/chrome/browser/lookalikes/lookalike_url_service.cc b/chrome/browser/lookalikes/lookalike_url_service.cc index c7bc57b..8e7f3c3 100644 --- a/chrome/browser/lookalikes/lookalike_url_service.cc +++ b/chrome/browser/lookalikes/lookalike_url_service.cc
@@ -13,6 +13,7 @@ #include "base/memory/singleton.h" #include "base/task/post_task.h" #include "base/time/default_clock.h" +#include "base/trace_event/trace_event.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/engagement/site_engagement_service_factory.h" #include "chrome/browser/profiles/incognito_helpers.h" @@ -75,11 +76,15 @@ std::vector<DomainInfo> UpdateEngagedSitesOnWorkerThread( base::Time now, scoped_refptr<HostContentSettingsMap> map) { + TRACE_EVENT0("navigation", + "LookalikeUrlService UpdateEngagedSitesOnWorkerThread"); std::vector<DomainInfo> new_engaged_sites; auto details = site_engagement::SiteEngagementService::GetAllDetailsInBackground(now, map); + TRACE_EVENT1("navigation", "LookalikeUrlService SiteEngagementService", + "site_count", details.size()); for (const site_engagement::mojom::SiteEngagementDetails& detail : details) { if (!detail.origin.SchemeIsHTTPOrHTTPS()) { continue; @@ -121,6 +126,7 @@ void LookalikeUrlService::ForceUpdateEngagedSites( EngagedSitesCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + TRACE_EVENT0("navigation", "LookalikeUrlService::ForceUpdateEngagedSites"); // Queue an update on a worker thread if necessary. if (!update_in_progress_) { @@ -156,7 +162,9 @@ void LookalikeUrlService::OnUpdateEngagedSitesCompleted( std::vector<DomainInfo> new_engaged_sites) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - + DCHECK(update_in_progress_); + TRACE_EVENT0("navigation", + "LookalikeUrlService::OnUpdateEngagedSitesCompleted"); engaged_sites_.swap(new_engaged_sites); last_engagement_fetch_time_ = clock_->Now(); update_in_progress_ = false;
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc index f6aa3f4..1e588e70 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -1188,8 +1188,8 @@ if (auto first_contentful_paint = ad_frame_data.earliest_first_contentful_paint()) { - ADS_HISTOGRAM("AdPaintTiming.NavigationToFirstContentfulPaint2", - PAGE_LOAD_HISTOGRAM, visibility, + ADS_HISTOGRAM("AdPaintTiming.NavigationToFirstContentfulPaint3", + PAGE_LOAD_LONG_HISTOGRAM, visibility, first_contentful_paint.value()); } }
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc index 7020d17c..9d725eb 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -1000,15 +1000,15 @@ ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)); histogram_tester.ExpectTotalCount( - "PageLoad.Clients.Ads.AdPaintTiming.NavigationToFirstContentfulPaint2", + "PageLoad.Clients.Ads.AdPaintTiming.NavigationToFirstContentfulPaint3", 1); histogram_tester.ExpectTotalCount( "PageLoad.Clients.Ads.Visible.AdPaintTiming." - "NavigationToFirstContentfulPaint2", + "NavigationToFirstContentfulPaint3", 1); histogram_tester.ExpectTotalCount( "PageLoad.Clients.Ads.NonVisible.AdPaintTiming." - "NavigationToFirstContentfulPaint2", + "NavigationToFirstContentfulPaint3", 0); }
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc index 3d934b0..567a50b 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -2857,7 +2857,7 @@ NavigateFrame(kNonAdUrl, main_frame); histogram_tester().ExpectTotalCount( - "AdPaintTiming.NavigationToFirstContentfulPaint2", 0); + "AdPaintTiming.NavigationToFirstContentfulPaint3", 0); } TEST_F(AdsPageLoadMetricsObserverTest, FirstContentfulPaint_Recorded) { @@ -2875,7 +2875,7 @@ NavigateFrame(kNonAdUrl, main_frame); histogram_tester().ExpectUniqueSample( - SuffixedHistogram("AdPaintTiming.NavigationToFirstContentfulPaint2"), 100, + SuffixedHistogram("AdPaintTiming.NavigationToFirstContentfulPaint3"), 100, 1); auto entries = test_ukm_recorder().GetEntriesByName( @@ -2908,7 +2908,7 @@ // The histogram value should be that of the earliest FCP recorded. histogram_tester().ExpectUniqueSample( - SuffixedHistogram("AdPaintTiming.NavigationToFirstContentfulPaint2"), 90, + SuffixedHistogram("AdPaintTiming.NavigationToFirstContentfulPaint3"), 90, 1); auto entries = test_ukm_recorder().GetEntriesByName( @@ -2942,7 +2942,7 @@ // The histogram value should be that of the earliest FCP recorded. histogram_tester().ExpectUniqueSample( - SuffixedHistogram("AdPaintTiming.NavigationToFirstContentfulPaint2"), 90, + SuffixedHistogram("AdPaintTiming.NavigationToFirstContentfulPaint3"), 90, 1); auto entries = test_ukm_recorder().GetEntriesByName( @@ -2971,7 +2971,7 @@ // The histogram value should be that of the earliest FCP recorded. histogram_tester().ExpectUniqueSample( - SuffixedHistogram("AdPaintTiming.NavigationToFirstContentfulPaint2"), 90, + SuffixedHistogram("AdPaintTiming.NavigationToFirstContentfulPaint3"), 90, 1); auto entries = test_ukm_recorder().GetEntriesByName(
diff --git a/chrome/browser/paint_preview/paint_preview_browsertest.cc b/chrome/browser/paint_preview/paint_preview_browsertest.cc index 5ea42d8b..65f62ed 100644 --- a/chrome/browser/paint_preview/paint_preview_browsertest.cc +++ b/chrome/browser/paint_preview/paint_preview_browsertest.cc
@@ -373,15 +373,7 @@ // occurs *during* crash handling, leaving the frame in an invalid state and // leading to a crash when it subsequently unloaded. // This is fixed by deferring it to a PostTask. -// Flaky on Mac. TODO(https://crbug.com/1160608): Enabled this test. -#if defined(OS_MAC) -#define MAYBE_DontReloadInRenderProcessExit \ - DISABLED_DontReloadInRenderProcessExit -#else -#define MAYBE_DontReloadInRenderProcessExit DontReloadInRenderProcessExit -#endif -IN_PROC_BROWSER_TEST_P(PaintPreviewBrowserTest, - MAYBE_DontReloadInRenderProcessExit) { +IN_PROC_BROWSER_TEST_P(PaintPreviewBrowserTest, DontReloadInRenderProcessExit) { // In the FileSystem variant of this test, blocking needs to be permitted to // allow cleanup to work during the crash. base::ScopedAllowBlockingForTesting scope;
diff --git a/chrome/browser/password_manager/android/credential_leak_controller_android.cc b/chrome/browser/password_manager/android/credential_leak_controller_android.cc index 6c2b562..f223c605 100644 --- a/chrome/browser/password_manager/android/credential_leak_controller_android.cc +++ b/chrome/browser/password_manager/android/credential_leak_controller_android.cc
@@ -12,6 +12,7 @@ #include "chrome/common/url_constants.h" #include "components/password_manager/core/browser/leak_detection_dialog_utils.h" #include "ui/android/window_android.h" +#include "url/android/gurl_android.h" using password_manager::metrics_util::LeakDialogDismissalReason; using password_manager::metrics_util::LogLeakDialogTypeAndDismissalReason; @@ -62,7 +63,7 @@ } else if (ShouldShowChangePasswordButton()) { Java_PasswordChangeLauncher_start( env, window_android_->GetJavaObject(), - base::android::ConvertUTF8ToJavaString(env, origin_.spec()), + url::GURLAndroid::FromNativeGURL(env, origin_), base::android::ConvertUTF16ToJavaString(env, username_)); }
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc index 382c7725..f4e57be4 100644 --- a/chrome/browser/pdf/pdf_extension_test.cc +++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -1776,10 +1776,11 @@ ~PDFExtensionLinkClickTest() override {} protected: - void LoadTestLinkPdfGetGuestContents() { + content::WebContents* LoadTestLinkPdfGetGuestContents() { GURL test_pdf_url(embedded_test_server()->GetURL("/pdf/test-link.pdf")); guest_contents_ = LoadPdfGetGuestContents(test_pdf_url); - ASSERT_TRUE(guest_contents_); + EXPECT_TRUE(guest_contents_); + return guest_contents_; } // The rectangle of the link in test-link.pdf is [72 706 164 719] in PDF user @@ -1974,6 +1975,49 @@ EXPECT_EQ("http://www.example.com/", url.spec()); } +namespace { +// Fails the test if a navigation is started in the given WebContents. +class FailOnNavigation : public content::WebContentsObserver { + public: + explicit FailOnNavigation(content::WebContents* contents) + : content::WebContentsObserver(contents) {} + + // content::WebContentsObserver: + void DidStartNavigation( + content::NavigationHandle* navigation_handle) override { + ADD_FAILURE() << "Unexpected navigation"; + } +}; +} // namespace + +// If the PDF viewer can't navigate the tab using a tab id, make sure it doesn't +// try to navigate the mime handler extension's frame. +// Regression test for https://crbug.com/1158381 +IN_PROC_BROWSER_TEST_P(PDFExtensionLinkClickTest, LinkClickInPdfInNonTab) { + // For ease of testing, we'll still load the PDF in a tab, but we clobber the + // tab id in the viewer to make it think it's not in a tab. + WebContents* guest_contents = LoadTestLinkPdfGetGuestContents(); + ASSERT_TRUE(guest_contents); + ASSERT_TRUE( + content::ExecuteScript(guest_contents, + "window.viewer.browserApi.getStreamInfo().tabId = " + " chrome.tabs.TAB_ID_NONE;")); + + FailOnNavigation fail_if_mimehandler_navigates(guest_contents); + content::SimulateMouseClickAt( + GetWebContentsForInputRouting(), blink::WebInputEvent::kNoModifiers, + blink::WebMouseEvent::Button::kLeft, GetLinkPosition()); + + // Since the guest contents is for a mime handling extension (in this case, + // the PDF viewer extension), it must not navigate away from the extension. If + // |fail_if_mimehandler_navigates| doesn't see a navigation, we consider the + // test to have passed. + base::RunLoop run_loop; + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); + run_loop.Run(); +} + INSTANTIATE_TEST_SUITE_P(/* no prefix */, PDFExtensionLinkClickTest, testing::Bool());
diff --git a/chrome/browser/policy/system_features_policy_browsertest.cc b/chrome/browser/policy/system_features_policy_browsertest.cc index 1773c147..9347bbc 100644 --- a/chrome/browser/policy/system_features_policy_browsertest.cc +++ b/chrome/browser/policy/system_features_policy_browsertest.cc
@@ -18,6 +18,7 @@ #include "chromeos/constants/chromeos_features.h" #include "components/policy/core/common/policy_pref_names.h" #include "components/policy/policy_constants.h" +#include "components/services/app_service/public/mojom/types.mojom.h" #include "components/strings/grit/components_strings.h" #include "content/public/test/browser_test.h" #include "content/public/test/test_navigation_observer.h" @@ -55,18 +56,25 @@ } // Disables specified system features or enables all if system_features is - // empty. - void UpdateSystemFeaturesDisableList(base::Value system_features) { + // empty. Updates disabled mode for disabled system features. + void UpdateSystemFeaturesDisableList(base::Value system_features, + const char* disabled_mode) { PolicyMap policies; policies.Set(key::kSystemFeaturesDisableList, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, std::move(system_features), nullptr); + if (disabled_mode) { + policies.Set(key::kSystemFeaturesDisableMode, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value(disabled_mode), nullptr); + } UpdateProviderPolicy(policies); } void VerifyAppState(const char* app_id, apps::mojom::Readiness expected_readiness, - bool blocked_icon) { + bool blocked_icon, + apps::mojom::OptionalBool expected_visibility) { auto* profile = browser()->profile(); extensions::ExtensionRegistry* registry = extensions::ExtensionRegistry::Get(profile); @@ -77,8 +85,8 @@ proxy->FlushMojoCallsForTesting(); proxy->AppRegistryCache().ForOneApp( - app_id, - [&expected_readiness, &blocked_icon](const apps::AppUpdate& update) { + app_id, [&expected_readiness, &blocked_icon, + &expected_visibility](const apps::AppUpdate& update) { EXPECT_EQ(expected_readiness, update.Readiness()); if (blocked_icon) { EXPECT_TRUE(apps::IconEffects::kBlocked & @@ -87,6 +95,9 @@ EXPECT_FALSE(apps::IconEffects::kBlocked & update.IconKey()->icon_effects); } + EXPECT_EQ(expected_visibility, update.ShowInLauncher()); + EXPECT_EQ(expected_visibility, update.ShowInSearch()); + EXPECT_EQ(expected_visibility, update.ShowInShelf()); }); } @@ -97,55 +108,85 @@ IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, DisableCameraBeforeInstall) { base::Value system_features(base::Value::Type::LIST); system_features.Append(kCameraFeature); - UpdateSystemFeaturesDisableList(std::move(system_features)); + UpdateSystemFeaturesDisableList(std::move(system_features), nullptr); EnableExtensions(false); VerifyAppState(extension_misc::kCameraAppId, - apps::mojom::Readiness::kDisabledByPolicy, true); + apps::mojom::Readiness::kDisabledByPolicy, true, + apps::mojom::OptionalBool::kTrue); - UpdateSystemFeaturesDisableList(base::Value()); + UpdateSystemFeaturesDisableList(base::Value(), nullptr); VerifyAppState(extension_misc::kCameraAppId, apps::mojom::Readiness::kReady, - false); + false, apps::mojom::OptionalBool::kTrue); } IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, DisableCameraAfterInstall) { EnableExtensions(false); base::Value system_features(base::Value::Type::LIST); system_features.Append(kCameraFeature); - UpdateSystemFeaturesDisableList(std::move(system_features)); + UpdateSystemFeaturesDisableList(std::move(system_features), nullptr); VerifyAppState(extension_misc::kCameraAppId, - apps::mojom::Readiness::kDisabledByPolicy, true); + apps::mojom::Readiness::kDisabledByPolicy, true, + apps::mojom::OptionalBool::kTrue); - UpdateSystemFeaturesDisableList(base::Value()); + UpdateSystemFeaturesDisableList(base::Value(), nullptr); VerifyAppState(extension_misc::kCameraAppId, apps::mojom::Readiness::kReady, - false); + false, apps::mojom::OptionalBool::kTrue); } IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, DisableWebStoreBeforeInstall) { base::Value system_features(base::Value::Type::LIST); system_features.Append(kWebStoreFeature); - UpdateSystemFeaturesDisableList(std::move(system_features)); + UpdateSystemFeaturesDisableList(std::move(system_features), nullptr); EnableExtensions(true); VerifyAppState(extensions::kWebStoreAppId, - apps::mojom::Readiness::kDisabledByPolicy, true); + apps::mojom::Readiness::kDisabledByPolicy, true, + apps::mojom::OptionalBool::kTrue); - UpdateSystemFeaturesDisableList(base::Value()); + UpdateSystemFeaturesDisableList(base::Value(), nullptr); VerifyAppState(extensions::kWebStoreAppId, apps::mojom::Readiness::kReady, - false); + false, apps::mojom::OptionalBool::kTrue); } IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, DisableWebStoreAfterInstall) { EnableExtensions(false); base::Value system_features(base::Value::Type::LIST); system_features.Append(kWebStoreFeature); - UpdateSystemFeaturesDisableList(std::move(system_features)); + UpdateSystemFeaturesDisableList(std::move(system_features), nullptr); VerifyAppState(extensions::kWebStoreAppId, - apps::mojom::Readiness::kDisabledByPolicy, true); + apps::mojom::Readiness::kDisabledByPolicy, true, + apps::mojom::OptionalBool::kTrue); - UpdateSystemFeaturesDisableList(base::Value()); + UpdateSystemFeaturesDisableList(base::Value(), nullptr); VerifyAppState(extensions::kWebStoreAppId, apps::mojom::Readiness::kReady, - false); + false, apps::mojom::OptionalBool::kTrue); +} + +IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, + DisableWebStoreAfterInstallWithModes) { + EnableExtensions(false); + base::Value system_features(base::Value::Type::LIST); + system_features.Append(kWebStoreFeature); + // Disable app with default mode (blocked).. + UpdateSystemFeaturesDisableList(system_features.Clone(), nullptr); + VerifyAppState(extensions::kWebStoreAppId, + apps::mojom::Readiness::kDisabledByPolicy, true, + apps::mojom::OptionalBool::kTrue); + // Disable and hide app. + UpdateSystemFeaturesDisableList(system_features.Clone(), kHiddenDisableMode); + VerifyAppState(extensions::kWebStoreAppId, + apps::mojom::Readiness::kDisabledByPolicy, true, + apps::mojom::OptionalBool::kFalse); + // Disable and block app. + UpdateSystemFeaturesDisableList(system_features.Clone(), kBlockedDisableMode); + VerifyAppState(extensions::kWebStoreAppId, + apps::mojom::Readiness::kDisabledByPolicy, true, + apps::mojom::OptionalBool::kTrue); + // Enable app + UpdateSystemFeaturesDisableList(base::Value(), nullptr); + VerifyAppState(extensions::kWebStoreAppId, apps::mojom::Readiness::kReady, + false, apps::mojom::OptionalBool::kTrue); } IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, @@ -154,29 +195,31 @@ base::Value system_features(base::Value::Type::LIST); system_features.Append(kWebStoreFeature); system_features.Append(kCameraFeature); - UpdateSystemFeaturesDisableList(std::move(system_features)); + UpdateSystemFeaturesDisableList(std::move(system_features), nullptr); VerifyAppState(extensions::kWebStoreAppId, - apps::mojom::Readiness::kDisabledByPolicy, true); + apps::mojom::Readiness::kDisabledByPolicy, true, + apps::mojom::OptionalBool::kTrue); VerifyAppState(extension_misc::kCameraAppId, - apps::mojom::Readiness::kDisabledByPolicy, true); + apps::mojom::Readiness::kDisabledByPolicy, true, + apps::mojom::OptionalBool::kTrue); - UpdateSystemFeaturesDisableList(base::Value()); + UpdateSystemFeaturesDisableList(base::Value(), nullptr); VerifyAppState(extensions::kWebStoreAppId, apps::mojom::Readiness::kReady, - false); + false, apps::mojom::OptionalBool::kTrue); } IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, RedirectChromeSettingsURL) { PolicyMap policies; base::Value system_features(base::Value::Type::LIST); system_features.Append(kBrowserSettingsFeature); - UpdateSystemFeaturesDisableList(std::move(system_features)); + UpdateSystemFeaturesDisableList(std::move(system_features), nullptr); GURL settings_url = GURL(chrome::kChromeUISettingsURL); EXPECT_EQ(l10n_util::GetStringUTF16(IDS_CHROME_URLS_DISABLED_PAGE_HEADER), GetWebUITitle(settings_url)); - UpdateSystemFeaturesDisableList(base::Value()); + UpdateSystemFeaturesDisableList(base::Value(), nullptr); EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SETTINGS_SETTINGS), GetWebUITitle(settings_url)); }
diff --git a/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc b/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc index 5d16987d..01881f3 100644 --- a/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc +++ b/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
@@ -64,7 +64,6 @@ #endif using content::WebContents; -using content::WebContentsObserver; namespace printing { @@ -117,21 +116,25 @@ bool source_is_pdf; }; -// Observes the print preview webpage. Once it observes the PreviewPageCount -// message, will send a sequence of commands to the print preview dialog and +// Implements PrintPreviewUI::TestDelegate. Once DidGetPreviewPageCount() is +// called, will send a sequence of commands to the print preview dialog and // change the settings of the preview dialog. -class PrintPreviewObserver : public WebContentsObserver { +class PrintPreviewDelegate : printing::PrintPreviewUI::TestDelegate { public: - PrintPreviewObserver(Browser* browser, + PrintPreviewDelegate(Browser* browser, WebContents* dialog, const base::FilePath& pdf_file_save_path) - : WebContentsObserver(dialog), - browser_(browser), + : browser_(browser), state_(kWaitingToSendSaveAsPdf), failed_setting_("None"), - pdf_file_save_path_(pdf_file_save_path) {} - - ~PrintPreviewObserver() override {} + pdf_file_save_path_(pdf_file_save_path) { + printing::PrintPreviewUI::SetDelegateForTesting(this); + } + PrintPreviewDelegate(const PrintPreviewDelegate&) = delete; + PrintPreviewDelegate& operator=(const PrintPreviewDelegate&) = delete; + ~PrintPreviewDelegate() override { + printing::PrintPreviewUI::SetDelegateForTesting(nullptr); + } // Sets closure for the observer so that it can end the loop. void set_quit_closure(base::OnceClosure closure) { @@ -144,13 +147,6 @@ std::move(quit_closure_)); } - bool OnMessageReceived(const IPC::Message& message) override { - IPC_BEGIN_MESSAGE_MAP(PrintPreviewObserver, message) - IPC_MESSAGE_HANDLER(PrintHostMsg_DidStartPreview, OnDidStartPreview) - IPC_END_MESSAGE_MAP() - return false; - } - // Gets the web contents for the print preview dialog so that the UI and // other elements can be accessed. WebContents* GetDialog() { @@ -206,7 +202,7 @@ // Called by |GetUI()->handler_|, it is a callback function that call // |EndLoop| when an attempt to save the PDF has been made. GetUI()->SetPdfSavedClosureForTesting(base::BindOnce( - &PrintPreviewObserver::EndLoop, base::Unretained(this))); + &PrintPreviewDelegate::EndLoop, base::Unretained(this))); ASSERT_FALSE(pdf_file_save_path_.empty()); GetUI()->SetSelectedFileForTesting(pdf_file_save_path_); return; @@ -231,21 +227,21 @@ // listens for 'UILoadedForTest' and 'UIFailedLoadingForTest.' class UIDoneLoadingMessageHandler : public content::WebUIMessageHandler { public: - explicit UIDoneLoadingMessageHandler(PrintPreviewObserver* observer) - : observer_(observer) {} + explicit UIDoneLoadingMessageHandler(PrintPreviewDelegate* delegate) + : delegate_(delegate) {} ~UIDoneLoadingMessageHandler() override {} - // When a setting has been set succesfully, this is called and the observer + // When a setting has been set successfully, this is called and the delegate // is told to send the next setting to be set. void HandleDone(const base::ListValue* /* args */) { - observer_->ManipulatePreviewSettings(); + delegate_->ManipulatePreviewSettings(); } // Ends the test because a setting was not set successfully. Called when // this class hears 'UIFailedLoadingForTest.' void HandleFailure(const base::ListValue* /* args */) { - FAIL() << "Failed to set: " << observer_->GetFailedSetting(); + FAIL() << "Failed to set: " << delegate_->GetFailedSetting(); } // Allows this class to listen for the 'UILoadedForTest' and @@ -267,19 +263,11 @@ } private: - PrintPreviewObserver* const observer_; - - DISALLOW_COPY_AND_ASSIGN(UIDoneLoadingMessageHandler); + PrintPreviewDelegate* const delegate_; }; - // Called when the observer gets the IPC message with the preview document's - // properties. - void OnDidStartPreview(const mojom::DidStartPreviewParams& params, - const printing::mojom::PreviewIds& ids) { - WebContents* web_contents = GetDialog(); - ASSERT_TRUE(web_contents); - Observe(web_contents); - + // PrintPreviewUI::TestDelegate: + void DidGetPreviewPageCount(uint32_t page_count) override { PrintPreviewUI* ui = GetUI(); ASSERT_TRUE(ui); ASSERT_TRUE(ui->web_ui()); @@ -288,24 +276,18 @@ std::make_unique<UIDoneLoadingMessageHandler>(this)); ui->SendEnableManipulateSettingsForTest(); } - - void DidCloneToNewWebContents(WebContents* old_web_contents, - WebContents* new_web_contents) override { - Observe(new_web_contents); - } + void DidRenderPreviewPage(content::WebContents* preview_dialog) override {} Browser* browser_; base::OnceClosure quit_closure_; std::unique_ptr<PrintPreviewSettings> settings_; - // State of the observer. The state indicates what message to send - // next. The state advances whenever the message handler calls - // ManipulatePreviewSettings() on the observer. + // |state_| that indicates what message to send next. The state advances + // whenever the message handler calls ManipulatePreviewSettings() on the + // delegate. State state_; std::string failed_setting_; const base::FilePath pdf_file_save_path_; - - DISALLOW_COPY_AND_ASSIGN(PrintPreviewObserver); }; class PrintPreviewPdfGeneratedBrowserTest : public InProcessBrowserTest { @@ -317,14 +299,14 @@ // for all the settings to be set, then save the preview to PDF. void NavigateAndPrint(const base::FilePath::StringType& file_name, const PrintPreviewSettings& settings) { - print_preview_observer_->SetPrintPreviewSettings(settings); + print_preview_delegate_->SetPrintPreviewSettings(settings); base::FilePath path(file_name); GURL gurl = net::FilePathToFileURL(base::MakeAbsoluteFilePath(path)); ui_test_utils::NavigateToURL(browser(), gurl); base::RunLoop loop; - print_preview_observer_->set_quit_closure(loop.QuitClosure()); + print_preview_delegate_->set_quit_closure(loop.QuitClosure()); chrome::Print(browser()); loop.Run(); @@ -461,31 +443,17 @@ std::cerr.flush(); } - // Duplicates the tab that was created when the browser opened. This is done - // so that the observer can listen to the duplicated tab as soon as possible - // and start listening for messages related to print preview. - void DuplicateTab() { + void CreatePreviewDelegate() { WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); ASSERT_TRUE(tab); - - print_preview_observer_ = std::make_unique<PrintPreviewObserver>( + print_preview_delegate_ = std::make_unique<PrintPreviewDelegate>( browser(), tab, pdf_file_save_path_); - chrome::DuplicateTab(browser()); - - WebContents* initiator = - browser()->tab_strip_model()->GetActiveWebContents(); - ASSERT_TRUE(initiator); - ASSERT_NE(tab, initiator); } - // Resets the test so that another web page can be printed. It also deletes - // the duplicated tab as it isn't needed anymore. + // Resets the test so that another web page can be printed. void Reset() { png_output_.clear(); - ASSERT_EQ(2, browser()->tab_strip_model()->count()); - chrome::CloseTab(browser()); - ASSERT_EQ(1, browser()->tab_strip_model()->count()); } // Creates a temporary directory to store a text file that will be used for @@ -554,7 +522,7 @@ &png_output_)); } - std::unique_ptr<PrintPreviewObserver> print_preview_observer_; + std::unique_ptr<PrintPreviewDelegate> print_preview_delegate_; base::FilePath pdf_file_save_path_; // Vector for storing the PNG to be sent to the layout test framework. @@ -615,7 +583,7 @@ cmd = base::UTF8ToWide(input); #endif - DuplicateTab(); + CreatePreviewDelegate(); PrintPreviewSettings settings( true, "", false, false, mojom::MarginType::kDefaultMargins, cmd.find(file_extension) != base::FilePath::StringType::npos);
diff --git a/chrome/browser/privacy_sandbox/android/BUILD.gn b/chrome/browser/privacy_sandbox/android/BUILD.gn index c2393f18..e9c25ca 100644 --- a/chrome/browser/privacy_sandbox/android/BUILD.gn +++ b/chrome/browser/privacy_sandbox/android/BUILD.gn
@@ -21,6 +21,7 @@ "//components/browser_ui/settings/android:java", "//third_party/android_deps:androidx_fragment_fragment_java", "//third_party/android_deps:androidx_preference_preference_java", + "//ui/android:ui_full_java", ] resources_package = "org.chromium.chrome.browser.privacy_sandbox" }
diff --git a/chrome/browser/privacy_sandbox/android/java/res/xml/privacy_sandbox_preferences.xml b/chrome/browser/privacy_sandbox/android/java/res/xml/privacy_sandbox_preferences.xml index 16c1632..d650ca1 100644 --- a/chrome/browser/privacy_sandbox/android/java/res/xml/privacy_sandbox_preferences.xml +++ b/chrome/browser/privacy_sandbox/android/java/res/xml/privacy_sandbox_preferences.xml
@@ -6,26 +6,25 @@ <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> + <org.chromium.components.browser_ui.settings.TextMessagePreference + android:summary="@string/privacy_sandbox_description" + app:allowDividerBelow="false" /> + + <PreferenceCategory + android:title="@string/privacy_sandbox_trial_title"/> + + <org.chromium.components.browser_ui.settings.TextMessagePreference + android:key="privacy_sandbox_trial_description" + app:allowDividerBelow="false" /> + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference android:key="privacy_sandbox_toggle" - android:title="@string/privacy_sandbox_title" + android:title="@string/privacy_sandbox_toggle" android:persistent="false" app:allowDividerBelow="false" /> <org.chromium.components.browser_ui.settings.TextMessagePreference - android:key="subtitle" - android:title="@string/privacy_sandbox_subtitle" - app:allowDividerBelow="false" /> - - <org.chromium.components.browser_ui.settings.TextMessagePreference - android:summary="@string/privacy_sandbox_bullet_one" - android:icon="@drawable/ic_people_24dp" - app:allowDividerBelow="false" /> - - <org.chromium.components.browser_ui.settings.TextMessagePreference - android:summary="@string/privacy_sandbox_bullet_two" - android:icon="@drawable/ic_data_viz_grey" - app:iconTint="@color/default_icon_color_tint_list" + android:summary="@string/privacy_sandbox_toggle_description" app:allowDividerBelow="false" /> </PreferenceScreen>
diff --git a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSettingsFragment.java b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSettingsFragment.java index facce0a..2653185 100644 --- a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSettingsFragment.java +++ b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSettingsFragment.java
@@ -13,11 +13,16 @@ import androidx.preference.PreferenceFragmentCompat; import org.chromium.components.browser_ui.settings.SettingsUtils; +import org.chromium.ui.text.SpanApplier; +import org.chromium.ui.text.SpanApplier.SpanInfo; +import org.chromium.ui.widget.ChromeBulletSpan; /** * Settings fragment for privacy sandbox settings. This class represents a View in the MVC paradigm. */ public class PrivacySandboxSettingsFragment extends PreferenceFragmentCompat { + public static final String TRIAL_DESCRIPTION_PREFERENCE = "privacy_sandbox_trial_description"; + /** * Initializes all the objects related to the preferences page. */ @@ -26,6 +31,12 @@ // Add all preferences and set the title. getActivity().setTitle(R.string.prefs_privacy_sandbox); SettingsUtils.addPreferencesFromResource(this, R.xml.privacy_sandbox_preferences); + // Format the trial description, which has bullet points. + findPreference(TRIAL_DESCRIPTION_PREFERENCE) + .setSummary(SpanApplier.applySpans( + getContext().getString(R.string.privacy_sandbox_trial_description), + new SpanInfo("<li1>", "</li1>", new ChromeBulletSpan(getContext())), + new SpanInfo("<li2>", "</li2>", new ChromeBulletSpan(getContext())))); } @Override
diff --git a/chrome/browser/profiles/profile_destroyer.cc b/chrome/browser/profiles/profile_destroyer.cc index 1c6cdcc211f..0a8ba8c 100644 --- a/chrome/browser/profiles/profile_destroyer.cc +++ b/chrome/browser/profiles/profile_destroyer.cc
@@ -151,15 +151,11 @@ if (pending_destroyers_ == NULL) pending_destroyers_ = new DestroyerSet; pending_destroyers_->insert(this); - for (auto i = hosts->begin(); i != hosts->end(); ++i) { - (*i)->AddObserver(this); - // For each of the observations, we bump up our reference count. - // It will go back to 0 and free us when all hosts are terminated. - ++num_hosts_; - } + for (auto* host : *hosts) + observations_.AddObservation(host); // If we are going to wait for render process hosts, we don't want to do it // for longer than kTimerDelaySeconds. - if (num_hosts_) { + if (observations_.IsObservingAnySource()) { timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(kTimerDelaySeconds), base::BindOnce(&ProfileDestroyer::DestroyProfile, weak_ptr_factory_.GetWeakPtr())); @@ -182,9 +178,9 @@ num_hosts_ ? ProfileDestructionType::kDelayedAndCrashed : ProfileDestructionType::kDelayed); - CHECK_EQ(0U, num_hosts_) << "Some render process hosts were not " - << "destroyed early enough!"; - DCHECK(pending_destroyers_ != NULL); + CHECK(!observations_.IsObservingAnySource()) + << "Some render process hosts were not destroyed early enough!"; + DCHECK(pending_destroyers_); auto iter = pending_destroyers_->find(this); DCHECK(iter != pending_destroyers_->end()); pending_destroyers_->erase(iter); @@ -198,9 +194,8 @@ content::RenderProcessHost* host) { TRACE_EVENT2("shutdown", "ProfileDestroyer::RenderProcessHostDestroyed", "profile", profile_, "render_process_host", host); - DCHECK_GT(num_hosts_, 0u); - --num_hosts_; - if (num_hosts_ == 0) { + observations_.RemoveObservation(host); + if (!observations_.IsObservingAnySource()) { // Delay the destruction one step further in case other observers need to // look at the profile attached to the host. base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/chrome/browser/profiles/profile_destroyer.h b/chrome/browser/profiles/profile_destroyer.h index 30d8ee3..0c42525 100644 --- a/chrome/browser/profiles/profile_destroyer.h +++ b/chrome/browser/profiles/profile_destroyer.h
@@ -10,16 +10,14 @@ #include <set> #include "base/memory/ref_counted.h" +#include "base/scoped_multi_source_observation.h" #include "base/timer/timer.h" +#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host_observer.h" class Profile; class ProfileImpl; -namespace content { -class RenderProcessHost; -} - // We use this class to destroy the off the record profile so that we can make // sure it gets done asynchronously after all render process hosts are gone. class ProfileDestroyer : public content::RenderProcessHostObserver { @@ -71,6 +69,10 @@ // We don't want to wait forever, so we have a cancellation timer. base::OneShotTimer timer_; + base::ScopedMultiSourceObservation<content::RenderProcessHost, + content::RenderProcessHostObserver> + observations_{this}; + // Used to count down the number of render process host left. uint32_t num_hosts_;
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog.html b/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog.html index b8f5a83..8202e9c 100644 --- a/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog.html +++ b/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog.html
@@ -87,7 +87,9 @@ --oobe-adaptive-dialog-content-direction: column; --oobe-adaptive-dialog-item-alignment: center; --oobe-text-alignment: center; - --oobe-adaptive-dialog-content-width: 100%; + --oobe-adaptive-dialog-content-width: calc( + var(--oobe-adaptive-dialog-width) - + 2 * var(--oobe-adaptive-dialog-content-padding)); /* Header takes 40% of the width remaining after applying padding */ --oobe-adaptive-dialog-header-width: clamp(302px, calc(0.4 * (var(--oobe-adaptive-dialog-width) -
diff --git a/chrome/browser/resources/pdf/BUILD.gn b/chrome/browser/resources/pdf/BUILD.gn index 6882668..020938c 100644 --- a/chrome/browser/resources/pdf/BUILD.gn +++ b/chrome/browser/resources/pdf/BUILD.gn
@@ -245,6 +245,7 @@ js_library("navigator") { deps = [ + ":browser_api", ":open_pdf_params_parser", ":viewport", ]
diff --git a/chrome/browser/resources/pdf/browser_api.js b/chrome/browser/resources/pdf/browser_api.js index 50f912a..75d21fd7 100644 --- a/chrome/browser/resources/pdf/browser_api.js +++ b/chrome/browser/resources/pdf/browser_api.js
@@ -86,6 +86,27 @@ } /** + * Navigates the current tab. + * @param {string} url The URL to navigate the tab to. + */ + navigateInCurrentTab(url) { + const tabId = this.getStreamInfo().tabId; + // We need to use the tabs API to navigate because + // |window.location.href| cannot be used. This PDF extension is not loaded + // in the top level frame (it's embedded using MimeHandlerView). Using + // |window.location| would navigate the wrong frame, so we can't + // use it as a fallback. If it turns out that we do need a way to navigate + // in non-tab cases, we would need to create another mechanism to + // communicate with MimeHandler code in the browser (e.g. via + // mimeHandlerPrivate), which could then navigate the correct frame. + // Furthermore, navigations to local resources would be blocked with + // |window.location|. + if (chrome.tabs && tabId !== chrome.tabs.TAB_ID_NONE) { + chrome.tabs.update(tabId, {url: url}); + } + } + + /** * Sets the browser zoom. * @param {number} zoom The zoom factor to send to the browser. * @return {Promise} A promise that will be resolved when the browser zoom
diff --git a/chrome/browser/resources/pdf/navigator.js b/chrome/browser/resources/pdf/navigator.js index 1e37b1e..51ffa74 100644 --- a/chrome/browser/resources/pdf/navigator.js +++ b/chrome/browser/resources/pdf/navigator.js
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {BrowserApi} from './browser_api.js'; import {OpenPdfParamsParser} from './open_pdf_params_parser.js'; import {Viewport} from './viewport.js'; @@ -33,24 +34,15 @@ // navigating. /** @implements {NavigatorDelegate} */ export class NavigatorDelegateImpl { - /** - * @param {number} tabId The tab ID of the PDF viewer or -1 if the viewer is - * not displayed in a tab. - */ - constructor(tabId) { - /** @private {number} */ - this.tabId_ = tabId; + /** @param {!BrowserApi} browserApi */ + constructor(browserApi) { + /** @private {!BrowserApi} */ + this.browserApi_ = browserApi; } /** @override */ navigateInCurrentTab(url) { - // When the PDFviewer is inside a browser tab, prefer the tabs API because - // it can navigate from one file:// URL to another. - if (chrome.tabs && this.tabId_ !== -1) { - chrome.tabs.update(this.tabId_, {url: url}); - } else { - window.location.href = url; - } + this.browserApi_.navigateInCurrentTab(url); } /** @override */
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js index b7047dfa3..2ee0f63 100644 --- a/chrome/browser/resources/pdf/pdf_viewer.js +++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -428,11 +428,10 @@ 'keydown', e => this.handleKeyEvent_(/** @type {!KeyboardEvent} */ (e))); - const tabId = this.browserApi.getStreamInfo().tabId; this.navigator_ = new PdfNavigator( this.originalUrl, this.viewport, /** @type {!OpenPdfParamsParser} */ (this.paramsParser), - new NavigatorDelegateImpl(tabId)); + new NavigatorDelegateImpl(browserApi)); // Listen for save commands from the browser. if (chrome.mimeHandlerPrivate && chrome.mimeHandlerPrivate.onSave) {
diff --git a/chrome/browser/resources/signin/profile_picker/profile_card.html b/chrome/browser/resources/signin/profile_picker/profile_card.html index 0f3ec10..1f2dfd43 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_card.html +++ b/chrome/browser/resources/signin/profile_picker/profile_card.html
@@ -9,9 +9,8 @@ } cr-button { - background-color: var(--profile-card-background-color); + --hover-bg-color: none; /* Stick to the profile card hover color. */ border: none; - border-radius: inherit; box-shadow: none; flex-direction: column; height: inherit; @@ -19,10 +18,6 @@ width: inherit; } - :host-context(.focus-outline-visible) cr-button:focus { - box-shadow: 0 0 0 2px rgba(var(--google-blue-600-rgb), .4); - } - #avatarContainer { height: var(--avatar-icon-size); position: relative; @@ -35,7 +30,8 @@ --domain-icon-border-size: 2px; align-items: center; background-color: white; - border: var(--domain-icon-border-size) solid var(--profile-card-background-color); + border: + var(--domain-icon-border-size) solid var(--profile-card-hover-color); border-radius: 50%; box-shadow: 0 0 2px rgba(60, 64, 67, 0.12), 0 0 6px rgba(60, 64, 67, 0.15); display: flex; @@ -123,7 +119,8 @@ <div id="profileCardContainer"> <cr-button on-click="onProfileClick_" - aria-label="[[i18n('profileCardButtonLabel', profileState.localProfileName)]]"> + aria-label="[[i18n( + 'profileCardButtonLabel', profileState.localProfileName)]]"> <div id="avatarContainer"> <img class="profile-avatar" alt="" src="[[profileState.avatarIcon]]"> <div id="iconContainer" hidden="[[!profileState.isManaged]]">
diff --git a/chrome/browser/resources/signin/profile_picker/profile_card_menu.html b/chrome/browser/resources/signin/profile_picker/profile_card_menu.html index d1ff0ec..2ba12a0e 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_card_menu.html +++ b/chrome/browser/resources/signin/profile_picker/profile_card_menu.html
@@ -51,7 +51,7 @@ #profileCardContainer { align-items: center; - background-color: var(--profile-card-background-color); + background-color: var(--profile-card-hover-color); border-radius: 12px 0 0 12px; display: flex; flex-direction: column;
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html index e1061c0..2e2e7acd 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html +++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
@@ -55,9 +55,10 @@ } .profiles-container { - --grid-gutter: 16px; + --grid-gutter: 8px; align-items: center; display: grid; + /* Actual gap: --grid-gutter + 2 * --profile-item-margin = 16px */ grid-column-gap: var(--grid-gutter); grid-row-gap: var(--grid-gutter); grid-template-columns: repeat(auto-fit, calc(var(--profile-item-width) + @@ -74,7 +75,8 @@ .profile-item { align-items: center; - border-radius: 12px; + border: 1px solid var(--google-grey-300); + border-radius: 8px; display: flex; flex-direction: column; height: var(--profile-item-height); @@ -83,9 +85,15 @@ width: var(--profile-item-width); } - #addProfile { - border: 1px dashed; - border-color: var(--google-grey-400); + .profile-item:focus-within, + .profile-item:hover { + background-color: var(--profile-card-hover-color); + } + + #addProfile.profile-item { + --hover-bg-color: none; + border: 1px dashed var(--google-grey-300); + box-shadow: none; position: relative; } @@ -94,13 +102,11 @@ top: 0; } - cr-icon-button[iron-icon='profiles:add'] { - --cr-icon-button-icon-size: var(--avatar-icon-size); - --cr-icon-button-size: 84px; - --cr-icon-button-fill-color: var(--google-grey-refresh-100); - --cr-icon-button-margin-end: 0; - --cr-icon-button-margin-start: 0; - --cr-icon-button-stroke-color: var(--google-grey-refresh-700); + iron-icon[icon='profiles:add'] { + --iron-icon-height: var(--avatar-icon-size); + --iron-icon-width: var(--avatar-icon-size); + --iron-icon-fill-color: var(--google-grey-refresh-100); + --iron-icon-stroke-color: var(--google-grey-refresh-700); } #browseAsGuestButton { @@ -130,15 +136,14 @@ background: url(images/dark_mode_right_banner_image.svg); } - #addProfile { + .profile-item, + #addProfile.profile-item { border-color: var(--google-grey-refresh-700); - position: relative; } - cr-icon-button[iron-icon='profiles:add'] { - --cr-icon-button-fill-color: var(--google-grey-refresh-500); - --cr-icon-button-stroke-color: rgb(48, 48, 50); - color: var(--google-grey-refresh-500); + iron-icon[icon='profiles:add'] { + --iron-icon-fill-color: var(--google-grey-refresh-500); + --iron-icon-stroke-color: rgb(48, 48, 50); } } </style> @@ -159,14 +164,13 @@ class="profile-item" profile-state="[[item]]"> </profile-card> </template> - <div id="addProfile" class="profile-item"> + <cr-button id="addProfile" class="profile-item" + on-click="onAddProfileClick_" aria-labelledby="addProfileButtonLabel"> <div id="addProfileButtonLabel" class="profile-card-info"> $i18n{addSpaceButton} </div> - <cr-icon-button iron-icon="profiles:add" - on-click="onAddProfileClick_" aria-labelledby="addProfileButtonLabel"> - </cr-icon-button> - </div> + <iron-icon icon="profiles:add"></iron-icon> + </cr-button> </div> </div> <div id="rightBanner" class="banner"></div>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html index 1ea85fcd..5a5097e 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html +++ b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
@@ -5,13 +5,13 @@ --scrollbar-width: 4px; --scrollbar-background: var(--google-grey-refresh-100); --footer-margin: 40px; - --profile-card-background-color: var(--md-background-color); + --profile-card-hover-color: var(--md-background-color); } @media (prefers-color-scheme: dark) { :host { --scrollbar-background: var(--google-grey-800); - --profile-card-background-color: var(--google-grey-800); + --profile-card-hover-color: var(--google-grey-800); } }
diff --git a/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ChromeBasePreferenceTest.java b/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ChromeBasePreferenceTest.java index 427b5e2..e9af1be2 100644 --- a/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ChromeBasePreferenceTest.java +++ b/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ChromeBasePreferenceTest.java
@@ -38,8 +38,7 @@ /** * Tests of {@link ChromeBasePreference}. * - * TODO(chouinard): Once SettingsLauncher and SettingsActivity have compontentized interfaces, these - * test should be moved to //components/browser_ui/settings/. + * TODO(crbug.com/1166810): Move these tests to //components/browser_ui/settings/. */ @RunWith(ChromeJUnit4ClassRunner.class) public class ChromeBasePreferenceTest {
diff --git a/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ChromeImageViewPreferenceTest.java b/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ChromeImageViewPreferenceTest.java index 9ea9484..dc3438b27 100644 --- a/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ChromeImageViewPreferenceTest.java +++ b/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ChromeImageViewPreferenceTest.java
@@ -36,8 +36,7 @@ /** * Tests of {@link ChromeImageViewPreference}. * - * TODO(chouinard): Once SettingsLauncher and SettingsActivity have compontentized interfaces, these - * tests should be moved to //components/browser_ui/settings/. + * TODO(crbug.com/1166810): Move these tests to //components/browser_ui/settings/. */ @RunWith(ChromeJUnit4ClassRunner.class) public class ChromeImageViewPreferenceTest {
diff --git a/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ManagedPreferencesUtilsTest.java b/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ManagedPreferencesUtilsTest.java index 4e898ee..9293dea 100644 --- a/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ManagedPreferencesUtilsTest.java +++ b/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/ManagedPreferencesUtilsTest.java
@@ -37,9 +37,7 @@ /** * Tests of {@link ManagedPreferencesUtils}. * - * TODO(chouinard): Once SettingsLauncher and SettingsActivity have - * compontentized interfaces, these test should be moved to - * //components/browser_ui/settings/. + * TODO(crbug.com/1166810): Move these tests to //components/browser_ui/settings/. */ @RunWith(ChromeJUnit4ClassRunner.class) public class ManagedPreferencesUtilsTest {
diff --git a/chrome/browser/signin/chrome_signin_helper.cc b/chrome/browser/signin/chrome_signin_helper.cc index 5bb714a9..5f54d36a 100644 --- a/chrome/browser/signin/chrome_signin_helper.cc +++ b/chrome/browser/signin/chrome_signin_helper.cc
@@ -49,7 +49,7 @@ #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h" #if defined(OS_ANDROID) -#include "chrome/browser/android/signin/signin_utils.h" +#include "chrome/browser/android/signin/signin_bridge.h" #include "ui/android/view_android.h" #else #include "chrome/browser/ui/browser_commands.h" @@ -303,7 +303,7 @@ // See https://crbug.com/1145031#c5 for details. return; } - SigninUtils::OpenAccountPickerBottomSheet( + SigninBridge::OpenAccountPickerBottomSheet( window, manage_accounts_params.continue_url.empty() ? chrome::kChromeUINativeNewTabURL : manage_accounts_params.continue_url); @@ -322,8 +322,7 @@ auto* window = web_contents->GetNativeView()->GetWindowAndroid(); if (!window) return; - SigninUtils::OpenAccountManagementScreen(window, service_type, - manage_accounts_params.email); + SigninBridge::OpenAccountManagementScreen(window, service_type); } #endif // BUILDFLAG(IS_CHROMEOS_ASH) #endif // BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.cc b/chrome/browser/signin/dice_web_signin_interceptor.cc index ce9d9bc7f..92b9a1c 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor.cc
@@ -9,6 +9,7 @@ #include "base/check.h" #include "base/hash/hash.h" #include "base/i18n/case_conversion.h" +#include "base/metrics/field_trial_params.h" #include "base/metrics/histogram_functions.h" #include "base/optional.h" #include "base/strings/utf_string_conversions.h" @@ -48,6 +49,8 @@ constexpr char kProfileCreationInterceptionDeclinedPref[] = "signin.ProfileCreationInterceptionDeclinedPref"; +constexpr char kProfileSwitchInterceptionDeclinedPref[] = + "signin.ProfileSwitchInterceptionDeclinedPref"; void RecordSigninInterceptionHeuristicOutcome( SigninInterceptionHeuristicOutcome outcome) { @@ -148,6 +151,7 @@ void DiceWebSigninInterceptor::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { registry->RegisterDictionaryPref(kProfileCreationInterceptionDeclinedPref); + registry->RegisterDictionaryPref(kProfileSwitchInterceptionDeclinedPref); registry->RegisterBooleanPref(prefs::kSigninInterceptionEnabled, true); } @@ -176,6 +180,10 @@ email, &g_browser_process->profile_manager()->GetProfileAttributesStorage()); if (switch_to_entry) { + if (HasUserDeclinedProfileSwitch(email)) { + return SigninInterceptionHeuristicOutcome:: + kAbortUserDeclinedProfileForAccount; + } if (entry) *entry = switch_to_entry; return SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch; @@ -275,7 +283,8 @@ interception_bubble_handle_ = delegate_->ShowSigninInterceptionBubble( web_contents, bubble_parameters, base::BindOnce(&DiceWebSigninInterceptor::OnProfileSwitchChoice, - base::Unretained(this), entry->GetPath())); + base::Unretained(this), account_info->email, + entry->GetPath())); was_interception_ui_displayed_ = true; } else { // Interception is aborted. @@ -484,9 +493,12 @@ } void DiceWebSigninInterceptor::OnProfileSwitchChoice( + const std::string& email, const base::FilePath& profile_path, SigninInterceptionResult switch_profile) { if (switch_profile != SigninInterceptionResult::kAccepted) { + if (switch_profile == SigninInterceptionResult::kDeclined) + RecordProfileSwitchDeclined(email); Reset(); return; } @@ -570,8 +582,7 @@ kProfileCreationInterceptionDeclinedPref); std::string key = GetPersistentEmailHash(email); base::Optional<int> declined_count = update->FindIntKey(key); - update->SetIntKey( - key, declined_count.has_value() ? declined_count.value() + 1 : 1); + update->SetIntKey(key, declined_count.value_or(0) + 1); } bool DiceWebSigninInterceptor::HasUserDeclinedProfileCreation( @@ -585,3 +596,31 @@ return declined_count && declined_count.value() >= kMaxProfileCreationDeclinedCount; } + +void DiceWebSigninInterceptor::RecordProfileSwitchDeclined( + const std::string& email) { + DictionaryPrefUpdate update(profile_->GetPrefs(), + kProfileSwitchInterceptionDeclinedPref); + std::string key = GetPersistentEmailHash(email); + base::Optional<int> declined_count = update->FindIntKey(key); + update->SetIntKey(key, declined_count.value_or(0) + 1); +} + +bool DiceWebSigninInterceptor::HasUserDeclinedProfileSwitch( + const std::string& email) const { + const base::DictionaryValue* pref_data = profile_->GetPrefs()->GetDictionary( + kProfileSwitchInterceptionDeclinedPref); + base::Optional<int> declined_count = + pref_data->FindIntKey(GetPersistentEmailHash(email)); + + // The limit is controlled by an experiment. Zero value completely turns off + // the profile switch bubble. Negative values mean there is no limit. By + // default, there is no limit. + int max_profile_switch_declined_count = + base::GetFieldTrialParamByFeatureAsInt( + kDiceWebSigninInterceptionFeature, + "max_profile_switch_declined_count", -1); + + return max_profile_switch_declined_count >= 0 && + declined_count.value_or(0) >= max_profile_switch_declined_count; +}
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.h b/chrome/browser/signin/dice_web_signin_interceptor.h index 5465468..97d19149 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor.h +++ b/chrome/browser/signin/dice_web_signin_interceptor.h
@@ -271,7 +271,8 @@ SigninInterceptionResult create); // Called after the user chose whether the session should continue in a new // profile. - void OnProfileSwitchChoice(const base::FilePath& profile_path, + void OnProfileSwitchChoice(const std::string& email, + const base::FilePath& profile_path, SigninInterceptionResult switch_profile); // Called when the new profile is created or loaded from disk. @@ -287,17 +288,23 @@ // Returns a 8-bit hash of the email that can be persisted. static std::string GetPersistentEmailHash(const std::string& email); - // Should be called when the user declines profile creation, in order to - // remember their decision. This information is stored in prefs. Only a hash - // of the email is saved, as Chrome does not need to store the actual email, - // but only need to compare emails. The hash has low entropy to ensure it - // cannot be reversed. + // Should be called when the user declines profile creation or profile switch, + // in order to remember their decision. This information is stored in prefs. + // Only a hash of the email is saved, as Chrome does not need to store the + // actual email, but only need to compare emails. The hash has low entropy to + // ensure it cannot be reversed. void RecordProfileCreationDeclined(const std::string& email); + void RecordProfileSwitchDeclined(const std::string& email); // Checks if the user previously declined 2 times creating a new profile for // this account. bool HasUserDeclinedProfileCreation(const std::string& email) const; + // Checks if the user previously declined more than a threshold number of + // times switching to a new profile for this account. The limit is set up + // via an experiment parameter. + bool HasUserDeclinedProfileSwitch(const std::string& email) const; + Profile* const profile_; signin::IdentityManager* const identity_manager_; std::unique_ptr<Delegate> delegate_;
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc index c3ba70e..0c2ada8 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "base/callback.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" @@ -482,7 +483,7 @@ MaybeIntercept(account_info.account_id); } -TEST_F(DiceWebSigninInterceptorTest, DeclineRepeatedly) { +TEST_F(DiceWebSigninInterceptorTest, DeclineCreationRepeatedly) { base::HistogramTester histogram_tester; AccountInfo primary_account_info = identity_test_env()->MakeUnconsentedPrimaryAccountAvailable( @@ -523,15 +524,6 @@ SigninInterceptionHeuristicOutcome::kAbortUserDeclinedProfileForAccount, 1); - // Even with a slightly different email. - MaybeIntercept(account_info.account_id); - account_info.email = "al.ice@example.com"; - EXPECT_EQ(interceptor()->is_interception_in_progress(), false); - histogram_tester.ExpectBucketCount( - "Signin.Intercept.HeuristicOutcome", - SigninInterceptionHeuristicOutcome::kAbortUserDeclinedProfileForAccount, - 2); - // Another account can still be intercepted. account_info.email = "oscar@example.com"; identity_test_env()->UpdateAccountInfoForAccount(account_info); @@ -550,6 +542,141 @@ EXPECT_EQ(interceptor()->is_interception_in_progress(), true); } +TEST_F(DiceWebSigninInterceptorTest, DeclineSwitchRepeatedly_NoLimit) { + base::HistogramTester histogram_tester; + // Setup for profile switch interception. + std::string email = "bob@example.com"; + AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); + Profile* profile_2 = CreateTestingProfile("Profile 2"); + ProfileAttributesEntry* entry = nullptr; + ASSERT_TRUE(profile_attributes_storage()->GetProfileAttributesWithPath( + profile_2->GetPath(), &entry)); + entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(email), + /*is_consented_primary_account=*/false); + + // Test that the profile switch can be declined multiple times. + DiceWebSigninInterceptor::Delegate::BubbleParameters expected_parameters = { + DiceWebSigninInterceptor::SigninInterceptionType::kProfileSwitch, + account_info, AccountInfo(), SkColor()}; + for (int i = 0; i < 10; ++i) { + EXPECT_CALL(*mock_delegate(), + ShowSigninInterceptionBubble( + web_contents(), MatchBubbleParameters(expected_parameters), + testing::_)) + .WillOnce(testing::WithArg<2>(testing::Invoke( + [](base::OnceCallback<void(SigninInterceptionResult)> callback) { + std::move(callback).Run(SigninInterceptionResult::kDeclined); + return nullptr; + }))); + MaybeIntercept(account_info.account_id); + EXPECT_EQ(interceptor()->is_interception_in_progress(), false); + histogram_tester.ExpectUniqueSample( + "Signin.Intercept.HeuristicOutcome", + SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch, i + 1); + } +} + +TEST_F(DiceWebSigninInterceptorTest, + DeclineSwitchRepeatedly_LimitedByExperiment) { + const int kMaxProfileSwitchDeclinedCount = 3; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeatureWithParameters( + kDiceWebSigninInterceptionFeature, + {{"max_profile_switch_declined_count", + base::NumberToString(kMaxProfileSwitchDeclinedCount)}}); + + base::HistogramTester histogram_tester; + // Setup for profile switch interception. + std::string email = "bob@example.com"; + AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); + Profile* profile_2 = CreateTestingProfile("Profile 2"); + ProfileAttributesEntry* entry = nullptr; + ASSERT_TRUE(profile_attributes_storage()->GetProfileAttributesWithPath( + profile_2->GetPath(), &entry)); + entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(email), + /*is_consented_primary_account=*/false); + + // Decline the interception kMaxProfileSwitchDeclinedCount times. + DiceWebSigninInterceptor::Delegate::BubbleParameters expected_parameters = { + DiceWebSigninInterceptor::SigninInterceptionType::kProfileSwitch, + account_info, AccountInfo(), SkColor()}; + for (int i = 0; i < kMaxProfileSwitchDeclinedCount; ++i) { + EXPECT_CALL(*mock_delegate(), + ShowSigninInterceptionBubble( + web_contents(), MatchBubbleParameters(expected_parameters), + testing::_)) + .WillOnce(testing::WithArg<2>(testing::Invoke( + [](base::OnceCallback<void(SigninInterceptionResult)> callback) { + std::move(callback).Run(SigninInterceptionResult::kDeclined); + return nullptr; + }))); + MaybeIntercept(account_info.account_id); + EXPECT_EQ(interceptor()->is_interception_in_progress(), false); + histogram_tester.ExpectUniqueSample( + "Signin.Intercept.HeuristicOutcome", + SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch, i + 1); + } + + // Next time the interception is not shown again. + MaybeIntercept(account_info.account_id); + EXPECT_EQ(interceptor()->is_interception_in_progress(), false); + histogram_tester.ExpectBucketCount( + "Signin.Intercept.HeuristicOutcome", + SigninInterceptionHeuristicOutcome::kAbortUserDeclinedProfileForAccount, + 1); + + // Another account can still be intercepted. + account_info.email = "oscar@example.com"; + identity_test_env()->UpdateAccountInfoForAccount(account_info); + Profile* profile_3 = CreateTestingProfile("Profile 3"); + ProfileAttributesEntry* entry_2 = nullptr; + ASSERT_TRUE(profile_attributes_storage()->GetProfileAttributesWithPath( + profile_3->GetPath(), &entry_2)); + entry_2->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(account_info.email), + /*is_consented_primary_account=*/false); + + expected_parameters = { + DiceWebSigninInterceptor::SigninInterceptionType::kProfileSwitch, + account_info, AccountInfo(), SkColor()}; + EXPECT_CALL(*mock_delegate(), + ShowSigninInterceptionBubble( + web_contents(), MatchBubbleParameters(expected_parameters), + testing::_)); + MaybeIntercept(account_info.account_id); + histogram_tester.ExpectBucketCount( + "Signin.Intercept.HeuristicOutcome", + SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch, + kMaxProfileSwitchDeclinedCount + 1); + EXPECT_EQ(interceptor()->is_interception_in_progress(), true); +} + +TEST_F(DiceWebSigninInterceptorTest, + DeclineSwitchRepeatedly_DisabledByExperiment) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeatureWithParameters( + kDiceWebSigninInterceptionFeature, + {{"max_profile_switch_declined_count", "0"}}); + + base::HistogramTester histogram_tester; + // Setup for profile switch interception. + std::string email = "bob@example.com"; + AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); + Profile* profile_2 = CreateTestingProfile("Profile 2"); + ProfileAttributesEntry* entry = nullptr; + ASSERT_TRUE(profile_attributes_storage()->GetProfileAttributesWithPath( + profile_2->GetPath(), &entry)); + entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(email), + /*is_consented_primary_account=*/false); + + // The interception is not shown even at first attempt. + MaybeIntercept(account_info.account_id); + EXPECT_EQ(interceptor()->is_interception_in_progress(), false); + histogram_tester.ExpectBucketCount( + "Signin.Intercept.HeuristicOutcome", + SigninInterceptionHeuristicOutcome::kAbortUserDeclinedProfileForAccount, + 1); +} + TEST_F(DiceWebSigninInterceptorTest, PersistentHash) { // The hash is persistent (the value should never change). EXPECT_EQ("email_174", @@ -558,10 +685,13 @@ EXPECT_NE(interceptor()->GetPersistentEmailHash("bob@gmail.com"), interceptor()->GetPersistentEmailHash("alice@example.com")); // Equivalent emails get the same hash. - EXPECT_EQ(interceptor()->GetPersistentEmailHash("bo.b@gmail.com"), - interceptor()->GetPersistentEmailHash("bob@gmail.com")); EXPECT_EQ(interceptor()->GetPersistentEmailHash("bob"), interceptor()->GetPersistentEmailHash("bob@gmail.com")); + EXPECT_EQ(interceptor()->GetPersistentEmailHash("bo.b@gmail.com"), + interceptor()->GetPersistentEmailHash("bob@gmail.com")); + // Dots are removed only for gmail accounts. + EXPECT_NE(interceptor()->GetPersistentEmailHash("alice@example.com"), + interceptor()->GetPersistentEmailHash("al.ice@example.com")); } // Interception other than the profile switch require at least 2 accounts.
diff --git a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc index b4a0510..47173f566 100644 --- a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc +++ b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
@@ -479,17 +479,6 @@ EXPECT_TRUE(GetEnableSpellcheckState()); } -// When the renderer notifies that it corrected a word, the render process -// host should record UMA stats about the correction. -IN_PROC_BROWSER_TEST_F(SpellcheckServiceHostBrowserTest, NotifyChecked) { - const char kMisspellRatio[] = "SpellCheck.MisspellRatio"; - - base::HistogramTester tester; - tester.ExpectTotalCount(kMisspellRatio, 0); - NotifyChecked(); - tester.ExpectTotalCount(kMisspellRatio, 1); -} - #if BUILDFLAG(USE_RENDERER_SPELLCHECKER) // When the renderer requests the spelling service for correcting text, the // render process host should call the remote spelling service.
diff --git a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc index 926e2177..6f4d020 100644 --- a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/browser/url_and_title.h" +#include "components/sync/base/client_tag_hash.h" #include "components/sync/driver/profile_sync_service.h" #include "components/sync/engine_impl/bookmark_update_preprocessing.h" #include "components/sync/engine_impl/loopback_server/loopback_server_entity.h" @@ -157,6 +158,15 @@ } }; +class SingleClientBookmarksSyncTestWithEnabledClientTags : public SyncTest { + public: + SingleClientBookmarksSyncTestWithEnabledClientTags() + : SyncTest(SINGLE_CLIENT) { + feature_list_.InitAndEnableFeature( + switches::kSyncUseClientTagForBookmarkCommits); + } +}; + IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTestWithVerifier, Sanity) { ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; @@ -1499,4 +1509,29 @@ .Wait()); } +IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTestWithEnabledClientTags, + CommitLocalCreationWithClientTag) { + ASSERT_TRUE(SetupSync()); + + const std::string kTitle = "Title"; + const BookmarkNode* folder = AddFolder( + kSingleProfileIndex, GetOtherNode(kSingleProfileIndex), 0, kTitle); + + // Wait until the local bookmark gets committed. + ASSERT_TRUE(bookmarks_helper::ServerBookmarksEqualityChecker( + GetSyncService(kSingleProfileIndex), GetFakeServer(), + {{kTitle, /*url=*/GURL()}}, + /*cryptographer=*/nullptr) + .Wait()); + + // Verify the client tag hash was committed to the server. + std::vector<sync_pb::SyncEntity> server_bookmarks = + GetFakeServer()->GetSyncEntitiesByModelType(syncer::BOOKMARKS); + ASSERT_EQ(1u, server_bookmarks.size()); + EXPECT_EQ(server_bookmarks[0].client_defined_unique_tag(), + syncer::ClientTagHash::FromUnhashed( + syncer::BOOKMARKS, folder->guid().AsLowercaseString()) + .value()); +} + } // namespace
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManager.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManager.java index 0431494..93bf6b3 100644 --- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManager.java +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManager.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.tabmodel; import android.app.Activity; -import android.util.Pair; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier; @@ -35,13 +34,11 @@ * @param nextTabPolicySupplier An instance of {@link NextTabPolicySupplier}. * @param index The index of the requested {@link TabModelSelector}. Not guaranteed to be the * index of the {@link TabModelSelector} returned. - * @return {@link Pair} of the index and the {@link TabModelSelector} assigned to that index, or - * {@code null} if there are too many + * @return A {@link TabModelSelector} index, or {@code null} if there are too many * {@link TabModelSelector}s already built. */ - Pair<Integer, TabModelSelector> requestSelector(Activity activity, - TabCreatorManager tabCreatorManager, NextTabPolicySupplier nextTabPolicySupplier, - int index); + TabModelSelector requestSelector(Activity activity, TabCreatorManager tabCreatorManager, + NextTabPolicySupplier nextTabPolicySupplier, int index); /** * An index that represents the invalid state (i.e. when the window wasn't found in the list).
diff --git a/chrome/browser/tabmodel/internal/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerImpl.java b/chrome/browser/tabmodel/internal/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerImpl.java index c676af1..0e08abd 100644 --- a/chrome/browser/tabmodel/internal/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerImpl.java +++ b/chrome/browser/tabmodel/internal/android/java/src/org/chromium/chrome/browser/tabmodel/TabWindowManagerImpl.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.tabmodel; import android.app.Activity; -import android.util.Pair; import android.util.SparseArray; import org.chromium.base.ActivityState; @@ -44,18 +43,10 @@ } @Override - public Pair<Integer, TabModelSelector> requestSelector(Activity activity, - TabCreatorManager tabCreatorManager, NextTabPolicySupplier nextTabPolicySupplier, - int index) { + public TabModelSelector requestSelector(Activity activity, TabCreatorManager tabCreatorManager, + NextTabPolicySupplier nextTabPolicySupplier, int index) { if (mAssignments.get(activity) != null) { - TabModelSelector assignedSelector = mAssignments.get(activity); - for (int i = 0; i < mSelectors.size(); i++) { - if (mSelectors.get(i) == assignedSelector) { - return Pair.create(i, assignedSelector); - } - } - throw new IllegalStateException( - "TabModelSelector is assigned to an Activity but has no index."); + return mAssignments.get(activity); } if (index < 0 || index >= mSelectors.size()) index = 0; @@ -77,7 +68,7 @@ mSelectors.set(index, selector); mAssignments.put(activity, selector); - return Pair.create(index, selector); + return selector; } @Override
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index afee70a..6907f9e 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -2588,6 +2588,8 @@ "webui/signin/inline_login_handler_chromeos.h", "webui/signin/inline_login_handler_modal_delegate.cc", "webui/signin/inline_login_handler_modal_delegate.h", + "webui/signin/signin_helper_chromeos.cc", + "webui/signin/signin_helper_chromeos.h", "webui/version/version_handler_chromeos.cc", "webui/version/version_handler_chromeos.h", "window_sizer/window_sizer_chromeos.cc",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 0492b39b..9b1a925 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -778,21 +778,24 @@ Access payment methods </message> - <!-- Privacy Sandbox Settings. Used by //chrome/browser/privacy/settings. --> + <!-- Privacy Sandbox Settings. Used by //chrome/browser/privacy_sandbox. --> <message name="IDS_PREFS_PRIVACY_SANDBOX" desc="Title for the 'Privacy sandbox' page."> Privacy sandbox </message> - <message name="IDS_PRIVACY_SANDBOX_TITLE" desc="Title for the Privacy Sandbox toggle."> - Web crowd and ad measurement + <message name="IDS_PRIVACY_SANDBOX_DESCRIPTION" desc=""> + Privacy Sandbox is a set of new technologies that will eventually protect people from cross-site tracking mechanisms, like third-party cookies, while preserving web content and services that depend on those mechanisms today. Chrome is working with website developers, publishers, advertisers, and other browsers to develop this new technology. </message> - <message name="IDS_PRIVACY_SANDBOX_SUBTITLE" desc="Description for the privacy sandbox toggle."> - By joining a Web Crowd, you allow websites to make your web experience relevant without using personally identifiable information. Similar to a crowd in a concert, websites and advertisers can only know thousands of users share a similar interest. + <message name="IDS_PRIVACY_SANDBOX_TRIAL_TITLE" desc=""> + Privacy Sandbox trial </message> - <message name="IDS_PRIVACY_SANDBOX_BULLET_ONE" desc="First bullet point of the Privacy Sandbox description."> - Allow websites and apps to give you a more relevant experience using a non-identifiable alias. + <message name="IDS_PRIVACY_SANDBOX_TRIAL_DESCRIPTION" desc=""> + Privacy Sandbox is not widely released yet. During this trial period:\n<ph name="BEGIN_LIST_ITEM1"><li1></ph>Website and app developers can try out the ability to create relevant experiences without accessing uniquely identifiable information about you<ph name="END_LIST_ITEM1"></li1></ph>\n<ph name="BEGIN_LIST_ITEM2"><li2></ph>Users can opt out of the trial using the controls on this page.<ph name="END_LIST_ITEM2"></li2></ph> </message> - <message name="IDS_PRIVACY_SANDBOX_BULLET_TWO" desc="Second bullet point of the Privacy Sandbox description"> - Allow advertisers to study ad campaigns using non-identifiable information. + <message name="IDS_PRIVACY_SANDBOX_TOGGLE" desc="Title for the Privacy Sandbox toggle."> + Crowdmasking + </message> + <message name="IDS_PRIVACY_SANDBOX_TOGGLE_DESCRIPTION" desc=""> + When on, websites won’t be able to use information that personally identifies you to make their sites more relevant. Similar to a crowd in a concert, sites can only know that thousands of users share a similar interest.\n\nYour “crowd” is based on sites you’ve visited. Advertisers can only see what sites the whole crowd visits, not what sites you personally visit. </message> <message name="IDS_PRIVACY_SANDBOX_SNACKBAR_MESSAGE" desc="The text displayed in the snackbar, which gives the user an option to navigate to the Privacy Sandbox settings page. 'Privacy sandbox' has TC ID 5753235213964358658."> Explore the Privacy Sandbox
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_BULLET_ONE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_BULLET_ONE.png.sha1 deleted file mode 100644 index c2faed2..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_BULLET_ONE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -c7e4215bdaca99c5779f861088625bf12a23893f \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_BULLET_TWO.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_BULLET_TWO.png.sha1 deleted file mode 100644 index c2faed2..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_BULLET_TWO.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -c7e4215bdaca99c5779f861088625bf12a23893f \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_DESCRIPTION.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..e390b7c6 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +ad621d4b76db8fe8a958472c451b28a81cf65dfe \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_SUBTITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_SUBTITLE.png.sha1 deleted file mode 100644 index 9e11f48..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_SUBTITLE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -a9b460c04d8c8fc10c5bc27c649879387db23d77 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TITLE.png.sha1 deleted file mode 100644 index 9e11f48..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TITLE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -a9b460c04d8c8fc10c5bc27c649879387db23d77 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TOGGLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TOGGLE.png.sha1 new file mode 100644 index 0000000..e390b7c6 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TOGGLE.png.sha1
@@ -0,0 +1 @@ +ad621d4b76db8fe8a958472c451b28a81cf65dfe \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TOGGLE_DESCRIPTION.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TOGGLE_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..e390b7c6 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TOGGLE_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +ad621d4b76db8fe8a958472c451b28a81cf65dfe \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TRIAL_DESCRIPTION.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TRIAL_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..e390b7c6 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TRIAL_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +ad621d4b76db8fe8a958472c451b28a81cf65dfe \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TRIAL_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TRIAL_TITLE.png.sha1 new file mode 100644 index 0000000..e390b7c6 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_TRIAL_TITLE.png.sha1
@@ -0,0 +1 @@ +ad621d4b76db8fe8a958472c451b28a81cf65dfe \ No newline at end of file
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc index 618dee3..e65394d 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.cc +++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -1229,6 +1229,7 @@ } base::FilePath GetStartupProfilePath(const base::FilePath& user_data_dir, + const base::FilePath& cur_dir, const base::CommandLine& command_line) { // If the browser is launched due to activation on Windows native notification, // the profile id encoded in the notification launch id should be chosen over @@ -1254,14 +1255,6 @@ command_line.GetSwitchValuePath(switches::kProfileDirectory)); } - return g_browser_process->profile_manager()->GetLastUsedProfileDir( - user_data_dir); -} - -#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) -Profile* GetStartupProfile(const base::FilePath& user_data_dir, - const base::FilePath& cur_dir, - const base::CommandLine& command_line) { ProfileManager* profile_manager = g_browser_process->profile_manager(); #if !BUILDFLAG(IS_CHROMEOS_ASH) if (ShouldShowProfilePickerAtProcessLaunch(profile_manager, command_line)) { @@ -1281,13 +1274,21 @@ // profile picker lives) also exists (or is creatable). // TODO(crbug.com/1150326): Refactor this to indicate more directly that // profile picker should be shown (returning an enum, or so). - return guest_profile; + return ProfileManager::GetGuestProfilePath(); } } #endif // !BUILDFLAG(IS_CHROMEOS_ASH) + return profile_manager->GetLastUsedProfileDir(user_data_dir); +} + +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) +Profile* GetStartupProfile(const base::FilePath& user_data_dir, + const base::FilePath& cur_dir, + const base::CommandLine& command_line) { + ProfileManager* profile_manager = g_browser_process->profile_manager(); base::FilePath profile_path = - GetStartupProfilePath(user_data_dir, command_line); + GetStartupProfilePath(user_data_dir, cur_dir, command_line); Profile* profile = profile_manager->GetProfile(profile_path); // If there is no entry in profile attributes storage, the profile is deleted,
diff --git a/chrome/browser/ui/startup/startup_browser_creator.h b/chrome/browser/ui/startup/startup_browser_creator.h index cb43506..7f4b56f9 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.h +++ b/chrome/browser/ui/startup/startup_browser_creator.h
@@ -211,6 +211,7 @@ // Returns the path that contains the profile that should be loaded on process // startup. base::FilePath GetStartupProfilePath(const base::FilePath& user_data_dir, + const base::FilePath& cur_dir, const base::CommandLine& command_line); #if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID)
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc index ee2b5f6..4d68e65 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -2235,4 +2235,37 @@ INSTANTIATE_TEST_SUITE_P(All, GuestStartupBrowserCreatorPickerTest, /*ephemeral_guest_profile_enabled=*/testing::Bool()); + +class StartupBrowserCreatorPickerNoParamsTest + : public StartupBrowserCreatorPickerTestBase {}; + +// Create a secondary profile in a separate PRE run because the existence of +// profiles is checked during startup in the actual test. +IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorPickerNoParamsTest, + PRE_ShowPickerWhenAlreadyLaunched) { + CreateMultipleProfiles(); + // Need to close the browser window manually so that the real test does not + // treat it as session restore. + CloseAllBrowsers(); +} + +IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorPickerNoParamsTest, + ShowPickerWhenAlreadyLaunched) { + // Preprequisite: The picker is shown on the first start-up + ASSERT_EQ(0u, chrome::GetTotalBrowserCount()); + + // Simulate a second start when the browser is already running. + ProfileManager* profile_manager = g_browser_process->profile_manager(); + base::FilePath user_data_dir = profile_manager->user_data_dir(); + base::FilePath current_dir = base::FilePath(); + base::CommandLine command_line(base::CommandLine::NO_PROGRAM); + StartupBrowserCreator::ProcessCommandLineAlreadyRunning( + command_line, current_dir, + GetStartupProfilePath(user_data_dir, current_dir, command_line)); + base::RunLoop().RunUntilIdle(); + + // The picker is shown again if no profile was previously opened. + EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); +} + #endif // !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc index af800f70..dc57b7bd 100644 --- a/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc
@@ -407,7 +407,7 @@ #define MAYBE_InvokeUi_ManyPermissions InvokeUi_ManyPermissions #endif IN_PROC_BROWSER_TEST_F(ExtensionInstallDialogViewInteractiveBrowserTest, - InvokeUi_ManyPermissions) { + MAYBE_InvokeUi_ManyPermissions) { for (int i = 0; i < 20; i++) AddPermission("Example permission"); ShowAndVerifyUi();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc index 7c4d2d4..59328940 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc
@@ -476,7 +476,7 @@ #define MAYBE_EmitAccessibilityEventsOnButtonFocusHint EmitAccessibilityEventsOnButtonFocusHint #endif IN_PROC_BROWSER_TEST_F(OmniboxPopupContentsViewTest, - EmitAccessibilityEventsOnButtonFocusHint) { + MAYBE_EmitAccessibilityEventsOnButtonFocusHint) { TestAXEventObserver observer; CreatePopupForTestQuery(); ACMatches matches;
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc index 4a64a6c..43fc9ed 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
@@ -33,7 +33,6 @@ #include "chrome/browser/web_applications/test/web_app_install_observer.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_registrar.h" -#include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" @@ -64,6 +63,12 @@ "Win"; #endif // BUILDFLAG(IS_CHROMEOS_ASH) +// Command-line switch that overrides test case input. Takes a comma +// separated list of testing actions. This aids in development of tests +// by allowing one to run a single test at a time, and avoid running every +// test case in the suite. +const char kWebAppIntegrationTestCase[] = "web-app-integration-test-case"; + std::string StripAllWhitespace(std::string line) { std::string output; output.reserve(line.size()); @@ -86,10 +91,24 @@ return file_path.AppendASCII(file_name); } +std::string GetCommandLineTestOverride() { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(kWebAppIntegrationTestCase)) { + return command_line->GetSwitchValueASCII(kWebAppIntegrationTestCase); + } + return ""; +} + std::vector<std::string> ReadTestInputFile(const std::string& file_name) { + std::vector<std::string> test_cases; + std::string command_line_test_case = GetCommandLineTestOverride(); + if (!command_line_test_case.empty()) { + test_cases.push_back(StripAllWhitespace(command_line_test_case)); + return test_cases; + } + base::FilePath file = GetTestFilePath(file_name); std::string contents; - std::vector<std::string> test_cases; if (!base::ReadFileToString(file, &contents)) { return test_cases; }
diff --git a/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc b/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc index c0fcee0..35ebb98a 100644 --- a/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "build/build_config.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_list.h" @@ -214,8 +215,14 @@ ExpectTabs(browser(), {start_url_}); } +// Flaky on lacros: https://crbug.com/1167176 +#if BUILDFLAG(IS_CHROMEOS_LACROS) +#define MAYBE_CaptureLinksNewClient DISABLED_CaptureLinksNewClient +#else +#define MAYBE_CaptureLinksNewClient CaptureLinksNewClient +#endif IN_PROC_BROWSER_TEST_F(WebAppDeclarativeLinkCapturingBrowserTest, - CaptureLinksNewClient) { + MAYBE_CaptureLinksNewClient) { InstallTestApp("/web_apps/capture_links_new_client.html"); Navigate(browser(), out_of_scope_);
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc index c521456..900d4a0 100644 --- a/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -622,7 +622,9 @@ response.SetStringKey( "aboutPageEndOfLifeMessage", l10n_util::GetStringFUTF16( - eol_string_id, base::TimeFormatMonthAndYear(eol_info.eol_date), + eol_string_id, + base::TimeFormatMonthAndYear(eol_info.eol_date, + /*time_zone=*/icu::TimeZone::getGMT()), base::ASCIIToUTF16(has_eol_passed ? chrome::kEolNotificationURL : chrome::kAutoUpdatePolicyURL))); } else {
diff --git a/chrome/browser/ui/webui/signin/OWNERS b/chrome/browser/ui/webui/signin/OWNERS index 5a70aec..f44c3be 100644 --- a/chrome/browser/ui/webui/signin/OWNERS +++ b/chrome/browser/ui/webui/signin/OWNERS
@@ -7,4 +7,5 @@ per-file inline_login_handler_impl*=file://chrome/credential_provider/OWNERS per-file inline_login_handler.*=file://chrome/credential_provider/OWNERS -per-file inline_login_*_chromeos.*=file://chromeos/components/account_manager/OWNERS +per-file inline_login_*_chromeos*=file://chromeos/components/account_manager/OWNERS +per-file signin_helper_chromeos.*=file://chromeos/components/account_manager/OWNERS
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc index 42d96a0a..ab46bdf 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
@@ -25,6 +25,7 @@ #include "chrome/browser/ui/webui/chromeos/edu_coexistence_state_tracker.h" #include "chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h" #include "chrome/browser/ui/webui/signin/inline_login_handler.h" +#include "chrome/browser/ui/webui/signin/signin_helper_chromeos.h" #include "chrome/common/pref_names.h" #include "chromeos/components/account_manager/account_manager_factory.h" #include "chromeos/constants/chromeos_features.h" @@ -81,102 +82,6 @@ return kCrosAddAccountEduFlow; } -// A helper class for completing the inline login flow. Primarily, it is -// responsible for exchanging the auth code, obtained after a successful user -// sign in, for OAuth tokens and subsequently populating Chrome OS -// AccountManager with these tokens. -// This object is supposed to be used in a one-shot fashion and it deletes -// itself after its work is complete. -class SigninHelper : public GaiaAuthConsumer { - public: - SigninHelper( - chromeos::AccountManager* account_manager, - const base::RepeatingClosure& close_dialog_closure, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - const std::string& gaia_id, - const std::string& email, - const std::string& auth_code, - const std::string& signin_scoped_device_id) - : account_manager_(account_manager), - close_dialog_closure_(close_dialog_closure), - email_(email), - url_loader_factory_(url_loader_factory), - gaia_auth_fetcher_(this, - gaia::GaiaSource::kChrome, - url_loader_factory) { - account_key_ = ::account_manager::AccountKey{ - gaia_id, account_manager::AccountType::kGaia}; - - DCHECK(!signin_scoped_device_id.empty()); - gaia_auth_fetcher_.StartAuthCodeForOAuth2TokenExchangeWithDeviceId( - auth_code, signin_scoped_device_id); - } - - ~SigninHelper() override = default; - - protected: - // GaiaAuthConsumer overrides. - void OnClientOAuthSuccess(const ClientOAuthResult& result) override { - // Flow of control after this call: - // |AccountManager::UpsertAccount| updates / inserts the account and calls - // its |Observer|s, one of which is - // |ProfileOAuth2TokenServiceDelegateChromeOS|. - // |ProfileOAuth2TokenServiceDelegateChromeOS::OnTokenUpserted| seeds the - // Gaia id and email id for this account in |AccountTrackerService| and - // invokes |FireRefreshTokenAvailable|. This causes the account to propagate - // throughout the Identity Service chain, including in - // |AccountFetcherService|. |AccountFetcherService::OnRefreshTokenAvailable| - // invokes |AccountTrackerService::StartTrackingAccount|, triggers a fetch - // for the account information from Gaia and updates this information into - // |AccountTrackerService|. At this point the account will be fully added to - // the system. - UpsertAccount(result.refresh_token); - - CloseDialogAndExit(); - } - - void OnClientOAuthFailure(const GoogleServiceAuthError& error) override { - // TODO(sinhak): Display an error. - CloseDialogAndExit(); - } - - void UpsertAccount(const std::string& refresh_token) { - account_manager_->UpsertAccount(account_key_, email_, refresh_token); - } - - void CloseDialogAndExit() { - close_dialog_closure_.Run(); - Exit(); - } - - void Exit() { - base::SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); - } - - chromeos::AccountManager* GetAccountManager() { return account_manager_; } - - const std::string GetEmail() { return email_; } - - const scoped_refptr<network::SharedURLLoaderFactory> GetUrlLoaderFactory() { - return url_loader_factory_; - } - - private: - // A non-owning pointer to Chrome OS AccountManager. - chromeos::AccountManager* const account_manager_; - // A closure to close the hosting dialog window. - base::RepeatingClosure close_dialog_closure_; - // The user's AccountKey for which |this| object has been created. - ::account_manager::AccountKey account_key_; - // The user's email for which |this| object has been created. - const std::string email_; - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - // Used for exchanging auth code for OAuth tokens. - GaiaAuthFetcher gaia_auth_fetcher_; - - DISALLOW_COPY_AND_ASSIGN(SigninHelper); -}; - // A version of SigninHelper for child users. After obtaining OAuth token it // logs the parental consent with provided parent id and rapt. After successful // consent logging populates Chrome OS AccountManager with the token.
diff --git a/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc b/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc new file mode 100644 index 0000000..1ea11a85 --- /dev/null +++ b/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc
@@ -0,0 +1,83 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/signin/signin_helper_chromeos.h" + +#include "google_apis/gaia/gaia_auth_fetcher.h" + +namespace chromeos { + +SigninHelper::SigninHelper( + chromeos::AccountManager* account_manager, + const base::RepeatingClosure& close_dialog_closure, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& gaia_id, + const std::string& email, + const std::string& auth_code, + const std::string& signin_scoped_device_id) + : account_manager_(account_manager), + close_dialog_closure_(close_dialog_closure), + email_(email), + url_loader_factory_(std::move(url_loader_factory)), + gaia_auth_fetcher_(this, gaia::GaiaSource::kChrome, url_loader_factory) { + account_key_ = ::account_manager::AccountKey{ + gaia_id, ::account_manager::AccountType::kGaia}; + + DCHECK(!signin_scoped_device_id.empty()); + gaia_auth_fetcher_.StartAuthCodeForOAuth2TokenExchangeWithDeviceId( + auth_code, signin_scoped_device_id); +} + +SigninHelper::~SigninHelper() = default; + +void SigninHelper::OnClientOAuthSuccess(const ClientOAuthResult& result) { + // Flow of control after this call: + // |AccountManager::UpsertAccount| updates / inserts the account and calls + // its |Observer|s, one of which is + // |ProfileOAuth2TokenServiceDelegateChromeOS|. + // |ProfileOAuth2TokenServiceDelegateChromeOS::OnTokenUpserted| seeds the + // Gaia id and email id for this account in |AccountTrackerService| and + // invokes |FireRefreshTokenAvailable|. This causes the account to propagate + // throughout the Identity Service chain, including in + // |AccountFetcherService|. |AccountFetcherService::OnRefreshTokenAvailable| + // invokes |AccountTrackerService::StartTrackingAccount|, triggers a fetch + // for the account information from Gaia and updates this information into + // |AccountTrackerService|. At this point the account will be fully added to + // the system. + UpsertAccount(result.refresh_token); + + CloseDialogAndExit(); +} + +void SigninHelper::OnClientOAuthFailure(const GoogleServiceAuthError& error) { + // TODO(sinhak): Display an error. + CloseDialogAndExit(); +} + +void SigninHelper::UpsertAccount(const std::string& refresh_token) { + account_manager_->UpsertAccount(account_key_, email_, refresh_token); +} + +void SigninHelper::CloseDialogAndExit() { + close_dialog_closure_.Run(); + Exit(); +} + +void SigninHelper::Exit() { + base::SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); +} + +chromeos::AccountManager* SigninHelper::GetAccountManager() { + return account_manager_; +} + +std::string SigninHelper::GetEmail() { + return email_; +} + +scoped_refptr<network::SharedURLLoaderFactory> +SigninHelper::GetUrlLoaderFactory() { + return url_loader_factory_; +} +} // namespace chromeos
diff --git a/chrome/browser/ui/webui/signin/signin_helper_chromeos.h b/chrome/browser/ui/webui/signin/signin_helper_chromeos.h new file mode 100644 index 0000000..1a4bcff --- /dev/null +++ b/chrome/browser/ui/webui/signin/signin_helper_chromeos.h
@@ -0,0 +1,72 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_HELPER_CHROMEOS_H_ +#define CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_HELPER_CHROMEOS_H_ + +#include "chromeos/components/account_manager/account_manager.h" +#include "google_apis/gaia/gaia_auth_consumer.h" +#include "google_apis/gaia/gaia_auth_fetcher.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" + +namespace chromeos { + +// A helper class for completing the inline login flow. Primarily, it is +// responsible for exchanging the auth code, obtained after a successful user +// sign in, for OAuth tokens and subsequently populating Chrome OS +// AccountManager with these tokens. +// This object is supposed to be used in a one-shot fashion and it deletes +// itself after its work is complete. +class SigninHelper : public GaiaAuthConsumer { + public: + SigninHelper( + chromeos::AccountManager* account_manager, + const base::RepeatingClosure& close_dialog_closure, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& gaia_id, + const std::string& email, + const std::string& auth_code, + const std::string& signin_scoped_device_id); + + SigninHelper(const SigninHelper&) = delete; + SigninHelper& operator=(const SigninHelper&) = delete; + ~SigninHelper() override; + + protected: + // GaiaAuthConsumer overrides. + void OnClientOAuthSuccess(const ClientOAuthResult& result) override; + void OnClientOAuthFailure(const GoogleServiceAuthError& error) override; + + void UpsertAccount(const std::string& refresh_token); + + // Closes the inline login dialog and calls `Exit`. + void CloseDialogAndExit(); + + // Deletes this object. + void Exit(); + + chromeos::AccountManager* GetAccountManager(); + + // Returns email address of the account being added. + std::string GetEmail(); + + scoped_refptr<network::SharedURLLoaderFactory> GetUrlLoaderFactory(); + + private: + // A non-owning pointer to Chrome OS AccountManager. + chromeos::AccountManager* const account_manager_; + // A closure to close the hosting dialog window. + base::RepeatingClosure close_dialog_closure_; + // The user's AccountKey for which |this| object has been created. + ::account_manager::AccountKey account_key_; + // The user's email for which |this| object has been created. + const std::string email_; + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + // Used for exchanging auth code for OAuth tokens. + GaiaAuthFetcher gaia_auth_fetcher_; +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_HELPER_CHROMEOS_H_
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 4083a16..8395422 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-master-1610690109-4d1151c59ad39afee419f9fccf0374e5470965d9.profdata +chrome-linux-master-1610711423-18f006eac9d09987835ac3798b0f3a285cb6646c.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 2a303a21..fd959ae 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-master-1610679078-fe2bb289a257049a216843cebd228815ff771bd5.profdata +chrome-win32-master-1610711423-66d1757656af1c1220147c4ed72bfc529787f050.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 743bb94b..4dfa432 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1610679078-e6bf7486827a51823717a01d08f3ea1e32a813ef.profdata +chrome-win64-master-1610711423-bdaee35d021c9a50df10abe9e0067f035c4386a3.profdata
diff --git a/chrome/installer/mac/signing/model.py b/chrome/installer/mac/signing/model.py index 490df48..a5d3c40 100644 --- a/chrome/installer/mac/signing/model.py +++ b/chrome/installer/mac/signing/model.py
@@ -178,7 +178,8 @@ creator_code=None, channel_customize=False, package_as_dmg=True, - package_as_pkg=False): + package_as_pkg=False, + inflation_kilobytes=0): """Creates a new Distribution object. All arguments are optional. Args: @@ -208,6 +209,8 @@ the product. package_as_pkg: If True, then a .pkg file will be created containing the product. + inflation_kilobytes: If non-zero, a blob of this size will be + inserted into the DMG. Incompatible with package_as_pkg = True. """ if channel_customize: # Side-by-side channels must have a distinct names and creator @@ -226,6 +229,10 @@ self.channel_customize = channel_customize self.package_as_dmg = package_as_dmg self.package_as_pkg = package_as_pkg + self.inflation_kilobytes = inflation_kilobytes + + # inflation_kilobytes are only inserted into DMGs + assert not self.inflation_kilobytes or self.package_as_dmg def brandless_copy(self): """Derives and returns a copy of this Distribution object, identical
diff --git a/chrome/installer/mac/signing/pipeline.py b/chrome/installer/mac/signing/pipeline.py index c5a005a..59f20d1 100644 --- a/chrome/installer/mac/signing/pipeline.py +++ b/chrome/installer/mac/signing/pipeline.py
@@ -413,6 +413,12 @@ ] # yapf: enable + if dist.inflation_kilobytes: + pkg_dmg += [ + '--copy', + '{}/inflation.bin:/.background/inflation.bin'.format(packaging_dir) + ] + if config.is_chrome_branded(): # yapf: disable pkg_dmg += [ @@ -506,6 +512,8 @@ customizations.append(dist.creator_code) if dist.branding_code and _include_branding_code_in_app(dist): customizations.append(dist.branding_code) + if dist.inflation_kilobytes: + customizations.append(str(dist.inflation_kilobytes)) return '-'.join(customizations) @@ -607,6 +615,14 @@ notary_paths.work, _intermediate_work_dir_name(dist_config.distribution))) + if dist.inflation_kilobytes: + inflation_path = os.path.join( + paths.packaging_dir(config), 'inflation.bin') + commands.run_command([ + 'dd', 'if=/dev/urandom', 'of=' + inflation_path, + 'bs=1000', 'count={}'.format(dist.inflation_kilobytes) + ]) + if dist.package_as_dmg: dmg_path = _package_and_sign_dmg(paths, dist_config)
diff --git a/chrome/installer/mac/signing/pipeline_test.py b/chrome/installer/mac/signing/pipeline_test.py index 9ef55066..b204b338 100644 --- a/chrome/installer/mac/signing/pipeline_test.py +++ b/chrome/installer/mac/signing/pipeline_test.py
@@ -823,6 +823,72 @@ mock.call._package_installer_tools(mock.ANY, mock.ANY), ]) + def test_sign_inflated_distribution_dmg(self, **kwargs): + manager = mock.Mock() + for attr in kwargs: + manager.attach_mock(kwargs[attr], attr) + + app_uuid = 'f38ee49c-c55b-4a10-a4f5-aaaa17636b76' + dmg_uuid = '9f49067e-a13d-436a-8016-3a22a4f6ef92' + kwargs['submit'].side_effect = [app_uuid, dmg_uuid] + kwargs['wait_for_results'].side_effect = [ + iter([app_uuid]), iter([dmg_uuid]) + ] + kwargs[ + '_package_and_sign_dmg'].return_value = '/$O/AppProduct-99.0.9999.99.dmg' + + class Config(test_config.TestConfig): + + @property + def distributions(self): + return [ + model.Distribution( + inflation_kilobytes=5000, + package_as_dmg=True, + package_as_pkg=False), + ] + + config = Config() + + pipeline.sign_all(self.paths, config) + + self.assertEqual(1, kwargs['_package_installer_tools'].call_count) + + manager.assert_has_calls([ + # First customize the distribution and sign it. + mock.call._customize_and_sign_chrome(mock.ANY, mock.ANY, + '/$W_1/stable-5000', mock.ANY), + + # Prepare the app for notarization. + mock.call.run_command([ + 'zip', '--recurse-paths', '--symlinks', '--quiet', + '/$W_1/AppProduct-99.0.9999.99.zip', 'App Product.app' + ], + cwd='/$W_1/stable-5000'), + mock.call.submit('/$W_1/AppProduct-99.0.9999.99.zip', mock.ANY), + mock.call.shutil.rmtree('/$W_2'), + mock.call.wait_for_results({app_uuid: None}.keys(), mock.ANY), + mock.call._staple_chrome( + self.paths.replace_work('/$W_1/stable-5000'), mock.ANY), + mock.call.run_command([ + 'dd', 'if=/dev/urandom', + 'of=/$I/Product Packaging/inflation.bin', 'bs=1000', + 'count=5000' + ]), + + # Make the DMG. + mock.call._package_and_sign_dmg(mock.ANY, mock.ANY), + + # Notarize the DMG. + mock.call.submit('/$O/AppProduct-99.0.9999.99.dmg', mock.ANY), + mock.call.wait_for_results({dmg_uuid: None}.keys(), mock.ANY), + mock.call.staple('/$O/AppProduct-99.0.9999.99.dmg'), + mock.call.shutil.rmtree('/$W_1'), + + # Package the installer tools. + mock.call._package_installer_tools(mock.ANY, mock.ANY), + ]) + def test_sign_basic_distribution_pkg(self, **kwargs): manager = mock.Mock() for attr in kwargs:
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 1d98268..b466ee1 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2505,7 +2505,6 @@ "../browser/chromeos/file_manager/video_player_browsertest.cc", "../browser/chromeos/file_manager/video_player_jstest.cc", "../browser/chromeos/first_run/drive_first_run_browsertest.cc", - "../browser/chromeos/full_restore/app_launch_handler_browsertest.cc", "../browser/chromeos/input_method/input_method_engine_browsertests.cc", "../browser/chromeos/input_method/native_input_method_engine_browsertest.cc", "../browser/chromeos/input_method/textinput_browsertest.cc",
diff --git a/chrome/test/data/extensions/api_test/automation/sites/iframenav/iframe-button.html b/chrome/test/data/extensions/api_test/automation/sites/iframenav/iframe-button.html new file mode 100644 index 0000000..3008b51 --- /dev/null +++ b/chrome/test/data/extensions/api_test/automation/sites/iframenav/iframe-button.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<body> +<div> + <button onClick="doNav();"> + First Button + </button> +</div> +</body> +<script> +function doNav() { + window.parent.doNavFunc(); +} +</script> +</html>
diff --git a/chrome/test/data/extensions/api_test/automation/sites/iframenav/iframe-button2.html b/chrome/test/data/extensions/api_test/automation/sites/iframenav/iframe-button2.html new file mode 100644 index 0000000..f04382e --- /dev/null +++ b/chrome/test/data/extensions/api_test/automation/sites/iframenav/iframe-button2.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> +<body> +<div> + <button> + Second Button + </button> +</div> +</body> +</html>
diff --git a/chrome/test/data/extensions/api_test/automation/sites/iframenav/iframe-top.html b/chrome/test/data/extensions/api_test/automation/sites/iframenav/iframe-top.html new file mode 100644 index 0000000..23490f7b --- /dev/null +++ b/chrome/test/data/extensions/api_test/automation/sites/iframenav/iframe-top.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> + +<div> + <iframe id="frame1" src="iframe-button.html"></iframe> +</div> + +<script> + function doNavFunc() { + let iframe = document.getElementById("frame1"); + iframe.src="iframe-button2.html"; + } +</script> + +</html>
diff --git a/chrome/test/data/extensions/api_test/automation/tests/desktop/iframenav.html b/chrome/test/data/extensions/api_test/automation/tests/desktop/iframenav.html new file mode 100644 index 0000000..664957b0 --- /dev/null +++ b/chrome/test/data/extensions/api_test/automation/tests/desktop/iframenav.html
@@ -0,0 +1,7 @@ +<!-- + * Copyright 2021 The Chromium Authors. All rights reserved. Use of this + * source code is governed by a BSD-style license that can be found in the + * LICENSE file. +--> +<script src="common.js"></script> +<script src="iframenav.js"></script>
diff --git a/chrome/test/data/extensions/api_test/automation/tests/desktop/iframenav.js b/chrome/test/data/extensions/api_test/automation/tests/desktop/iframenav.js new file mode 100644 index 0000000..ef80ef33a --- /dev/null +++ b/chrome/test/data/extensions/api_test/automation/tests/desktop/iframenav.js
@@ -0,0 +1,54 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var firstButton = undefined; +var clicked = false; + +function checkNodes(rootNode) { + // Grab the first button and hold on to it. + if (!firstButton) { + firstButton = findAutomationNode(rootNode, function(n) { + return n.name == 'First Button' + }); + } + + // Search for second button. + const secondButton = findAutomationNode(rootNode, function(n) { + return n.name == 'Second Button' + }); + + // If we have the first but not the second, click the + // switch button to swap out the frame. + if (firstButton && !secondButton && !clicked) { + firstButton.doDefault(); + clicked = true; + } + + // Still waiting for expected state. If neither button + // was found yet, keep polling. + if (!firstButton || firstButton.role || !secondButton) { + setTimeout(checkNodes.bind(this, rootNode), 100); + return; + } + + // Repetitive check with the above condition, but to make it clear to the + // reader what's being tested. If the first button's role is still valid, + // the test failed because its tree should have been destroyed. + chrome.test.assertTrue(!!firstButton && !!secondButton); + chrome.test.assertTrue(!firstButton.role && !!secondButton.role); + chrome.test.succeed(); +} + +var allTests = [ + function treeDestroyedTest() { + chrome.test.getConfig(function(config) { + const url = 'http://a.com:' + config.testServer.port + '/iframenav/iframe-top.html'; + chrome.tabs.create({url: url}); + + chrome.automation.getDesktop(checkNodes.bind(this)); + }); + }, +]; + +chrome.test.runTests(allTests);
diff --git a/chrome/test/data/webui/signin/local_profile_customization_focus_test.js b/chrome/test/data/webui/signin/local_profile_customization_focus_test.js index 23b649c..c50181d 100644 --- a/chrome/test/data/webui/signin/local_profile_customization_focus_test.js +++ b/chrome/test/data/webui/signin/local_profile_customization_focus_test.js
@@ -48,7 +48,7 @@ /** @param {!ProfilePickerMainViewElement} mainView */ function navigateToProfileCreationFromMainView(mainView) { mainView.$$('#addProfile').focus(); - mainView.$$('#addProfile').querySelectorAll('cr-icon-button')[0].click(); + mainView.$$('#addProfile').click(); flush(); }
diff --git a/chrome/test/data/webui/signin/profile_picker_app_test.js b/chrome/test/data/webui/signin/profile_picker_app_test.js index 4083880..7203d5e 100644 --- a/chrome/test/data/webui/signin/profile_picker_app_test.js +++ b/chrome/test/data/webui/signin/profile_picker_app_test.js
@@ -82,8 +82,8 @@ 'profiles-list-changed', [browserProxy.profileSample]); flushTasks(); assertEquals( - mainView.shadowRoot.querySelectorAll('profile-card').length, 1); - mainView.$$('#addProfile').querySelectorAll('cr-icon-button')[0].click(); + mainView.$$('#wrapper').querySelectorAll('profile-card').length, 1); + mainView.$$('#addProfile').click(); await waitForProfileCretionLoad(); assertEquals( testElement.shadowRoot.querySelectorAll('[slot=view]').length, 2);
diff --git a/chromecast/browser/cast_network_contexts.cc b/chromecast/browser/cast_network_contexts.cc index de42438..3f33336e 100644 --- a/chromecast/browser/cast_network_contexts.cc +++ b/chromecast/browser/cast_network_contexts.cc
@@ -30,6 +30,10 @@ namespace chromecast { namespace shell { +namespace { +constexpr char kCookieStoreFile[] = "Cookies"; +} // namespace + // SharedURLLoaderFactory backed by a CastNetworkContexts and its system // NetworkContext. Transparently handles crashes. class CastNetworkContexts::URLLoaderFactoryForSystem @@ -193,6 +197,13 @@ network_context_params->accept_language = CastHttpUserAgentSettings::AcceptLanguage(); + auto* browser_context = CastBrowserProcess::GetInstance()->browser_context(); + DCHECK(browser_context); + network_context_params->cookie_path = + browser_context->GetPath().Append(kCookieStoreFile); + network_context_params->restore_old_session_cookies = false; + network_context_params->persist_session_cookies = true; + // Disable idle sockets close on memory pressure, if instructed by DCS. On // memory constrained devices: // 1. if idle sockets are closed when memory pressure happens, cast_shell will
diff --git a/chromeos/components/sync_wifi/local_network_collector_impl.cc b/chromeos/components/sync_wifi/local_network_collector_impl.cc index f24a7271..7e0fe08e 100644 --- a/chromeos/components/sync_wifi/local_network_collector_impl.cc +++ b/chromeos/components/sync_wifi/local_network_collector_impl.cc
@@ -209,14 +209,8 @@ properties->type_properties->get_wifi()->auto_connect)); proto.set_is_preferred(IsPreferredProtoFromMojo(properties->priority)); - if (properties->metered) { - proto.set_metered( - properties->metered->active_value - ? sync_pb:: - WifiConfigurationSpecifics_MeteredOption_METERED_OPTION_YES - : sync_pb:: - WifiConfigurationSpecifics_MeteredOption_METERED_OPTION_NO); - } + // TODO(crbug/1128692): Restore support for the metered property when mojo + // networks track the "Automatic" state. bool is_proxy_modified = network_metadata_store_->GetIsFieldExternallyModified(
diff --git a/chromeos/components/sync_wifi/network_type_conversions.cc b/chromeos/components/sync_wifi/network_type_conversions.cc index d3b30e7..a201ba3 100644 --- a/chromeos/components/sync_wifi/network_type_conversions.cc +++ b/chromeos/components/sync_wifi/network_type_conversions.cc
@@ -276,17 +276,8 @@ ? 1 : 0); - if (specifics.has_metered() && - specifics.metered() != - sync_pb:: - WifiConfigurationSpecifics_MeteredOption_METERED_OPTION_UNSPECIFIED && - specifics.metered() != - sync_pb:: - WifiConfigurationSpecifics_MeteredOption_METERED_OPTION_AUTO) { - config->metered = network_config::mojom::MeteredConfig::New( - specifics.metered() == - sync_pb::WifiConfigurationSpecifics_MeteredOption_METERED_OPTION_YES); - } + // TODO(crbug/1128692): Restore support for the metered property when mojo + // networks track the "Automatic" state. // For backwards compatibility, any available custom nameservers are still // applied when the dns_option is not set.
diff --git a/chromeos/constants/chromeos_switches.cc b/chromeos/constants/chromeos_switches.cc index 8c308b92..09f86733 100644 --- a/chromeos/constants/chromeos_switches.cc +++ b/chromeos/constants/chromeos_switches.cc
@@ -33,10 +33,6 @@ const char kAggressiveCacheDiscardThreshold[] = "aggressive-cache-discard"; -const char kAggressiveTabDiscardThreshold[] = "aggressive-tab-discard"; - -const char kAggressiveThreshold[] = "aggressive"; - // If this flag is passed, failed policy fetches will not cause profile // initialization to fail. This is useful for tests because it means that // tests don't have to mock out the policy infrastructure. @@ -145,13 +141,6 @@ // Sets ARC Terms Of Service hostname url for testing. const char kArcTosHostForTests[] = "arc-tos-host-for-tests"; -// If this flag is present then the device had ARC M available and gets ARC N -// when updating. -// TODO(pmarko): Remove this when we assess that it's not necessary anymore: -// crbug.com/761348. -const char kArcTransitionMigrationRequired[] = - "arc-transition-migration-required"; - // If this flag is set, it indicates that this device is a "Cellular First" // device. Cellular First devices use cellular telephone data networks as // their primary means of connecting to the internet. @@ -169,8 +158,6 @@ // non-user-writable JPEG file). const char kChildWallpaperSmall[] = "child-wallpaper-small"; -const char kConservativeThreshold[] = "conservative"; - // Forces CrOS region value. const char kCrosRegion[] = "cros-region"; @@ -235,9 +222,6 @@ // Disables requests for an enterprise machine certificate during attestation. const char kDisableMachineCertRequest[] = "disable-machine-cert-request"; -// Disables the multiple display layout UI. -const char kDisableMultiDisplayLayout[] = "disable-multi-display-layout"; - // Disables the ChromeVox hint timer in OOBE, which can lead to unexpected // behavior during tests. const char kDisableOOBEChromeVoxHintTimerForTesting[] = @@ -363,11 +347,6 @@ // "keyboard-bottom-left", keyboard-bottom-right", "keyboard-top-right". const char kFingerprintSensorLocation[] = "fingerprint-sensor-location"; -// Forces Chrome to use CertVerifyProcBuiltin for verification of server -// certificates, ignoring the status of -// net::features::kCertVerifierBuiltinFeature. -const char kForceCertVerifierBuiltin[] = "force-cert-verifier-builtin"; - // Passed to Chrome the first time that it's run after the system boots. // Not passed on restart after sign out. const char kFirstExecAfterBoot[] = "first-exec-after-boot"; @@ -490,11 +469,6 @@ // notes. If unset, a hardcoded list is used instead. const char kNoteTakingAppIds[] = "note-taking-app-ids"; -// Forces OOBE/login to force show a comma-separated list of screens from -// chromeos::kScreenNames in oobe_screen.cc. Supported screens are: -// user-image -const char kOobeForceShowScreen[] = "oobe-force-show-screen"; - // Allows the eula url to be overridden for tests. const char kOobeEulaUrlForTests[] = "oobe-eula-url-for-tests";
diff --git a/chromeos/constants/chromeos_switches.h b/chromeos/constants/chromeos_switches.h index f979f91..307586aa 100644 --- a/chromeos/constants/chromeos_switches.h +++ b/chromeos/constants/chromeos_switches.h
@@ -25,9 +25,6 @@ COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kAggressiveCacheDiscardThreshold[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) -extern const char kAggressiveTabDiscardThreshold[]; -COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kAggressiveThreshold[]; -COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kAllowFailedPolicyFetchForTest[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kAllowRAInDevMode[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kAppAutoLaunched[]; @@ -57,12 +54,9 @@ COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kArcScale[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kArcStartMode[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kArcTosHostForTests[]; -COMPONENT_EXPORT(CHROMEOS_CONSTANTS) -extern const char kArcTransitionMigrationRequired[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kCellularFirst[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kChildWallpaperLarge[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kChildWallpaperSmall[]; -COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kConservativeThreshold[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kCrosRegion[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kCrosRegionsMode[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kCrosRegionsModeHide[]; @@ -91,8 +85,6 @@ extern const char kDisableLoginAnimations[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kDisableMachineCertRequest[]; -COMPONENT_EXPORT(CHROMEOS_CONSTANTS) -extern const char kDisableMultiDisplayLayout[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kDisableNewZIPUnpacker[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kDisableOOBEChromeVoxHintTimerForTesting[]; @@ -153,8 +145,6 @@ COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kFingerprintSensorLocation[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) -extern const char kForceCertVerifierBuiltin[]; -COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kForceDevToolsAvailable[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kForceFirstRunUI[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) @@ -190,7 +180,6 @@ extern const char kNeedArcMigrationPolicyCheck[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kNoteTakingAppIds[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kOobeEulaUrlForTests[]; -COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kOobeForceShowScreen[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kOobeForceTabletFirstRun[]; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kOobeGuestSession[];
diff --git a/chromeos/lacros/BUILD.gn b/chromeos/lacros/BUILD.gn index c70fef7c..403b557 100644 --- a/chromeos/lacros/BUILD.gn +++ b/chromeos/lacros/BUILD.gn
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/rules.gni") import("//build/config/chromeos/ui_mode.gni") import("//build/config/linux/gtk/gtk.gni") import("//build/lacros/lacros_resource_sizes.gni") @@ -30,3 +31,41 @@ lacros_resource_sizes_test("resource_sizes_lacros_chrome") { data_deps = [ "//chrome:chrome" ] } + +# "cros_board" set in the GN args defines the board used to build lacros-chrome, +# while the "override_board" here defines the board on which to test the built +# binary, for more details, please refer to the "generate_runner_script" +# template in //build/config/chromeos/rules.gni. +template("lacros_tast_test_helper") { + forward_variables_from(invoker, [ "override_board" ]) + assert(defined(override_board), "override_board is required") + lacros_tast_test(target_name) { + # TODO(crbug.com/1158590): use --attr-expr instead of hard-coding the tests. + tast_tests = [ + "lacros.AudioPlay", + "lacros.AppLauncherLaunch", + "lacros.Basic", + "lacros.ShelfLaunch", + ] + } +} + +# On Chromium CI, only a very limited number of boards are supported: +# amd64-generic, eve, kevin etc, so just hard-coding them for simplicity. +if (is_chromeos_device) { + _boards = string_split(cros_boards, ":") + + string_split(cros_boards_with_qemu_images, ":") + foreach(b, _boards) { + if (b == "amd64-generic") { + lacros_tast_test_helper("lacros_tast_tests_amd64_generic") { + override_board = "amd64-generic" + } + } + + if (b == "eve") { + lacros_tast_test_helper("lacros_tast_tests_eve") { + override_board = "eve" + } + } + } +}
diff --git a/chromeos/memory/pressure/pressure.cc b/chromeos/memory/pressure/pressure.cc index af0954b..92c33a2 100644 --- a/chromeos/memory/pressure/pressure.cc +++ b/chromeos/memory/pressure/pressure.cc
@@ -82,8 +82,8 @@ } bool SupportsPSI() { - static bool supports_psi = - base::PathExists(base::FilePath("/proc/pressure/")); + // Checking path existence in procfs is fast. + static bool supports_psi = access("/proc/pressure/", F_OK) == 0; return supports_psi; }
diff --git a/components/BUILD.gn b/components/BUILD.gn index 39781322..2006fd7 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -225,6 +225,7 @@ "//components/safe_browsing/ios:unit_tests", "//components/security_state/ios:unit_tests", "//components/signin/ios/browser:unit_tests", + "//components/signin/public/identity_manager/objc:unit_tests", "//components/translate/ios/browser:unit_tests", "//components/ukm/ios:unit_tests", ]
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn index 293c7dd..4923996 100644 --- a/components/arc/BUILD.gn +++ b/components/arc/BUILD.gn
@@ -396,6 +396,7 @@ "enterprise/arc_data_snapshotd_bridge_unittest.cc", "enterprise/arc_data_snapshotd_manager_unittest.cc", "enterprise/snapshot_hours_policy_service_unittest.cc", + "enterprise/snapshot_reboot_controller_unittest.cc", "enterprise/snapshot_session_controller_unittest.cc", "ime/arc_ime_service_unittest.cc", "ime/key_event_result_receiver_unittest.cc",
diff --git a/components/arc/enterprise/BUILD.gn b/components/arc/enterprise/BUILD.gn index 58e3c83..107fabd 100644 --- a/components/arc/enterprise/BUILD.gn +++ b/components/arc/enterprise/BUILD.gn
@@ -13,6 +13,8 @@ "arc_data_snapshotd_manager.h", "snapshot_hours_policy_service.cc", "snapshot_hours_policy_service.h", + "snapshot_reboot_controller.cc", + "snapshot_reboot_controller.h", "snapshot_session_controller.cc", "snapshot_session_controller.h", ] @@ -23,6 +25,7 @@ "//chromeos/cryptohome", "//chromeos/dbus:dbus", "//chromeos/dbus/arc:arc", + "//chromeos/dbus/power", "//chromeos/dbus/upstart:upstart", "//components/arc:prefs", "//components/prefs",
diff --git a/components/arc/enterprise/arc_data_snapshotd_manager.cc b/components/arc/enterprise/arc_data_snapshotd_manager.cc index 1e105d6..9c02f71b 100644 --- a/components/arc/enterprise/arc_data_snapshotd_manager.cc +++ b/components/arc/enterprise/arc_data_snapshotd_manager.cc
@@ -52,12 +52,33 @@ !command_line->HasSwitch(chromeos::switches::kLoginManager); } +// Returns true if it is the first Chrome start up after reboot. +bool IsFirstExecAfterBoot() { + return user_manager::UserManager::Get() && + user_manager::UserManager::Get()->IsFirstExecAfterBoot(); +} + // Enables ozone platform headless via command line. void EnableHeadlessMode() { auto* command_line = base::CommandLine::ForCurrentProcess(); command_line->AppendSwitchASCII(switches::kOzonePlatform, "headless"); } +// Returns non-empty account ID string if a MGS is active. +// Otherwise returns an empty string. +std::string GetMgsCryptohomeAccountId() { + // Take snapshots only for MGSs. + if (user_manager::UserManager::Get() && + user_manager::UserManager::Get()->IsLoggedInAsPublicAccount() && + user_manager::UserManager::Get()->GetActiveUser()) { + return cryptohome::Identification(user_manager::UserManager::Get() + ->GetActiveUser() + ->GetAccountId()) + .id(); + } + return std::string(); +} + } // namespace bool ArcDataSnapshotdManager::is_snapshot_enabled_for_testing_ = false; @@ -287,7 +308,8 @@ if (IsRestoredSession()) { state_ = State::kRestored; } else { - if (snapshot_.is_blocked_ui_mode() && IsSnapshotEnabled()) { + if (snapshot_.is_blocked_ui_mode() && IsSnapshotEnabled() && + IsFirstExecAfterBoot()) { state_ = State::kBlockedUi; EnableHeadlessMode(); } @@ -334,7 +356,7 @@ std::move(callback).Run(); return; } - std::string account_id = GetCryptohomeAccountId(); + std::string account_id = GetMgsCryptohomeAccountId(); if (!account_id.empty() && IsSnapshotEnabled() && (snapshot_.last() || snapshot_.previous())) { state_ = State::kLoading; @@ -439,9 +461,11 @@ case State::kMgsLaunched: case State::kMgsToLaunch: state_ = State::kStopping; + snapshot_.set_blocked_ui_mode(false); if (session_controller_) session_controller_->RemoveObserver(this); session_controller_.reset(); + reboot_controller_.reset(); break; // Otherwise, stop all flows, clear snapshots and do not restart browser. case State::kNone: @@ -454,11 +478,48 @@ } void ArcDataSnapshotdManager::OnSnapshotUpdateEndTimeChanged() { - if (policy_service_.snapshot_update_end_time().is_null()) + if (policy_service_.snapshot_update_end_time().is_null()) { + // Process the end of the snapshot update interval. + if (reboot_controller_) { + // Stop the reboot process if already requested. + snapshot_.set_blocked_ui_mode(false); + snapshot_.Sync(); + } + reboot_controller_.reset(); return; + } if (!IsSnapshotEnabled()) return; - // TODO(pbond): may be start a reboot process to update a snapshot. + // Snapshot can be updated if necessary. Inside the snapshot update interval. + // Do not request the reboot of device if already requested. + if (reboot_controller_) + return; + // Do not reboot if last and previous snapshots exist and should not be + // updated. + if (snapshot_.last() && !snapshot_.last()->updated() && + snapshot_.previous() && !snapshot_.previous()->updated()) { + return; + } + + switch (state_) { + case State::kNone: + case State::kLoading: + case State::kRestored: + case State::kRunning: + snapshot_.set_blocked_ui_mode(true); + snapshot_.Sync(); + + // Request device to be reboot in a blocked UI mode. + reboot_controller_ = std::make_unique<SnapshotRebootController>(); + return; + case State::kBlockedUi: + case State::kMgsToLaunch: + case State::kMgsLaunched: + case State::kStopping: + // Do not reboot the device if in blocked UI mode or in process of + // disabling the feature. + return; + } } bool ArcDataSnapshotdManager::IsSnapshotEnabled() { @@ -663,7 +724,7 @@ OnSnapshotTaken(false /* success */); return; } - std::string account_id = GetCryptohomeAccountId(); + std::string account_id = GetMgsCryptohomeAccountId(); if (account_id.empty() || state_ != State::kMgsLaunched) { LOG(ERROR) << "Cryptohome account ID is empty."; OnSnapshotTaken(false /* success */); @@ -738,18 +799,5 @@ LOG(ERROR) << "Failed to update UI progress bar."; } -std::string ArcDataSnapshotdManager::GetCryptohomeAccountId() { - // Take snapshots only for MGSs. - if (user_manager::UserManager::Get() && - user_manager::UserManager::Get()->IsLoggedInAsPublicAccount() && - user_manager::UserManager::Get()->GetActiveUser()) { - return cryptohome::Identification(user_manager::UserManager::Get() - ->GetActiveUser() - ->GetAccountId()) - .id(); - } - return ""; -} - } // namespace data_snapshotd } // namespace arc
diff --git a/components/arc/enterprise/arc_data_snapshotd_manager.h b/components/arc/enterprise/arc_data_snapshotd_manager.h index f9c1512..a754587 100644 --- a/components/arc/enterprise/arc_data_snapshotd_manager.h +++ b/components/arc/enterprise/arc_data_snapshotd_manager.h
@@ -12,6 +12,7 @@ #include "base/memory/weak_ptr.h" #include "components/arc/enterprise/arc_apps_tracker.h" #include "components/arc/enterprise/snapshot_hours_policy_service.h" +#include "components/arc/enterprise/snapshot_reboot_controller.h" #include "components/arc/enterprise/snapshot_session_controller.h" #include "components/session_manager/core/session_manager_observer.h" @@ -107,6 +108,8 @@ bool is_last() const { return is_last_; } + bool updated() const { return updated_; } + private: SnapshotInfo(const std::string& os_version, const std::string& creation_date, @@ -255,6 +258,10 @@ session_controller_ = std::move(session_controller); } + SnapshotRebootController* get_reboot_controller_for_testing() const { + return reboot_controller_.get(); + } + private: // Attempts to arc-data-snapshotd daemon regardless of state of the class. // Runs |callback| once finished. @@ -307,10 +314,6 @@ // Called once a progress bar is updated. void OnUiUpdated(bool success); - // Returns non-empty account ID string if a MGS is active. - // Otherwise returns an empty string. - std::string GetCryptohomeAccountId(); - static bool is_snapshot_enabled_for_testing_; SnapshotHoursPolicyService policy_service_; @@ -333,6 +336,9 @@ // events. std::unique_ptr<SnapshotSessionController> session_controller_; + // Initialized only when the device reboot is requested. + std::unique_ptr<SnapshotRebootController> reboot_controller_; + // Used for cancelling previously posted tasks to daemon. base::WeakPtrFactory<ArcDataSnapshotdManager> daemon_weak_ptr_factory_{this}; // WeakPtrFactory to use for callbacks.
diff --git a/components/arc/enterprise/arc_data_snapshotd_manager_unittest.cc b/components/arc/enterprise/arc_data_snapshotd_manager_unittest.cc index bf26288..3a46b87 100644 --- a/components/arc/enterprise/arc_data_snapshotd_manager_unittest.cc +++ b/components/arc/enterprise/arc_data_snapshotd_manager_unittest.cc
@@ -147,11 +147,16 @@ upstart_client_ = std::make_unique<TestUpstartClient>(); arc::prefs::RegisterLocalStatePrefs(local_state_.registry()); + + base::CommandLine::ForCurrentProcess()->AppendSwitch( + chromeos::switches::kFirstExecAfterBoot); } void SetUp() override { SetDBusClientAvailability(true /* is_available */); } void TearDown() override { + ArcDataSnapshotdManager::set_snapshot_enabled_for_testing( + false /* enabled */); manager_.reset(); apps_tracker_ = nullptr; delegate_ = nullptr; @@ -689,6 +694,69 @@ false /* expected_blocked_ui_mode */); } +// Test that if the snapshot update interval is not started (end time is null), +// the device is not rebooted. +TEST_F(ArcDataSnapshotdManagerBasicTest, OnSnapshotUpdateEndTimeNullFailure) { + SetupLocalState(false /* blocked_ui_mode */); + ArcDataSnapshotdManager::set_snapshot_enabled_for_testing(true /* enabled */); + ExpectStopDaemon(false /* success */); + auto* manager = CreateManager(base::DoNothing()); + manager->OnSnapshotUpdateEndTimeChanged(); + EXPECT_FALSE(manager->get_reboot_controller_for_testing()); +} + +// Test that if snapshot feature is not enabled, the device is not rebooted. +TEST_F(ArcDataSnapshotdManagerBasicTest, + OnSnapshotUpdateEndTimeDisabledFailure) { + SetupLocalState(false /* blocked_ui_mode */); + auto* manager = CreateManager(base::DoNothing()); + manager->policy_service()->set_snapshot_update_end_time_for_testing( + base::Time::Now()); + manager->OnSnapshotUpdateEndTimeChanged(); + EXPECT_FALSE(manager->get_reboot_controller_for_testing()); +} + +// Test that if both snapshots exist and no need to update them, the device is +// not rebooted. +TEST_F(ArcDataSnapshotdManagerBasicTest, OnSnapshotUpdateEndTimeExistsFailure) { + SetupLocalState(false /* blocked_ui_mode */); + ArcDataSnapshotdManager::set_snapshot_enabled_for_testing(true /* enabled */); + ExpectStopDaemon(false /* success */); + auto* manager = CreateManager(base::DoNothing()); + manager->policy_service()->set_snapshot_update_end_time_for_testing( + base::Time::Now()); + manager->OnSnapshotUpdateEndTimeChanged(); + EXPECT_FALSE(manager->get_reboot_controller_for_testing()); +} + +// Test the end time changed twice in a raw scenario. +TEST_F(ArcDataSnapshotdManagerBasicTest, OnSnapshotUpdateEndTimeChanged) { + ArcDataSnapshotdManager::set_snapshot_enabled_for_testing(true /* enabled */); + ExpectStopDaemon(false /* success */); + auto* manager = CreateManager(base::DoNothing()); + manager->policy_service()->set_snapshot_update_end_time_for_testing( + base::Time::Now()); + // Request reboot in blocked UI mode. + manager->OnSnapshotUpdateEndTimeChanged(); + EXPECT_TRUE(manager->get_reboot_controller_for_testing()); + CheckSnapshots(0 /* expected_snapshots_number */, + true /* expected_blocked_ui_mode */); + + // The reboot is requested above. + manager->OnSnapshotUpdateEndTimeChanged(); + EXPECT_TRUE(manager->get_reboot_controller_for_testing()); + CheckSnapshots(0 /* expected_snapshots_number */, + true /* expected_blocked_ui_mode */); + + // Stop requesting a reboot if not inside the snapshot update interval. + manager->policy_service()->set_snapshot_update_end_time_for_testing( + base::Time()); + manager->OnSnapshotUpdateEndTimeChanged(); + EXPECT_FALSE(manager->get_reboot_controller_for_testing()); + CheckSnapshots(0 /* expected_snapshots_number */, + false /* expected_blocked_ui_mode */); +} + // Test that no one state should lead to any changes except when MGS is expected // to be launched. TEST_P(ArcDataSnapshotdManagerStateTest, OnSnapshotSessionStarted) { @@ -774,6 +842,35 @@ false /* expected_blocked_ui_mode */); } +TEST_P(ArcDataSnapshotdManagerStateTest, OnSnapshotUpdateEndTimeChanged) { + ArcDataSnapshotdManager::set_snapshot_enabled_for_testing(true /* enabled */); + ExpectStopDaemon(false /* success */); + auto* manager = CreateManager(base::DoNothing()); + manager->policy_service()->set_snapshot_update_end_time_for_testing( + base::Time::Now()); + manager->set_state_for_testing(expected_state()); + manager->OnSnapshotUpdateEndTimeChanged(); + + switch (expected_state()) { + case ArcDataSnapshotdManager::State::kNone: + case ArcDataSnapshotdManager::State::kLoading: + case ArcDataSnapshotdManager::State::kRestored: + case ArcDataSnapshotdManager::State::kRunning: + EXPECT_TRUE(manager->get_reboot_controller_for_testing()); + CheckSnapshots(0 /* expected_snapshots_number */, + true /* expected_blocked_ui_mode */); + break; + case ArcDataSnapshotdManager::State::kBlockedUi: + case ArcDataSnapshotdManager::State::kMgsToLaunch: + case ArcDataSnapshotdManager::State::kMgsLaunched: + case ArcDataSnapshotdManager::State::kStopping: + EXPECT_FALSE(manager->get_reboot_controller_for_testing()); + CheckSnapshots(0 /* expected_snapshots_number */, + false /* expected_blocked_ui_mode */); + break; + } +} + INSTANTIATE_TEST_SUITE_P( ArcDataSnapshotdManagerTest, ArcDataSnapshotdManagerStateTest,
diff --git a/components/arc/enterprise/snapshot_hours_policy_service.h b/components/arc/enterprise/snapshot_hours_policy_service.h index 640aa4e..3a8618f 100644 --- a/components/arc/enterprise/snapshot_hours_policy_service.h +++ b/components/arc/enterprise/snapshot_hours_policy_service.h
@@ -69,6 +69,10 @@ } const util::WallClockTimer* get_timer_for_testing() const { return &timer_; } + void set_snapshot_update_end_time_for_testing(base::Time time) { + snapshot_update_end_time_ = time; + } + private: // Processes the policy update: either ArcEnabled and // DeviceArcDataSnapshotHours.
diff --git a/components/arc/enterprise/snapshot_reboot_controller.cc b/components/arc/enterprise/snapshot_reboot_controller.cc new file mode 100644 index 0000000..fbd8959d --- /dev/null +++ b/components/arc/enterprise/snapshot_reboot_controller.cc
@@ -0,0 +1,91 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/arc/enterprise/snapshot_reboot_controller.h" + +#include "base/logging.h" +#include "chromeos/dbus/power/power_manager_client.h" +#include "components/session_manager/core/session_manager.h" +#include "components/user_manager/user_manager.h" + +namespace arc { +namespace data_snapshotd { + +namespace { + +// Requests reboot. The reboot may not happen immediately. +void RequestReboot() { + chromeos::PowerManagerClient::Get()->RequestRestart( + power_manager::REQUEST_RESTART_OTHER, "ARC data snapshot"); +} + +// Returns true if any user is logged in. +bool IsUserLoggedIn() { + return user_manager::UserManager::Get() && + user_manager::UserManager::Get()->IsUserLoggedIn(); +} + +} // namespace + +const int kMaxRebootAttempts = 3; +const base::TimeDelta kRebootAttemptDelay = base::TimeDelta::FromMinutes(5); + +SnapshotRebootController::SnapshotRebootController() { + session_manager::SessionManager::Get()->AddObserver(this); + if (IsUserLoggedIn()) { + // TODO (pbond): show notification. + } else { + // The next operation after reboot is blocking, ensure no one uses device + // during the next 5 mins. + StartRebootTimer(); + } +} + +SnapshotRebootController::~SnapshotRebootController() { + session_manager::SessionManager::Get()->RemoveObserver(this); +} + +void SnapshotRebootController::OnSessionStateChanged() { + if (IsUserLoggedIn()) { + StopRebootTimer(); + // TODO(pbond): show notification. + } else { + // The next operation after reboot is blocking, ensure no one uses device + // during the next 5 mins. + StartRebootTimer(); + } +} + +void SnapshotRebootController::StartRebootTimer() { + if (reboot_timer_.IsRunning()) + return; + reboot_attempts_ = 0; + SetRebootTimer(); +} + +void SnapshotRebootController::SetRebootTimer() { + reboot_timer_.Start(FROM_HERE, kRebootAttemptDelay, + base::BindOnce(&SnapshotRebootController::OnRebootTimer, + weak_ptr_factory_.GetWeakPtr())); +} + +void SnapshotRebootController::StopRebootTimer() { + reboot_attempts_ = 0; + if (!reboot_timer_.IsRunning()) + return; + reboot_timer_.Stop(); +} + +void SnapshotRebootController::OnRebootTimer() { + reboot_attempts_++; + RequestReboot(); + if (reboot_attempts_ >= kMaxRebootAttempts) { + LOG(ERROR) << "The number of reboot attempts exceeded for ARC snapshots."; + return; + } + SetRebootTimer(); +} + +} // namespace data_snapshotd +} // namespace arc
diff --git a/components/arc/enterprise/snapshot_reboot_controller.h b/components/arc/enterprise/snapshot_reboot_controller.h new file mode 100644 index 0000000..e0ad5871 --- /dev/null +++ b/components/arc/enterprise/snapshot_reboot_controller.h
@@ -0,0 +1,52 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_ARC_ENTERPRISE_SNAPSHOT_REBOOT_CONTROLLER_H_ +#define COMPONENTS_ARC_ENTERPRISE_SNAPSHOT_REBOOT_CONTROLLER_H_ + +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "components/session_manager/core/session_manager_observer.h" + +namespace arc { +namespace data_snapshotd { + +// Maximum number of consequent reboot attempts. +extern const int kMaxRebootAttempts; + +// A time delta between reboot attempts. +extern const base::TimeDelta kRebootAttemptDelay; + +// This class observes the MGS state changes and requests a reboot as soon as +// possible. +class SnapshotRebootController + : public session_manager::SessionManagerObserver { + public: + SnapshotRebootController(); + SnapshotRebootController(const SnapshotRebootController&) = delete; + ~SnapshotRebootController() override; + + SnapshotRebootController& operator=(const SnapshotRebootController&) = delete; + + // session_manager::SessionManagerObserver overrides: + void OnSessionStateChanged() override; + + base::OneShotTimer* get_timer_for_testing() { return &reboot_timer_; } + + private: + void StartRebootTimer(); + void SetRebootTimer(); + void StopRebootTimer(); + void OnRebootTimer(); + + base::OneShotTimer reboot_timer_; + int reboot_attempts_ = 0; + + base::WeakPtrFactory<SnapshotRebootController> weak_ptr_factory_{this}; +}; + +} // namespace data_snapshotd +} // namespace arc + +#endif // COMPONENTS_ARC_ENTERPRISE_SNAPSHOT_REBOOT_CONTROLLER_H_
diff --git a/components/arc/enterprise/snapshot_reboot_controller_unittest.cc b/components/arc/enterprise/snapshot_reboot_controller_unittest.cc new file mode 100644 index 0000000..52a7b5a1 --- /dev/null +++ b/components/arc/enterprise/snapshot_reboot_controller_unittest.cc
@@ -0,0 +1,105 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/arc/enterprise/snapshot_reboot_controller.h" +#include "base/test/task_environment.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power/fake_power_manager_client.h" +#include "components/account_id/account_id.h" +#include "components/session_manager/core/session_manager.h" +#include "components/user_manager/fake_user_manager.h" +#include "components/user_manager/scoped_user_manager.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace arc { +namespace data_snapshotd { + +namespace { + +constexpr char kPublicAccountEmail[] = "public@localhost"; + +chromeos::FakePowerManagerClient* client() { + return chromeos::FakePowerManagerClient::Get(); +} + +} // namespace + +class SnapshotRebootControllerTest : public testing::Test { + public: + void SetUp() override { + // Initialize fake D-Bus client. + chromeos::DBusThreadManager::Initialize(); + EXPECT_TRUE(chromeos::DBusThreadManager::Get()->IsUsingFakes()); + + chromeos::PowerManagerClient::InitializeFake(); + + fake_user_manager_ = new user_manager::FakeUserManager(); + scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>( + base::WrapUnique(fake_user_manager_)); + } + + void TearDown() override { + chromeos::PowerManagerClient::Shutdown(); + + chromeos::DBusThreadManager::Shutdown(); + scoped_user_manager_.reset(); + fake_user_manager_ = nullptr; + } + + void LoginUserSession() { + auto account_id = AccountId::FromUserEmail(kPublicAccountEmail); + user_manager()->AddUser(account_id); + + user_manager()->UserLoggedIn( + account_id, account_id.GetUserEmail() + "-hash", false, false); + } + + void FastForwardAttempt() { + task_environment_.FastForwardBy(kRebootAttemptDelay); + task_environment_.RunUntilIdle(); + } + + user_manager::FakeUserManager* user_manager() { return fake_user_manager_; } + + private: + base::test::TaskEnvironment task_environment_{ + base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + + session_manager::SessionManager session_manager_; + user_manager::FakeUserManager* fake_user_manager_; + std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_; +}; + +TEST_F(SnapshotRebootControllerTest, UserLoggedIn) { + LoginUserSession(); + EXPECT_TRUE(user_manager()->IsUserLoggedIn()); + SnapshotRebootController controller; + EXPECT_FALSE(controller.get_timer_for_testing()->IsRunning()); + EXPECT_EQ(0, client()->num_request_restart_calls()); +} + +TEST_F(SnapshotRebootControllerTest, BasicReboot) { + SnapshotRebootController controller; + EXPECT_EQ(0, client()->num_request_restart_calls()); + for (int i = 0; i < kMaxRebootAttempts; i++) { + EXPECT_TRUE(controller.get_timer_for_testing()->IsRunning()); + FastForwardAttempt(); + EXPECT_EQ(i + 1, client()->num_request_restart_calls()); + } + EXPECT_FALSE(controller.get_timer_for_testing()->IsRunning()); +} + +TEST_F(SnapshotRebootControllerTest, OnSessionStateChangedLogin) { + SnapshotRebootController controller; + EXPECT_TRUE(controller.get_timer_for_testing()->IsRunning()); + + LoginUserSession(); + controller.OnSessionStateChanged(); + EXPECT_FALSE(controller.get_timer_for_testing()->IsRunning()); + EXPECT_EQ(0, client()->num_request_restart_calls()); +} + +} // namespace data_snapshotd +} // namespace arc
diff --git a/components/arc/mojom/BUILD.gn b/components/arc/mojom/BUILD.gn index 74128c4..5784d111 100644 --- a/components/arc/mojom/BUILD.gn +++ b/components/arc/mojom/BUILD.gn
@@ -391,6 +391,7 @@ ":mojom", "//ui/base/ime:text_input_types", "//ui/events", + "//ui/events/ozone/layout", ] }
diff --git a/components/arc/mojom/ime_mojom_traits.cc b/components/arc/mojom/ime_mojom_traits.cc index ddf8023..870444b 100644 --- a/components/arc/mojom/ime_mojom_traits.cc +++ b/components/arc/mojom/ime_mojom_traits.cc
@@ -7,6 +7,8 @@ #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/keycode_converter.h" #include "ui/events/keycodes/keyboard_code_conversion.h" +#include "ui/events/ozone/layout/keyboard_layout_engine.h" +#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" namespace mojo { using KeyEventUniquePtr = std::unique_ptr<ui::KeyEvent>; @@ -38,8 +40,10 @@ ui::KeyboardCode key_code; ui::DomKey dom_key; - if (!DomCodeToUsLayoutDomKey(dom_code, flags, &dom_key, &key_code)) + if (!ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup( + dom_code, flags, &dom_key, &key_code)) { return false; + } *out = std::make_unique<ui::KeyEvent>(type, key_code, dom_code, flags, dom_key, base::TimeTicks::Now());
diff --git a/components/autofill/core/browser/autofill_download_manager.cc b/components/autofill/core/browser/autofill_download_manager.cc index e356433a..097f5b9 100644 --- a/components/autofill/core/browser/autofill_download_manager.cc +++ b/components/autofill/core/browser/autofill_download_manager.cc
@@ -590,10 +590,12 @@ std::vector<variations::VariationID>* AutofillDownloadManager::active_experiments_ = nullptr; -AutofillDownloadManager::AutofillDownloadManager(AutofillDriver* driver, - Observer* observer, - const std::string& api_key, - LogManager* log_manager) +AutofillDownloadManager::AutofillDownloadManager( + AutofillDriver* driver, + Observer* observer, + const std::string& api_key, + IsRawMetadataUploadingEnabled is_raw_metadata_uploading_enabled, + LogManager* log_manager) : driver_(driver), observer_(observer), api_key_(api_key), @@ -601,7 +603,8 @@ autofill_server_url_(GetAutofillServerURL()), throttle_reset_period_(GetThrottleResetPeriod()), max_form_cache_size_(kAutofillDownloadManagerMaxFormCacheSize), - loader_backoff_(&kAutofillBackoffPolicy) { + loader_backoff_(&kAutofillBackoffPolicy), + is_raw_metadata_uploading_enabled_(is_raw_metadata_uploading_enabled) { DCHECK(observer_); } @@ -610,6 +613,7 @@ : AutofillDownloadManager(driver, observer, kDefaultAPIKey, + IsRawMetadataUploadingEnabled(false), /*log_manager=*/nullptr) {} AutofillDownloadManager::~AutofillDownloadManager() = default; @@ -706,7 +710,8 @@ std::vector<FormSignature> form_signatures; if (!form.EncodeUploadRequest(available_field_types, form_was_autofilled, login_form_signature, observed_submission, - &upload, &form_signatures)) { + is_raw_metadata_uploading_enabled_, &upload, + &form_signatures)) { return false; }
diff --git a/components/autofill/core/browser/autofill_download_manager.h b/components/autofill/core/browser/autofill_download_manager.h index 8aaececf..afd5e4dc 100644 --- a/components/autofill/core/browser/autofill_download_manager.h +++ b/components/autofill/core/browser/autofill_download_manager.h
@@ -19,6 +19,7 @@ #include "base/memory/weak_ptr.h" #include "base/strings/string_piece.h" #include "base/time/time.h" +#include "base/types/strong_alias.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/common/signatures.h" @@ -50,6 +51,8 @@ REQUEST_QUERY, REQUEST_UPLOAD, }; + using IsRawMetadataUploadingEnabled = + base::StrongAlias<class IsRawMetadataUploadingEnabledTag, bool>; // An interface used to notify clients of AutofillDownloadManager. class Observer { @@ -79,16 +82,18 @@ // |driver| must outlive this instance. // |observer| - observer to notify on successful completion or error. - // Uses an API callback function that gives an empty string. - AutofillDownloadManager(AutofillDriver* driver, Observer* observer); - // |driver| must outlive this instance. - // |observer| - observer to notify on successful completion or error. // |api_key| - API key to add to API request query parameters. Will only take // effect if using API. - AutofillDownloadManager(AutofillDriver* driver, - Observer* observer, - const std::string& api_key, - LogManager* log_manager); + AutofillDownloadManager( + AutofillDriver* driver, + Observer* observer, + const std::string& api_key, + IsRawMetadataUploadingEnabled is_raw_metadata_uploading_enabled, + LogManager* log_manager); + // |driver| must outlive this instance. + // |observer| - observer to notify on successful completion or error. + // Uses an API callback function that gives an empty string. + AutofillDownloadManager(AutofillDriver* driver, Observer* observer); virtual ~AutofillDownloadManager(); // Starts a query request to Autofill servers. The observer is called with the @@ -225,6 +230,10 @@ // Used for exponential backoff of requests. net::BackoffEntry loader_backoff_; + // Whether form data (e.g. form and field names) can be uploaded in clear + // text. + bool is_raw_metadata_uploading_enabled_ = false; + base::WeakPtrFactory<AutofillDownloadManager> weak_factory_{this}; };
diff --git a/components/autofill/core/browser/autofill_download_manager_unittest.cc b/components/autofill/core/browser/autofill_download_manager_unittest.cc index 47fde356..bf06e7d 100644 --- a/components/autofill/core/browser/autofill_download_manager_unittest.cc +++ b/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -158,10 +158,12 @@ Observer* observer, const std::string& api_key, size_t length) - : AutofillDownloadManager(driver, - observer, - api_key, - /*log_manager=*/nullptr), + : AutofillDownloadManager( + driver, + observer, + api_key, + AutofillDownloadManager::IsRawMetadataUploadingEnabled(false), + /*log_manager=*/nullptr), length_(length) {} protected: @@ -343,8 +345,10 @@ form_structures.push_back(std::make_unique<FormStructure>(form)); // Make download manager. - AutofillDownloadManager download_manager(&driver_, this, "dummykey", - /*log_manager=*/nullptr); + AutofillDownloadManager download_manager( + &driver_, this, "dummykey", + AutofillDownloadManager::IsRawMetadataUploadingEnabled(false), + /*log_manager=*/nullptr); // Request with id 0. base::HistogramTester histogram; @@ -533,8 +537,10 @@ std::vector<std::unique_ptr<FormStructure>> form_structures; form_structures.push_back(std::make_unique<FormStructure>(form)); - AutofillDownloadManager download_manager(&driver_, this, "dummykey", - /*log_manager=*/nullptr); + AutofillDownloadManager download_manager( + &driver_, this, "dummykey", + AutofillDownloadManager::IsRawMetadataUploadingEnabled(false), + /*log_manager=*/nullptr); // Start the query request and look if it is successful. No response was // received yet. @@ -722,7 +728,7 @@ // We don't want upload throttling for testing purpose. {features::kAutofillUploadThrottling}); - // Build the form structures that we want to query. + // Build the form structures that we want to upload. FormData form; FormFieldData field; @@ -739,8 +745,10 @@ form_structure.set_submission_source(SubmissionSource::FORM_SUBMISSION); std::unique_ptr<PrefService> pref_service = test::PrefServiceForTesting(); - AutofillDownloadManager download_manager(&driver_, this, "dummykey", - /*log_manager=*/nullptr); + AutofillDownloadManager download_manager( + &driver_, this, "dummykey", + AutofillDownloadManager::IsRawMetadataUploadingEnabled(false), + /*log_manager=*/nullptr); EXPECT_TRUE(download_manager.StartUploadRequest(form_structure, true, ServerFieldTypeSet(), "", true, pref_service.get())); @@ -786,6 +794,80 @@ net::HTTP_OK, 1); } +TEST_F(AutofillDownloadManagerTest, UploadWithRawMetadata) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + // Enabled + {}, + // Disabled + // We don't want upload throttling for testing purpose. + {features::kAutofillUploadThrottling}); + + for (bool is_raw_metadata_uploading_enabled : {false, true}) { + SCOPED_TRACE(testing::Message() << "is_raw_metadata_uploading_enabled = " + << is_raw_metadata_uploading_enabled); + // Build the form structures that we want to upload. + FormData form; + form.name = UTF8ToUTF16("form1"); + FormFieldData field; + + field.name = UTF8ToUTF16("firstname"); + field.form_control_type = "text"; + form.fields.push_back(field); + + field.name = UTF8ToUTF16("lastname"); + field.form_control_type = "text"; + form.fields.push_back(field); + FormStructure form_structure(form); + form_structure.set_submission_source(SubmissionSource::FORM_SUBMISSION); + + std::unique_ptr<PrefService> pref_service = test::PrefServiceForTesting(); + AutofillDownloadManager download_manager( + &driver_, this, "dummykey", + AutofillDownloadManager::IsRawMetadataUploadingEnabled( + is_raw_metadata_uploading_enabled), + /*log_manager=*/nullptr); + EXPECT_TRUE(download_manager.StartUploadRequest(form_structure, true, + ServerFieldTypeSet(), "", + true, pref_service.get())); + + // Inspect the request that the test URL loader sent. + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + network::TestURLLoaderFactory::PendingRequest* request = + test_url_loader_factory_.GetPendingRequest(0); + + // Assert some of the fields within the uploaded proto to make sure it was + // filled with something else than default data. + AutofillUploadRequest autofill_upload_request; + EXPECT_TRUE( + GetUploadRequestProtoFromRequest(request, &autofill_upload_request)); + AutofillUploadContents upload = autofill_upload_request.upload(); + EXPECT_GT(upload.client_version().size(), 0U); + EXPECT_EQ(FormSignature(upload.form_signature()), + form_structure.form_signature()); + // Only a few strings are tested, full testing happens in FormStructure's + // tests. + ASSERT_EQ(is_raw_metadata_uploading_enabled, upload.has_form_name()); + ASSERT_EQ(is_raw_metadata_uploading_enabled, upload.field()[0].has_name()); + ASSERT_EQ(is_raw_metadata_uploading_enabled, upload.field()[1].has_type()); + if (is_raw_metadata_uploading_enabled) { + EXPECT_EQ(form.name, UTF8ToUTF16(upload.form_name())); + EXPECT_EQ(form.fields[0].name, UTF8ToUTF16(upload.field()[0].name())); + EXPECT_EQ(form.fields[1].form_control_type, upload.field()[1].type()); + } + + test_url_loader_factory_.SimulateResponseForPendingRequest( + request->request.url.spec(), ""); + EXPECT_EQ(1U, responses_.size()); + EXPECT_EQ(AutofillDownloadManagerTest::UPLOAD_SUCCESSFULL, + responses_.front().type_of_response); + + ASSERT_EQ(0, test_url_loader_factory_.NumPending()); + test_url_loader_factory_.ClearResponses(); + responses_.clear(); + } +} + TEST_F(AutofillDownloadManagerTest, BackoffLogic_Query) { FormData form; FormFieldData field;
diff --git a/components/autofill/core/browser/autofill_handler.cc b/components/autofill/core/browser/autofill_handler.cc index e513358..d3036399 100644 --- a/components/autofill/core/browser/autofill_handler.cc +++ b/components/autofill/core/browser/autofill_handler.cc
@@ -102,6 +102,13 @@ channel != version_info::Channel::BETA; } +// static +bool AutofillHandler::IsRawMetadataUploadingEnabled( + version_info::Channel channel) { + return channel == version_info::Channel::CANARY || + channel == version_info::Channel::DEV; +} + AutofillHandler::AutofillHandler( AutofillDriver* driver, LogManager* log_manager, @@ -112,7 +119,10 @@ is_rich_query_enabled_(IsRichQueryEnabled(channel)) { if (enable_download_manager == ENABLE_AUTOFILL_DOWNLOAD_MANAGER) { download_manager_ = std::make_unique<AutofillDownloadManager>( - driver, this, GetAPIKeyForUrl(channel), log_manager); + driver, this, GetAPIKeyForUrl(channel), + AutofillDownloadManager::IsRawMetadataUploadingEnabled( + IsRawMetadataUploadingEnabled(channel)), + log_manager); } }
diff --git a/components/autofill/core/browser/autofill_handler.h b/components/autofill/core/browser/autofill_handler.h index 53aeb287..7ad7078d 100644 --- a/components/autofill/core/browser/autofill_handler.h +++ b/components/autofill/core/browser/autofill_handler.h
@@ -55,6 +55,10 @@ // neither on the STABLE nor BETA release channel. static bool IsRichQueryEnabled(version_info::Channel channel); + // Raw metadata uploading enabled iff this Chrome instance is on Canary or Dev + // channel. + static bool IsRawMetadataUploadingEnabled(version_info::Channel channel); + // TODO(crbug.com/1151542): Move to anonymous namespace once // AutofillManager::OnLoadedServerPredictions() moves to AutofillHandler. static void LogAutofillTypePredictionsAvailable(
diff --git a/components/autofill/core/browser/autofill_regexes.cc b/components/autofill/core/browser/autofill_regexes.cc index 4875a11..fc38787 100644 --- a/components/autofill/core/browser/autofill_regexes.cc +++ b/components/autofill/core/browser/autofill_regexes.cc
@@ -4,8 +4,8 @@ #include "components/autofill/core/browser/autofill_regexes.h" +#include <map> #include <memory> -#include <unordered_map> #include <utility> #include "base/check.h" @@ -28,19 +28,20 @@ AutofillRegexes() = default; // Returns the compiled regex matcher corresponding to |pattern|. - icu::RegexMatcher* GetMatcher(const base::string16& pattern); + icu::RegexMatcher* GetMatcher(const base::StringPiece16& pattern); private: ~AutofillRegexes() = default; // Maps patterns to their corresponding regex matchers. - std::unordered_map<base::string16, std::unique_ptr<icu::RegexMatcher>> + std::map<base::string16, std::unique_ptr<icu::RegexMatcher>, std::less<>> matchers_; DISALLOW_COPY_AND_ASSIGN(AutofillRegexes); }; -icu::RegexMatcher* AutofillRegexes::GetMatcher(const base::string16& pattern) { +icu::RegexMatcher* AutofillRegexes::GetMatcher( + const base::StringPiece16& pattern) { auto it = matchers_.find(pattern); if (it == matchers_.end()) { const icu::UnicodeString icu_pattern(false, pattern.data(), @@ -62,8 +63,8 @@ namespace autofill { -bool MatchesPattern(const base::string16& input, - const base::string16& pattern, +bool MatchesPattern(const base::StringPiece16& input, + const base::StringPiece16& pattern, base::string16* match, int32_t group_to_be_captured) { static base::NoDestructor<AutofillRegexes> g_autofill_regexes;
diff --git a/components/autofill/core/browser/autofill_regexes.h b/components/autofill/core/browser/autofill_regexes.h index 585e88e2..4ec3fce0 100644 --- a/components/autofill/core/browser/autofill_regexes.h +++ b/components/autofill/core/browser/autofill_regexes.h
@@ -6,6 +6,7 @@ #define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_ #include "base/strings/string16.h" +#include "base/strings/string_piece.h" // Parsing utilities. namespace autofill { @@ -13,8 +14,8 @@ // Case-insensitive regular expression matching. // Returns true if |pattern| is found in |input|. // The |group_to_be_captured| numbered group is captured into |match|. -bool MatchesPattern(const base::string16& input, - const base::string16& pattern, +bool MatchesPattern(const base::StringPiece16& input, + const base::StringPiece16& pattern, base::string16* match = nullptr, int32_t group_to_be_captured = 0);
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc index d7379a38..71475e4 100644 --- a/components/autofill/core/browser/autofill_test_utils.cc +++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -830,28 +830,6 @@ type_validities->add_validity(validity_states[i]); } -void FillQueryField(AutofillQueryContents::Form::Field* field, - unsigned signature, - const char* name, - const char* control_type) { - field->set_signature(signature); - if (name) - field->set_name(name); - if (control_type) - field->set_type(control_type); -} - -void FillQueryField(AutofillPageQueryRequest_Form_Field* field, - unsigned signature, - const char* name, - const char* control_type) { - field->set_signature(signature); - if (name) - field->set_name(name); - if (control_type) - field->set_control_type(control_type); -} - void GenerateTestAutofillPopup( AutofillExternalDelegate* autofill_external_delegate) { int query_id = 1;
diff --git a/components/autofill/core/browser/autofill_test_utils.h b/components/autofill/core/browser/autofill_test_utils.h index 2e79e04..0f5e2b7 100644 --- a/components/autofill/core/browser/autofill_test_utils.h +++ b/components/autofill/core/browser/autofill_test_utils.h
@@ -302,18 +302,6 @@ unsigned autofill_type, const std::vector<unsigned>& validity_states); -// Fills the query form |field| with the information passed by parameter. If the -// value of a const char* parameter is NULL, the corresponding attribute won't -// be set at all, as opposed to being set to empty string. -void FillQueryField(AutofillQueryContents::Form::Field* field, - unsigned signature, - const char* name, - const char* control_type); -void FillQueryField(AutofillPageQueryRequest_Form_Field* field, - unsigned signature, - const char* name, - const char* control_type); - // Creates the structure of signatures that would be encoded by // FormStructure::EncodeUploadRequest() and FormStructure::EncodeQueryRequest() // and consumed by FormStructure::ParseQueryResponse() and
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc index c975f25..6e4fb42 100644 --- a/components/autofill/core/browser/form_structure.cc +++ b/components/autofill/core/browser/form_structure.cc
@@ -747,6 +747,7 @@ bool form_was_autofilled, const std::string& login_form_signature, bool observed_submission, + bool is_raw_metadata_uploading_enabled, AutofillUploadContents* upload, std::vector<FormSignature>* encoded_signatures) const { DCHECK(AllTypesCaptured(*this, available_field_types)); @@ -779,7 +780,7 @@ upload); } - if (IsAutofillFieldMetadataEnabled()) { + if (is_raw_metadata_uploading_enabled) { upload->set_action_signature(StrToHash64Bit(target_url_.host())); if (!form_name().empty()) upload->set_form_name(base::UTF16ToUTF8(form_name())); @@ -799,7 +800,8 @@ if (IsMalformed()) return false; // Malformed form, skip it. - EncodeFormForUpload(upload, encoded_signatures); + EncodeFormForUpload(is_raw_metadata_uploading_enabled, upload, + encoded_signatures); return true; } @@ -986,13 +988,6 @@ return forms; } -// static -bool FormStructure::IsAutofillFieldMetadataEnabled() { - const std::string group_name = - base::FieldTrialList::FindFullName("AutofillFieldMetadata"); - return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE); -} - std::unique_ptr<FormStructure> FormStructure::CreateForPasswordManagerUpload( FormSignature form_signature, const std::vector<FieldSignature>& field_signatures) { @@ -1996,17 +1991,11 @@ if (is_rich_query_enabled_) { EncodeFieldMetadataForQuery(*field, added_field->mutable_metadata()); } - - if (IsAutofillFieldMetadataEnabled()) { - added_field->set_control_type(field->form_control_type); - - if (!field->name.empty()) - added_field->set_name(base::UTF16ToUTF8(field->name)); - } } } void FormStructure::EncodeFormForUpload( + bool is_raw_metadata_uploading_enabled, AutofillUploadContents* upload, std::vector<FormSignature>* encoded_signatures) const { DCHECK(!IsMalformed()); @@ -2069,7 +2058,7 @@ added_field->mutable_randomized_field_metadata()); } - if (IsAutofillFieldMetadataEnabled()) { + if (is_raw_metadata_uploading_enabled) { added_field->set_type(field->form_control_type); if (!field->name.empty())
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h index 927a33d..4b8cd4e 100644 --- a/components/autofill/core/browser/form_structure.h +++ b/components/autofill/core/browser/form_structure.h
@@ -79,6 +79,7 @@ bool form_was_autofilled, const std::string& login_form_signature, bool observed_submission, + bool is_raw_metadata_uploading_enabled, autofill::AutofillUploadContents* upload, std::vector<FormSignature>* encoded_signatures) const; @@ -494,6 +495,7 @@ std::vector<FormSignature>* queried_form_signatures) const; void EncodeFormForUpload( + bool is_raw_metadata_uploading_enabled, autofill::AutofillUploadContents* upload, std::vector<FormSignature>* encoded_signatures) const;
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc index 69870f71..1679e31 100644 --- a/components/autofill/core/browser/form_structure_unittest.cc +++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -11,7 +11,6 @@ #include "base/base64.h" #include "base/command_line.h" #include "base/feature_list.h" -#include "base/metrics/field_trial.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -73,21 +72,7 @@ return base::NumberToString(StrToHash64Bit(str)); } - void SetUp() override { - // By default this trial is enabled on tests. - EnableAutofillMetadataFieldTrial(); - } - protected: - void InitFeature(base::test::ScopedFeatureList* feature_list, - const base::Feature& feature, - bool is_enabled) { - if (is_enabled) - feature_list->InitAndEnableFeature(feature); - else - feature_list->InitAndDisableFeature(feature); - } - bool FormShouldBeParsed(const FormData form) { return FormStructure(form).ShouldBeParsed(); } @@ -106,12 +91,6 @@ return FormStructure(form).ShouldBeQueried(); } - void DisableAutofillMetadataFieldTrial() { - field_trial_ = nullptr; - scoped_feature_list_.Reset(); - scoped_feature_list_.Init(); - } - void SetUpForEncoder() { scoped_feature_list_.Reset(); scoped_feature_list_.InitWithFeatures( @@ -126,17 +105,8 @@ } private: - void EnableAutofillMetadataFieldTrial() { - scoped_feature_list_.Reset(); - scoped_feature_list_.Init(); - field_trial_ = base::FieldTrialList::CreateFieldTrial( - "AutofillFieldMetadata", "Enabled"); - field_trial_->group(); - } - uint32_t id_counter_ = 10; base::test::ScopedFeatureList scoped_feature_list_; - scoped_refptr<base::FieldTrial> field_trial_; }; class ParameterizedFormStructureTest @@ -2356,16 +2326,11 @@ AutofillPageQueryRequest::Form* query_form = query.add_forms(); query_form->set_signature(form_structure.form_signature().value()); - test::FillQueryField(query_form->add_fields(), 412125936U, "name_on_card", - "text"); - test::FillQueryField(query_form->add_fields(), 1917667676U, "billing_address", - "text"); - test::FillQueryField(query_form->add_fields(), 2226358947U, "card_number", - "text"); - test::FillQueryField(query_form->add_fields(), 747221617U, "expiration_month", - "text"); - test::FillQueryField(query_form->add_fields(), 4108155786U, "expiration_year", - "text"); + query_form->add_fields()->set_signature(412125936U); + query_form->add_fields()->set_signature(1917667676U); + query_form->add_fields()->set_signature(2226358947U); + query_form->add_fields()->set_signature(747221617U); + query_form->add_fields()->set_signature(4108155786U); std::string expected_query_string; ASSERT_TRUE(query.SerializeToString(&expected_query_string)); @@ -2414,19 +2379,13 @@ query_form = query.add_forms(); query_form->set_signature(form_structure3.form_signature().value()); - test::FillQueryField(query_form->add_fields(), 412125936U, "name_on_card", - "text"); - test::FillQueryField(query_form->add_fields(), 1917667676U, "billing_address", - "text"); - test::FillQueryField(query_form->add_fields(), 2226358947U, "card_number", - "text"); - test::FillQueryField(query_form->add_fields(), 747221617U, "expiration_month", - "text"); - test::FillQueryField(query_form->add_fields(), 4108155786U, "expiration_year", - "text"); + query_form->add_fields()->set_signature(412125936U); + query_form->add_fields()->set_signature(1917667676U); + query_form->add_fields()->set_signature(2226358947U); + query_form->add_fields()->set_signature(747221617U); + query_form->add_fields()->set_signature(4108155786U); for (int i = 0; i < 5; ++i) { - test::FillQueryField(query_form->add_fields(), 509334676U, "address", - "text"); + query_form->add_fields()->set_signature(509334676U); } ASSERT_TRUE(query.SerializeToString(&expected_query_string)); @@ -2701,7 +2660,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload, + available_field_types, false, std::string(), true, true, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -2714,7 +2673,7 @@ AutofillUploadContents encoded_upload2; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, true, std::string(), true, &encoded_upload2, + available_field_types, true, std::string(), true, true, &encoded_upload2, &signatures)); encoded_upload2.SerializeToString(&encoded_upload_string); @@ -2769,7 +2728,7 @@ AutofillUploadContents encoded_upload3; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload3, + available_field_types, false, std::string(), true, true, &encoded_upload3, &signatures)); encoded_upload3.SerializeToString(&encoded_upload_string); @@ -2905,7 +2864,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload, + available_field_types, false, std::string(), true, true, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -3046,7 +3005,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload, + available_field_types, false, std::string(), true, true, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -3181,7 +3140,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload, + available_field_types, false, std::string(), true, true, &encoded_upload, &signatures)); EXPECT_EQ(signatures, expected_signatures); @@ -3195,7 +3154,7 @@ AutofillUploadContents encoded_upload2; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, true, std::string(), true, &encoded_upload2, + available_field_types, true, std::string(), true, true, &encoded_upload2, &signatures)); EXPECT_EQ(signatures, expected_signatures); @@ -3253,7 +3212,7 @@ AutofillUploadContents encoded_upload3; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload3, + available_field_types, false, std::string(), true, true, &encoded_upload3, &signatures)); EXPECT_EQ(signatures, expected_signatures); @@ -3284,7 +3243,7 @@ AutofillUploadContents encoded_upload4; EXPECT_FALSE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload4, + available_field_types, false, std::string(), true, true, &encoded_upload4, &signatures)); } @@ -3419,7 +3378,8 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, true, "42", true, &encoded_upload, &signatures)); + available_field_types, true, "42", true, true, &encoded_upload, + &signatures)); std::string encoded_upload_string; encoded_upload.SerializeToString(&encoded_upload_string); @@ -3508,7 +3468,7 @@ AutofillUploadContents encoded_upload; std::vector<FormSignature> signatures; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, true, std::string(), true, &encoded_upload, + available_field_types, true, std::string(), true, true, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -3517,8 +3477,6 @@ } TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) { - DisableAutofillMetadataFieldTrial(); - std::unique_ptr<FormStructure> form_structure; std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; @@ -3618,7 +3576,8 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, true, std::string(), true, &encoded_upload, + available_field_types, true, std::string(), true, + /*is_raw_metadata_uploading_enabled=*/false, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -3709,7 +3668,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( available_field_types, true, std::string(), - /* observed_submission= */ false, &encoded_upload, &signatures)); + /* observed_submission= */ false, true, &encoded_upload, &signatures)); std::string encoded_upload_string; encoded_upload.SerializeToString(&encoded_upload_string); @@ -3791,7 +3750,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, true, std::string(), true, &encoded_upload, + available_field_types, true, std::string(), true, true, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -3879,7 +3838,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, true, std::string(), true, &encoded_upload, + available_field_types, true, std::string(), true, true, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -3964,7 +3923,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, true, std::string(), true, &encoded_upload, + available_field_types, true, std::string(), true, true, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -4054,7 +4013,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, true, std::string(), true, &encoded_upload, + available_field_types, true, std::string(), true, true, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -4063,9 +4022,8 @@ } // Sending field metadata to the server is disabled. -TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadataTrial) { - DisableAutofillMetadataFieldTrial(); - +TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadata) { + // Metadata uploading is disabled by a parameter of |EncodeUploadRequest|. std::unique_ptr<FormStructure> form_structure; std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; @@ -4155,7 +4113,8 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, true, std::string(), true, &encoded_upload, + available_field_types, true, std::string(), true, + /*is_raw_metadata_uploading_enabled=*/false, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -4236,7 +4195,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure.EncodeUploadRequest(available_field_types, false, - std::string(), true, + std::string(), true, true, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -4267,7 +4226,7 @@ AutofillUploadContents encoded_upload2; EXPECT_TRUE(form_structure.EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload2, + available_field_types, false, std::string(), true, true, &encoded_upload2, &signatures)); encoded_upload2.SerializeToString(&encoded_upload_string); @@ -4321,7 +4280,7 @@ AutofillUploadContents encoded_upload3; EXPECT_TRUE(form_structure.EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload3, + available_field_types, false, std::string(), true, true, &encoded_upload3, &signatures)); encoded_upload3.SerializeToString(&encoded_upload_string); @@ -4353,7 +4312,7 @@ AutofillUploadContents encoded_upload4; EXPECT_TRUE(form_structure.EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload4, + available_field_types, false, std::string(), true, true, &encoded_upload4, &signatures)); encoded_upload4.SerializeToString(&encoded_upload_string); @@ -4421,7 +4380,7 @@ AutofillUploadContents encoded_upload5; EXPECT_TRUE(form_structure.EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload5, + available_field_types, false, std::string(), true, true, &encoded_upload5, &signatures)); encoded_upload5.SerializeToString(&encoded_upload_string); @@ -4531,7 +4490,7 @@ AutofillUploadContents encoded_upload; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload, + available_field_types, false, std::string(), true, true, &encoded_upload, &signatures)); std::string encoded_upload_string; @@ -4555,7 +4514,7 @@ AutofillUploadContents encoded_upload2; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload2, + available_field_types, false, std::string(), true, true, &encoded_upload2, &signatures)); encoded_upload2.SerializeToString(&encoded_upload_string); @@ -4573,7 +4532,7 @@ AutofillUploadContents encoded_upload3; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload3, + available_field_types, false, std::string(), true, true, &encoded_upload3, &signatures)); encoded_upload3.SerializeToString(&encoded_upload_string); @@ -4599,7 +4558,7 @@ AutofillUploadContents encoded_upload4; EXPECT_TRUE(form_structure->EncodeUploadRequest( - available_field_types, false, std::string(), true, &encoded_upload4, + available_field_types, false, std::string(), true, true, &encoded_upload4, &signatures)); encoded_upload4.SerializeToString(&encoded_upload_string); @@ -4634,7 +4593,7 @@ EXPECT_TRUE(form_structure.EncodeUploadRequest( {{}} /* available_field_types */, false /* form_was_autofilled */, std::string() /* login_form_signature */, true /* observed_submission */, - &upload, &signatures)); + true /* is_raw_metadata_uploading_enabled */, &upload, &signatures)); EXPECT_EQ(true, upload.passwords_revealed()); } @@ -4658,7 +4617,8 @@ EXPECT_TRUE(form_structure.EncodeUploadRequest( {{}} /* available_field_types */, false /* form_was_autofilled */, std::string() /* login_form_signature */, - true /* observed_submission */, &upload, &signatures)); + true /* observed_submission */, + false /* is_raw_metadata_uploading_enabled */, &upload, &signatures)); EXPECT_EQ(is_form_tag, upload.has_form_tag()); } } @@ -4715,7 +4675,7 @@ ASSERT_TRUE(form_structure.EncodeUploadRequest( {{}} /* available_field_types */, false /* form_was_autofilled */, std::string() /* login_form_signature */, true /* observed_submission */, - &upload, &signatures)); + false /* is_raw_metadata_uploading_enabled */, &upload, &signatures)); const auto form_signature = form_structure.form_signature(); @@ -4858,7 +4818,7 @@ form_structure.set_randomized_encoder(RandomizedEncoder::Create(&prefs)); AutofillUploadContents upload = AutofillUploadContents(); std::vector<FormSignature> signatures; - form_structure.EncodeUploadRequest({}, true, "", true, &upload, + form_structure.EncodeUploadRequest({}, true, "", true, true, &upload, &signatures); EXPECT_EQ(has_consent, upload.randomized_form_metadata().has_url()); @@ -5011,9 +4971,8 @@ AutofillPageQueryRequest::Form* query_form = query.add_forms(); query_form->set_signature(form_structure.form_signature().value()); - test::FillQueryField(query_form->add_fields(), 239111655U, "username", - "text"); - test::FillQueryField(query_form->add_fields(), 420638584U, "email", "text"); + query_form->add_fields()->set_signature(239111655U); + query_form->add_fields()->set_signature(420638584U); std::string expected_query_string; ASSERT_TRUE(query.SerializeToString(&expected_query_string)); @@ -5067,11 +5026,9 @@ AutofillPageQueryRequest::Form* query_form = query.add_forms(); query_form->set_signature(form_structure.form_signature().value()); - test::FillQueryField(query_form->add_fields(), 239111655U, "username", - "text"); - test::FillQueryField(query_form->add_fields(), 420638584U, "email", "text"); - test::FillQueryField(query_form->add_fields(), 2051817934U, "password", - "password"); + query_form->add_fields()->set_signature(239111655U); + query_form->add_fields()->set_signature(420638584U); + query_form->add_fields()->set_signature(2051817934U); std::string expected_query_string; ASSERT_TRUE(query.SerializeToString(&expected_query_string)); @@ -5126,11 +5083,9 @@ AutofillPageQueryRequest::Form* query_form = query.add_forms(); query_form->set_signature(form_structure.form_signature().value()); - test::FillQueryField(query_form->add_fields(), 239111655U, "username", - "text"); - test::FillQueryField(query_form->add_fields(), 420638584U, "email", "text"); - test::FillQueryField(query_form->add_fields(), 2051817934U, "password", - "password"); + query_form->add_fields()->set_signature(239111655U); + query_form->add_fields()->set_signature(420638584U); + query_form->add_fields()->set_signature(2051817934U); std::string expected_query_string; ASSERT_TRUE(query.SerializeToString(&expected_query_string)); @@ -5178,9 +5133,8 @@ AutofillPageQueryRequest::Form* query_form = query.add_forms(); query_form->set_signature(form_structure.form_signature().value()); - test::FillQueryField(query_form->add_fields(), 239111655U, "username", - "text"); - test::FillQueryField(query_form->add_fields(), 1318412689U, nullptr, "text"); + query_form->add_fields()->set_signature(239111655U); + query_form->add_fields()->set_signature(1318412689U); std::string expected_query_string; ASSERT_TRUE(query.SerializeToString(&expected_query_string)); @@ -5197,59 +5151,6 @@ EXPECT_EQ(expected_query_string, encoded_query_string); } -// Sending field metadata to the server is disabled. -TEST_F(FormStructureTestImpl, EncodeQueryRequest_DisabledMetadataTrial) { - DisableAutofillMetadataFieldTrial(); - - FormData form; - // No name set for the form. - form.url = GURL("http://cool.com"); - form.action = form.url.Resolve("/login"); - - FormFieldData field; - field.label = ASCIIToUTF16("username"); - field.name = ASCIIToUTF16("username"); - field.form_control_type = "text"; - field.unique_renderer_id = MakeFieldRendererId(); - form.fields.push_back(field); - - field.label = base::string16(); - field.name = ASCIIToUTF16("country"); - field.form_control_type = "text"; - field.check_status = FormFieldData::CheckStatus::kNotCheckable; - field.unique_renderer_id = MakeFieldRendererId(); - form.fields.push_back(field); - - FormStructure form_structure(form); - std::vector<FormStructure*> forms; - forms.push_back(&form_structure); - std::vector<FormSignature> encoded_signatures; - AutofillPageQueryRequest encoded_query; - - // Create the expected query and serialize it to a string. - AutofillPageQueryRequest query; - query.set_client_version(GetProductNameAndVersionForUserAgent()); - AutofillPageQueryRequest::Form* query_form = query.add_forms(); - query_form->set_signature(form_structure.form_signature().value()); - - test::FillQueryField(query_form->add_fields(), 239111655U, nullptr, nullptr); - test::FillQueryField(query_form->add_fields(), 3654076265U, nullptr, nullptr); - - std::string expected_query_string; - ASSERT_TRUE(query.SerializeToString(&expected_query_string)); - - const FormSignature kExpectedSignature(7635954436925888745UL); - - ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query, - &encoded_signatures)); - ASSERT_EQ(1U, encoded_signatures.size()); - EXPECT_EQ(kExpectedSignature, encoded_signatures.front()); - - std::string encoded_query_string; - encoded_query.SerializeToString(&encoded_query_string); - EXPECT_EQ(expected_query_string, encoded_query_string); -} - TEST_F(FormStructureTestImpl, PossibleValues) { FormData form_data; form_data.url = GURL("http://www.foo.com/"); @@ -7911,8 +7812,8 @@ ASSERT_EQ(FieldSignature(100u), form->field(2)->GetFieldSignature()); EXPECT_TRUE(form->EncodeUploadRequest( {} /* available_field_types */, false /* form_was_autofilled */, - "" /*login_form_signature*/, true /*observed_submission*/, &upload, - &signatures)); + "" /*login_form_signature*/, true /*observed_submission*/, + true /* is_raw_metadata_uploading_enabled */, &upload, &signatures)); } // Tests if a new logical form is started with the second appearance of a field
diff --git a/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher_unittest.cc b/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher_unittest.cc index 0d51602..0ffb217a4 100644 --- a/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher_unittest.cc +++ b/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher_unittest.cc
@@ -4,7 +4,6 @@ #include "components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.h" -#include "base/android/locale_utils.h" #include "base/containers/flat_map.h" #include "base/test/task_environment.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -71,9 +70,8 @@ EXPECT_EQ(map.at("onboarding_text"), "Text"); }); - fetcher()->FetchOnboardingDefinition("BUY_MOVIE_TICKETS", - base::android::GetDefaultLocaleString(), - 300, std::move(callback)); + fetcher()->FetchOnboardingDefinition("BUY_MOVIE_TICKETS", "en-US", 300, + std::move(callback)); EXPECT_EQ(1, GetNumberOfPendingRequests()); SimulateResponse(); EXPECT_EQ(0, GetNumberOfPendingRequests());
diff --git a/components/autofill_assistant/browser/features.cc b/components/autofill_assistant/browser/features.cc index f4440f9..229f62be 100644 --- a/components/autofill_assistant/browser/features.cc +++ b/components/autofill_assistant/browser/features.cc
@@ -24,14 +24,6 @@ "AutofillAssistantDisableOnboardingFlow", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillAssistantProactiveHelp{ - "AutofillAssistantProactiveHelp", base::FEATURE_DISABLED_BY_DEFAULT}; - -// Use Chrome's TabHelper system to deal with the life cycle of WebContent's -// depending Autofill Assistant objects. -const base::Feature kAutofillAssistantWithTabHelper{ - "AutofillAssistantWithTabHelper", base::FEATURE_DISABLED_BY_DEFAULT}; - // By default, proactive help is only offered if MSBB is turned on. This feature // flag allows disabling the link. Proactive help can still be offered to users // so long as no communication to a remote backend is required. Specifically, @@ -40,5 +32,20 @@ "AutofillAssistantDisableProactiveHelpTiedToMSBB", base::FEATURE_DISABLED_BY_DEFAULT}; +// Whether autofill assistant should load the DFM for trigger scripts when +// necessary. Without this feature, trigger scripts will exit if the DFM is not +// available. +const base::Feature kAutofillAssistantLoadDFMForTriggerScripts{ + "AutofillAssistantLoadDFMForTriggerScripts", + base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kAutofillAssistantProactiveHelp{ + "AutofillAssistantProactiveHelp", base::FEATURE_DISABLED_BY_DEFAULT}; + +// Use Chrome's TabHelper system to deal with the life cycle of WebContent's +// depending Autofill Assistant objects. +const base::Feature kAutofillAssistantWithTabHelper{ + "AutofillAssistantWithTabHelper", base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/features.h b/components/autofill_assistant/browser/features.h index 8821243..7b1efcd 100644 --- a/components/autofill_assistant/browser/features.h +++ b/components/autofill_assistant/browser/features.h
@@ -17,9 +17,10 @@ extern const base::Feature kAutofillAssistantChromeEntry; extern const base::Feature kAutofillAssistantDirectActions; extern const base::Feature kAutofillAssistantDisableOnboardingFlow; +extern const base::Feature kAutofillAssistantDisableProactiveHelpTiedToMSBB; +extern const base::Feature kAutofillAssistantLoadDFMForTriggerScripts; extern const base::Feature kAutofillAssistantProactiveHelp; extern const base::Feature kAutofillAssistantWithTabHelper; -extern const base::Feature kAutofillAssistantDisableProactiveHelpTiedToMSBB; } // namespace features } // namespace autofill_assistant
diff --git a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java index fc68d6ff..c45f747 100644 --- a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java +++ b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java
@@ -31,6 +31,7 @@ import org.chromium.services.media_session.MediaMetadata; import org.chromium.services.media_session.MediaPosition; import org.chromium.ui.base.WindowAndroid; +import org.chromium.url.GURL; import java.util.Collections; import java.util.List; @@ -440,7 +441,7 @@ // Don't waste time trying to find it. if (!mMaybeHasFavicon) return false; - String pageUrl = mWebContents.getLastCommittedUrl(); + GURL pageUrl = mWebContents.getLastCommittedUrl(); int size = MediaNotificationImageUtils.MINIMAL_MEDIA_IMAGE_SIZE_PX; if (mLargeIconBridge == null) { mLargeIconBridge = new LargeIconBridge(mDelegate.getBrowserContextHandle()); @@ -453,7 +454,7 @@ } }; - return mLargeIconBridge.getLargeIconForStringUrl(pageUrl, size, callback); + return mLargeIconBridge.getLargeIconForUrl(pageUrl, size, callback); } /**
diff --git a/components/browser_ui/styles/android/BUILD.gn b/components/browser_ui/styles/android/BUILD.gn index 763967d..b6b8880 100644 --- a/components/browser_ui/styles/android/BUILD.gn +++ b/components/browser_ui/styles/android/BUILD.gn
@@ -154,7 +154,6 @@ "java/res/drawable/ic_music_note_24dp.xml", "java/res/drawable/ic_offline_pin_24dp_on_dark_bg.xml", "java/res/drawable/ic_offline_pin_24dp_on_light_bg.xml", - "java/res/drawable/ic_people_24dp.xml", "java/res/drawable/ic_permission_location_filled.xml", "java/res/drawable/ic_play_circle_filled_24dp_on_dark_bg.xml", "java/res/drawable/ic_play_circle_filled_24dp_on_light_bg.xml",
diff --git a/components/browser_ui/styles/android/java/res/drawable/ic_people_24dp.xml b/components/browser_ui/styles/android/java/res/drawable/ic_people_24dp.xml deleted file mode 100644 index 0c667784..0000000 --- a/components/browser_ui/styles/android/java/res/drawable/ic_people_24dp.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2020 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="@color/default_icon_color" - android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/> -</vector>
diff --git a/components/domain_reliability/quic_error_mapping.cc b/components/domain_reliability/quic_error_mapping.cc index 57ff62e..c34c6dfc 100644 --- a/components/domain_reliability/quic_error_mapping.cc +++ b/components/domain_reliability/quic_error_mapping.cc
@@ -436,6 +436,18 @@ {quic::QUIC_INVALID_PRIORITY_UPDATE, "quic::quic_invalid_priority_update"}, {quic::QUIC_PEER_PORT_CHANGE_HANDSHAKE_UNCONFIRMED, "quic.peer_port_change_handshake_unconfirmed"}, + + {quic::QUIC_TLS_BAD_CERTIFICATE, "quic::quic_tls_bad_certificate"}, + {quic::QUIC_TLS_UNSUPPORTED_CERTIFICATE, + "quic::quic_tls_unsupported_certificate"}, + {quic::QUIC_TLS_CERTIFICATE_REVOKED, "quic::quic_tls_certificate_revoked"}, + {quic::QUIC_TLS_CERTIFICATE_EXPIRED, "quic::quic_tls_certificate_expired"}, + {quic::QUIC_TLS_CERTIFICATE_UNKNOWN, "quic::quic_tls_certificate_unknown"}, + {quic::QUIC_TLS_INTERNAL_ERROR, "quic::quic_tls_internal_error"}, + {quic::QUIC_TLS_UNRECOGNIZED_NAME, "quic::quic_tls_unrecognized_name"}, + {quic::QUIC_TLS_CERTIFICATE_REQUIRED, + "quic::quic_tls_certificate_required"}, + // No error. Used as bound while iterating. {quic::QUIC_LAST_ERROR, "quic.last_error"}};
diff --git a/components/external_intents/android/BUILD.gn b/components/external_intents/android/BUILD.gn index 2eccc0ef..5dc05eb5 100644 --- a/components/external_intents/android/BUILD.gn +++ b/components/external_intents/android/BUILD.gn
@@ -86,6 +86,8 @@ "//third_party/android_support_test_runner:runner_java", "//third_party/junit", "//ui/android:ui_java", + "//url:gurl_java", + "//url:gurl_junit_test_support", "//url:origin_java", ] }
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java index 568bca91..d00e56b8 100644 --- a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java +++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
@@ -57,6 +57,7 @@ import org.chromium.ui.UiUtils; import org.chromium.ui.base.PageTransition; import org.chromium.ui.base.PermissionCallback; +import org.chromium.url.GURL; import org.chromium.url.URI; import java.lang.annotation.Retention; @@ -938,9 +939,9 @@ // TODO(https://crbug.com/1009539): Replace this host parsing with a UrlUtilities or GURL // function call. - String lastCommittedUrl = getLastCommittedUrl(); + GURL lastCommittedUrl = getLastCommittedUrl(); String previousUriString = - lastCommittedUrl != null ? lastCommittedUrl : params.getReferrerUrl(); + lastCommittedUrl != null ? lastCommittedUrl.getSpec() : params.getReferrerUrl(); if (previousUriString == null || (!isLink && !isFormSubmit)) return false; URI currentUri; @@ -1793,7 +1794,7 @@ * @return The last committed URL from the WebContents. */ @VisibleForTesting - protected String getLastCommittedUrl() { + protected GURL getLastCommittedUrl() { if (mDelegate.getWebContents() == null) return null; return mDelegate.getWebContents().getLastCommittedUrl(); }
diff --git a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java index 65b43d8..97e2ce2 100644 --- a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java +++ b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
@@ -42,6 +42,7 @@ import org.chromium.content_public.browser.test.NativeLibraryTestUtils; import org.chromium.ui.base.PageTransition; import org.chromium.ui.base.WindowAndroid; +import org.chromium.url.GURL; import org.chromium.url.Origin; import java.net.URISyntaxException; @@ -1376,8 +1377,8 @@ .expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT, START_OTHER_ACTIVITY); - mUrlHandler.mLastCommittedUrl = "https://refertest.com"; - checkUrl("http://refertest.com") + mUrlHandler.mLastCommittedUrl = new GURL("https://refertest.com"); + checkUrl("https://refertest.com") .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE); } @@ -1980,7 +1981,7 @@ private static class ExternalNavigationHandlerForTesting extends ExternalNavigationHandler { public String defaultSmsPackageName; - public String mLastCommittedUrl; + public GURL mLastCommittedUrl; public boolean mIsSerpReferrer; public boolean mShouldRequestFileAccess; public String mNewUrlAfterClobbering; @@ -2018,7 +2019,7 @@ } @Override - protected String getLastCommittedUrl() { + protected GURL getLastCommittedUrl() { return mLastCommittedUrl; }
diff --git a/components/invalidation/impl/invalidation_service_test_template.cc b/components/invalidation/impl/invalidation_service_test_template.cc index d7f3e34..9e5f934d 100644 --- a/components/invalidation/impl/invalidation_service_test_template.cc +++ b/components/invalidation/impl/invalidation_service_test_template.cc
@@ -4,24 +4,23 @@ #include "components/invalidation/impl/invalidation_service_test_template.h" -namespace internal { +namespace invalidation { BoundFakeInvalidationHandler::BoundFakeInvalidationHandler( - const invalidation::InvalidationService& invalidator) + const InvalidationService& invalidator) : invalidator_(invalidator), - last_retrieved_state_(invalidation::DEFAULT_INVALIDATION_ERROR) {} + last_retrieved_state_(DEFAULT_INVALIDATION_ERROR) {} BoundFakeInvalidationHandler::~BoundFakeInvalidationHandler() = default; -invalidation::InvalidatorState -BoundFakeInvalidationHandler::GetLastRetrievedState() const { +InvalidatorState BoundFakeInvalidationHandler::GetLastRetrievedState() const { return last_retrieved_state_; } void BoundFakeInvalidationHandler::OnInvalidatorStateChange( - invalidation::InvalidatorState state) { + InvalidatorState state) { FakeInvalidationHandler::OnInvalidatorStateChange(state); last_retrieved_state_ = invalidator_.GetInvalidatorState(); } -} // namespace internal +} // namespace invalidation
diff --git a/components/invalidation/impl/invalidation_service_test_template.h b/components/invalidation/impl/invalidation_service_test_template.h index 572c15f..e559972 100644 --- a/components/invalidation/impl/invalidation_service_test_template.h +++ b/components/invalidation/impl/invalidation_service_test_template.h
@@ -82,28 +82,24 @@ #include "components/invalidation/public/topic_invalidation_map.h" #include "testing/gtest/include/gtest/gtest.h" -// TODO(crbug.com/1031125): consider moving this file content under invalidation -// namespace, instead of specifying it everywhere (invalidation::internal if -// polluting invalidation namespace is a concern, though it already pollutes -// global namespace). +namespace invalidation { template <typename InvalidatorTestDelegate> class InvalidationServiceTest : public testing::Test { protected: InvalidationServiceTest() = default; - invalidation::InvalidationService* - CreateAndInitializeInvalidationService() { + InvalidationService* CreateAndInitializeInvalidationService() { this->delegate_.CreateInvalidationService(); return this->delegate_.GetInvalidationService(); } InvalidatorTestDelegate delegate_; - const invalidation::Topic topic1 = "BOOKMARK"; - const invalidation::Topic topic2 = "PREFERENCE"; - const invalidation::Topic topic3 = "AUTOFILL"; - const invalidation::Topic topic4 = "PUSH_MESSAGE"; + const Topic topic1 = "BOOKMARK"; + const Topic topic2 = "PREFERENCE"; + const Topic topic3 = "AUTOFILL"; + const Topic topic4 = "PUSH_MESSAGE"; }; TYPED_TEST_SUITE_P(InvalidationServiceTest); @@ -113,39 +109,33 @@ // between. The handler should only see invalidations when its registered and // its IDs are registered. TYPED_TEST_P(InvalidationServiceTest, Basic) { - invalidation::InvalidationService* const invalidator = + InvalidationService* const invalidator = this->CreateAndInitializeInvalidationService(); - invalidation::FakeInvalidationHandler handler; + FakeInvalidationHandler handler; invalidator->RegisterInvalidationHandler(&handler); - invalidation::TopicInvalidationMap invalidation_map; - invalidation_map.Insert( - invalidation::Invalidation::Init(this->topic1, 1, "1")); - invalidation_map.Insert( - invalidation::Invalidation::Init(this->topic2, 2, "2")); - invalidation_map.Insert( - invalidation::Invalidation::Init(this->topic3, 3, "3")); + TopicInvalidationMap invalidation_map; + invalidation_map.Insert(Invalidation::Init(this->topic1, 1, "1")); + invalidation_map.Insert(Invalidation::Init(this->topic2, 2, "2")); + invalidation_map.Insert(Invalidation::Init(this->topic3, 3, "3")); // Should be ignored since no IDs are registered to |handler|. this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); EXPECT_EQ(0, handler.GetInvalidationCount()); - invalidation::TopicSet topics; + TopicSet topics; topics.insert(this->topic1); topics.insert(this->topic2); EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler, topics)); - this->delegate_.TriggerOnInvalidatorStateChange( - invalidation::INVALIDATIONS_ENABLED); - EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); + this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED); + EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); - invalidation::TopicInvalidationMap expected_invalidations; - expected_invalidations.Insert( - invalidation::Invalidation::Init(this->topic1, 1, "1")); - expected_invalidations.Insert( - invalidation::Invalidation::Init(this->topic2, 2, "2")); + TopicInvalidationMap expected_invalidations; + expected_invalidations.Insert(Invalidation::Init(this->topic1, 1, "1")); + expected_invalidations.Insert(Invalidation::Init(this->topic2, 2, "2")); this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); EXPECT_EQ(1, handler.GetInvalidationCount()); @@ -155,25 +145,20 @@ topics.insert(this->topic3); EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler, topics)); - expected_invalidations = invalidation::TopicInvalidationMap(); - expected_invalidations.Insert( - invalidation::Invalidation::Init(this->topic2, 2, "2")); - expected_invalidations.Insert( - invalidation::Invalidation::Init(this->topic3, 3, "3")); + expected_invalidations = TopicInvalidationMap(); + expected_invalidations.Insert(Invalidation::Init(this->topic2, 2, "2")); + expected_invalidations.Insert(Invalidation::Init(this->topic3, 3, "3")); // Removed Topics should not be notified, newly-added ones should. this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); EXPECT_EQ(2, handler.GetInvalidationCount()); EXPECT_THAT(expected_invalidations, Eq(handler.GetLastInvalidationMap())); - this->delegate_.TriggerOnInvalidatorStateChange( - invalidation::TRANSIENT_INVALIDATION_ERROR); - EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR, - handler.GetInvalidatorState()); + this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler.GetInvalidatorState()); - this->delegate_.TriggerOnInvalidatorStateChange( - invalidation::INVALIDATIONS_ENABLED); - EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); + this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED); + EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); invalidator->UnregisterInvalidationHandler(&handler); @@ -188,13 +173,13 @@ // registered should get invalidations, and the ones that have registered // topics should receive invalidations for those topics. TYPED_TEST_P(InvalidationServiceTest, MultipleHandlers) { - invalidation::InvalidationService* const invalidator = + InvalidationService* const invalidator = this->CreateAndInitializeInvalidationService(); - invalidation::FakeInvalidationHandler handler1; - invalidation::FakeInvalidationHandler handler2; - invalidation::FakeInvalidationHandler handler3; - invalidation::FakeInvalidationHandler handler4; + FakeInvalidationHandler handler1; + FakeInvalidationHandler handler2; + FakeInvalidationHandler handler3; + FakeInvalidationHandler handler4; invalidator->RegisterInvalidationHandler(&handler1); invalidator->RegisterInvalidationHandler(&handler2); @@ -202,14 +187,14 @@ invalidator->RegisterInvalidationHandler(&handler4); { - invalidation::TopicSet topics; + TopicSet topics; topics.insert(this->topic1); topics.insert(this->topic2); EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler1, topics)); } { - invalidation::TopicSet topics; + TopicSet topics; topics.insert(this->topic3); EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler2, topics)); } @@ -217,48 +202,36 @@ // Don't register any topics for handler3. { - invalidation::TopicSet topics; + TopicSet topics; topics.insert(this->topic4); EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler4, topics)); } invalidator->UnregisterInvalidationHandler(&handler4); - this->delegate_.TriggerOnInvalidatorStateChange( - invalidation::INVALIDATIONS_ENABLED); - EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, - handler1.GetInvalidatorState()); - EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, - handler2.GetInvalidatorState()); - EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, - handler3.GetInvalidatorState()); - EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR, - handler4.GetInvalidatorState()); + this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED); + EXPECT_EQ(INVALIDATIONS_ENABLED, handler1.GetInvalidatorState()); + EXPECT_EQ(INVALIDATIONS_ENABLED, handler2.GetInvalidatorState()); + EXPECT_EQ(INVALIDATIONS_ENABLED, handler3.GetInvalidatorState()); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler4.GetInvalidatorState()); { - invalidation::TopicInvalidationMap invalidation_map; - invalidation_map.Insert( - invalidation::Invalidation::Init(this->topic1, 1, "1")); - invalidation_map.Insert( - invalidation::Invalidation::Init(this->topic2, 2, "2")); - invalidation_map.Insert( - invalidation::Invalidation::Init(this->topic3, 3, "3")); - invalidation_map.Insert( - invalidation::Invalidation::Init(this->topic4, 4, "4")); + TopicInvalidationMap invalidation_map; + invalidation_map.Insert(Invalidation::Init(this->topic1, 1, "1")); + invalidation_map.Insert(Invalidation::Init(this->topic2, 2, "2")); + invalidation_map.Insert(Invalidation::Init(this->topic3, 3, "3")); + invalidation_map.Insert(Invalidation::Init(this->topic4, 4, "4")); this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); - invalidation::TopicInvalidationMap expected_invalidations; - expected_invalidations.Insert( - invalidation::Invalidation::Init(this->topic1, 1, "1")); - expected_invalidations.Insert( - invalidation::Invalidation::Init(this->topic2, 2, "2")); + TopicInvalidationMap expected_invalidations; + expected_invalidations.Insert(Invalidation::Init(this->topic1, 1, "1")); + expected_invalidations.Insert(Invalidation::Init(this->topic2, 2, "2")); EXPECT_EQ(1, handler1.GetInvalidationCount()); EXPECT_THAT(expected_invalidations, Eq(handler1.GetLastInvalidationMap())); - expected_invalidations = invalidation::TopicInvalidationMap(); - expected_invalidations.Insert( - invalidation::Invalidation::Init(this->topic3, 3, "3")); + expected_invalidations = TopicInvalidationMap(); + expected_invalidations.Insert(Invalidation::Init(this->topic3, 3, "3")); EXPECT_EQ(1, handler2.GetInvalidationCount()); EXPECT_THAT(expected_invalidations, Eq(handler2.GetLastInvalidationMap())); @@ -267,16 +240,11 @@ EXPECT_EQ(0, handler4.GetInvalidationCount()); } - this->delegate_.TriggerOnInvalidatorStateChange( - invalidation::TRANSIENT_INVALIDATION_ERROR); - EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR, - handler1.GetInvalidatorState()); - EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR, - handler2.GetInvalidatorState()); - EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR, - handler3.GetInvalidatorState()); - EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR, - handler4.GetInvalidatorState()); + this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler1.GetInvalidatorState()); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler2.GetInvalidatorState()); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler3.GetInvalidatorState()); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler4.GetInvalidatorState()); invalidator->UnregisterInvalidationHandler(&handler3); invalidator->UnregisterInvalidationHandler(&handler2); @@ -286,18 +254,18 @@ // Multiple registrations by different handlers on the same Topic should return // false. TYPED_TEST_P(InvalidationServiceTest, MultipleRegistrations) { - invalidation::InvalidationService* const invalidator = + InvalidationService* const invalidator = this->CreateAndInitializeInvalidationService(); - invalidation::FakeInvalidationHandler handler1; - invalidation::FakeInvalidationHandler handler2; + FakeInvalidationHandler handler1; + FakeInvalidationHandler handler2; invalidator->RegisterInvalidationHandler(&handler1); invalidator->RegisterInvalidationHandler(&handler2); // Registering both handlers for the same topic. First call should succeed, // second should fail. - invalidation::TopicSet topics; + TopicSet topics; topics.insert(this->topic1); EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler1, topics)); EXPECT_FALSE(invalidator->UpdateInterestedTopics(&handler2, topics)); @@ -309,114 +277,93 @@ // Make sure that passing an empty set to UpdateInterestedTopics clears // the corresponding entries for the handler. TYPED_TEST_P(InvalidationServiceTest, EmptySetUnregisters) { - invalidation::InvalidationService* const invalidator = + InvalidationService* const invalidator = this->CreateAndInitializeInvalidationService(); - invalidation::FakeInvalidationHandler handler1; + FakeInvalidationHandler handler1; // Control observer. - invalidation::FakeInvalidationHandler handler2; + FakeInvalidationHandler handler2; invalidator->RegisterInvalidationHandler(&handler1); invalidator->RegisterInvalidationHandler(&handler2); { - invalidation::TopicSet topics; + TopicSet topics; topics.insert(this->topic1); topics.insert(this->topic2); EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler1, topics)); } { - invalidation::TopicSet topics; + TopicSet topics; topics.insert(this->topic3); EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler2, topics)); } // Unregister the topics for the first observer. It should not receive any // further invalidations. - EXPECT_TRUE( - invalidator->UpdateInterestedTopics(&handler1, invalidation::TopicSet())); + EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler1, TopicSet())); - this->delegate_.TriggerOnInvalidatorStateChange( - invalidation::INVALIDATIONS_ENABLED); - EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, - handler1.GetInvalidatorState()); - EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, - handler2.GetInvalidatorState()); + this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED); + EXPECT_EQ(INVALIDATIONS_ENABLED, handler1.GetInvalidatorState()); + EXPECT_EQ(INVALIDATIONS_ENABLED, handler2.GetInvalidatorState()); { - invalidation::TopicInvalidationMap invalidation_map; - invalidation_map.Insert( - invalidation::Invalidation::Init(this->topic1, 1, "1")); - invalidation_map.Insert( - invalidation::Invalidation::Init(this->topic2, 2, "2")); - invalidation_map.Insert( - invalidation::Invalidation::Init(this->topic3, 3, "3")); + TopicInvalidationMap invalidation_map; + invalidation_map.Insert(Invalidation::Init(this->topic1, 1, "1")); + invalidation_map.Insert(Invalidation::Init(this->topic2, 2, "2")); + invalidation_map.Insert(Invalidation::Init(this->topic3, 3, "3")); this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); EXPECT_EQ(0, handler1.GetInvalidationCount()); EXPECT_EQ(1, handler2.GetInvalidationCount()); } - this->delegate_.TriggerOnInvalidatorStateChange( - invalidation::TRANSIENT_INVALIDATION_ERROR); - EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR, - handler1.GetInvalidatorState()); - EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR, - handler2.GetInvalidatorState()); + this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler1.GetInvalidatorState()); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler2.GetInvalidatorState()); invalidator->UnregisterInvalidationHandler(&handler2); invalidator->UnregisterInvalidationHandler(&handler1); } -namespace internal { - // A FakeInvalidationHandler that is "bound" to a specific // InvalidationService. This is for cross-referencing state information with // the bound InvalidationService. -class BoundFakeInvalidationHandler - : public invalidation::FakeInvalidationHandler { +class BoundFakeInvalidationHandler : public FakeInvalidationHandler { public: - explicit BoundFakeInvalidationHandler( - const invalidation::InvalidationService& invalidator); + explicit BoundFakeInvalidationHandler(const InvalidationService& invalidator); ~BoundFakeInvalidationHandler() override; // Returns the last return value of GetInvalidatorState() on the // bound invalidator from the last time the invalidator state // changed. - invalidation::InvalidatorState GetLastRetrievedState() const; + InvalidatorState GetLastRetrievedState() const; // InvalidationHandler implementation. - void OnInvalidatorStateChange(invalidation::InvalidatorState state) override; + void OnInvalidatorStateChange(InvalidatorState state) override; private: - const invalidation::InvalidationService& invalidator_; - invalidation::InvalidatorState last_retrieved_state_; + const InvalidationService& invalidator_; + InvalidatorState last_retrieved_state_; DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler); }; -} // namespace internal - TYPED_TEST_P(InvalidationServiceTest, GetInvalidatorStateAlwaysCurrent) { - invalidation::InvalidationService* const invalidator = + InvalidationService* const invalidator = this->CreateAndInitializeInvalidationService(); - internal::BoundFakeInvalidationHandler handler(*invalidator); + BoundFakeInvalidationHandler handler(*invalidator); invalidator->RegisterInvalidationHandler(&handler); - this->delegate_.TriggerOnInvalidatorStateChange( - invalidation::INVALIDATIONS_ENABLED); - EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); - EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, - handler.GetLastRetrievedState()); + this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED); + EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); + EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetLastRetrievedState()); - this->delegate_.TriggerOnInvalidatorStateChange( - invalidation::TRANSIENT_INVALIDATION_ERROR); - EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR, - handler.GetInvalidatorState()); - EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR, - handler.GetLastRetrievedState()); + this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler.GetInvalidatorState()); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler.GetLastRetrievedState()); invalidator->UnregisterInvalidationHandler(&handler); } @@ -428,4 +375,6 @@ EmptySetUnregisters, GetInvalidatorStateAlwaysCurrent); +} // namespace invalidation + #endif // COMPONENTS_INVALIDATION_IMPL_INVALIDATION_SERVICE_TEST_TEMPLATE_H_
diff --git a/components/js_injection/browser/js_to_browser_messaging.cc b/components/js_injection/browser/js_to_browser_messaging.cc index e2a4e18..68aa371 100644 --- a/components/js_injection/browser/js_to_browser_messaging.cc +++ b/components/js_injection/browser/js_to_browser_messaging.cc
@@ -72,6 +72,10 @@ std::vector<blink::MessagePortDescriptor> ports) { DCHECK(render_frame_host_); + // This generally shouldn't happen, and may indicate a compromised renderer. + if (render_frame_host_->IsInactiveAndDisallowReactivation()) + return; + content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host_); @@ -119,6 +123,10 @@ void JsToBrowserMessaging::SetBrowserToJsMessaging( mojo::PendingAssociatedRemote<mojom::BrowserToJsMessaging> java_to_js_messaging) { + // This generally shouldn't happen, and may indicate a compromised renderer. + if (render_frame_host_->IsInactiveAndDisallowReactivation()) + return; + // A RenderFrame may inject JsToBrowserMessaging in the JavaScript context // more than once because of reusing of RenderFrame. host_.reset();
diff --git a/components/lookalikes/core/lookalike_url_util.cc b/components/lookalikes/core/lookalike_url_util.cc index 6b0a225..c65ba8d6 100644 --- a/components/lookalikes/core/lookalike_url_util.cc +++ b/components/lookalikes/core/lookalike_url_util.cc
@@ -23,6 +23,7 @@ #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/time/default_clock.h" +#include "base/trace_event/trace_event.h" #include "base/values.h" #include "components/lookalikes/core/features.h" #include "components/security_interstitials/core/pref_names.h" @@ -381,6 +382,7 @@ DomainInfo::DomainInfo(const DomainInfo&) = default; DomainInfo GetDomainInfo(const std::string& hostname) { + TRACE_EVENT0("navigation", "GetDomainInfo"); if (net::HostStringIsLocalhost(hostname) || net::IsHostnameNonUnique(hostname)) { return DomainInfo(std::string(), std::string(), std::string(),
diff --git a/components/no_state_prefetch/browser/prerender_manager.cc b/components/no_state_prefetch/browser/prerender_manager.cc index ae248992..863327f3 100644 --- a/components/no_state_prefetch/browser/prerender_manager.cc +++ b/components/no_state_prefetch/browser/prerender_manager.cc
@@ -977,6 +977,7 @@ content::RenderProcessHost* host) { DCHECK_CURRENTLY_ON(BrowserThread::UI); size_t erased = prerender_process_hosts_.erase(host); + host->RemoveObserver(this); DCHECK_EQ(1u, erased); }
diff --git a/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java b/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java index ce9a755..9051f6a5 100644 --- a/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java +++ b/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
@@ -147,26 +147,26 @@ @Test @MediumTest - public void nestedLinkClickTest() throws Exception { + @DisableIf.Build(message = "Test is failing on Android P, see crbug.com/1110939.", + sdk_is_greater_than = VERSION_CODES.O_MR1, sdk_is_less_than = VERSION_CODES.Q) + public void + nestedLinkClickTest() throws Exception { initPlayerManager(true); final View playerHostView = mPlayerManager.getView(); assertLinkUrl(playerHostView, 220, 220, TEST_IN_VIEWPORT_LINK_URL); assertLinkUrl(playerHostView, 300, 270, TEST_IN_VIEWPORT_LINK_URL); - // Temporarily commenting out as this is flaky on P. + UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + int deviceHeight = device.getDisplayHeight(); + int statusBarHeight = statusBarHeight(); + int navigationBarHeight = navigationBarHeight(); + int padding = 20; + int fromY = deviceHeight - navigationBarHeight - padding; + int toY = statusBarHeight + padding; + mLinkClickHandler.mUrl = null; + device.swipe(300, fromY, 300, toY, 10); - // UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - // int deviceHeight = device.getDisplayHeight(); - // int statusBarHeight = statusBarHeight(); - // int navigationBarHeight = navigationBarHeight(); - // int padding = 20; - // int fromY = deviceHeight - navigationBarHeight - padding; - // int toY = statusBarHeight + padding; - // mLinkClickHandler.mUrl = null; - // device.swipe(300, fromY, 300, toY, 10); - - // Manually click as assertLinkUrl() doesn't handle subframe scrolls well. - // assertLinkUrl(playerHostView, 200, 1500, TEST_OUT_OF_VIEWPORT_LINK_URL); + assertLinkUrl(playerHostView, 200, 1500, TEST_OUT_OF_VIEWPORT_LINK_URL); } @Test
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc index 0271d4fe..65e4549e 100644 --- a/components/password_manager/core/browser/password_form_manager.cc +++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -1054,9 +1054,17 @@ } } + // TODO(crbug.com/959776): This currently only considers a possible username + // valid if a credential with the same username already exists for the same + // site. This is too conservative, and we should allow any possible username + // that matches a credential on any site in the user's password store. + std::vector<base::string16> usernames; + usernames.reserve(GetBestMatches().size()); + base::ranges::transform(GetBestMatches(), std::back_inserter(usernames), + &PasswordForm::username_value); + bool is_possible_username_valid = IsPossibleUsernameValid( - *possible_username, parsed_submitted_form_->signon_realm, - base::Time::Now()); + *possible_username, parsed_submitted_form_->signon_realm, usernames); LogUsingPossibleUsername(client_, /*is_used*/ is_possible_username_valid, "Local heuristics"); return is_possible_username_valid;
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc index 11a093f4..c2ac2ff 100644 --- a/components/password_manager/core/browser/password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -2098,8 +2098,8 @@ feature_list.InitAndEnableFeature(features::kUsernameFirstFlow); CreateFormManager(observed_form_only_password_fields_); - fetcher_->NotifyFetchCompleted(); - const base::string16 possible_username = ASCIIToUTF16("possible_username"); + SetNonFederatedAndNotifyFetchCompleted({&saved_match_}); + const base::string16 possible_username = ASCIIToUTF16("test@example.com"); PossibleUsernameData possible_username_data( saved_match_.signon_realm, autofill::FieldRendererId(1), possible_username, base::Time::Now(), 0 /* driver_id */); @@ -2117,7 +2117,8 @@ #else // Local heuristics on Android for username first flow are not supported, so // the username should not be taken from the username form. - EXPECT_TRUE(form_manager_->GetPendingCredentials().username_value.empty()); + EXPECT_EQ(saved_match_.username_value, + form_manager_->GetPendingCredentials().username_value); #endif // !defined(OS_ANDROID) } @@ -2808,8 +2809,8 @@ base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(features::kUsernameFirstFlow); CreateFormManager(observed_form_only_password_fields_); - fetcher_->NotifyFetchCompleted(); - const base::string16 possible_username = ASCIIToUTF16("possible_username"); + SetNonFederatedAndNotifyFetchCompleted({&saved_match_}); + const base::string16 possible_username = ASCIIToUTF16("test@example.org"); PossibleUsernameData possible_username_data( saved_match_.signon_realm, autofill::FieldRendererId(1u), possible_username, base::Time::Now(), 0 /* driver_id */);
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc index 511dd4ac..a94b333 100644 --- a/components/password_manager/core/browser/password_manager_unittest.cc +++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -74,8 +74,10 @@ using base::Feature; using base::TestMockTimeTaskRunner; using testing::_; +using testing::AllOf; using testing::AnyNumber; using testing::ByMove; +using testing::Field; using testing::Invoke; using testing::IsNull; using testing::Mock; @@ -3410,11 +3412,12 @@ base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(features::kUsernameFirstFlow); EXPECT_CALL(*store_, GetLogins(_, _)) - .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get()))); + .WillRepeatedly( + WithArg<1>(InvokeConsumer(store_.get(), MakeSavedForm()))); PasswordForm form(MakeSimpleFormWithOnlyPasswordField()); // Simulate the user typed a username in username form. - const base::string16 username = ASCIIToUTF16("username1"); + const base::string16 username = ASCIIToUTF16("googleuser@gmail.com"); EXPECT_CALL(driver_, GetLastCommittedURL()).WillOnce(ReturnRef(form.url)); manager()->OnUserModifiedNonPasswordField(&driver_, FieldRendererId(1001), username /* value */); @@ -3438,21 +3441,24 @@ // Simulates successful submission. manager()->OnPasswordFormsRendered(&driver_, {} /* observed */, true); - // Simulate saving the form, as if the info bar was accepted. - PasswordForm saved_form; - EXPECT_CALL(*store_, AddLogin(_)).WillOnce(SaveArg<0>(&saved_form)); ASSERT_TRUE(form_manager_to_save); - form_manager_to_save->Save(); - -#if defined(OS_ANDROID) - // Local heuristics on Android for username first flow are not supported, so - // the username should not be taken from the username form. - EXPECT_TRUE(saved_form.username_value.empty()); +#if !defined(OS_ANDROID) + EXPECT_CALL(*store_, + AddLogin(AllOf(Field(&PasswordForm::username_value, username), + Field(&PasswordForm::password_value, password)))); #else - EXPECT_EQ(username, saved_form.username_value); + // Local heuristics on Android for username first flow are not supported, so + // the username should not be taken from the username form. Furthermore, since + // there is no change to the already saved username, this should trigger an + // update flow, rather than a save flow. + EXPECT_CALL( + *store_, + UpdateLogin(AllOf( + Field(&PasswordForm::username_value, MakeSavedForm().username_value), + Field(&PasswordForm::password_value, password)))); #endif // defined(OS_ANDROID) - - EXPECT_EQ(password, saved_form.password_value); + // Simulate saving the form, as if the info bar was accepted. + form_manager_to_save->Save(); } #if !defined(OS_IOS)
diff --git a/components/password_manager/core/browser/possible_username_data.cc b/components/password_manager/core/browser/possible_username_data.cc index 4bdfc27e..fb1c26a 100644 --- a/components/password_manager/core/browser/possible_username_data.cc +++ b/components/password_manager/core/browser/possible_username_data.cc
@@ -4,7 +4,12 @@ #include "components/password_manager/core/browser/possible_username_data.h" -#include "base/strings/string_util.h" +#include <vector> + +#include "base/containers/contains.h" +#include "base/strings/string16.h" +#include "base/strings/string_piece.h" +#include "components/password_manager/core/browser/leak_detection/encryption_utils.h" using base::char16; using base::TimeDelta; @@ -26,29 +31,25 @@ default; PossibleUsernameData::~PossibleUsernameData() = default; -bool IsPossibleUsernameValid(const PossibleUsernameData& possible_username, - const std::string& submitted_signon_realm, - const base::Time now) { +bool IsPossibleUsernameValid( + const PossibleUsernameData& possible_username, + const std::string& submitted_signon_realm, + const std::vector<base::string16>& possible_usernames) { if (submitted_signon_realm != possible_username.signon_realm) return false; + // The goal is to avoid false positives in considering which strings might be // username. In the initial version of the username first flow it is better to - // be conservative in that. - // TODO(https://crbug.com/959776): Reconsider allowing non-ascii symbols in - // username for the username first flow. - if (!base::IsStringASCII(possible_username.value)) - return false; - for (char16 c : possible_username.value) { - if (base::IsUnicodeWhitespace(c)) - return false; - } - - if (now - possible_username.last_change > - kMaxDelayBetweenTypingUsernameAndSubmission) { + // be conservative in that. This check only allows usernames that match + // existing usernames after canonicalization. + base::string16 (*Canonicalize)(base::StringPiece16) = &CanonicalizeUsername; + if (!base::Contains(possible_usernames, Canonicalize(possible_username.value), + Canonicalize)) { return false; } - return true; + return base::Time::Now() - possible_username.last_change <= + kMaxDelayBetweenTypingUsernameAndSubmission; } } // namespace password_manager
diff --git a/components/password_manager/core/browser/possible_username_data.h b/components/password_manager/core/browser/possible_username_data.h index e905789ab..2c47e526 100644 --- a/components/password_manager/core/browser/possible_username_data.h +++ b/components/password_manager/core/browser/possible_username_data.h
@@ -6,6 +6,7 @@ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_POSSIBLE_USERNAME_DATA_H_ #include <string> +#include <vector> #include "base/optional.h" #include "base/strings/string16.h" @@ -18,8 +19,8 @@ // The maximum time between the user typed in a text field and subsequent // submission of the password form, such that the typed value is considered to // be possible to be username. -constexpr base::TimeDelta kMaxDelayBetweenTypingUsernameAndSubmission = - base::TimeDelta::FromSeconds(60); +constexpr auto kMaxDelayBetweenTypingUsernameAndSubmission = + base::TimeDelta::FromMinutes(1); // Contains information that the user typed in a text field. It might be the // username during username first flow. @@ -47,12 +48,14 @@ // Checks that |possible_username| might represent an username: // 1.|possible_username.signon_realm| == |submitted_signon_realm| -// 2.|possible_username.value| does not have whitespaces and non-ASCII symbols. -// 3.|possible_username.value.last_change| was not more than 60 seconds before -// now. -bool IsPossibleUsernameValid(const PossibleUsernameData& possible_username, - const std::string& submitted_signon_realm, - const base::Time now); +// 2.|possible_username.value| is contained in |possible_usernames| after +// canonicalization. +// 3.|possible_username.value.last_change| was not more than +// |kMaxDelayBetweenTypingUsernameAndSubmission| ago. +bool IsPossibleUsernameValid( + const PossibleUsernameData& possible_username, + const std::string& submitted_signon_realm, + const std::vector<base::string16>& possible_usernames); } // namespace password_manager
diff --git a/components/password_manager/core/browser/possible_username_data_unittest.cc b/components/password_manager/core/browser/possible_username_data_unittest.cc index 0fd9d39..08b2000 100644 --- a/components/password_manager/core/browser/possible_username_data_unittest.cc +++ b/components/password_manager/core/browser/possible_username_data_unittest.cc
@@ -5,10 +5,10 @@ #include "components/password_manager/core/browser/possible_username_data.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/task_environment.h" #include "components/autofill/core/common/renderer_id.h" #include "testing/gtest/include/gtest/gtest.h" -using base::ASCIIToUTF16; using base::Time; using base::TimeDelta; @@ -16,71 +16,65 @@ namespace { -class IsPossibleUsernameValidTest : public testing::Test { - public: - IsPossibleUsernameValidTest() - : possible_username_data_( - "https://example.com/" /* submitted_signon_realm */, - autofill::FieldRendererId(1u), - ASCIIToUTF16("username") /* value */, - base::Time::Now() /* last_change */, - 10 /* driver_id */) {} +constexpr base::char16 kUser[] = STRING16_LITERAL("user"); +class IsPossibleUsernameValidTest : public testing::Test { protected: - PossibleUsernameData possible_username_data_; + base::test::SingleThreadTaskEnvironment task_environment_{ + base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME}; + PossibleUsernameData possible_username_data_{ + "https://example.com/" /* submitted_signon_realm */, + autofill::FieldRendererId(1u), kUser /* value */, + base::Time::Now() /* last_change */, 10 /* driver_id */}; }; TEST_F(IsPossibleUsernameValidTest, Valid) { - EXPECT_TRUE(IsPossibleUsernameValid(possible_username_data_, - possible_username_data_.signon_realm, - possible_username_data_.last_change)); + EXPECT_TRUE(IsPossibleUsernameValid( + possible_username_data_, possible_username_data_.signon_realm, {kUser})); } // Check that if time delta between last change and submission is more than 60 // seconds, than data is invalid. TEST_F(IsPossibleUsernameValidTest, TimeDeltaBeforeLastChangeAndSubmission) { - Time valid_submission_time = possible_username_data_.last_change + - kMaxDelayBetweenTypingUsernameAndSubmission; - Time invalid_submission_time = - valid_submission_time + TimeDelta::FromSeconds(1); - EXPECT_TRUE(IsPossibleUsernameValid(possible_username_data_, - possible_username_data_.signon_realm, - valid_submission_time)); - EXPECT_FALSE(IsPossibleUsernameValid(possible_username_data_, - possible_username_data_.signon_realm, - invalid_submission_time)); + task_environment_.FastForwardBy(kMaxDelayBetweenTypingUsernameAndSubmission); + EXPECT_TRUE(IsPossibleUsernameValid( + possible_username_data_, possible_username_data_.signon_realm, {kUser})); + task_environment_.FastForwardBy(TimeDelta::FromSeconds(1)); + EXPECT_FALSE(IsPossibleUsernameValid( + possible_username_data_, possible_username_data_.signon_realm, {kUser})); } TEST_F(IsPossibleUsernameValidTest, SignonRealm) { EXPECT_FALSE(IsPossibleUsernameValid(possible_username_data_, - "https://m.example.com/", - possible_username_data_.last_change)); + "https://m.example.com/", {kUser})); EXPECT_FALSE(IsPossibleUsernameValid(possible_username_data_, - "https://google.com/", - possible_username_data_.last_change)); + "https://google.com/", {kUser})); } TEST_F(IsPossibleUsernameValidTest, PossibleUsernameValue) { - PossibleUsernameData possible_username_data = possible_username_data_; + // Different capitalization is okay. + EXPECT_TRUE(IsPossibleUsernameValid(possible_username_data_, + possible_username_data_.signon_realm, + {STRING16_LITERAL("USER")})); + // Different email hosts are okay. + EXPECT_TRUE(IsPossibleUsernameValid(possible_username_data_, + possible_username_data_.signon_realm, + {STRING16_LITERAL("user@gmail.com")})); - // White spaces are not allowed in username. - possible_username_data.value = ASCIIToUTF16("user name"); - EXPECT_FALSE(IsPossibleUsernameValid(possible_username_data, - possible_username_data.signon_realm, - possible_username_data.last_change)); + // Other usernames are okay. + EXPECT_TRUE(IsPossibleUsernameValid(possible_username_data_, + possible_username_data_.signon_realm, + {kUser, STRING16_LITERAL("alice")})); - // New lines are not allowed in username. - possible_username_data.value = ASCIIToUTF16("user\nname"); - EXPECT_FALSE(IsPossibleUsernameValid(possible_username_data, - possible_username_data.signon_realm, - possible_username_data.last_change)); + // No usernames are not okay. + EXPECT_FALSE(IsPossibleUsernameValid( + possible_username_data_, possible_username_data_.signon_realm, {})); - // Digits and special characters are ok. - possible_username_data.value = ASCIIToUTF16("User_name1234!+&%#\'\"@"); - EXPECT_TRUE(IsPossibleUsernameValid(possible_username_data, - possible_username_data.signon_realm, - possible_username_data.last_change)); + // Completely different usernames are not okay. + EXPECT_FALSE(IsPossibleUsernameValid( + possible_username_data_, possible_username_data_.signon_realm, + {STRING16_LITERAL("alice"), STRING16_LITERAL("bob")})); } } // namespace
diff --git a/components/payments/content/android/BUILD.gn b/components/payments/content/android/BUILD.gn index b977170..eb60baa 100644 --- a/components/payments/content/android/BUILD.gn +++ b/components/payments/content/android/BUILD.gn
@@ -288,6 +288,7 @@ "//third_party/junit", "//third_party/mockito:mockito_java", "//url:gurl_java", + "//url:gurl_junit_test_support", "//url:origin_java", ] }
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/OriginSecurityChecker.java b/components/payments/content/android/java/src/org/chromium/components/payments/OriginSecurityChecker.java index ea0f9bf..4dcfc70 100644 --- a/components/payments/content/android/java/src/org/chromium/components/payments/OriginSecurityChecker.java +++ b/components/payments/content/android/java/src/org/chromium/components/payments/OriginSecurityChecker.java
@@ -6,6 +6,7 @@ import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; +import org.chromium.url.GURL; /** Helper for origin security. */ @JNINamespace("payments") @@ -17,7 +18,7 @@ * @param url The URL to check. * @return Whether the origin of the URL is secure. */ - public static boolean isOriginSecure(String url) { + public static boolean isOriginSecure(GURL url) { return OriginSecurityCheckerJni.get().isOriginSecure(url); } @@ -27,7 +28,7 @@ * @param url The URL to check. * @return Whether the scheme of the URL is cryptographic. */ - public static boolean isSchemeCryptographic(String url) { + public static boolean isSchemeCryptographic(GURL url) { return OriginSecurityCheckerJni.get().isSchemeCryptographic(url); } @@ -35,7 +36,7 @@ @NativeMethods interface Natives { - boolean isOriginSecure(String url); - boolean isSchemeCryptographic(String url); + boolean isOriginSecure(GURL url); + boolean isSchemeCryptographic(GURL url); } }
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentRequestService.java b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentRequestService.java index f846965..72ef34a 100644 --- a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentRequestService.java +++ b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentRequestService.java
@@ -226,7 +226,7 @@ * @param url The URL to check. * @return Whether the origin of the URL is secure. */ - default boolean isOriginSecure(String url) { + default boolean isOriginSecure(GURL url) { return OriginSecurityChecker.isOriginSecure(url); } @@ -263,7 +263,7 @@ * @param url The URL to check. * @return Whether the page is allowed to use web payment APIs. */ - default boolean isOriginAllowedToUseWebPaymentApis(String url) { + default boolean isOriginAllowedToUseWebPaymentApis(GURL url) { return UrlUtil.isOriginAllowedToUseWebPaymentApis(url); } @@ -429,7 +429,8 @@ return false; } // TODO(crbug.com/992593): replace UrlFormatter with GURL operations. - mTopLevelOrigin = mDelegate.formatUrlForSecurityDisplay(mWebContents.getLastCommittedUrl()); + mTopLevelOrigin = + mDelegate.formatUrlForSecurityDisplay(mWebContents.getLastCommittedUrl().getSpec()); mMerchantName = mWebContents.getTitle(); mCertificateChain = mDelegate.getCertificateChain(mWebContents);
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/UrlUtil.java b/components/payments/content/android/java/src/org/chromium/components/payments/UrlUtil.java index 5a4d206..4bbada577 100644 --- a/components/payments/content/android/java/src/org/chromium/components/payments/UrlUtil.java +++ b/components/payments/content/android/java/src/org/chromium/components/payments/UrlUtil.java
@@ -6,6 +6,7 @@ import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; +import org.chromium.url.GURL; /** URL validity checker for web payment APIs. */ @JNINamespace("payments::android") @@ -15,7 +16,7 @@ * @param url The URL to check. * @return Whether the page is allowed to use web payment APIs. */ - public static boolean isOriginAllowedToUseWebPaymentApis(String url) { + public static boolean isOriginAllowedToUseWebPaymentApis(GURL url) { return UrlUtilJni.get().isOriginAllowedToUseWebPaymentApis(url); } @@ -25,14 +26,14 @@ * @param url The URL to check. * @return Whether this is a local development URL. */ - public static boolean isLocalDevelopmentUrl(String url) { + public static boolean isLocalDevelopmentUrl(GURL url) { return UrlUtilJni.get().isLocalDevelopmentUrl(url); } /** The interface implemented by the automatically generated JNI bindings class UrlUtilJni. */ @NativeMethods /* package */ interface Natives { - boolean isOriginAllowedToUseWebPaymentApis(String url); - boolean isLocalDevelopmentUrl(String url); + boolean isOriginAllowedToUseWebPaymentApis(GURL url); + boolean isLocalDevelopmentUrl(GURL url); } }
diff --git a/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceBuilder.java b/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceBuilder.java index 5da36d2..a8ba8ee 100644 --- a/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceBuilder.java +++ b/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceBuilder.java
@@ -17,6 +17,8 @@ import org.chromium.payments.mojom.PaymentMethodData; import org.chromium.payments.mojom.PaymentOptions; import org.chromium.payments.mojom.PaymentRequestClient; +import org.chromium.url.GURL; +import org.chromium.url.JUnitTestGURLs; import org.chromium.url.Origin; import java.util.Collection; @@ -60,7 +62,7 @@ JourneyLogger journeyLogger) { mDelegate = this; mWebContents = Mockito.mock(WebContents.class); - setTopLevelOrigin("https://top.level.origin"); + setTopLevelOrigin(JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_1)); mRenderFrameHost = Mockito.mock(RenderFrameHost.class); setFrameOrigin("https://frame.origin"); Origin origin = Mockito.mock(Origin.class); @@ -122,7 +124,7 @@ } @Override - public boolean isOriginSecure(String url) { + public boolean isOriginSecure(GURL url) { return mIsOriginSecure; } @@ -142,7 +144,7 @@ } @Override - public boolean isOriginAllowedToUseWebPaymentApis(String lastCommittedUrl) { + public boolean isOriginAllowedToUseWebPaymentApis(GURL lastCommittedUrl) { return mIsOriginAllowedToUseWebPaymentApis; } @@ -230,7 +232,7 @@ return this; } - /* package */ PaymentRequestServiceBuilder setTopLevelOrigin(String topLevelOrigin) { + /* package */ PaymentRequestServiceBuilder setTopLevelOrigin(GURL topLevelOrigin) { Mockito.doReturn(topLevelOrigin).when(mWebContents).getLastCommittedUrl(); return this; }
diff --git a/components/payments/content/android/origin_security_checker_android.cc b/components/payments/content/android/origin_security_checker_android.cc index d5c535e..7228fb4 100644 --- a/components/payments/content/android/origin_security_checker_android.cc +++ b/components/payments/content/android/origin_security_checker_android.cc
@@ -6,6 +6,7 @@ #include "base/android/scoped_java_ref.h" #include "components/payments/content/android/jni_headers/OriginSecurityChecker_jni.h" #include "services/network/public/cpp/is_potentially_trustworthy.h" +#include "url/android/gurl_android.h" #include "url/gurl.h" namespace payments { @@ -19,17 +20,17 @@ // static jboolean JNI_OriginSecurityChecker_IsOriginSecure( JNIEnv* env, - const JavaParamRef<jstring>& jurl) { - GURL url(ConvertJavaStringToUTF8(env, jurl)); - return url.is_valid() && network::IsUrlPotentiallyTrustworthy(url); + const JavaParamRef<jobject>& j_url) { + std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_url); + return url->is_valid() && network::IsUrlPotentiallyTrustworthy(*url); } // static jboolean JNI_OriginSecurityChecker_IsSchemeCryptographic( JNIEnv* env, - const JavaParamRef<jstring>& jurl) { - GURL url(ConvertJavaStringToUTF8(env, jurl)); - return url.is_valid() && url.SchemeIsCryptographic(); + const JavaParamRef<jobject>& j_url) { + std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_url); + return url->is_valid() && url->SchemeIsCryptographic(); } } // namespace payments
diff --git a/components/payments/content/android/url_util.cc b/components/payments/content/android/url_util.cc index f0f56d99..66dc734 100644 --- a/components/payments/content/android/url_util.cc +++ b/components/payments/content/android/url_util.cc
@@ -6,6 +6,7 @@ #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" #include "components/payments/content/android/jni_headers/UrlUtil_jni.h" +#include "url/android/gurl_android.h" #include "url/gurl.h" namespace payments { @@ -14,17 +15,17 @@ // static jboolean JNI_UrlUtil_IsOriginAllowedToUseWebPaymentApis( JNIEnv* env, - const base::android::JavaParamRef<jstring>& jurl) { - return UrlUtil::IsOriginAllowedToUseWebPaymentApis( - GURL(base::android::ConvertJavaStringToUTF8(env, jurl))); + const base::android::JavaParamRef<jobject>& j_url) { + std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_url); + return UrlUtil::IsOriginAllowedToUseWebPaymentApis(*url); } // static jboolean JNI_UrlUtil_IsLocalDevelopmentUrl( JNIEnv* env, - const base::android::JavaParamRef<jstring>& jurl) { - return UrlUtil::IsLocalDevelopmentUrl( - GURL(base::android::ConvertJavaStringToUTF8(env, jurl))); + const base::android::JavaParamRef<jobject>& j_url) { + std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_url); + return UrlUtil::IsLocalDevelopmentUrl(*url); } } // namespace android
diff --git a/components/policy/core/common/cloud/cloud_policy_client_unittest.cc b/components/policy/core/common/cloud/cloud_policy_client_unittest.cc index 03523610..d63300cd 100644 --- a/components/policy/core/common/cloud/cloud_policy_client_unittest.cc +++ b/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
@@ -165,8 +165,6 @@ // A mock class to allow us to set expectations on upload callbacks. class MockStatusCallbackObserver { public: - MockStatusCallbackObserver() = default; - MOCK_METHOD1(OnCallbackComplete, void(bool)); }; @@ -174,8 +172,6 @@ // callbacks. class MockRemoteCommandsObserver { public: - MockRemoteCommandsObserver() = default; - MOCK_METHOD3(OnRemoteCommandsFetched, void(DeviceManagementStatus, const std::vector<em::RemoteCommand>&, @@ -184,16 +180,12 @@ class MockDeviceDMTokenCallbackObserver { public: - MockDeviceDMTokenCallbackObserver() = default; - MOCK_METHOD1(OnDeviceDMTokenRequested, std::string(const std::vector<std::string>&)); }; class MockRobotAuthCodeCallbackObserver { public: - MockRobotAuthCodeCallbackObserver() = default; - MOCK_METHOD2(OnRobotAuthCodeFetched, void(DeviceManagementStatus, const std::string&)); }; @@ -205,6 +197,20 @@ MOCK_METHOD1(OnResponseReceived, void(base::Optional<base::Value>)); }; +std::string CreatePolicyData(const std::string& policy_value) { + em::PolicyData policy_data; + policy_data.set_policy_type(dm_protocol::kChromeUserPolicyType); + policy_data.set_policy_value(policy_value); + return policy_data.SerializeAsString(); +} + +em::DeviceManagementResponse GetPolicyResponse() { + em::DeviceManagementResponse policy_response; + policy_response.mutable_policy_response()->add_responses()->set_policy_data( + CreatePolicyData("fake-policy-data")); + return policy_response; +} + } // namespace class CloudPolicyClientTest : public testing::Test { @@ -249,7 +255,7 @@ em::CertificateBasedDeviceRegistrationData data; data.set_certificate_type(em::CertificateBasedDeviceRegistrationData:: - ENTERPRISE_ENROLLMENT_CERTIFICATE); + ENTERPRISE_ENROLLMENT_CERTIFICATE); data.set_device_certificate(kEnrollmentCertificate); em::DeviceRegisterRequest* request = data.mutable_device_register_request(); @@ -268,8 +274,9 @@ em::CertificateBasedDeviceRegisterRequest* cert_based_register_request = cert_based_registration_request_ - .mutable_certificate_based_register_request(); - fake_signing_service_.SignDataSynchronously(data.SerializeAsString(), + .mutable_certificate_based_register_request(); + fake_signing_service_.SignDataSynchronously( + data.SerializeAsString(), cert_based_register_request->mutable_signed_request()); em::PolicyFetchRequest* policy_fetch_request = @@ -278,12 +285,9 @@ policy_fetch_request->set_signature_type(em::PolicyFetchRequest::SHA1_RSA); policy_fetch_request->set_verification_key_hash(kPolicyVerificationKeyHash); policy_fetch_request->set_device_dm_token(kDeviceDMToken); - policy_response_.mutable_policy_response() - ->add_responses() - ->set_policy_data(CreatePolicyData("fake-policy-data")); - registration_response_.mutable_register_response()-> - set_device_management_token(kDMToken); + registration_response_.mutable_register_response() + ->set_device_management_token(kDMToken); failed_reregistration_response_.mutable_register_response() ->set_device_management_token(kDMToken2); @@ -338,19 +342,19 @@ remote_command_request_.mutable_remote_command_request() ->set_send_secure_commands(true); - attribute_update_permission_request_. - mutable_device_attribute_update_permission_request(); - attribute_update_permission_response_. - mutable_device_attribute_update_permission_response()-> - set_result( + attribute_update_permission_request_ + .mutable_device_attribute_update_permission_request(); + attribute_update_permission_response_ + .mutable_device_attribute_update_permission_response() + ->set_result( em::DeviceAttributeUpdatePermissionResponse_ResultType_ATTRIBUTE_UPDATE_ALLOWED); - attribute_update_request_.mutable_device_attribute_update_request()-> - set_asset_id(kAssetId); - attribute_update_request_.mutable_device_attribute_update_request()-> - set_location(kLocation); - attribute_update_response_.mutable_device_attribute_update_response()-> - set_result( + attribute_update_request_.mutable_device_attribute_update_request() + ->set_asset_id(kAssetId); + attribute_update_request_.mutable_device_attribute_update_request() + ->set_location(kLocation); + attribute_update_response_.mutable_device_attribute_update_response() + ->set_result( em::DeviceAttributeUpdateResponse_ResultType_ATTRIBUTE_UPDATE_SUCCESS); gcm_id_update_request_.mutable_gcm_id_update_request()->set_gcm_id(kGcmID); @@ -387,13 +391,9 @@ #endif } - void SetUp() override { - CreateClient(); - } + void SetUp() override { CreateClient(); } - void TearDown() override { - client_->RemoveObserver(&observer_); - } + void TearDown() override { client_->RemoveObserver(&observer_); } void RegisterClient(const std::string& device_dm_token) { EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); @@ -474,17 +474,11 @@ service_.StartJobAsync(net_error, response_code))); } - void CheckPolicyResponse() { + void CheckPolicyResponse( + const em::DeviceManagementResponse& policy_response) { ASSERT_TRUE(client_->GetPolicyFor(policy_type_, std::string())); EXPECT_THAT(*client_->GetPolicyFor(policy_type_, std::string()), - MatchProto(policy_response_.policy_response().responses(0))); - } - - std::string CreatePolicyData(const std::string& policy_value) { - em::PolicyData policy_data; - policy_data.set_policy_type(dm_protocol::kChromeUserPolicyType); - policy_data.set_policy_value(policy_value); - return policy_data.SerializeAsString(); + MatchProto(policy_response.policy_response().responses(0))); } void AttemptUploadEncryptedWaitUntilIdle( @@ -522,7 +516,6 @@ // Protobufs used in successful responses. em::DeviceManagementResponse registration_response_; em::DeviceManagementResponse failed_reregistration_response_; - em::DeviceManagementResponse policy_response_; em::DeviceManagementResponse unregistration_response_; em::DeviceManagementResponse upload_certificate_response_; em::DeviceManagementResponse upload_status_response_; @@ -542,7 +535,7 @@ std::string job_payload_; std::string client_id_; std::string policy_type_; - MockDeviceManagementService service_; + StrictMock<MockDeviceManagementService> service_; StrictMock<MockCloudPolicyClientObserver> observer_; StrictMock<MockStatusCallbackObserver> callback_observer_; StrictMock<MockDeviceDMTokenCallbackObserver> @@ -560,23 +553,24 @@ }; TEST_F(CloudPolicyClientTest, Init) { - EXPECT_CALL(service_, StartJob(_)).Times(0); EXPECT_FALSE(client_->is_registered()); EXPECT_FALSE(client_->GetPolicyFor(policy_type_, std::string())); EXPECT_EQ(0, client_->fetched_invalidation_version()); } TEST_F(CloudPolicyClientTest, SetupRegistrationAndPolicyFetch) { - EXPECT_CALL(service_, StartJob(_)).Times(0); - EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); - EXPECT_CALL(device_dmtoken_callback_observer_, OnDeviceDMTokenRequested(_)) + const em::DeviceManagementResponse policy_response = GetPolicyResponse(); + + EXPECT_CALL(observer_, OnRegistrationStateChanged); + EXPECT_CALL(device_dmtoken_callback_observer_, + OnDeviceDMTokenRequested(std::vector<std::string>())) .WillOnce(Return(kDeviceDMToken)); client_->SetupRegistration(kDMToken, client_id_, std::vector<std::string>()); EXPECT_TRUE(client_->is_registered()); EXPECT_FALSE(client_->GetPolicyFor(policy_type_, std::string())); - ExpectAndCaptureJob(/*response=*/policy_response_); - EXPECT_CALL(observer_, OnPolicyFetched(_)); + ExpectAndCaptureJob(/*response=*/policy_response); + EXPECT_CALL(observer_, OnPolicyFetched); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_POLICY_FETCH, @@ -585,11 +579,12 @@ EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); } TEST_F(CloudPolicyClientTest, SetupRegistrationAndPolicyFetchWithOAuthToken) { - EXPECT_CALL(service_, StartJob(_)).Times(0); + const em::DeviceManagementResponse policy_response = GetPolicyResponse(); + EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); EXPECT_CALL(device_dmtoken_callback_observer_, OnDeviceDMTokenRequested(_)) .WillOnce(Return(kDeviceDMToken)); @@ -598,7 +593,7 @@ EXPECT_TRUE(client_->is_registered()); EXPECT_FALSE(client_->GetPolicyFor(policy_type_, std::string())); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -610,12 +605,14 @@ EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); } #if defined(OS_WIN) || defined(OS_APPLE) || \ (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) TEST_F(CloudPolicyClientTest, RegistrationWithTokenAndPolicyFetch) { + const em::DeviceManagementResponse policy_response = GetPolicyResponse(); + ExpectAndCaptureJob(/*response=*/registration_response_); EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); EXPECT_CALL(device_dmtoken_callback_observer_, OnDeviceDMTokenRequested(_)) @@ -630,7 +627,7 @@ EXPECT_FALSE(client_->GetPolicyFor(policy_type_, std::string())); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -640,11 +637,13 @@ EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); } #endif TEST_F(CloudPolicyClientTest, RegistrationAndPolicyFetch) { + const em::DeviceManagementResponse policy_response = GetPolicyResponse(); + ExpectAndCaptureJob(/*response=*/registration_response_); EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); EXPECT_CALL(device_dmtoken_callback_observer_, OnDeviceDMTokenRequested(_)) @@ -666,7 +665,7 @@ EXPECT_FALSE(client_->GetPolicyFor(policy_type_, std::string())); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -676,10 +675,12 @@ EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); } TEST_F(CloudPolicyClientTest, RegistrationAndPolicyFetchWithOAuthToken) { + const em::DeviceManagementResponse policy_response = GetPolicyResponse(); + ExpectAndCaptureJob(/*response=*/registration_response_); EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); EXPECT_CALL(device_dmtoken_callback_observer_, OnDeviceDMTokenRequested(_)) @@ -702,7 +703,7 @@ EXPECT_FALSE(client_->GetPolicyFor(policy_type_, std::string())); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -714,10 +715,12 @@ EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); } TEST_F(CloudPolicyClientTest, RegistrationWithCertificateAndPolicyFetch) { + const em::DeviceManagementResponse policy_response = GetPolicyResponse(); + EXPECT_CALL(device_dmtoken_callback_observer_, OnDeviceDMTokenRequested(_)) .WillOnce(Return(kDeviceDMToken)); ExpectAndCaptureJob(/*response=*/registration_response_); @@ -739,7 +742,7 @@ EXPECT_FALSE(client_->GetPolicyFor(policy_type_, std::string())); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -749,7 +752,7 @@ EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); } TEST_F(CloudPolicyClientTest, RegistrationWithCertificateFailToSignRequest) { @@ -798,8 +801,8 @@ } TEST_F(CloudPolicyClientTest, RegistrationNoToken) { - registration_response_.mutable_register_response()-> - clear_device_management_token(); + registration_response_.mutable_register_response() + ->clear_device_management_token(); ExpectAndCaptureJob(/*response=*/registration_response_); EXPECT_CALL(observer_, OnClientError(_)); CloudPolicyClient::RegistrationParameters register_user( @@ -889,38 +892,47 @@ TEST_F(CloudPolicyClientTest, PolicyUpdate) { RegisterClient(); - ExpectAndCaptureJob(/*response=*/policy_response_); - EXPECT_CALL(observer_, OnPolicyFetched(_)); - client_->FetchPolicy(); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_POLICY_FETCH, - job_type_); - EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken)); - EXPECT_EQ(job_request_.SerializePartialAsString(), - policy_request_.SerializePartialAsString()); - CheckPolicyResponse(); + { + const em::DeviceManagementResponse policy_response = GetPolicyResponse(); - policy_response_.mutable_policy_response()->clear_responses(); - policy_response_.mutable_policy_response()->add_responses()->set_policy_data( - CreatePolicyData("updated-fake-policy-data")); - ExpectAndCaptureJob(/*response=*/policy_response_); - EXPECT_CALL(observer_, OnPolicyFetched(_)); - client_->FetchPolicy(); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_POLICY_FETCH, - job_type_); - EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken)); - EXPECT_EQ(job_request_.SerializePartialAsString(), - policy_request_.SerializePartialAsString()); - EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - CheckPolicyResponse(); + ExpectAndCaptureJob(/*response=*/policy_response); + EXPECT_CALL(observer_, OnPolicyFetched(_)); + client_->FetchPolicy(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_POLICY_FETCH, + job_type_); + EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken)); + EXPECT_EQ(job_request_.SerializePartialAsString(), + policy_request_.SerializePartialAsString()); + CheckPolicyResponse(policy_response); + } + + { + em::DeviceManagementResponse policy_response; + policy_response.mutable_policy_response()->add_responses()->set_policy_data( + CreatePolicyData("updated-fake-policy-data")); + + ExpectAndCaptureJob(/*response=*/policy_response); + EXPECT_CALL(observer_, OnPolicyFetched(_)); + client_->FetchPolicy(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_POLICY_FETCH, + job_type_); + EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken)); + EXPECT_EQ(job_request_.SerializePartialAsString(), + policy_request_.SerializePartialAsString()); + EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); + CheckPolicyResponse(policy_response); + } } TEST_F(CloudPolicyClientTest, PolicyFetchWithMetaData) { + em::DeviceManagementResponse policy_response = GetPolicyResponse(); + RegisterClient(); - const base::Time timestamp( - base::Time::UnixEpoch() + base::TimeDelta::FromDays(20)); + const base::Time timestamp(base::Time::UnixEpoch() + + base::TimeDelta::FromDays(20)); client_->set_last_policy_timestamp(timestamp); client_->set_public_key_version(42); em::PolicyFetchRequest* policy_fetch_request = @@ -928,7 +940,7 @@ policy_fetch_request->set_timestamp(timestamp.ToJavaTime()); policy_fetch_request->set_public_key_version(42); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -937,10 +949,12 @@ EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken)); EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); } TEST_F(CloudPolicyClientTest, PolicyFetchWithInvalidation) { + em::DeviceManagementResponse policy_response = GetPolicyResponse(); + RegisterClient(); int64_t previous_version = client_->fetched_invalidation_version(); @@ -951,7 +965,7 @@ policy_fetch_request->set_invalidation_version(12345); policy_fetch_request->set_invalidation_payload("12345"); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -960,18 +974,20 @@ EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken)); EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); EXPECT_EQ(12345, client_->fetched_invalidation_version()); } TEST_F(CloudPolicyClientTest, PolicyFetchWithInvalidationNoPayload) { + const em::DeviceManagementResponse policy_response = GetPolicyResponse(); + RegisterClient(); int64_t previous_version = client_->fetched_invalidation_version(); client_->SetInvalidationInfo(-12345, std::string()); EXPECT_EQ(previous_version, client_->fetched_invalidation_version()); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -980,16 +996,18 @@ EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken)); EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); EXPECT_EQ(-12345, client_->fetched_invalidation_version()); } // Tests that previous OAuth token is no longer sent in policy fetch after its // value was cleared. TEST_F(CloudPolicyClientTest, PolicyFetchClearOAuthToken) { + const em::DeviceManagementResponse policy_response = GetPolicyResponse(); + RegisterClient(); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->SetOAuthTokenAsAdditionalAuth(kOAuthToken); client_->FetchPolicy(); @@ -1001,9 +1019,9 @@ Contains(Pair(dm_protocol::kParamOAuthToken, kOAuthToken))); EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->SetOAuthTokenAsAdditionalAuth(""); client_->FetchPolicy(); @@ -1013,14 +1031,15 @@ EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken)); EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); } TEST_F(CloudPolicyClientTest, BadPolicyResponse) { + em::DeviceManagementResponse policy_response; + RegisterClient(); - policy_response_.clear_policy_response(); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnClientError(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -1032,11 +1051,11 @@ EXPECT_FALSE(client_->GetPolicyFor(policy_type_, std::string())); EXPECT_EQ(DM_STATUS_RESPONSE_DECODING_ERROR, client_->status()); - policy_response_.mutable_policy_response()->add_responses()->set_policy_data( + policy_response.mutable_policy_response()->add_responses()->set_policy_data( CreatePolicyData("fake-policy-data")); - policy_response_.mutable_policy_response()->add_responses()->set_policy_data( + policy_response.mutable_policy_response()->add_responses()->set_policy_data( CreatePolicyData("excess-fake-policy-data")); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -1046,7 +1065,7 @@ EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); } TEST_F(CloudPolicyClientTest, PolicyRequestFailure) { @@ -1119,13 +1138,15 @@ } TEST_F(CloudPolicyClientTest, PolicyFetchWithExtensionPolicy) { + em::DeviceManagementResponse policy_response = GetPolicyResponse(); + RegisterClient(); - // Set up the |expected_responses| and |policy_response_|. + // Set up the |expected_responses| and |policy_response|. static const char* kExtensions[] = { - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - "cccccccccccccccccccccccccccccccc", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "cccccccccccccccccccccccccccccccc", }; typedef std::map<std::pair<std::string, std::string>, em::PolicyFetchResponse> ResponseMap; @@ -1135,7 +1156,7 @@ std::string()); // Copy the user policy fetch request. expected_responses[key].CopyFrom( - policy_response_.policy_response().responses(0)); + policy_response.policy_response().responses(0)); expected_namespaces.insert(key); key.first = dm_protocol::kChromeExtensionPolicyType; expected_namespaces.insert(key); @@ -1145,7 +1166,7 @@ policy_data.set_policy_type(key.first); policy_data.set_settings_entity_id(key.second); expected_responses[key].set_policy_data(policy_data.SerializeAsString()); - policy_response_.mutable_policy_response()->add_responses()->CopyFrom( + policy_response.mutable_policy_response()->add_responses()->CopyFrom( expected_responses[key]); } @@ -1156,7 +1177,7 @@ service_.CaptureJobType(&job_type), service_.CaptureRequest(&policy_request_), service_.StartJobAsync(net::OK, DeviceManagementService::kSuccess, - policy_response_))); + policy_response))); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->AddPolicyTypeToFetch(dm_protocol::kChromeExtensionPolicyType, std::string()); @@ -1396,7 +1417,9 @@ job_type); // Now initiate a policy fetch - this should not cancel the upload job. - ExpectAndCaptureJob(/*response=*/policy_response_); + const em::DeviceManagementResponse policy_response = GetPolicyResponse(); + + ExpectAndCaptureJob(/*response=*/policy_response); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy(); base::RunLoop().RunUntilIdle(); @@ -1405,7 +1428,7 @@ EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken)); EXPECT_EQ(job_request_.SerializePartialAsString(), policy_request_.SerializePartialAsString()); - CheckPolicyResponse(); + CheckPolicyResponse(policy_response); // upload_status_job->SendResponse(DM_STATUS_SUCCESS, // upload_status_response_); @@ -2226,7 +2249,7 @@ base::Unretained(&robot_auth_code_callback_observer_))); base::RunLoop().RunUntilIdle(); - ExpectAndCaptureJob(/*response=*/policy_response_); + ExpectAndCaptureJob(/*response=*/GetPolicyResponse()); EXPECT_CALL(observer_, OnPolicyFetched(_)); client_->FetchPolicy();
diff --git a/components/signin/public/identity_manager/objc/BUILD.gn b/components/signin/public/identity_manager/objc/BUILD.gn index 950157c..ceea196 100644 --- a/components/signin/public/identity_manager/objc/BUILD.gn +++ b/components/signin/public/identity_manager/objc/BUILD.gn
@@ -11,3 +11,23 @@ public_deps = [ "//components/signin/public/identity_manager" ] } + +source_set("unit_tests") { + testonly = true + + configs += [ "//build/config/compiler:enable_arc" ] + + sources = [ "identity_manager_observer_bridge_unittest.mm" ] + + deps = [ + ":objc", + "//base/test:test_support", + "//components/signin/public/identity_manager:test_support", + "//services/network:test_support", + "//testing/gtest", + ] + + if (is_ios) { + deps += [ "//components/signin/public/identity_manager/ios:test_support" ] + } +}
diff --git a/components/signin/public/identity_manager/objc/identity_manager_observer_bridge_unittest.mm b/components/signin/public/identity_manager/objc/identity_manager_observer_bridge_unittest.mm new file mode 100644 index 0000000..13b4e20 --- /dev/null +++ b/components/signin/public/identity_manager/objc/identity_manager_observer_bridge_unittest.mm
@@ -0,0 +1,200 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "components/signin/public/identity_manager/objc/identity_manager_observer_bridge.h" + +#import "base/test/task_environment.h" +#import "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h" +#import "components/signin/public/identity_manager/identity_test_environment.h" +#import "components/signin/public/identity_manager/primary_account_change_event.h" +#import "services/network/test/test_url_loader_factory.h" +#import "testing/gtest/include/gtest/gtest.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface ObserverBridgeDelegateFake + : NSObject <IdentityManagerObserverBridgeDelegate> + +@property(nonatomic, assign) NSInteger onPrimaryAccountSetCount; +@property(nonatomic, assign) NSInteger onPrimaryAccountClearedCount; +@property(nonatomic, assign) NSInteger onRefreshTokenUpdatedForAccountCount; +@property(nonatomic, assign) NSInteger onRefreshTokenRemovedForAccountCount; +@property(nonatomic, assign) NSInteger onRefreshTokensLoadedCount; +@property(nonatomic, assign) NSInteger onAccountsInCookieUpdatedCount; +@property(nonatomic, assign) + NSInteger onEndBatchOfRefreshTokenStateChangesCount; + +@property(nonatomic, assign) CoreAccountInfo receivedPrimaryAccountInfo; +@property(nonatomic, assign) CoreAccountId receivedAccountId; +@property(nonatomic, assign) + signin::AccountsInCookieJarInfo receivedccountsInCookieJarInfo; +@property(nonatomic, assign) GoogleServiceAuthError receivedError; + +@end + +@implementation ObserverBridgeDelegateFake + +- (void)onPrimaryAccountSet:(const CoreAccountInfo&)primaryAccountInfo { + ++self.onPrimaryAccountSetCount; + self.receivedPrimaryAccountInfo = primaryAccountInfo; +} + +- (void)onPrimaryAccountCleared: + (const CoreAccountInfo&)previousPrimaryAccountInfo { + ++self.onPrimaryAccountClearedCount; + self.receivedPrimaryAccountInfo = previousPrimaryAccountInfo; +} + +- (void)onRefreshTokenUpdatedForAccount:(const CoreAccountInfo&)accountInfo { + ++self.onRefreshTokenUpdatedForAccountCount; + self.receivedPrimaryAccountInfo = accountInfo; +} + +- (void)onRefreshTokenRemovedForAccount:(const CoreAccountId&)accountId { + ++self.onRefreshTokenRemovedForAccountCount; + self.receivedAccountId = accountId; +} + +- (void)onRefreshTokensLoaded { + ++self.onRefreshTokensLoadedCount; +} + +- (void)onAccountsInCookieUpdated: + (const signin::AccountsInCookieJarInfo&)accountsInCookieJarInfo + error:(const GoogleServiceAuthError&)error { + ++self.onAccountsInCookieUpdatedCount; + self.receivedccountsInCookieJarInfo = accountsInCookieJarInfo; + self.receivedError = error; +} + +- (void)onEndBatchOfRefreshTokenStateChanges { + ++self.onEndBatchOfRefreshTokenStateChangesCount; +} + +@end + +namespace signin { + +class IdentityManagerObserverBridgeTest : public testing::Test { + protected: + IdentityManagerObserverBridgeTest() + : identity_test_env_(&test_url_loader_factory_) { + observer_bridge_delegate_ = [[ObserverBridgeDelegateFake alloc] init]; + signin::IdentityManager* identity_manager = + identity_test_env_.identity_manager(); + observer_bridge_ = std::make_unique<signin::IdentityManagerObserverBridge>( + identity_manager, observer_bridge_delegate_); + account_id_ = CoreAccountId("accountid"); + account_info_.account_id = account_id_; + account_info_.gaia = "joegaia"; + account_info_.email = "joe@example.com"; + + const std::string gaia_id = signin::GetTestGaiaIdForEmail("1@mail.com"); + gaia::ListedAccount one; + one.id = CoreAccountId(gaia_id); + just_one_.push_back(one); + } + ~IdentityManagerObserverBridgeTest() override {} + + public: + IdentityManagerObserverBridgeTest(const IdentityManagerObserverBridgeTest&) = + delete; + IdentityManagerObserverBridgeTest& operator=( + const IdentityManagerObserverBridgeTest&) = delete; + + protected: + base::test::TaskEnvironment task_environment_; + network::TestURLLoaderFactory test_url_loader_factory_; + signin::IdentityTestEnvironment identity_test_env_; + std::unique_ptr<signin::IdentityManagerObserverBridge> observer_bridge_; + ObserverBridgeDelegateFake* observer_bridge_delegate_; + CoreAccountId account_id_; + CoreAccountInfo account_info_; + const std::vector<gaia::ListedAccount> no_account_; + std::vector<gaia::ListedAccount> just_one_; +}; + +// Tests IdentityManagerObserverBridge::OnPrimaryAccountChanged(), with set +// event. +TEST_F(IdentityManagerObserverBridgeTest, TestOnPrimaryAccountSet) { + PrimaryAccountChangeEvent::State previous_state; + PrimaryAccountChangeEvent::State current_state(account_info_, + signin::ConsentLevel::kSync); + PrimaryAccountChangeEvent event_details(previous_state, current_state); + observer_bridge_.get()->OnPrimaryAccountChanged(event_details); + EXPECT_EQ(1, observer_bridge_delegate_.onPrimaryAccountSetCount); + EXPECT_EQ(account_info_, + observer_bridge_delegate_.receivedPrimaryAccountInfo); +} + +// Tests IdentityManagerObserverBridge::OnPrimaryAccountChanged(), with clear +// event. +TEST_F(IdentityManagerObserverBridgeTest, TestOnPrimaryAccountCleared) { + PrimaryAccountChangeEvent::State previous_state(account_info_, + signin::ConsentLevel::kSync); + PrimaryAccountChangeEvent::State current_state; + PrimaryAccountChangeEvent event_details(previous_state, current_state); + observer_bridge_.get()->OnPrimaryAccountChanged(event_details); + EXPECT_EQ(1, observer_bridge_delegate_.onPrimaryAccountClearedCount); + EXPECT_EQ(account_info_, + observer_bridge_delegate_.receivedPrimaryAccountInfo); +} + +// Tests IdentityManagerObserverBridge::OnRefreshTokenUpdatedForAccount() +TEST_F(IdentityManagerObserverBridgeTest, TestOnRefreshTokenUpdatedForAccount) { + observer_bridge_.get()->OnRefreshTokenUpdatedForAccount(account_info_); + EXPECT_EQ(1, observer_bridge_delegate_.onRefreshTokenUpdatedForAccountCount); + EXPECT_EQ(account_info_, + observer_bridge_delegate_.receivedPrimaryAccountInfo); +} + +// Tests IdentityManagerObserverBridge::OnRefreshTokenRemovedForAccount() +TEST_F(IdentityManagerObserverBridgeTest, OnRefreshTokenRemovedForAccount) { + CoreAccountId account_id; + observer_bridge_.get()->OnRefreshTokenRemovedForAccount(account_id); + EXPECT_EQ(1, observer_bridge_delegate_.onRefreshTokenRemovedForAccountCount); +} + +// Tests IdentityManagerObserverBridge::OnRefreshTokensLoaded() +TEST_F(IdentityManagerObserverBridgeTest, OnRefreshTokensLoaded) { + observer_bridge_.get()->OnRefreshTokensLoaded(); + EXPECT_EQ(1, observer_bridge_delegate_.onRefreshTokensLoadedCount); +} + +// Tests IdentityManagerObserverBridge::OnAccountsInCookieUpdated() with no +// error. +TEST_F(IdentityManagerObserverBridgeTest, + OnAccountsInCookieUpdatedWithNoError) { + signin::AccountsInCookieJarInfo accounts_in_cookie_jar_info = { + true, just_one_, no_account_}; + GoogleServiceAuthError noError(GoogleServiceAuthError::State::NONE); + observer_bridge_.get()->OnAccountsInCookieUpdated(accounts_in_cookie_jar_info, + noError); + EXPECT_EQ(1, observer_bridge_delegate_.onAccountsInCookieUpdatedCount); + EXPECT_EQ(noError, observer_bridge_delegate_.receivedError); +} + +// Tests IdentityManagerObserverBridge::OnAccountsInCookieUpdated() with error. +TEST_F(IdentityManagerObserverBridgeTest, OnAccountsInCookieUpdatedWithError) { + signin::AccountsInCookieJarInfo accounts_in_cookie_jar_info = { + false, no_account_, just_one_}; + GoogleServiceAuthError error( + GoogleServiceAuthError::State::CONNECTION_FAILED); + observer_bridge_.get()->OnAccountsInCookieUpdated(accounts_in_cookie_jar_info, + error); + EXPECT_EQ(1, observer_bridge_delegate_.onAccountsInCookieUpdatedCount); + EXPECT_EQ(error, observer_bridge_delegate_.receivedError); +} + +// Tests IdentityManagerObserverBridge::OnEndBatchOfRefreshTokenStateChanges(). +TEST_F(IdentityManagerObserverBridgeTest, + OnEndBatchOfRefreshTokenStateChanges) { + observer_bridge_.get()->OnEndBatchOfRefreshTokenStateChanges(); + EXPECT_EQ( + 1, observer_bridge_delegate_.onEndBatchOfRefreshTokenStateChangesCount); +} + +}
diff --git a/components/spellcheck/browser/spellcheck_host_metrics.cc b/components/spellcheck/browser/spellcheck_host_metrics.cc index 4e658ee..c9bee576 100644 --- a/components/spellcheck/browser/spellcheck_host_metrics.cc +++ b/components/spellcheck/browser/spellcheck_host_metrics.cc
@@ -60,9 +60,6 @@ RecordReplacedWordStats(0); } - int percentage = (100 * misspelled_word_count_) / spellchecked_word_count_; - UMA_HISTOGRAM_PERCENTAGE("SpellCheck.MisspellRatio", percentage); - // Collects actual number of checked words, excluding duplication. base::MD5Digest digest; base::MD5Sum(reinterpret_cast<const unsigned char*>(word.c_str()), @@ -101,14 +98,6 @@ void SpellCheckHostMetrics::RecordReplacedWordStats(int delta) { replaced_word_count_ += delta; - if (misspelled_word_count_) { - // zero |misspelled_word_count_| is possible when an extension - // gives the misspelling, which is not recorded as a part of this - // metrics. - int percentage = (100 * replaced_word_count_) / misspelled_word_count_; - UMA_HISTOGRAM_PERCENTAGE("SpellCheck.ReplaceRatio", percentage); - } - if (suggestion_show_count_) { int percentage = (100 * replaced_word_count_) / suggestion_show_count_; UMA_HISTOGRAM_PERCENTAGE("SpellCheck.SuggestionHitRatio", percentage);
diff --git a/components/sync/engine_impl/commit_contribution_impl.cc b/components/sync/engine_impl/commit_contribution_impl.cc index 67ebb67..b73c9b2 100644 --- a/components/sync/engine_impl/commit_contribution_impl.cc +++ b/components/sync/engine_impl/commit_contribution_impl.cc
@@ -197,7 +197,12 @@ commit_proto->set_id_string(entity_data.id); // Populate client_defined_unique_tag only for non-bookmark and non-Nigori // data types. - if (type != BOOKMARKS && type != NIGORI) { + if (type == NIGORI) { + // Client tags are irrelevant for NIGORI (it uses the root node). + } else if (type != BOOKMARKS || + !entity_data.client_tag_hash.value().empty()) { + // The client tag is mandatory for all datatypes except bookmarks, and + // experimental for bookmarks (behind feature toggle). commit_proto->set_client_defined_unique_tag( entity_data.client_tag_hash.value()); }
diff --git a/components/sync/protocol/bookmark_model_metadata.proto b/components/sync/protocol/bookmark_model_metadata.proto index d07ee5c..6b52c8ea 100644 --- a/components/sync/protocol/bookmark_model_metadata.proto +++ b/components/sync/protocol/bookmark_model_metadata.proto
@@ -46,4 +46,12 @@ // is required to populate the client tag (and be considered invalid // otherwise). optional int64 last_sync_time = 4; + + // Represents whether bookmark commits sent to the server (most importantly + // creations) populate client tags. This is a layer on top of the usual + // FeatureList to avoid risky transitions during startup, to guard against + // in-flight commits. + // TODO(crbug.com/1032052): remove this code when the logic is enabled by + // default and enforced to true upon startup. + optional bool bookmark_client_tags_in_protocol_enabled = 5; }
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_client.cc b/components/sync/trusted_vault/standalone_trusted_vault_client.cc index 98a8eda..4b78da2 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_client.cc +++ b/components/sync/trusted_vault/standalone_trusted_vault_client.cc
@@ -147,7 +147,8 @@ std::unique_ptr<TrustedVaultConnection> connection; GURL trusted_vault_service_gurl = ExtractTrustedVaultServiceURLFromCommandLine(); - if (trusted_vault_service_gurl.is_valid()) { + if (base::FeatureList::IsEnabled(switches::kFollowTrustedVaultKeyRotation) && + trusted_vault_service_gurl.is_valid()) { connection = std::make_unique<TrustedVaultConnectionImpl>( trusted_vault_service_gurl, url_loader_factory->Clone(), std::make_unique<TrustedVaultAccessTokenFetcherImpl>(
diff --git a/components/sync_bookmarks/bookmark_local_changes_builder.cc b/components/sync_bookmarks/bookmark_local_changes_builder.cc index 849ae46..6c5b57b 100644 --- a/components/sync_bookmarks/bookmark_local_changes_builder.cc +++ b/components/sync_bookmarks/bookmark_local_changes_builder.cc
@@ -47,6 +47,19 @@ data->creation_time = syncer::ProtoTimeToTime(metadata->creation_time()); data->modification_time = syncer::ProtoTimeToTime(metadata->modification_time()); + + if (entity->has_final_guid() && + bookmark_tracker_->bookmark_client_tags_in_protocol_enabled()) { + DCHECK(!metadata->client_tag_hash().empty()); + data->client_tag_hash = + syncer::ClientTagHash::FromHashed(metadata->client_tag_hash()); + DCHECK(metadata->is_deleted() || + data->client_tag_hash == + syncer::ClientTagHash::FromUnhashed( + syncer::BOOKMARKS, + entity->bookmark_node()->guid().AsLowercaseString())); + } + if (!metadata->is_deleted()) { const bookmarks::BookmarkNode* node = entity->bookmark_node(); // Skip current entity if its favicon is not loaded yet. It will be
diff --git a/components/sync_bookmarks/bookmark_model_merger.cc b/components/sync_bookmarks/bookmark_model_merger.cc index b5b5719..a13f8307 100644 --- a/components/sync_bookmarks/bookmark_model_merger.cc +++ b/components/sync_bookmarks/bookmark_model_merger.cc
@@ -331,6 +331,7 @@ return false; } if (!HasExpectedBookmarkGuid(update_entity.specifics.bookmark(), + update_entity.client_tag_hash, update_entity.originator_cache_guid, update_entity.originator_client_item_id)) { // Ignore updates with an unexpected GUID.
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/components/sync_bookmarks/bookmark_remote_updates_handler.cc index 55a0c90..d5ee58f4 100644 --- a/components/sync_bookmarks/bookmark_remote_updates_handler.cc +++ b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -240,6 +240,7 @@ continue; } if (!HasExpectedBookmarkGuid(update_entity.specifics.bookmark(), + update_entity.client_tag_hash, update_entity.originator_cache_guid, update_entity.originator_client_item_id)) { // Ignore updates with an unexpected GUID. @@ -292,13 +293,25 @@ // assume that it was never committed. The server will track the client that // sent up the original commit and return this in a get updates response. We // need to check if we have an entry that didn't get its server id updated - // correctly. The server sends down a |originator_cache_guid| and an - // |original_client_item_id|. If we have a entry by that description, we - // should update the |sync_id| in |bookmark_tracker_|. The rest of code will - // handle this a conflict and adjust the model if needed. + // correctly. The server sends down |original_client_item_id| (regular case) + // or |client_provided_unique_tag| (experimental). If the tracker contains + // a matching entry, it should be treated as update. const SyncedBookmarkTracker::Entity* old_tracked_entity = bookmark_tracker_->GetEntityForSyncId( update_entity.originator_client_item_id); + if (!old_tracked_entity && !update_entity.client_tag_hash.value().empty()) { + // There's currently no way to perform a lookup by client tag hash. As an + // approximation, the bookmark node's GUID can be used, which is the same + // as the temporary sync ID assigned upon local creation (just like + // originator client ID). This doesn't work for remote deletions, which + // don't include a GUID in specifics, but the existing UMA data for + // DuplicateBookmarkEntityOnRemoteUpdateCondition::kServerIdTombstone + // indicates that users don't in practice run into this. + // TODO(crbug.com/1143246): Adopt proper lookups by client tag hash once + // the tracker supports this. + old_tracked_entity = bookmark_tracker_->GetEntityForSyncId( + remote_guid.AsLowercaseString()); + } if (old_tracked_entity) { if (tracked_entity) { DCHECK_NE(tracked_entity, old_tracked_entity);
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc index c02f124..a8932be 100644 --- a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc +++ b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -1004,6 +1004,8 @@ bookmark_specifics->set_legacy_canonicalized_title(kTitle); bookmark_specifics->set_url(kUrl.spec()); data.is_folder = false; + data.originator_client_item_id = bookmark_specifics->guid(); + syncer::UpdateResponseData response_data; response_data.entity = std::move(data); // Similar to what's done in the loopback_server. @@ -1055,6 +1057,8 @@ bookmark_specifics->set_icon_url(kIconUrl.spec()); bookmark_specifics->set_favicon("PNG"); data.is_folder = false; + data.originator_client_item_id = bookmark_specifics->guid(); + syncer::UpdateResponseData response_data; response_data.entity = std::move(data); // Similar to what's done in the loopback_server. @@ -1093,6 +1097,8 @@ bookmark_specifics->set_legacy_canonicalized_title(kTitle); bookmark_specifics->set_url(kUrl.spec()); data.is_folder = false; + data.originator_client_item_id = bookmark_specifics->guid(); + syncer::UpdateResponseData response_data; response_data.entity = std::move(data); // Similar to what's done in the loopback_server. @@ -1111,7 +1117,7 @@ // server but the commit respone isn't received for some reason. Further updates // to that entity should update the sync id in the tracker. TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest, - ShouldUpdateSyncIdWhenRecevingAnUpdateForNewlyCreatedLocalNode) { + ShouldUpdateSyncIdWhenRecevingUpdateForNewlyCreatedLocalNode) { const std::string kCacheGuid = "generated_id"; const std::string kOriginatorClientItemId = base::GUID::GenerateRandomV4().AsLowercaseString(); @@ -1121,7 +1127,6 @@ base::TimeDelta::FromSeconds(1)); sync_pb::ModelTypeState model_type_state; - model_type_state.set_cache_guid(kCacheGuid); model_type_state.set_initial_sync_done(true); const sync_pb::UniquePosition unique_position; @@ -1147,7 +1152,6 @@ syncer::UpdateResponseDataList updates; syncer::EntityData data; data.id = kSyncId; - data.originator_cache_guid = kCacheGuid; data.originator_client_item_id = kOriginatorClientItemId; // Set the other required fields. data.unique_position = syncer::UniquePosition::InitialPosition( @@ -1173,6 +1177,71 @@ EXPECT_THAT(entity->bookmark_node(), Eq(&node)); } +// Same as above for bookmarks created with client tags. +TEST_F( + BookmarkRemoteUpdatesHandlerWithInitialMergeTest, + ShouldUpdateSyncIdWhenRecevingUpdateForNewlyCreatedLocalNodeWithClientTag) { + base::test::ScopedFeatureList override_features; + override_features.InitAndEnableFeature( + switches::kSyncUseClientTagForBookmarkCommits); + + const std::string kBookmarkGuid = + base::GUID::GenerateRandomV4().AsLowercaseString(); + const std::string kSyncId = "server_id"; + const int64_t kServerVersion = 1000; + const base::Time kModificationTime(base::Time::Now() - + base::TimeDelta::FromSeconds(1)); + + sync_pb::ModelTypeState model_type_state; + model_type_state.set_initial_sync_done(true); + + const sync_pb::UniquePosition unique_position; + sync_pb::EntitySpecifics specifics; + sync_pb::BookmarkSpecifics* bookmark_specifics = specifics.mutable_bookmark(); + bookmark_specifics->set_guid(kBookmarkGuid); + bookmark_specifics->set_legacy_canonicalized_title("Title"); + bookmarks::BookmarkNode node( + /*id=*/1, base::GUID::ParseLowercase(kBookmarkGuid), GURL()); + // Track a sync entity (similar to what happens after a local creation). The + // |originator_client_item_id| is used a temp sync id and mark the entity that + // it needs to be committed.. + const SyncedBookmarkTracker::Entity* entity = + tracker()->Add(&node, /*sync_id=*/kBookmarkGuid, kServerVersion, + kModificationTime, unique_position, specifics); + tracker()->IncrementSequenceNumber(entity); + + ASSERT_THAT(tracker()->GetEntityForSyncId(kBookmarkGuid), Eq(entity)); + + // Now receive an update with the actual server id. + syncer::UpdateResponseDataList updates; + syncer::EntityData data; + data.id = kSyncId; + data.client_tag_hash = + syncer::ClientTagHash::FromUnhashed(syncer::BOOKMARKS, kBookmarkGuid); + // Set the other required fields. + data.unique_position = syncer::UniquePosition::InitialPosition( + syncer::UniquePosition::RandomSuffix()) + .ToProto(); + data.specifics = specifics; + data.specifics.mutable_bookmark()->set_guid(kBookmarkGuid); + data.is_folder = true; + + syncer::UpdateResponseData response_data; + response_data.entity = std::move(data); + // Similar to what's done in the loopback_server. + response_data.response_version = 0; + updates.push_back(std::move(response_data)); + + updates_handler()->Process(updates, + /*got_new_encryption_requirements=*/false); + + // The sync id in the tracker should have been updated. + EXPECT_THAT(tracker()->GetEntityForSyncId(kBookmarkGuid), IsNull()); + EXPECT_THAT(tracker()->GetEntityForSyncId(kSyncId), Eq(entity)); + EXPECT_THAT(entity->metadata()->server_id(), Eq(kSyncId)); + EXPECT_THAT(entity->bookmark_node(), Eq(&node)); +} + TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest, ShouldRecommitWhenEncryptionIsOutOfDate) { sync_pb::ModelTypeState model_type_state;
diff --git a/components/sync_bookmarks/bookmark_specifics_conversions.cc b/components/sync_bookmarks/bookmark_specifics_conversions.cc index 1857e0c..17b96c1 100644 --- a/components/sync_bookmarks/bookmark_specifics_conversions.cc +++ b/components/sync_bookmarks/bookmark_specifics_conversions.cc
@@ -394,14 +394,14 @@ } bool HasExpectedBookmarkGuid(const sync_pb::BookmarkSpecifics& specifics, + const syncer::ClientTagHash& client_tag_hash, const std::string& originator_cache_guid, const std::string& originator_client_item_id) { DCHECK(base::GUID::ParseLowercase(specifics.guid()).is_valid()); - if (originator_client_item_id.empty()) { - // This could be a future bookmark with a client tag instead of an - // originator client item ID. - NOTIMPLEMENTED(); + // If the client tag hash matches, that should already be good enough. + if (syncer::ClientTagHash::FromUnhashed( + syncer::BOOKMARKS, specifics.guid()) == client_tag_hash) { return true; }
diff --git a/components/sync_bookmarks/bookmark_specifics_conversions.h b/components/sync_bookmarks/bookmark_specifics_conversions.h index 18ac8ef..c5a3d49 100644 --- a/components/sync_bookmarks/bookmark_specifics_conversions.h +++ b/components/sync_bookmarks/bookmark_specifics_conversions.h
@@ -24,6 +24,7 @@ } // namespace sync_pb namespace syncer { +class ClientTagHash; struct EntityData; } // namespace syncer @@ -89,9 +90,8 @@ // Checks if bookmark specifics contain a GUID that matches the value that would // be inferred from other redundant fields. |specifics| must be valid as per // IsValidBookmarkSpecifics(). -// TODO(crbug.com/1032052): Replace this with an analogous function that -// verifies that the bookmark's client tag hash matches the GUID. bool HasExpectedBookmarkGuid(const sync_pb::BookmarkSpecifics& specifics, + const syncer::ClientTagHash& client_tag_hash, const std::string& originator_cache_guid, const std::string& originator_client_item_id);
diff --git a/components/sync_bookmarks/switches.cc b/components/sync_bookmarks/switches.cc index 16812cc..8fb804f 100644 --- a/components/sync_bookmarks/switches.cc +++ b/components/sync_bookmarks/switches.cc
@@ -19,4 +19,7 @@ const base::Feature kSyncIgnoreChangesInTouchIcons{ "SyncIgnoreChangesInTouchIcons", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kSyncUseClientTagForBookmarkCommits{ + "SyncUseClientTagForBookmarkCommits", base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace switches
diff --git a/components/sync_bookmarks/switches.h b/components/sync_bookmarks/switches.h index 2f6b220c..37b0de4 100644 --- a/components/sync_bookmarks/switches.h +++ b/components/sync_bookmarks/switches.h
@@ -17,6 +17,7 @@ extern const base::Feature kSyncDeduplicateAllBookmarksWithSameGUID; // TODO(crbug.com/1075709): remove after launch. extern const base::Feature kSyncIgnoreChangesInTouchIcons; +extern const base::Feature kSyncUseClientTagForBookmarkCommits; } // namespace switches
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.cc b/components/sync_bookmarks/synced_bookmark_tracker.cc index 04d12fd..ec5aa83 100644 --- a/components/sync_bookmarks/synced_bookmark_tracker.cc +++ b/components/sync_bookmarks/synced_bookmark_tracker.cc
@@ -222,6 +222,9 @@ auto tracker = base::WrapUnique(new SyncedBookmarkTracker( std::move(model_type_state), /*bookmarks_full_title_reuploaded=*/false, /*last_sync_time=*/base::Time::Now())); + tracker->bookmark_client_tags_in_protocol_enabled_ = + base::FeatureList::IsEnabled( + switches::kSyncUseClientTagForBookmarkCommits); return tracker; } @@ -236,23 +239,43 @@ return nullptr; } - auto tracker = - CreateEmpty(std::move(*model_metadata.mutable_model_type_state())); - // When the reupload feature is enabled and disabled again, there may occur // new entities which weren't reuploaded. const bool bookmarks_full_title_reuploaded = model_metadata.bookmarks_full_title_reuploaded() && base::FeatureList::IsEnabled(switches::kSyncReuploadBookmarkFullTitles); - if (bookmarks_full_title_reuploaded) { - tracker->SetBookmarksFullTitleReuploaded(); - } // If the field is not present, |last_sync_time| will be initialized with the // Unix epoch. - tracker->last_sync_time_ = + const base::Time last_sync_time = syncer::ProtoTimeToTime(model_metadata.last_sync_time()); + // base::WrapUnique() used because the constructor is private. + auto tracker = base::WrapUnique(new SyncedBookmarkTracker( + model_metadata.model_type_state(), bookmarks_full_title_reuploaded, + last_sync_time)); + + // Read |bookmark_client_tags_in_protocol_enabled_| while honoring the + // corresponding feature toggle too. + if (model_metadata.bookmark_client_tags_in_protocol_enabled()) { + // If the feature used to be enabled, it can continue to do so as long as + // the feature toggle is still enabled. If it becomes disabled, the boolean + // transitions to false immediately (independently of in-flight local + // changes) to guarantee that there is an effective kill switch. + tracker->bookmark_client_tags_in_protocol_enabled_ = + base::FeatureList::IsEnabled( + switches::kSyncUseClientTagForBookmarkCommits); + } else { + // If the feature used to be disabled, transitioning to true requires *NOT* + // having pending local changes (in-flight creations, strictly speaking, but + // that's too complex to implement), to avoid creating duplicates on the + // server (the same bookmark with and without a client tag). + tracker->bookmark_client_tags_in_protocol_enabled_ = + !tracker->HasLocalChanges() && + base::FeatureList::IsEnabled( + switches::kSyncUseClientTagForBookmarkCommits); + } + const CorruptionReason corruption_reason = tracker->InitEntitiesFromModelAndMetadata(model, std::move(model_metadata)); @@ -447,6 +470,9 @@ model_metadata.set_bookmarks_full_title_reuploaded( bookmarks_full_title_reuploaded_); model_metadata.set_last_sync_time(syncer::TimeToProtoTime(last_sync_time_)); + model_metadata.set_bookmark_client_tags_in_protocol_enabled( + bookmark_client_tags_in_protocol_enabled_); + for (const std::pair<const std::string, std::unique_ptr<Entity>>& pair : sync_id_to_entities_map_) { DCHECK(pair.second) << " for ID " << pair.first; @@ -758,6 +784,10 @@ return true; } +bool SyncedBookmarkTracker::bookmark_client_tags_in_protocol_enabled() const { + return bookmark_client_tags_in_protocol_enabled_; +} + void SyncedBookmarkTracker::TraverseAndAppend( const bookmarks::BookmarkNode* node, std::vector<const SyncedBookmarkTracker::Entity*>* ordered_entities) const {
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.h b/components/sync_bookmarks/synced_bookmark_tracker.h index 4217ec7..7310a303 100644 --- a/components/sync_bookmarks/synced_bookmark_tracker.h +++ b/components/sync_bookmarks/synced_bookmark_tracker.h
@@ -301,6 +301,10 @@ // reuploaded. bool ReuploadBookmarksOnLoadIfNeeded(); + // Returns whether bookmark commits sent to the server (most importantly + // creations) should populate client tags. + bool bookmark_client_tags_in_protocol_enabled() const; + private: // Enumeration of possible reasons why persisted metadata are considered // corrupted and don't match the bookmark model. Used in UMA metrics. Do not @@ -384,6 +388,12 @@ // required to populate the client tag (and be considered invalid otherwise). base::Time last_sync_time_; + // Represents whether bookmark commits sent to the server (most importantly + // creations) populate client tags. + // TODO(crbug.com/1032052): remove this code when the logic is enabled by + // default and enforced to true upon startup. + bool bookmark_client_tags_in_protocol_enabled_ = false; + DISALLOW_COPY_AND_ASSIGN(SyncedBookmarkTracker); };
diff --git a/components/viz/OWNERS b/components/viz/OWNERS index 13c6cfe..52f6f18db 100644 --- a/components/viz/OWNERS +++ b/components/viz/OWNERS
@@ -44,7 +44,7 @@ # overlays ccameron@chromium.org dcastagna@chromium.org -khushalsagar@chromium.org +vasilyt@chromium.org magchen@chromium.org # scheduling / begin frames
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index 3fb1c59..b594031 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -1980,7 +1980,7 @@ cocoa_role = NSAccessibilityGroupRole; } else if ((_owner->IsPlainTextField() && _owner->HasState(ax::mojom::State::kMultiline)) || - _owner->IsRichTextField()) { + (_owner->IsRichTextField() && !ui::IsComboBox(role))) { cocoa_role = NSAccessibilityTextAreaRole; } else if (role == ax::mojom::Role::kImage && _owner->HasExplicitlyEmptyName()) {
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 1a49164..6a90ae07 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -1802,6 +1802,10 @@ RunHtmlTest(FILE_PATH_LITERAL("img.html")); } +IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityImgBroken) { + RunHtmlTest(FILE_PATH_LITERAL("img-broken.html")); +} + IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityImgEmptyAlt) { RunHtmlTest(FILE_PATH_LITERAL("img-empty-alt.html")); } @@ -2098,6 +2102,11 @@ RunHtmlTest(FILE_PATH_LITERAL("list.html")); } +IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, + AccessibilityListTextRemoval) { + RunHtmlTest(FILE_PATH_LITERAL("list-text-removal.html")); +} + IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityListItemLevel) { RunHtmlTest(FILE_PATH_LITERAL("list-item-level.html")); }
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc index 0d0d4d2..115f5e7 100644 --- a/content/browser/back_forward_cache_browsertest.cc +++ b/content/browser/back_forward_cache_browsertest.cc
@@ -171,7 +171,6 @@ command_line->AppendSwitchASCII( switches::kAutoplayPolicy, switches::autoplay::kNoUserGestureRequiredPolicy); - command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures, "WakeLock"); ContentBrowserTest::SetUpCommandLine(command_line); }
diff --git a/content/browser/renderer_host/OWNERS b/content/browser/renderer_host/OWNERS index 7395c24..c232bf6 100644 --- a/content/browser/renderer_host/OWNERS +++ b/content/browser/renderer_host/OWNERS
@@ -22,7 +22,7 @@ per-file *mac*=ccameron@chromium.org # Android platform code. -per-file *android*=khushalsagar@chromium.org +per-file *android*=boliu@chromium.org # WebSQL. per-file web_database_*=jsbell@chromium.org
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc index 860eb907..21e9957 100644 --- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc +++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -3443,8 +3443,8 @@ EXPECT_EQ(url2b, other_controller.GetPendingEntry()->GetURL()); // Let the pending entry commit. - other_contents->TestDidNavigate(other_contents->GetMainFrame(), false, url2b, - ui::PAGE_TRANSITION_LINK); + other_contents->GetMainFrame()->SendNavigateWithTransition( + 0, false, url2b, ui::PAGE_TRANSITION_LINK); } // Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
diff --git a/content/browser/renderer_host/pepper/pepper_renderer_connection.cc b/content/browser/renderer_host/pepper/pepper_renderer_connection.cc index 75930be..7bba16a3 100644 --- a/content/browser/renderer_host/pepper/pepper_renderer_connection.cc +++ b/content/browser/renderer_host/pepper/pepper_renderer_connection.cc
@@ -11,15 +11,20 @@ #include "base/bind.h" #include "base/memory/ref_counted.h" #include "base/stl_util.h" +#include "content/browser/bad_message.h" #include "content/browser/browser_child_process_host_impl.h" +#include "content/browser/child_process_security_policy_impl.h" +#include "content/browser/plugin_service_impl.h" #include "content/browser/ppapi_plugin_process_host.h" #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h" #include "content/browser/renderer_host/pepper/pepper_file_ref_host.h" #include "content/browser/renderer_host/pepper/pepper_file_system_browser_host.h" #include "content/common/frame_messages.h" #include "content/common/pepper_renderer_instance_data.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" +#include "content/public/browser/storage_partition.h" #include "content/public/common/content_client.h" #include "ipc/ipc_message_macros.h" #include "ppapi/host/resource_host.h" @@ -94,11 +99,49 @@ } // namespace -PepperRendererConnection::PepperRendererConnection(int render_process_id) +class PepperRendererConnection::OpenChannelToPpapiPluginCallback + : public PpapiPluginProcessHost::PluginClient { + public: + OpenChannelToPpapiPluginCallback(PepperRendererConnection* filter, + OpenChannelToPepperPluginCallback callback) + : callback_(std::move(callback)), filter_(filter) {} + + void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle, + int* renderer_id) override { + // base::kNullProcessHandle indicates that the channel will be used by the + // browser itself. Make sure we never output that value here. + CHECK_NE(base::kNullProcessHandle, filter_->PeerHandle()); + *renderer_handle = filter_->PeerHandle(); + *renderer_id = filter_->render_process_id_; + } + + void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle, + base::ProcessId plugin_pid, + int plugin_child_id) override { + std::move(callback_).Run(mojo::MakeScopedHandle(channel_handle.mojo_handle), + plugin_pid, plugin_child_id); + delete this; + } + + bool Incognito() override { return filter_->incognito_; } + + private: + OpenChannelToPepperPluginCallback callback_; + scoped_refptr<PepperRendererConnection> filter_; +}; + +PepperRendererConnection::PepperRendererConnection( + int render_process_id, + PluginServiceImpl* plugin_service, + BrowserContext* browser_context, + StoragePartition* storage_partition) : BrowserMessageFilter(kPepperFilteredMessageClasses, base::size(kPepperFilteredMessageClasses)), BrowserAssociatedInterface<mojom::PepperIOHost>(this), - render_process_id_(render_process_id) { + render_process_id_(render_process_id), + incognito_(browser_context->IsOffTheRecord()), + plugin_service_(plugin_service), + profile_data_directory_(storage_partition->GetPath()) { // Only give the renderer permission for stable APIs. in_process_host_.reset(new BrowserPpapiHostImpl(this, ppapi::PpapiPermissions(), @@ -245,4 +288,73 @@ in_process_host_->DeleteInstance(instance); } +void PepperRendererConnection::DidCreateOutOfProcessPepperInstance( + int32_t plugin_child_id, + int32_t pp_instance, + bool is_external, + int32_t render_frame_id, + const GURL& document_url, + const GURL& plugin_url, + bool is_privileged_context, + DidCreateOutOfProcessPepperInstanceCallback callback) { + // It's important that we supply the render process ID ourselves based on the + // channel the message arrived on. We use the + // PP_Instance -> (process id, frame id) + // mapping to decide how to handle messages received from the (untrusted) + // plugin. An exploited renderer must not be able to insert fake mappings + // that may allow it access to other render processes. + PepperRendererInstanceData instance_data{render_process_id_, render_frame_id, + document_url, plugin_url, + is_privileged_context}; + if (is_external) { + // We provide the BrowserPpapiHost to the embedder, so it's safe to cast. + BrowserPpapiHostImpl* host = static_cast<BrowserPpapiHostImpl*>( + GetContentClient()->browser()->GetExternalBrowserPpapiHost( + plugin_child_id)); + if (host) + host->AddInstance(pp_instance, instance_data); + } else { + PpapiPluginProcessHost::DidCreateOutOfProcessInstance( + plugin_child_id, pp_instance, instance_data); + } + std::move(callback).Run(); +} + +void PepperRendererConnection::DidDeleteOutOfProcessPepperInstance( + int32_t plugin_child_id, + int32_t pp_instance, + bool is_external) { + if (is_external) { + // We provide the BrowserPpapiHost to the embedder, so it's safe to cast. + BrowserPpapiHostImpl* host = static_cast<BrowserPpapiHostImpl*>( + GetContentClient()->browser()->GetExternalBrowserPpapiHost( + plugin_child_id)); + if (host) + host->DeleteInstance(pp_instance); + } else { + PpapiPluginProcessHost::DidDeleteOutOfProcessInstance(plugin_child_id, + pp_instance); + } +} + +void PepperRendererConnection::OpenChannelToPepperPlugin( + const url::Origin& embedder_origin, + const base::FilePath& path, + const base::Optional<url::Origin>& origin_lock, + OpenChannelToPepperPluginCallback callback) { + // Enforce that the sender of the IPC (i.e. |render_process_id_|) is actually + // able/allowed to host a frame with |embedder_origin|. + auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); + if (!policy->CanAccessDataForOrigin(render_process_id_, embedder_origin)) { + bad_message::ReceivedBadMessage( + this, bad_message::RFMF_INVALID_PLUGIN_EMBEDDER_ORIGIN); + return; + } + + plugin_service_->OpenChannelToPpapiPlugin( + render_process_id_, embedder_origin, path, profile_data_directory_, + origin_lock, + new OpenChannelToPpapiPluginCallback(this, std::move(callback))); +} + } // namespace content
diff --git a/content/browser/renderer_host/pepper/pepper_renderer_connection.h b/content/browser/renderer_host/pepper/pepper_renderer_connection.h index b066c6fc..bc5c986 100644 --- a/content/browser/renderer_host/pepper/pepper_renderer_connection.h +++ b/content/browser/renderer_host/pepper/pepper_renderer_connection.h
@@ -24,7 +24,10 @@ namespace content { +class BrowserContext; class BrowserPpapiHostImpl; +class PluginServiceImpl; +class StoragePartition; // This class represents a connection from the browser to the renderer for // sending/receiving pepper ResourceHost related messages. When the browser @@ -34,7 +37,10 @@ : public BrowserMessageFilter, public BrowserAssociatedInterface<mojom::PepperIOHost> { public: - explicit PepperRendererConnection(int render_process_id); + PepperRendererConnection(int render_process_id, + PluginServiceImpl* plugin_service, + BrowserContext* browser_context, + StoragePartition* storage_partition); // BrowserMessageFilter overrides. bool OnMessageReceived(const IPC::Message& msg) override; @@ -42,6 +48,7 @@ private: ~PepperRendererConnection() override; + class OpenChannelToPpapiPluginCallback; // Returns the host for the child process for the given |child_process_id|. // If |child_process_id| is 0, returns the host owned by this // PepperRendererConnection, which serves as the host for in-process plugins. @@ -60,8 +67,26 @@ const GURL& document_url, const GURL& plugin_url) override; void DidDeleteInProcessInstance(int32_t instance) override; + void DidCreateOutOfProcessPepperInstance( + int32_t plugin_child_id, + int32_t pp_instance, + bool is_external, + int32_t render_frame_id, + const GURL& document_url, + const GURL& plugin_url, + bool is_priviledged_context, + DidCreateOutOfProcessPepperInstanceCallback callback) override; + void DidDeleteOutOfProcessPepperInstance(int32_t plugin_child_id, + int32_t pp_instance, + bool is_external) override; + void OpenChannelToPepperPlugin( + const url::Origin& embedder_origin, + const base::FilePath& path, + const base::Optional<url::Origin>& origin_lock, + OpenChannelToPepperPluginCallback callback) override; - int render_process_id_; + const int render_process_id_; + const bool incognito_; // We have a single BrowserPpapiHost per-renderer for all in-process plugins // running. This is just a work-around allowing new style resources to work @@ -69,6 +94,9 @@ // information (like the plugin name) won't be available. std::unique_ptr<BrowserPpapiHostImpl> in_process_host_; + PluginServiceImpl* const plugin_service_; + const base::FilePath profile_data_directory_; + DISALLOW_COPY_AND_ASSIGN(PepperRendererConnection); };
diff --git a/content/browser/renderer_host/render_frame_message_filter.cc b/content/browser/renderer_host/render_frame_message_filter.cc index 9cc3d07..17247f44 100644 --- a/content/browser/renderer_host/render_frame_message_filter.cc +++ b/content/browser/renderer_host/render_frame_message_filter.cc
@@ -70,34 +70,6 @@ } // namespace -class RenderFrameMessageFilter::OpenChannelToPpapiPluginCallback - : public RenderMessageCompletionCallback, - public PpapiPluginProcessHost::PluginClient { - public: - OpenChannelToPpapiPluginCallback(RenderFrameMessageFilter* filter, - IPC::Message* reply_msg) - : RenderMessageCompletionCallback(filter, reply_msg) {} - - void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle, - int* renderer_id) override { - // base::kNullProcessHandle indicates that the channel will be used by the - // browser itself. Make sure we never output that value here. - CHECK_NE(base::kNullProcessHandle, filter()->PeerHandle()); - *renderer_handle = filter()->PeerHandle(); - *renderer_id = filter()->render_process_id_; - } - - void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle, - base::ProcessId plugin_pid, - int plugin_child_id) override { - FrameHostMsg_OpenChannelToPepperPlugin::WriteReplyParams( - reply_msg(), channel_handle, plugin_pid, plugin_child_id); - SendReplyAndDeleteThis(); - } - - bool Incognito() override { return filter()->incognito_; } -}; - RenderFrameMessageFilter::RenderFrameMessageFilter( int render_process_id, PluginServiceImpl* plugin_service, @@ -105,8 +77,6 @@ StoragePartition* storage_partition) : BrowserMessageFilter(FrameMsgStart), plugin_service_(plugin_service), - profile_data_directory_(storage_partition->GetPath()), - incognito_(browser_context->IsOffTheRecord()), render_process_id_(render_process_id) {} RenderFrameMessageFilter::~RenderFrameMessageFilter() { @@ -118,12 +88,6 @@ bool handled = true; IPC_BEGIN_MESSAGE_MAP(RenderFrameMessageFilter, message) IPC_MESSAGE_HANDLER(FrameHostMsg_GetPluginInfo, OnGetPluginInfo) - IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_OpenChannelToPepperPlugin, - OnOpenChannelToPepperPlugin) - IPC_MESSAGE_HANDLER(FrameHostMsg_DidCreateOutOfProcessPepperInstance, - OnDidCreateOutOfProcessPepperInstance) - IPC_MESSAGE_HANDLER(FrameHostMsg_DidDeleteOutOfProcessPepperInstance, - OnDidDeleteOutOfProcessPepperInstance) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -155,67 +119,4 @@ allow_wildcard, nullptr, info, actual_mime_type); } -void RenderFrameMessageFilter::OnOpenChannelToPepperPlugin( - const url::Origin& embedder_origin, - const base::FilePath& path, - const base::Optional<url::Origin>& origin_lock, - IPC::Message* reply_msg) { - // Enforce that the sender of the IPC (i.e. |render_process_id_|) is actually - // able/allowed to host a frame with |embedder_origin|. - auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); - if (!policy->CanAccessDataForOrigin(render_process_id_, embedder_origin)) { - NOTREACHED() << embedder_origin; - bad_message::ReceivedBadMessage( - this, bad_message::RFMF_INVALID_PLUGIN_EMBEDDER_ORIGIN); - return; - } - - plugin_service_->OpenChannelToPpapiPlugin( - render_process_id_, embedder_origin, path, profile_data_directory_, - origin_lock, new OpenChannelToPpapiPluginCallback(this, reply_msg)); -} - -void RenderFrameMessageFilter::OnDidCreateOutOfProcessPepperInstance( - int plugin_child_id, - int32_t pp_instance, - PepperRendererInstanceData instance_data, - bool is_external) { - // It's important that we supply the render process ID ourselves based on the - // channel the message arrived on. We use the - // PP_Instance -> (process id, frame id) - // mapping to decide how to handle messages received from the (untrusted) - // plugin, so an exploited renderer must not be able to insert fake mappings - // that may allow it access to other render processes. - DCHECK_EQ(0, instance_data.render_process_id); - instance_data.render_process_id = render_process_id_; - if (is_external) { - // We provide the BrowserPpapiHost to the embedder, so it's safe to cast. - BrowserPpapiHostImpl* host = static_cast<BrowserPpapiHostImpl*>( - GetContentClient()->browser()->GetExternalBrowserPpapiHost( - plugin_child_id)); - if (host) - host->AddInstance(pp_instance, instance_data); - } else { - PpapiPluginProcessHost::DidCreateOutOfProcessInstance( - plugin_child_id, pp_instance, instance_data); - } -} - -void RenderFrameMessageFilter::OnDidDeleteOutOfProcessPepperInstance( - int plugin_child_id, - int32_t pp_instance, - bool is_external) { - if (is_external) { - // We provide the BrowserPpapiHost to the embedder, so it's safe to cast. - BrowserPpapiHostImpl* host = static_cast<BrowserPpapiHostImpl*>( - GetContentClient()->browser()->GetExternalBrowserPpapiHost( - plugin_child_id)); - if (host) - host->DeleteInstance(pp_instance); - } else { - PpapiPluginProcessHost::DidDeleteOutOfProcessInstance(plugin_child_id, - pp_instance); - } -} - } // namespace content
diff --git a/content/browser/renderer_host/render_frame_message_filter.h b/content/browser/renderer_host/render_frame_message_filter.h index 100c3936..74c9535 100644 --- a/content/browser/renderer_host/render_frame_message_filter.h +++ b/content/browser/renderer_host/render_frame_message_filter.h
@@ -60,8 +60,6 @@ friend class BrowserThread; friend class base::DeleteHelper<RenderFrameMessageFilter>; - class OpenChannelToPpapiPluginCallback; - ~RenderFrameMessageFilter() override; void OnGetPluginInfo(int render_frame_id, @@ -71,29 +69,8 @@ bool* found, WebPluginInfo* info, std::string* actual_mime_type); - void OnOpenChannelToPepperPlugin( - const url::Origin& embedder_origin, - const base::FilePath& path, - const base::Optional<url::Origin>& origin_lock, - IPC::Message* reply_msg); - void OnDidCreateOutOfProcessPepperInstance( - int plugin_child_id, - int32_t pp_instance, - PepperRendererInstanceData instance_data, - bool is_external); - void OnDidDeleteOutOfProcessPepperInstance(int plugin_child_id, - int32_t pp_instance, - bool is_external); - void OnOpenChannelToPpapiBroker(int routing_id, const base::FilePath& path); PluginServiceImpl* plugin_service_; - base::FilePath profile_data_directory_; - - // Initialized to 0, accessed on FILE thread only. - base::TimeTicks last_plugin_refresh_time_; - - // Whether this process is used for incognito contents. - const bool incognito_; const int render_process_id_; };
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc index 8863f4e..44a6012f 100644 --- a/content/browser/renderer_host/render_process_host_browsertest.cc +++ b/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -172,8 +172,7 @@ class RenderProcessHostTest : public ContentBrowserTest, public RenderProcessHostObserver { public: - RenderProcessHostTest() - : process_exits_(0), host_destructions_(0), use_frame_priority_(false) {} + RenderProcessHostTest() = default; void SetUp() override { if (use_frame_priority_) { @@ -201,11 +200,19 @@ RenderProcessHostImpl* impl = static_cast<RenderProcessHostImpl*>(process); impl->visible_clients_ = visible_clients; } + protected: - void set_process_exit_callback(base::OnceClosure callback) { + void SetProcessExitCallback(RenderProcessHost* rph, + base::OnceClosure callback) { + Observe(rph); process_exit_callback_ = std::move(callback); } + void Observe(RenderProcessHost* rph) { + DCHECK(!observation_.IsObserving()); + observation_.Observe(rph); + } + // RenderProcessHostObserver: void RenderProcessExited(RenderProcessHost* host, const ChildProcessTerminationInfo& info) override { @@ -215,16 +222,19 @@ } void RenderProcessHostDestroyed(RenderProcessHost* host) override { ++host_destructions_; + observation_.Reset(); } void WaitUntilProcessExits(int target) { while (process_exits_ < target) base::RunLoop().RunUntilIdle(); } - int process_exits_; - int host_destructions_; + base::ScopedObservation<RenderProcessHost, RenderProcessHostObserver> + observation_{this}; + int process_exits_ = 0; + int host_destructions_ = 0; base::OnceClosure process_exit_callback_; - bool use_frame_priority_; + bool use_frame_priority_ = false; base::test::ScopedFeatureList feature_list_; }; @@ -363,8 +373,7 @@ spare_renderer->BindReceiver(service.BindNewPipeAndPassReceiver()); base::RunLoop run_loop; - set_process_exit_callback(run_loop.QuitClosure()); - spare_renderer->AddObserver(this); // For process_exit_callback. + SetProcessExitCallback(spare_renderer, run_loop.QuitClosure()); // Should reply with a bad message and cause process death. { @@ -752,8 +761,12 @@ // Ensure that the ShellCloser observer is first, so that it will have first // dibs on the ProcessExited callback. - rph->AddObserver(&shell_closer); - rph->AddObserver(&observer_logger); + base::ScopedObservation<RenderProcessHost, RenderProcessHostObserver> + observation_1(&shell_closer); + base::ScopedObservation<RenderProcessHost, RenderProcessHostObserver> + observation_2(&observer_logger); + observation_1.Observe(rph); + observation_2.Observe(rph); // This will crash the render process, and start all the callbacks. // We can't use NavigateToURL here since it accesses the shell() after @@ -768,13 +781,6 @@ "ObserverLogger::RenderProcessExited " "ShellCloser::RenderProcessHostDestroyed " "ObserverLogger::RenderProcessHostDestroyed ", logging_string); - - // If the test fails, and somehow the RPH is still alive somehow, at least - // deregister the observers so that the test fails and doesn't also crash. - if (!observer_logger.host_destroyed()) { - rph->RemoveObserver(&shell_closer); - rph->RemoveObserver(&observer_logger); - } } IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, KillProcessOnBadMojoMessage) { @@ -787,13 +793,12 @@ host_destructions_ = 0; process_exits_ = 0; - rph->AddObserver(this); mojo::Remote<mojom::TestService> service; rph->BindReceiver(service.BindNewPipeAndPassReceiver()); base::RunLoop run_loop; - set_process_exit_callback(run_loop.QuitClosure()); + SetProcessExitCallback(rph, run_loop.QuitClosure()); // Should reply with a bad message and cause process death. { @@ -804,8 +809,6 @@ EXPECT_EQ(1, process_exits_); EXPECT_EQ(0, host_destructions_); - if (!host_destructions_) - rph->RemoveObserver(this); } // Observes a WebContents and a specific frame within it, and waits until they @@ -894,7 +897,6 @@ host_destructions_ = 0; process_exits_ = 0; - rph->AddObserver(this); mojo::Remote<mojom::TestService> service; rph->BindReceiver(service.BindNewPipeAndPassReceiver()); @@ -906,7 +908,7 @@ // must run after these notifications have been delivered. ScopedAllowRendererCrashes scoped_allow_renderer_crashes(rph); base::RunLoop run_loop; - set_process_exit_callback(media::BindToCurrentLoop(run_loop.QuitClosure())); + SetProcessExitCallback(rph, run_loop.QuitClosure()); service->DoSomething(base::DoNothing()); run_loop.Run(); } @@ -924,8 +926,6 @@ EXPECT_EQ(0, rph->get_media_stream_count_for_testing()); EXPECT_EQ(1, process_exits_); EXPECT_EQ(0, host_destructions_); - if (!host_destructions_) - rph->RemoveObserver(this); } // Test class instance to run specific setup steps for capture streams. @@ -996,7 +996,6 @@ host_destructions_ = 0; process_exits_ = 0; - rph->AddObserver(this); mojo::Remote<mojom::TestService> service; rph->BindReceiver(service.BindNewPipeAndPassReceiver()); @@ -1005,7 +1004,7 @@ // Force a bad message event to occur which will terminate the renderer. ScopedAllowRendererCrashes scoped_allow_renderer_crashes(rph); base::RunLoop run_loop; - set_process_exit_callback(media::BindToCurrentLoop(run_loop.QuitClosure())); + SetProcessExitCallback(rph, run_loop.QuitClosure()); service->DoSomething(base::DoNothing()); run_loop.Run(); } @@ -1022,8 +1021,6 @@ EXPECT_EQ(0, rph->get_media_stream_count_for_testing()); EXPECT_EQ(1, process_exits_); EXPECT_EQ(0, host_destructions_); - if (!host_destructions_) - rph->RemoveObserver(this); } // Tests that media stream count increments when getUserMedia() is @@ -1062,7 +1059,6 @@ host_destructions_ = 0; process_exits_ = 0; - rph->AddObserver(this); mojo::Remote<mojom::TestService> service; rph->BindReceiver(service.BindNewPipeAndPassReceiver()); @@ -1071,7 +1067,7 @@ // Force a bad message event to occur which will terminate the renderer. ScopedAllowRendererCrashes scoped_allow_renderer_crashes(rph); base::RunLoop run_loop; - set_process_exit_callback(media::BindToCurrentLoop(run_loop.QuitClosure())); + SetProcessExitCallback(rph, run_loop.QuitClosure()); service->DoSomething(base::DoNothing()); run_loop.Run(); } @@ -1088,8 +1084,6 @@ EXPECT_EQ(0, rph->get_media_stream_count_for_testing()); EXPECT_EQ(1, process_exits_); EXPECT_EQ(0, host_destructions_); - if (!host_destructions_) - rph->RemoveObserver(this); } IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, KeepAliveRendererProcess) { @@ -1119,7 +1113,7 @@ host_destructions_ = 0; process_exits_ = 0; - rph->AddObserver(this); + Observe(rph); rfh->SetKeepAliveTimeoutForTesting(base::TimeDelta::FromSeconds(30)); // Navigate to a site that will be in a different process. @@ -1130,8 +1124,6 @@ WaitUntilProcessExits(1); EXPECT_LT(base::TimeTicks::Now() - start, base::TimeDelta::FromSeconds(30)); - if (!host_destructions_) - rph->RemoveObserver(this); } IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, @@ -1186,7 +1178,7 @@ host_destructions_ = 0; process_exits_ = 0; - rph->AddObserver(this); + Observe(rph); rfh->SetKeepAliveTimeoutForTesting(base::TimeDelta::FromSeconds(1)); base::TimeTicks start = base::TimeTicks::Now(); @@ -1195,8 +1187,6 @@ WaitUntilProcessExits(1); EXPECT_GE(base::TimeTicks::Now() - start, base::TimeDelta::FromSeconds(1)); - if (!host_destructions_) - rph->RemoveObserver(this); } // Test is flaky on Android builders: https://crbug.com/875179 @@ -1223,7 +1213,7 @@ host_destructions_ = 0; process_exits_ = 0; - rph->AddObserver(this); + Observe(rph); rfh->SetKeepAliveTimeoutForTesting(base::TimeDelta::FromSeconds(1)); base::TimeTicks start = base::TimeTicks::Now(); @@ -1232,8 +1222,6 @@ WaitUntilProcessExits(1); EXPECT_GE(base::TimeTicks::Now() - start, base::TimeDelta::FromSeconds(1)); - if (!host_destructions_) - rph->RemoveObserver(this); } IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, ManyKeepaliveRequests) {
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 7e36c27d..f478602 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1930,7 +1930,9 @@ GetID(), PluginServiceImpl::GetInstance(), GetBrowserContext(), storage_partition_impl_)); - AddFilter(new PepperRendererConnection(GetID())); + AddFilter(new PepperRendererConnection( + GetID(), PluginServiceImpl::GetInstance(), GetBrowserContext(), + storage_partition_impl_)); #endif p2p_socket_dispatcher_host_ =
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index cb236a1..4948053 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -1055,7 +1055,7 @@ std::set<mojo::ReceiverId> dom_storage_receiver_ids_; // The observers watching our lifetime. - base::ObserverList<RenderProcessHostObserver>::Unchecked observers_; + base::ObserverList<RenderProcessHostObserver> observers_; // True if the process can be shut down suddenly. If this is true, then we're // sure that all the RenderViews in the process can be shutdown suddenly. If
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc index 1370a92d..6680dab8 100644 --- a/content/browser/web_contents/web_contents_android.cc +++ b/content/browser/web_contents/web_contents_android.cc
@@ -422,11 +422,11 @@ return *rwhva->GetCachedBackgroundColor(); } -ScopedJavaLocalRef<jstring> WebContentsAndroid::GetLastCommittedURL( +ScopedJavaLocalRef<jobject> WebContentsAndroid::GetLastCommittedURL( JNIEnv* env, const JavaParamRef<jobject>&) const { - return ConvertUTF8ToJavaString(env, - web_contents_->GetLastCommittedURL().spec()); + return url::GURLAndroid::FromNativeGURL(env, + web_contents_->GetLastCommittedURL()); } jboolean WebContentsAndroid::IsIncognito(JNIEnv* env,
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h index fc05cd6..e6375b4 100644 --- a/content/browser/web_contents/web_contents_android.h +++ b/content/browser/web_contents/web_contents_android.h
@@ -97,7 +97,7 @@ const base::android::JavaParamRef<jobject>& obj); jint GetBackgroundColor(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); - base::android::ScopedJavaLocalRef<jstring> GetLastCommittedURL( + base::android::ScopedJavaLocalRef<jobject> GetLastCommittedURL( JNIEnv* env, const base::android::JavaParamRef<jobject>&) const; jboolean IsIncognito(JNIEnv* env,
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc index f9b7b17..3d6de99 100644 --- a/content/browser/web_contents/web_contents_impl_unittest.cc +++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -771,9 +771,8 @@ EXPECT_TRUE(controller().NeedsReload()); controller().LoadIfNecessary(); - orig_rfh->PrepareForCommit(); - contents()->TestDidNavigate(orig_rfh, false, native_url, - ui::PAGE_TRANSITION_RELOAD); + orig_rfh->SendNavigateWithTransition(0, false, native_url, + ui::PAGE_TRANSITION_RELOAD); EXPECT_EQ(orig_instance, contents()->GetSiteInstance()); EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL()); EXPECT_FALSE(orig_instance->HasSite()); @@ -814,8 +813,8 @@ EXPECT_TRUE(controller().NeedsReload()); controller().LoadIfNecessary(); orig_rfh->PrepareForCommit(); - contents()->TestDidNavigate(orig_rfh, false, regular_url, - ui::PAGE_TRANSITION_RELOAD); + orig_rfh->SendNavigateWithTransition(0, false, regular_url, + ui::PAGE_TRANSITION_RELOAD); EXPECT_EQ(orig_instance, contents()->GetSiteInstance()); EXPECT_TRUE(orig_instance->HasSite()); EXPECT_EQ(AreDefaultSiteInstancesEnabled(), @@ -1244,8 +1243,8 @@ EXPECT_EQ(entry1, controller().GetLastCommittedEntry()); // When the second back commits, it should be ignored. - contents()->TestDidNavigate(google_rfh, false, url2, - ui::PAGE_TRANSITION_TYPED); + google_rfh->SendNavigateWithTransition(0, false, url2, + ui::PAGE_TRANSITION_TYPED); EXPECT_EQ(entry1, controller().GetLastCommittedEntry()); // The newly created process for url1 should be locked to chrome://gpu.
diff --git a/content/browser/webrtc/webrtc_audio_browsertest.cc b/content/browser/webrtc/webrtc_audio_browsertest.cc index 77f7efe..3ad8720 100644 --- a/content/browser/webrtc/webrtc_audio_browsertest.cc +++ b/content/browser/webrtc/webrtc_audio_browsertest.cc
@@ -25,18 +25,11 @@ namespace content { -#if defined(OS_ANDROID) -// Test fails on WebRTC Android FYI: https://crbug.com/1166107 -#define MAYBE_WebRtcAudioBrowserTest DISABLED_WebRtcAudioBrowserTest -#else -#define MAYBE_WebRtcAudioBrowserTest WebRtcAudioBrowserTest -#endif - // This class tests the scenario when permission to access mic or camera is // granted. -class MAYBE_WebRtcAudioBrowserTest : public WebRtcContentBrowserTestBase { +class WebRtcAudioBrowserTest : public WebRtcContentBrowserTestBase { public: - ~MAYBE_WebRtcAudioBrowserTest() override {} + ~WebRtcAudioBrowserTest() override {} void SetUpCommandLine(base::CommandLine* command_line) override { WebRtcContentBrowserTestBase::SetUpCommandLine(command_line); @@ -125,7 +118,7 @@ #endif // defined(OS_MAC) -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioBrowserTest, +IN_PROC_BROWSER_TEST_F(WebRtcAudioBrowserTest, MAYBE_CanMakeVideoCallAndThenRenegotiateToAudio) { std::string constraints = BuildConstraints(kAudioConstraints, kVideoConstraints); @@ -135,7 +128,7 @@ audio_only_constraints + ");"); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioBrowserTest, +IN_PROC_BROWSER_TEST_F(WebRtcAudioBrowserTest, MAYBE_EstablishAudioVideoCallAndEnsureAudioIsPlaying) { std::string constraints = BuildConstraints(kAudioConstraints, kVideoConstraints); @@ -143,7 +136,7 @@ constraints + ");"); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioBrowserTest, +IN_PROC_BROWSER_TEST_F(WebRtcAudioBrowserTest, MAYBE_EstablishAudioOnlyCallAndEnsureAudioIsPlaying) { std::string constraints = BuildConstraints(kAudioConstraints, kVideoConstraints); @@ -151,7 +144,7 @@ constraints + ");"); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioBrowserTest, +IN_PROC_BROWSER_TEST_F(WebRtcAudioBrowserTest, MAYBE_EstablishIsac16KCallAndEnsureAudioIsPlaying) { std::string constraints = BuildConstraints(kAudioConstraints, kVideoConstraints); @@ -159,7 +152,7 @@ "callWithIsac16KAndEnsureAudioIsPlaying(" + constraints + ");"); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioBrowserTest, +IN_PROC_BROWSER_TEST_F(WebRtcAudioBrowserTest, EstablishAudioVideoCallAndVerifyRemoteMutingWorks) { std::string constraints = BuildConstraints(kAudioConstraints, kVideoConstraints); @@ -167,7 +160,7 @@ "callAndEnsureRemoteAudioTrackMutingWorks(" + constraints + ");"); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioBrowserTest, +IN_PROC_BROWSER_TEST_F(WebRtcAudioBrowserTest, EstablishAudioVideoCallAndVerifyLocalMutingWorks) { std::string constraints = BuildConstraints(kAudioConstraints, kVideoConstraints); @@ -175,7 +168,7 @@ "callAndEnsureLocalAudioTrackMutingWorks(" + constraints + ");"); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioBrowserTest, +IN_PROC_BROWSER_TEST_F(WebRtcAudioBrowserTest, MAYBE_EnsureLocalVideoMuteDoesntMuteAudio) { std::string constraints = BuildConstraints(kAudioConstraints, kVideoConstraints); @@ -183,7 +176,7 @@ "callAndEnsureLocalVideoMutingDoesntMuteAudio(" + constraints + ");"); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioBrowserTest, +IN_PROC_BROWSER_TEST_F(WebRtcAudioBrowserTest, MAYBE_EnsureRemoteVideoMuteDoesntMuteAudio) { std::string constraints = BuildConstraints(kAudioConstraints, kVideoConstraints); @@ -191,7 +184,7 @@ "callAndEnsureRemoteVideoMutingDoesntMuteAudio(" + constraints + ");"); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioBrowserTest, +IN_PROC_BROWSER_TEST_F(WebRtcAudioBrowserTest, MAYBE_EstablishAudioVideoCallAndVerifyUnmutingWorks) { std::string constraints = BuildConstraints(kAudioConstraints, kVideoConstraints); @@ -202,7 +195,7 @@ // TODO(crbug.com/988432): This test is a temporary replacement for: // external/wpt/webrtc/RTCRtpReceiver-getSynchronizationSources.https.html IN_PROC_BROWSER_TEST_F( - MAYBE_WebRtcAudioBrowserTest, + WebRtcAudioBrowserTest, MAYBE_EstablishAudioOnlyCallAndVerifyGetSynchronizationSourcesWorks) { MakeAudioDetectingPeerConnectionCall( "testEstablishAudioOnlyCallAndVerifyGetSynchronizationSourcesWorks();");
diff --git a/content/browser/webrtc/webrtc_browsertest.cc b/content/browser/webrtc/webrtc_browsertest.cc index 1b9f385..a182211 100644 --- a/content/browser/webrtc/webrtc_browsertest.cc +++ b/content/browser/webrtc/webrtc_browsertest.cc
@@ -23,11 +23,8 @@ namespace content { -#if defined(OS_ANDROID) -// Renderer crashes under Android ASAN (ADDRESS_SANITIZER): -// https://crbug.com/408496. -// Test fails on WebRTC Android FYI (even without ASAN): -// https://crbug.com/1166107 +#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER) +// Renderer crashes under Android ASAN: https://crbug.com/408496. #define MAYBE_WebRtcBrowserTest DISABLED_WebRtcBrowserTest #else #define MAYBE_WebRtcBrowserTest WebRtcBrowserTest
diff --git a/content/browser/webrtc/webrtc_data_browsertest.cc b/content/browser/webrtc/webrtc_data_browsertest.cc index e35c7638..849914c 100644 --- a/content/browser/webrtc/webrtc_data_browsertest.cc +++ b/content/browser/webrtc/webrtc_data_browsertest.cc
@@ -20,11 +20,8 @@ namespace content { -#if defined(OS_ANDROID) -// Renderer crashes under Android ASAN (ADDRESS_SANITIZER): -// https://crbug.com/408496. -// Test fails on WebRTC Android FYI (even without ASAN): -// https://crbug.com/1166107 +#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER) +// Renderer crashes under Android ASAN: https://crbug.com/408496. #define MAYBE_WebRtcDataBrowserTest DISABLED_WebRtcDataBrowserTest #else #define MAYBE_WebRtcDataBrowserTest WebRtcDataBrowserTest
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index 4bb0498..04eeff9 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h
@@ -218,16 +218,6 @@ IPC_STRUCT_TRAITS_MEMBER(source) IPC_STRUCT_TRAITS_END() -#if BUILDFLAG(ENABLE_PLUGINS) -IPC_STRUCT_TRAITS_BEGIN(content::PepperRendererInstanceData) - IPC_STRUCT_TRAITS_MEMBER(render_process_id) - IPC_STRUCT_TRAITS_MEMBER(render_frame_id) - IPC_STRUCT_TRAITS_MEMBER(document_url) - IPC_STRUCT_TRAITS_MEMBER(plugin_url) - IPC_STRUCT_TRAITS_MEMBER(is_potentially_secure_plugin_context) -IPC_STRUCT_TRAITS_END() -#endif - // ----------------------------------------------------------------------------- // Messages sent from the browser to the renderer. @@ -258,59 +248,6 @@ content::WebPluginInfo /* plugin info */, std::string /* actual_mime_type */) -// A renderer sends this to the browser process when it wants to create a ppapi -// plugin. The browser will create the plugin process if necessary, and will -// return a handle to the channel on success. -// -// The plugin_child_id is the ChildProcessHost ID assigned in the browser -// process. This ID is valid only in the context of the browser process and is -// used to identify the proper process when the renderer notifies it that the -// plugin is hung. -// -// |embedder_origin| provides the origin of the frame that embeds the plugin -// (i.e. the origin of the document that contains the <embed> html tag). -// |embedder_origin| needs to be included in the message payload, because the -// message is received and handled on the IO thread in the browser process -// (where it is not possible to consult -// RenderFrameHostImpl::GetLastCommittedOrigin). -// -// On error an empty string and null handles are returned. -IPC_SYNC_MESSAGE_CONTROL3_3(FrameHostMsg_OpenChannelToPepperPlugin, - url::Origin /* embedder_origin */, - base::FilePath /* path */, - base::Optional<url::Origin>, /* origin_lock */ - IPC::ChannelHandle /* handle to channel */, - base::ProcessId /* plugin_pid */, - int /* plugin_child_id */) - -// Notification that a plugin has created a new plugin instance. The parameters -// indicate: -// - The plugin process ID that we're creating the instance for. -// - The instance ID of the instance being created. -// - A PepperRendererInstanceData struct which contains properties from the -// renderer which are associated with the plugin instance. This includes the -// routing ID of the associated RenderFrame and the URL of plugin. -// - Whether the plugin we're creating an instance for is external or internal. -// -// This message must be sync even though it returns no parameters to avoid -// a race condition with the plugin process. The plugin process sends messages -// to the browser that assume the browser knows about the instance. We need to -// make sure that the browser actually knows about the instance before we tell -// the plugin to run. -IPC_SYNC_MESSAGE_CONTROL4_0( - FrameHostMsg_DidCreateOutOfProcessPepperInstance, - int /* plugin_child_id */, - int32_t /* pp_instance */, - content::PepperRendererInstanceData /* creation_data */, - bool /* is_external */) - -// Notification that a plugin has destroyed an instance. This is the opposite of -// the "DidCreate" message above. -IPC_MESSAGE_CONTROL3(FrameHostMsg_DidDeleteOutOfProcessPepperInstance, - int /* plugin_child_id */, - int32_t /* pp_instance */, - bool /* is_external */) - #endif // BUILDFLAG(ENABLE_PLUGINS) // Used to tell the parent that the user right clicked on an area of the
diff --git a/content/common/pepper_plugin.mojom b/content/common/pepper_plugin.mojom index 2a13a4e..8627c0a 100644 --- a/content/common/pepper_plugin.mojom +++ b/content/common/pepper_plugin.mojom
@@ -6,6 +6,7 @@ import "mojo/public/mojom/base/file_path.mojom"; import "mojo/public/mojom/base/process_id.mojom"; +import "url/mojom/origin.mojom"; import "url/mojom/url.mojom"; // Generic Pepper messages. Implemented by the browser. @@ -32,6 +33,58 @@ // Notification that an in-process instance has been destroyed. DidDeleteInProcessInstance(int32 instance_id); + + // Notification that a plugin has created a new plugin instance. The + // parameters indicate: + // - The plugin process ID that we're creating the instance for. + // - The instance ID of the instance being created. + // - A PepperRendererInstanceData struct which contains properties from the + // renderer which are associated with the plugin instance. This includes + // the routing ID of the associated RenderFrame and the URL of plugin. + // - Whether the plugin we're creating an instance for is external or + // internal. + // + // This message must be sync even though it returns no parameters to avoid + // a race condition with the plugin process. The plugin process sends messages + // to the browser that assume the browser knows about the instance. We need to + // make sure that the browser actually knows about the instance before we tell + // the plugin to run. + [Sync] DidCreateOutOfProcessPepperInstance(int32 plugin_child_id, + int32 pp_instance, + bool is_external, + int32 frame_routing_id, + url.mojom.Url document_url, + url.mojom.Url plugin_url, + bool is_privileged_context) => (); + + // Notification that a plugin has destroyed an instance. + DidDeleteOutOfProcessPepperInstance(int32 plugin_child_id, + int32 pp_instance, + bool is_external); + + // A renderer sends this to the browser process when it wants to create a + // ppapi plugin. The browser will create the plugin process if necessary, + // and will return a handle to the channel on success. + // + // The plugin_child_id is the ChildProcessHost ID assigned in the browser + // process. This ID is valid only in the context of the browser process and is + // used to identify the proper process when the renderer notifies it that the + // plugin is hung. + // + // |embedder_origin| provides the origin of the frame that embeds the plugin + // (i.e. the origin of the document that contains the <embed> html tag). + // |embedder_origin| needs to be included in the message payload, because the + // message is received and handled on the IO thread in the browser process + // (where it is not possible to consult + // RenderFrameHostImpl::GetLastCommittedOrigin). + // + // On error null handles are returned. + [Sync] OpenChannelToPepperPlugin(url.mojom.Origin embedder_origin, + mojo_base.mojom.FilePath path, + url.mojom.Origin? origin_lock) => + (handle<message_pipe>? handle_to_channel, + mojo_base.mojom.ProcessId plugin_pid, + int32 plugin_child_id); }; // This interface is used on the renderer IO thread and is received on the
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java index 8bf6a35..6a12a878 100644 --- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -626,7 +626,7 @@ } @Override - public String getLastCommittedUrl() { + public GURL getLastCommittedUrl() { checkNotDestroyed(); return WebContentsImplJni.get().getLastCommittedURL( mNativeWebContentsAndroid, WebContentsImpl.this); @@ -1110,7 +1110,7 @@ void selectWordAroundCaret(long nativeWebContentsAndroid, WebContentsImpl caller); void adjustSelectionByCharacterOffset(long nativeWebContentsAndroid, WebContentsImpl caller, int startAdjust, int endAdjust, boolean showSelectionMenu); - String getLastCommittedURL(long nativeWebContentsAndroid, WebContentsImpl caller); + GURL getLastCommittedURL(long nativeWebContentsAndroid, WebContentsImpl caller); boolean isIncognito(long nativeWebContentsAndroid, WebContentsImpl caller); void resumeLoadingCreatedWebContents(long nativeWebContentsAndroid, WebContentsImpl caller); void evaluateJavaScript(long nativeWebContentsAndroid, WebContentsImpl caller,
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java index b8484cc..cdd90bb5 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -292,7 +292,7 @@ * * @return The last committed URL. */ - String getLastCommittedUrl(); + GURL getLastCommittedUrl(); /** * Get the InCognito state of WebContents.
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java index 7e29bee8..480c47a5 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -690,7 +690,7 @@ private void reloadPage() throws Exception { // Reload the page, then focus will be lost and keyboard should be hidden. - mRule.fullyLoadUrl(mRule.getWebContents().getLastCommittedUrl()); + mRule.fullyLoadUrl(mRule.getWebContents().getLastCommittedUrl().getSpec()); } @Test
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index 332c015..a8b4cc9 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn
@@ -286,6 +286,7 @@ "render_process_host.h", "render_process_host_creation_observer.h", "render_process_host_factory.h", + "render_process_host_observer.cc", "render_process_host_observer.h", "render_view_host.h", "render_widget_host.h",
diff --git a/content/public/browser/render_process_host_observer.cc b/content/public/browser/render_process_host_observer.cc new file mode 100644 index 0000000..44606995 --- /dev/null +++ b/content/public/browser/render_process_host_observer.cc
@@ -0,0 +1,16 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/browser/render_process_host_observer.h" +#include "base/check.h" + +namespace content { + +RenderProcessHostObserver::~RenderProcessHostObserver() { + // TODO(https://crbug.com/1153961): Instrumentation. When fixed, decide if + // this CHECK should be removed or turned into a DCHECK. + CHECK(!IsInObserverList()); +} + +} // namespace content
diff --git a/content/public/browser/render_process_host_observer.h b/content/public/browser/render_process_host_observer.h index 17e9ef2..c2400b5 100644 --- a/content/public/browser/render_process_host_observer.h +++ b/content/public/browser/render_process_host_observer.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_PUBLIC_BROWSER_RENDER_PROCESS_HOST_OBSERVER_H_ #define CONTENT_PUBLIC_BROWSER_RENDER_PROCESS_HOST_OBSERVER_H_ +#include "base/observer_list_types.h" #include "base/process/kill.h" #include "base/process/process_handle.h" #include "content/common/content_export.h" @@ -18,7 +19,7 @@ // in RenderProcessHost lifecycle events. Note that this does not allow // observing the creation of a RenderProcessHost. There is a separate observer // for that: RenderProcessHostCreationObserver. -class CONTENT_EXPORT RenderProcessHostObserver { +class CONTENT_EXPORT RenderProcessHostObserver : public base::CheckedObserver { public: // This method is invoked when the process was launched and the channel was // connected. This is the earliest time it is safe to call Shutdown on the @@ -48,7 +49,7 @@ virtual void RenderProcessHostDestroyed(RenderProcessHost* host) {} protected: - virtual ~RenderProcessHostObserver() {} + ~RenderProcessHostObserver() override; }; } // namespace content
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java index 10eecca..a0905f2 100644 --- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java +++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
@@ -184,7 +184,7 @@ int startAdjust, int endAdjust, boolean showSelectionMenu) {} @Override - public String getLastCommittedUrl() { + public GURL getLastCommittedUrl() { return null; }
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/HistoryUtils.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/HistoryUtils.java index 42ca1f82..8fe4da0 100644 --- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/HistoryUtils.java +++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/HistoryUtils.java
@@ -109,7 +109,7 @@ instrumentation, new Callable<String>() { @Override public String call() { - return webContents.getLastCommittedUrl(); + return webContents.getLastCommittedUrl().getSpec(); } }); }
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc index b6b9a277..c4692d2 100644 --- a/content/public/test/browser_test_utils.cc +++ b/content/public/test/browser_test_utils.cc
@@ -2299,33 +2299,19 @@ RenderProcessHostWatcher::RenderProcessHostWatcher( RenderProcessHost* render_process_host, WatchType type) - : render_process_host_(render_process_host), - type_(type), + : type_(type), did_exit_normally_(true), allow_renderer_crashes_( std::make_unique<ScopedAllowRendererCrashes>(render_process_host)), quit_closure_(run_loop_.QuitClosure()) { - render_process_host_->AddObserver(this); + observation_.Observe(render_process_host); } RenderProcessHostWatcher::RenderProcessHostWatcher(WebContents* web_contents, WatchType type) : RenderProcessHostWatcher(web_contents->GetMainFrame()->GetProcess(), type) {} - -RenderProcessHostWatcher::~RenderProcessHostWatcher() { - ClearProcessHost(); -} - -void RenderProcessHostWatcher::ClearProcessHost() { - // Although we would like to make it so that from here on, renderer crashes - // cause test failures, resetting ScopedAllowRendererCrashes inside the RPH - // observers is too soon. The current crash is notified to the testing - // framework *after* the observers run and we need this one to be ignored. - if (render_process_host_) - render_process_host_->RemoveObserver(this); - render_process_host_ = nullptr; -} +RenderProcessHostWatcher::~RenderProcessHostWatcher() = default; void RenderProcessHostWatcher::Wait() { run_loop_.Run(); @@ -2334,12 +2320,12 @@ << "RenderProcessHostWatcher::Wait() may only be called once"; allow_renderer_crashes_.reset(); // Call this here just in case something else quits the RunLoop. - ClearProcessHost(); + observation_.Reset(); } void RenderProcessHostWatcher::QuitRunLoop() { std::move(quit_closure_).Run(); - ClearProcessHost(); + observation_.Reset(); } void RenderProcessHostWatcher::RenderProcessReady(RenderProcessHost* host) { @@ -2358,7 +2344,6 @@ void RenderProcessHostWatcher::RenderProcessHostDestroyed( RenderProcessHost* host) { - render_process_host_ = nullptr; if (type_ == WATCH_FOR_HOST_DESTRUCTION) QuitRunLoop(); }
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h index 4baf625..a338f88b 100644 --- a/content/public/test/browser_test_utils.h +++ b/content/public/test/browser_test_utils.h
@@ -22,6 +22,7 @@ #include "base/optional.h" #include "base/process/process.h" #include "base/run_loop.h" +#include "base/scoped_observation.h" #include "base/strings/string16.h" #include "base/test/metrics/histogram_tester.h" #include "build/build_config.h" @@ -31,6 +32,7 @@ #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/render_frame_metadata_provider.h" +#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host_observer.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/web_contents_delegate.h" @@ -1096,8 +1098,6 @@ bool did_exit_normally() { return did_exit_normally_; } private: - // Stop observing and drop the reference to the RenderProcessHost. - void ClearProcessHost(); // Quit the run loop and clean up. void QuitRunLoop(); @@ -1107,7 +1107,8 @@ const ChildProcessTerminationInfo& info) override; void RenderProcessHostDestroyed(RenderProcessHost* host) override; - RenderProcessHost* render_process_host_; + base::ScopedObservation<RenderProcessHost, RenderProcessHostObserver> + observation_{this}; WatchType type_; bool did_exit_normally_;
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h index 4630d2a..b0d4e74 100644 --- a/content/public/test/mock_render_process_host.h +++ b/content/public/test/mock_render_process_host.h
@@ -260,7 +260,7 @@ int id_; bool has_connection_; BrowserContext* browser_context_; - base::ObserverList<RenderProcessHostObserver>::Unchecked observers_; + base::ObserverList<RenderProcessHostObserver> observers_; base::flat_set<PriorityClient*> priority_clients_; int prev_routing_id_;
diff --git a/content/public/test/web_contents_tester.h b/content/public/test/web_contents_tester.h index b886b41..e1c890bf 100644 --- a/content/public/test/web_contents_tester.h +++ b/content/public/test/web_contents_tester.h
@@ -26,7 +26,6 @@ namespace content { class BrowserContext; -class RenderFrameHost; // This interface allows embedders of content/ to write tests that depend on a // test version of WebContents. This interface can be retrieved from any @@ -93,17 +92,6 @@ // Sets the loading state to the given value. virtual void TestSetIsLoading(bool value) = 0; - // Simulates a navigation with the given information. - // - // Guidance for calling these: - // - did_create_new_entry should be true if simulating a navigation that - // created a new navigation entry; false for history navigations, reloads, - // and other navigations that don't affect the history list. - virtual void TestDidNavigate(RenderFrameHost* render_frame_host, - bool did_create_new_entry, - const GURL& url, - ui::PageTransition transition) = 0; - // Simulate this WebContents' main frame having an opener that points to the // main frame of |opener|. virtual void SetOpener(WebContents* opener) = 0;
diff --git a/content/renderer/pepper/host_dispatcher_wrapper.cc b/content/renderer/pepper/host_dispatcher_wrapper.cc index df6b1e85..4c48a5b 100644 --- a/content/renderer/pepper/host_dispatcher_wrapper.cc +++ b/content/renderer/pepper/host_dispatcher_wrapper.cc
@@ -6,6 +6,7 @@ #include "build/build_config.h" #include "content/common/frame_messages.h" +#include "content/renderer/pepper/pepper_browser_connection.h" #include "content/renderer/pepper/pepper_hung_plugin_filter.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" #include "content/renderer/pepper/pepper_proxy_channel_delegate_impl.h" @@ -87,13 +88,11 @@ bool is_privileged_context = plugin_instance->GetContainer()->GetDocument().IsSecureContext() && network::IsUrlPotentiallyTrustworthy(plugin_instance->GetPluginURL()); - render_frame->Send(new FrameHostMsg_DidCreateOutOfProcessPepperInstance( - plugin_child_id_, instance, - PepperRendererInstanceData( - 0, // The render process id will be supplied in the browser. + PepperBrowserConnection::Get(render_frame) + ->DidCreateOutOfProcessPepperInstance( + plugin_child_id_, instance, is_external_, render_frame->GetRoutingID(), host->GetDocumentURL(instance), - plugin_instance->GetPluginURL(), is_privileged_context), - is_external_)); + plugin_instance->GetPluginURL(), is_privileged_context); } } @@ -106,8 +105,9 @@ if (host) { RenderFrame* render_frame = host->GetRenderFrameForInstance(instance); if (render_frame) { - render_frame->Send(new FrameHostMsg_DidDeleteOutOfProcessPepperInstance( - plugin_child_id_, instance, is_external_)); + PepperBrowserConnection::Get(render_frame) + ->DidDeleteOutOfProcessPepperInstance(plugin_child_id_, instance, + is_external_); } } }
diff --git a/content/renderer/pepper/pepper_browser_connection.cc b/content/renderer/pepper/pepper_browser_connection.cc index 218e089..719adff 100644 --- a/content/renderer/pepper/pepper_browser_connection.cc +++ b/content/renderer/pepper/pepper_browser_connection.cc
@@ -43,15 +43,41 @@ int render_frame_id, const GURL& document_url, const GURL& plugin_url) { - if (auto* io_host = GetIOHost()) { - io_host->DidCreateInProcessInstance(instance, render_frame_id, document_url, - plugin_url); - } + if (!GetIOHost()) + return; + GetIOHost()->DidCreateInProcessInstance(instance, render_frame_id, + document_url, plugin_url); } void PepperBrowserConnection::DidDeleteInProcessInstance(PP_Instance instance) { - if (auto* io_host = GetIOHost()) - io_host->DidDeleteInProcessInstance(instance); + if (!GetIOHost()) + return; + GetIOHost()->DidDeleteInProcessInstance(instance); +} + +void PepperBrowserConnection::DidCreateOutOfProcessPepperInstance( + int32_t plugin_child_id, + int32_t pp_instance, + bool is_external, + int32_t render_frame_id, + const GURL& document_url, + const GURL& plugin_url, + bool is_priviledged_context) { + if (!GetIOHost()) + return; + GetIOHost()->DidCreateOutOfProcessPepperInstance( + plugin_child_id, pp_instance, is_external, render_frame_id, document_url, + plugin_url, is_priviledged_context); +} + +void PepperBrowserConnection::DidDeleteOutOfProcessPepperInstance( + int32_t plugin_child_id, + int32_t pp_instance, + bool is_external) { + if (!GetIOHost()) + return; + GetIOHost()->DidDeleteOutOfProcessPepperInstance(plugin_child_id, pp_instance, + is_external); } void PepperBrowserConnection::SendBrowserCreate(
diff --git a/content/renderer/pepper/pepper_browser_connection.h b/content/renderer/pepper/pepper_browser_connection.h index 4add11a..d93e166 100644 --- a/content/renderer/pepper/pepper_browser_connection.h +++ b/content/renderer/pepper/pepper_browser_connection.h
@@ -61,6 +61,23 @@ // Called when the renderer deletes an in-process instance. void DidDeleteInProcessInstance(PP_Instance instance); + // Called when the renderer creates an out of process instance. + void DidCreateOutOfProcessPepperInstance(int32_t plugin_child_id, + int32_t pp_instance, + bool is_external, + int32_t render_frame_id, + const GURL& document_url, + const GURL& plugin_url, + bool is_priviledged_context); + + // Called when the renderer deletes an out of process instance. + void DidDeleteOutOfProcessPepperInstance(int32_t plugin_child_id, + int32_t pp_instance, + bool is_external); + + // Return a bound PepperIOHost. This may return null in unittests. + mojom::PepperIOHost* GetIOHost(); + private: // RenderFrameObserver implementation. void OnDestruct() override; @@ -70,9 +87,6 @@ int32_t sequence_number, const std::vector<int>& pending_resource_host_ids); - // Return a bound PepperIOHost. This may return null in unittests. - mojom::PepperIOHost* GetIOHost(); - // Return the next sequence number. int32_t GetNextSequence();
diff --git a/content/renderer/pepper/plugin_module.cc b/content/renderer/pepper/plugin_module.cc index cb83ca23..6fd669e7 100644 --- a/content/renderer/pepper/plugin_module.cc +++ b/content/renderer/pepper/plugin_module.cc
@@ -24,6 +24,7 @@ #include "content/public/renderer/content_renderer_client.h" #include "content/renderer/pepper/host_dispatcher_wrapper.h" #include "content/renderer/pepper/host_globals.h" +#include "content/renderer/pepper/pepper_browser_connection.h" #include "content/renderer/pepper/pepper_hung_plugin_filter.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" #include "content/renderer/pepper/pepper_plugin_registry.h" @@ -697,13 +698,19 @@ } // Out of process: have the browser start the plugin process for us. - IPC::ChannelHandle channel_handle; + mojo::ScopedMessagePipeHandle channel_handle; base::ProcessId peer_pid = 0; int plugin_child_id = 0; - render_frame->Send(new FrameHostMsg_OpenChannelToPepperPlugin( + mojom::PepperIOHost* io_host = + PepperBrowserConnection::Get(render_frame)->GetIOHost(); + if (!io_host) { + // Couldn't be initialized. + return scoped_refptr<PluginModule>(); + } + io_host->OpenChannelToPepperPlugin( render_frame->GetWebFrame()->GetSecurityOrigin(), path, origin_lock, - &channel_handle, &peer_pid, &plugin_child_id)); - if (!channel_handle.is_mojo_channel_handle()) { + &channel_handle, &peer_pid, &plugin_child_id); + if (!channel_handle.is_valid()) { // Couldn't be initialized. return scoped_refptr<PluginModule>(); } @@ -717,7 +724,7 @@ module.get()); if (!module->CreateOutOfProcessModule(render_frame, path, permissions, - channel_handle, peer_pid, + channel_handle.release(), peer_pid, plugin_child_id, false, task_runner)) // is_external = false return scoped_refptr<PluginModule>();
diff --git a/content/shell/android/BUILD.gn b/content/shell/android/BUILD.gn index 1e64a0554..2ab1995 100644 --- a/content/shell/android/BUILD.gn +++ b/content/shell/android/BUILD.gn
@@ -146,6 +146,7 @@ "//net/android:net_java", "//third_party/android_deps:com_google_code_findbugs_jsr305_java", "//ui/android:ui_java", + "//url:gurl_java", ] sources = [
diff --git a/content/shell/android/java/src/org/chromium/content_shell/Shell.java b/content/shell/android/java/src/org/chromium/content_shell/Shell.java index 9cd02fa..0123f70 100644 --- a/content/shell/android/java/src/org/chromium/content_shell/Shell.java +++ b/content/shell/android/java/src/org/chromium/content_shell/Shell.java
@@ -196,7 +196,7 @@ public void loadUrl(String url) { if (url == null) return; - if (TextUtils.equals(url, mWebContents.getLastCommittedUrl())) { + if (TextUtils.equals(url, mWebContents.getLastCommittedUrl().getSpec())) { mNavigationController.reload(true); } else { mNavigationController.loadUrl(new LoadUrlParams(sanitizeUrl(url)));
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java index 2700ceec..331aa11d7 100644 --- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java +++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java
@@ -110,7 +110,7 @@ ContentShellActivity activity = launchContentShellWithUrl(isolatedTestFileUrl); Assert.assertNotNull(getActivity()); waitForActiveShellToBeDoneLoading(); - Assert.assertEquals(isolatedTestFileUrl, getWebContents().getLastCommittedUrl()); + Assert.assertEquals(isolatedTestFileUrl, getWebContents().getLastCommittedUrl().getSpec()); return activity; } @@ -250,8 +250,7 @@ Criteria.checkThat("Shell is null.", shell, Matchers.notNullValue()); Criteria.checkThat("Shell is still loading.", shell.isLoading(), Matchers.is(false)); Criteria.checkThat("Shell's URL is empty or null.", - shell.getWebContents().getLastCommittedUrl(), - Matchers.not(Matchers.isEmptyOrNullString())); + shell.getWebContents().getLastCommittedUrl().isEmpty(), Matchers.is(false)); }, WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL); }
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java index edf239c7..1a6b8ae 100644 --- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java +++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
@@ -122,7 +122,8 @@ super.onSaveInstanceState(outState); WebContents webContents = getActiveWebContents(); if (webContents != null) { - outState.putString(ACTIVE_SHELL_URL_KEY, webContents.getLastCommittedUrl()); + // TODO(yfriedman): crbug/783819 - This should use GURL serialize/deserialize. + outState.putString(ACTIVE_SHELL_URL_KEY, webContents.getLastCommittedUrl().getSpec()); } mWindowAndroid.saveInstanceState(outState);
diff --git a/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt b/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt index f30f15e3..a3fe1ad 100644 --- a/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt +++ b/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt
@@ -1,7 +1,8 @@ AXWebArea AXFocused=1 ++AXGroup ++++AXStaticText AXValue='Choose a fruit, with text content' -++AXPopUpButton AXLinkedUIElements=[:6] AXTitle='Choose a fruit, with text content' AXValue='Apple' +++AXComboBox AXLinkedUIElements=[:6] AXTitle='Choose a fruit, with text content' AXValue='Apple' + ++++AXStaticText AXValue='Apple' ++AXList ++++AXStaticText AXValue='Apple'
diff --git a/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt b/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt index 11d0f74..a3e1617 100644 --- a/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt +++ b/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt
@@ -1,10 +1,10 @@ AXWebArea -++AXPopUpButton AXHasPopup=1 AXPopupValue='menu' -++AXPopUpButton -++AXPopUpButton AXHasPopup=1 AXPopupValue='menu' -++AXPopUpButton AXHasPopup=1 AXPopupValue='listbox' -++AXPopUpButton AXHasPopup=1 AXPopupValue='grid' -++AXPopUpButton AXHasPopup=1 AXPopupValue='dialog' -++AXPopUpButton AXHasPopup=1 AXPopupValue='listbox' -++AXPopUpButton AXHasPopup=1 AXPopupValue='listbox' -++AXPopUpButton AXHasPopup=1 AXPopupValue='listbox' +++AXComboBox AXHasPopup=1 AXPopupValue='menu' +++AXComboBox +++AXComboBox AXHasPopup=1 AXPopupValue='menu' +++AXComboBox AXHasPopup=1 AXPopupValue='listbox' +++AXComboBox AXHasPopup=1 AXPopupValue='grid' +++AXComboBox AXHasPopup=1 AXPopupValue='dialog' +++AXComboBox AXHasPopup=1 AXPopupValue='listbox' +++AXComboBox AXHasPopup=1 AXPopupValue='listbox' +++AXComboBox AXHasPopup=1 AXPopupValue='listbox'
diff --git a/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt b/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt index 4c605836..c04259a 100644 --- a/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt +++ b/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt
@@ -1,7 +1,7 @@ AXWebArea -++AXGroup -++AXGroup AXOrientation='AXHorizontalOrientation' -++AXGroup AXOrientation='AXVerticalOrientation' +++AXComboBox +++AXComboBox AXOrientation='AXHorizontalOrientation' +++AXComboBox AXOrientation='AXVerticalOrientation' ++AXList AXOrientation='AXVerticalOrientation' ++AXList AXOrientation='AXHorizontalOrientation' ++AXList AXOrientation='AXVerticalOrientation'
diff --git a/content/test/data/accessibility/aria/aria-owns-crash-expected-blink.txt b/content/test/data/accessibility/aria/aria-owns-crash-expected-blink.txt index 9f5363fec..7e7aa07 100644 --- a/content/test/data/accessibility/aria/aria-owns-crash-expected-blink.txt +++ b/content/test/data/accessibility/aria/aria-owns-crash-expected-blink.txt
@@ -5,7 +5,10 @@ ++++++++genericContainer ignored invisible name='cats' ++++++++++comboBoxGrouping ignored invisible ++++++++++++textField ignored invisible +++++++++++++++genericContainer ignored invisible ++++++++++++listBox ignored invisible ++++++++++++++listItem ignored invisible ++++++++++++++++listMarker ignored invisible name='• ' +++++++++++++++++++staticText ignored name='• ' ++++++++genericContainer ignored invisible +
diff --git a/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt b/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt index b942711..96f8201 100644 --- a/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt +++ b/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt
@@ -1,12 +1,12 @@ AXWebArea ++AXGroup ++++AXStaticText AXValue='State' -++AXGroup AXTitle='State' +++AXComboBox AXTitle='State' ++++AXTextField AXLinkedUIElements=[:6] ++AXList ++++AXStaticText AXValue='Alabama' ++++AXStaticText AXFocused=1 AXValue='Alaska' -++AXGroup AXTitle='State' +++AXComboBox AXTitle='State' ++++AXTextField AXLinkedUIElements=[:11] ++AXList ++++AXStaticText AXValue='Alabama'
diff --git a/content/test/data/accessibility/event/aria-hidden-descendants-already-ignored-expected-auralinux.txt b/content/test/data/accessibility/event/aria-hidden-descendants-already-ignored-expected-auralinux.txt index e91acb5b..19466cf 100644 --- a/content/test/data/accessibility/event/aria-hidden-descendants-already-ignored-expected-auralinux.txt +++ b/content/test/data/accessibility/event/aria-hidden-descendants-already-ignored-expected-auralinux.txt
@@ -1,3 +1 @@ CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_HEADING) role=ROLE_TOOL_BAR ENABLED,HORIZONTAL,SENSITIVE,SHOWING,VISIBLE -CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_SECTION) role=ROLE_SECTION ENABLED,SENSITIVE,SHOWING,VISIBLE -CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_SECTION) role=ROLE_TOOL_BAR ENABLED,HORIZONTAL,SENSITIVE,SHOWING,VISIBLE \ No newline at end of file
diff --git a/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-auralinux.txt b/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-auralinux.txt new file mode 100644 index 0000000..16f2577c --- /dev/null +++ b/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-auralinux.txt
@@ -0,0 +1,13 @@ +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_ARTICLE) role=ROLE_TREE ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_LINK) role=ROLE_TREE_ITEM ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_LINK) role=ROLE_TREE_ITEM ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_LINK) role=ROLE_TREE_ITEM ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_PANEL) role=ROLE_ARTICLE ENABLED,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_SECTION) role=ROLE_LINK ENABLED,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_SECTION) role=ROLE_LINK ENABLED,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_SECTION) role=ROLE_LINK ENABLED,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_STATIC) role=ROLE_SECTION ENABLED,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_STATIC) role=ROLE_SECTION ENABLED,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_STATIC) role=ROLE_SECTION ENABLED,SENSITIVE,SHOWING,VISIBLE +=== Start Continuation === +CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_ARTICLE) role=ROLE_TREE ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
diff --git a/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-win.txt b/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-win.txt index 9ef6c48..39fbfa9d 100644 --- a/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-win.txt +++ b/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-win.txt
@@ -5,7 +5,4 @@ EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_OUTLINEITEM name="grandchild3" INVISIBLE,FOCUSABLE level=2 === Start Continuation === EVENT_OBJECT_REORDER on <div#tree> role=ROLE_SYSTEM_OUTLINE IA2_STATE_VERTICAL -EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_OUTLINEITEM name="grandchild1" FOCUSABLE level=2 PosInSet=1 SetSize=3 -EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_OUTLINEITEM name="grandchild2" FOCUSABLE level=2 PosInSet=2 SetSize=3 -EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_OUTLINEITEM name="grandchild3" FOCUSABLE level=2 PosInSet=3 SetSize=3 -EVENT_OBJECT_SHOW on <div#article> role=ROLE_SYSTEM_DOCUMENT +EVENT_OBJECT_SHOW on <div#article> role=ROLE_SYSTEM_DOCUMENT \ No newline at end of file
diff --git a/content/test/data/accessibility/html/img-broken-expected-blink.txt b/content/test/data/accessibility/html/img-broken-expected-blink.txt new file mode 100644 index 0000000..b726a242 --- /dev/null +++ b/content/test/data/accessibility/html/img-broken-expected-blink.txt
@@ -0,0 +1,6 @@ +rootWebArea name='done' +++genericContainer ignored +++++genericContainer +++++++image name='pipe' +++++++image name='control' +++++++image name='broken-control'
diff --git a/content/test/data/accessibility/html/img-broken.html b/content/test/data/accessibility/html/img-broken.html new file mode 100644 index 0000000..f45eaa95 --- /dev/null +++ b/content/test/data/accessibility/html/img-broken.html
@@ -0,0 +1,23 @@ +<!-- +@MAC-ALLOW:AXRoleDescription='image' +@WIN-ALLOW:xml-roles:* +@AURALINUX-ALLOW:xml-roles:* +@ANDROID-ALLOW:has_image +@WAIT-FOR:done +--> +<!-- When an image changes its broken state, it can get an extra user agent +shadow DOM content that visibly displays the alt text. This should not accidentally +cause extra ax children of the image to be created, since an image must be a leaf. +The test toggles the broken state back and forth several times in order to ensure +no illegal states in Blink are triggered (DCHECKs) --> +<img src="pipe.jpg" alt="pipe"><img src="pipe.jpg" alt="control"><img src="pipe-broken.jpg" alt="broken-control"> +<script> + let counter = 0; + function changeImageName() { + const first_img = document.querySelector('img'); + first_img.src = first_img.src == 'pipe.jpg' ? 'pipe-broken.jpg' : 'pipe.jpg'; + if (++counter == 4) + document.title = 'done'; + } + setInterval(changeImageName, 15); +</script>
diff --git a/content/test/data/accessibility/html/input-radio-checkbox-label-expected-blink.txt b/content/test/data/accessibility/html/input-radio-checkbox-label-expected-blink.txt index dcc2735..8ee8042 100644 --- a/content/test/data/accessibility/html/input-radio-checkbox-label-expected-blink.txt +++ b/content/test/data/accessibility/html/input-radio-checkbox-label-expected-blink.txt
@@ -3,11 +3,9 @@ ++++genericContainer ++++++labelText ignored ++++++++staticText ignored name='label ignored for radio button ' -++++++++++inlineTextBox ignored name='label ignored for radio button ' ++++++++radioButton name='label ignored for radio button' checkedState=false ++++++labelText ignored ++++++++staticText ignored name='label ignored for checkbox ' -++++++++++inlineTextBox ignored name='label ignored for checkbox ' ++++++++checkBox name='label ignored for checkbox' checkedState=false ++++++labelText name='label exposed for radio button ' ++++++++staticText name='label exposed for radio button '
diff --git a/content/test/data/accessibility/html/list-text-removal-expected-blink.txt b/content/test/data/accessibility/html/list-text-removal-expected-blink.txt new file mode 100644 index 0000000..ff968967 --- /dev/null +++ b/content/test/data/accessibility/html/list-text-removal-expected-blink.txt
@@ -0,0 +1,7 @@ +rootWebArea name='done' +++genericContainer ignored +++++genericContainer ignored +++++++list +++++++++listItem hierarchicalLevel=1 +++++++++++staticText name='item' +++++++++++++inlineTextBox name='item'
diff --git a/content/test/data/accessibility/html/list-text-removal.html b/content/test/data/accessibility/html/list-text-removal.html new file mode 100644 index 0000000..b2f254ac --- /dev/null +++ b/content/test/data/accessibility/html/list-text-removal.html
@@ -0,0 +1,33 @@ +<!-- +@BLINK-ALLOW:hierarchicalLevel* +@MAC-ALLOW:AXSubrole +@WAIT-FOR:done +--> +<html> + <style type="text/css"> + .inlineList li { + display: inline; + } + </style> + <body> + <ul class="inlineList"> + <li>item</li> + </ul>$ + </body> +<script> +function convertDollarToWhitespace(node) { + let child = node.firstChild; + while (child) { + if (child.nodeType == Node.ELEMENT_NODE) + convertDollarToWhitespace(child); + else if (child.nodeType == Node.TEXT_NODE && child.data.indexOf('$') >= 0) + child.data = ' \n '; + child = child.nextSibling; + } +} +setTimeout(() => { + convertDollarToWhitespace(document.body); + document.title = 'done'; +}, 500); +</script> +</html>
diff --git a/content/test/data/accessibility/html/object-image-error.html b/content/test/data/accessibility/html/object-image-error.html index 6744bb3..931d3e8 100644 --- a/content/test/data/accessibility/html/object-image-error.html +++ b/content/test/data/accessibility/html/object-image-error.html
@@ -3,8 +3,7 @@ @NO-LOAD-EXPECTED:broken.jpg --> <div> - <object data="./broken.jpg" - onerror="document.getElementById('done').innerText='complete'; "> + <object data="./broken.jpg"> Fallback </object> </div>
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc index 3572ec5..6eff45e2 100644 --- a/content/test/test_web_contents.cc +++ b/content/test/test_web_contents.cc
@@ -129,65 +129,6 @@ return WebContentsImpl::GetTitle(); } -void TestWebContents::TestDidNavigate(RenderFrameHost* render_frame_host, - bool did_create_new_entry, - const GURL& url, - ui::PageTransition transition) { - TestDidNavigateWithSequenceNumber(render_frame_host, did_create_new_entry, - url, Referrer(), transition, false, -1, -1); -} - -void TestWebContents::TestDidNavigateWithSequenceNumber( - RenderFrameHost* render_frame_host, - bool did_create_new_entry, - const GURL& url, - const Referrer& referrer, - ui::PageTransition transition, - bool was_within_same_document, - int item_sequence_number, - int document_sequence_number) { - TestRenderFrameHost* rfh = - static_cast<TestRenderFrameHost*>(render_frame_host); - rfh->InitializeRenderFrameIfNeeded(); - - if (!rfh->is_loading()) - rfh->SimulateNavigationStart(url); - - auto params = mojom::DidCommitProvisionalLoadParams::New(); - params->item_sequence_number = item_sequence_number; - params->document_sequence_number = document_sequence_number; - params->url = url; - params->base_url = GURL(); - params->referrer = blink::mojom::Referrer::From(referrer); - params->transition = transition; - params->redirects = std::vector<GURL>(); - params->should_update_history = true; - params->contents_mime_type = std::string("text/html"); - params->intended_as_new_entry = did_create_new_entry; - params->did_create_new_entry = did_create_new_entry; - params->should_replace_current_entry = false; - params->gesture = NavigationGestureUser; - params->method = "GET"; - params->post_id = 0; - params->http_status_code = 200; - params->url_is_unreachable = false; - if (item_sequence_number != -1 && document_sequence_number != -1) { - params->page_state = blink::PageState::CreateForTestingWithSequenceNumbers( - url, item_sequence_number, document_sequence_number); - } else { - params->page_state = blink::PageState::CreateFromURL(url); - } - params->original_request_url = GURL(); - params->is_overriding_user_agent = false; - params->history_list_was_cleared = false; - params->origin = url::Origin::Create(url); - params->insecure_request_policy = - blink::mojom::InsecureRequestPolicy::kLeaveInsecureRequestsAlone; - params->has_potentially_trustworthy_unique_origin = false; - - rfh->SendNavigateWithParams(std::move(params), was_within_same_document); -} - const std::string& TestWebContents::GetSaveFrameHeaders() { return save_frame_headers_; }
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h index 542419f..ec85a99a 100644 --- a/content/test/test_web_contents.h +++ b/content/test/test_web_contents.h
@@ -74,18 +74,6 @@ void NavigateAndFail(const GURL& url, int error_code) override; void TestSetIsLoading(bool value) override; - void TestDidNavigate(RenderFrameHost* render_frame_host, - bool did_create_new_entry, - const GURL& url, - ui::PageTransition transition) override; - void TestDidNavigateWithSequenceNumber(RenderFrameHost* render_frame_host, - bool did_create_new_entry, - const GURL& url, - const Referrer& referrer, - ui::PageTransition transition, - bool was_within_same_document, - int item_sequence_number, - int document_sequence_number); void SetOpener(WebContents* opener) override; const std::string& GetSaveFrameHeaders() override; const base::string16& GetSuggestedFileName() override;
diff --git a/docs/speed_metrics/webperf_okrs.md b/docs/speed_metrics/webperf_okrs.md index 7c9b631..28aa641 100644 --- a/docs/speed_metrics/webperf_okrs.md +++ b/docs/speed_metrics/webperf_okrs.md
@@ -29,6 +29,9 @@ ([bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1091754)). * Present proposal to security team, and begin socializing the proposal externally. * **A/B testing**: organize workshop on client-side A/B testing. +* **JS Sampling Profiler**: + * Complete the GC integration work. + * Ship the API. ## 2020 Q4 Progress @@ -38,6 +41,10 @@ [Intent to Ship](https://groups.google.com/a/chromium.org/g/blink-dev/c/RExJ9a3SmQw). * **Page abandonment**: made some data available publicly and socialized it in a [blogpost](https://calendar.perfplanet.com/2020/abandonment/). +* **JS Sampling Profiler**: + * Implemented the API so it requires COOP/COEP and gated it behind Document Policy. + * Finished a prototype of GC integration for the V8 sampling profiler (which will help reduce profiler startup time). + * Landed some initial support for code object refcounting. * **Smoothness**: published a proposal around dropped frames and presented it at TPAC. * **Back-forward cache**: determined that it is backwards compatible to expose a PerformanceNavigationTiming entry for back-forward navigations.
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn index 6616ad16..f6b7859 100644 --- a/extensions/BUILD.gn +++ b/extensions/BUILD.gn
@@ -305,7 +305,6 @@ "//components/dom_distiller/core:test_support", "//components/guest_view/browser:test_support", "//components/javascript_dialogs", - "//components/printing/common", "//components/resources", "//components/strings", "//components/sync",
diff --git a/extensions/DEPS b/extensions/DEPS index 4d8fbad..dbcdddc2 100644 --- a/extensions/DEPS +++ b/extensions/DEPS
@@ -41,9 +41,6 @@ ".*(test|test_util)\.(cc|h)$": [ "+content/public/test", ], - "mime_handler_view_browsertest.cc": [ - "+components/printing/common", - ], "mime_handler_view_interactive_uitest.cc": [ "+chrome/browser/ui/exclusive_access/exclusive_access_test.h", "+chrome/test/base/interactive_test_utils.h",
diff --git a/extensions/browser/api/automation_internal/automation_internal_api.cc b/extensions/browser/api/automation_internal/automation_internal_api.cc index c028d84..9bed7277 100644 --- a/extensions/browser/api/automation_internal/automation_internal_api.cc +++ b/extensions/browser/api/automation_internal/automation_internal_api.cc
@@ -20,6 +20,7 @@ #include "content/public/browser/browser_plugin_guest_manager.h" #include "content/public/browser/media_player_id.h" #include "content/public/browser/media_session.h" +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_widget_host.h" @@ -132,6 +133,10 @@ } // namespace +using OldAXTreeIdMap = std::map<content::NavigationHandle*, ui::AXTreeID>; +base::LazyInstance<OldAXTreeIdMap>::DestructorAtExit g_old_ax_tree = + LAZY_INSTANCE_INITIALIZER; + // Helper class that receives accessibility data from |WebContents|. class AutomationWebContentsObserver : public content::WebContentsObserver, @@ -154,6 +159,29 @@ router->DispatchAccessibilityEvents(extension_event_bundle); } + void DidStartNavigation(content::NavigationHandle* navigation) override { + content::RenderFrameHost* previous_rfh = content::RenderFrameHost::FromID( + navigation->GetPreviousRenderFrameHostId()); + DCHECK(previous_rfh); + g_old_ax_tree.Get()[navigation] = previous_rfh->GetAXTreeID(); + } + + void DidFinishNavigation(content::NavigationHandle* navigation) override { + ui::AXTreeID old_ax_tree = g_old_ax_tree.Get()[navigation]; + g_old_ax_tree.Get().erase(navigation); + + if (old_ax_tree == ui::AXTreeIDUnknown()) + return; + + ui::AXTreeID new_ax_tree = navigation->GetRenderFrameHost()->GetAXTreeID(); + + if (old_ax_tree == new_ax_tree) + return; + + AutomationEventRouter::GetInstance()->DispatchTreeDestroyedEvent( + old_ax_tree, browser_context_); + } + void AccessibilityLocationChangesReceived( const std::vector<content::AXLocationChangeNotificationDetails>& details) override { @@ -177,19 +205,6 @@ tree_id, browser_context_); } - void RenderFrameHostChanged(content::RenderFrameHost* old_host, - content::RenderFrameHost* new_host) override { - if (!old_host) - return; - - ui::AXTreeID tree_id = old_host->GetAXTreeID(); - if (tree_id == ui::AXTreeIDUnknown()) - return; - - AutomationEventRouter::GetInstance()->DispatchTreeDestroyedEvent( - tree_id, browser_context_); - } - void MediaStartedPlaying(const MediaPlayerInfo& video_type, const content::MediaPlayerId& id) override { content::AXEventNotificationDetails content_event_bundle;
diff --git a/extensions/browser/api/storage/storage_frontend.cc b/extensions/browser/api/storage/storage_frontend.cc index e988e2e..402ede1 100644 --- a/extensions/browser/api/storage/storage_frontend.cc +++ b/extensions/browser/api/storage/storage_frontend.cc
@@ -130,7 +130,7 @@ } void StorageFrontend::Init(scoped_refptr<ValueStoreFactory> factory) { - TRACE_EVENT0("browser,startup", "StorageFrontend::Init") + TRACE_EVENT0("browser,startup", "StorageFrontend::Init"); observers_ = new SettingsObserverList(); browser_context_observer_.reset(new DefaultObserver(browser_context_));
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc index d86ce6e..b281f98 100644 --- a/extensions/browser/extension_prefs.cc +++ b/extensions/browser/extension_prefs.cc
@@ -1993,7 +1993,7 @@ } void ExtensionPrefs::InitPrefStore() { - TRACE_EVENT0("browser,startup", "ExtensionPrefs::InitPrefStore") + TRACE_EVENT0("browser,startup", "ExtensionPrefs::InitPrefStore"); // When this is called, the PrefService is initialized and provides access // to the user preferences stored in a JSON file. @@ -2476,7 +2476,7 @@ void ExtensionPrefs::InitExtensionControlledPrefs( const ExtensionsInfo& extensions_info) { TRACE_EVENT0("browser,startup", - "ExtensionPrefs::InitExtensionControlledPrefs") + "ExtensionPrefs::InitExtensionControlledPrefs"); for (const auto& info : extensions_info) { const ExtensionId& extension_id = info->extension_id;
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc index b8548ad3..3c86e74 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
@@ -21,8 +21,6 @@ #include "components/guest_view/browser/test_guest_view_manager.h" #include "components/javascript_dialogs/app_modal_dialog_controller.h" #include "components/javascript_dialogs/app_modal_dialog_view.h" -#include "components/printing/common/print.mojom.h" -#include "components/printing/common/print_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents_observer.h" @@ -182,60 +180,6 @@ EXPECT_EQ(1U, gv_manager->num_guests_created()); } -#if BUILDFLAG(ENABLE_PRINT_PREVIEW) -class PrintPreviewWaiter : public content::BrowserMessageFilter { - public: - PrintPreviewWaiter() : BrowserMessageFilter(PrintMsgStart) {} - - bool OnMessageReceived(const IPC::Message& message) override { - IPC_BEGIN_MESSAGE_MAP(PrintPreviewWaiter, message) - IPC_MESSAGE_HANDLER(PrintHostMsg_DidStartPreview, OnDidStartPreview) - IPC_END_MESSAGE_MAP() - return false; - } - - void OnDidStartPreview(const printing::mojom::DidStartPreviewParams& params, - const printing::mojom::PreviewIds& ids) { - // Expect that there is at least one page. - did_load_ = true; - run_loop_.Quit(); - - EXPECT_TRUE(params.page_count >= 1); - } - - void Wait() { - if (!did_load_) - run_loop_.Run(); - } - - private: - ~PrintPreviewWaiter() override = default; - - bool did_load_ = false; - base::RunLoop run_loop_; -}; - -IN_PROC_BROWSER_TEST_F(MimeHandlerViewTest, EmbeddedThenPrint) { - RunTest("test_embedded.html"); - ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)); - auto* gv_manager = GetGuestViewManager(); - gv_manager->WaitForAllGuestsDeleted(); - EXPECT_EQ(1U, gv_manager->num_guests_created()); - - // Verify that print dialog comes up. - auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - auto* main_frame = web_contents->GetMainFrame(); - auto print_preview_waiter = base::MakeRefCounted<PrintPreviewWaiter>(); - web_contents->GetMainFrame()->GetProcess()->AddFilter( - print_preview_waiter.get()); - // Use setTimeout() to prevent ExecuteScript() from blocking on the print - // dialog. - ASSERT_TRUE(content::ExecuteScript( - main_frame, "setTimeout(function() { window.print(); }, 0)")); - print_preview_waiter->Wait(); -} -#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) - // This test start with an <object> that has a content frame. Then the content // frame (plugin frame) is navigated to a cross-origin target page. After the // navigation is completed, the <object> is set to render MimeHandlerView by
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc index 998d6d0..dd77a8b9 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
@@ -217,6 +217,7 @@ } void MimeHandlerViewGuest::DidAttachToEmbedder() { + DCHECK(stream_->handler_url().SchemeIs(extensions::kExtensionScheme)); web_contents()->GetController().LoadURL( stream_->handler_url(), content::Referrer(), ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string()); @@ -443,6 +444,18 @@ stream_->TakeTransferrableURLLoader()); } +void MimeHandlerViewGuest::DidFinishNavigation( + content::NavigationHandle* navigation_handle) { + if (navigation_handle->IsInMainFrame()) { + // We should not navigate the guest away from the handling extension. + const url::Origin handler_origin = + url::Origin::Create(stream_->handler_url()); + const url::Origin new_origin = + url::Origin::Create(navigation_handle->GetURL()); + CHECK(new_origin.IsSameOriginWith(handler_origin)); + } +} + void MimeHandlerViewGuest::FuseBeforeUnloadControl( mojo::PendingReceiver<mime_handler::BeforeUnloadControl> receiver) { if (!pending_before_unload_control_)
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h index a7f0b19a8..d9e22ce 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
@@ -175,6 +175,7 @@ void DocumentOnLoadCompletedInMainFrame() final; void ReadyToCommitNavigation( content::NavigationHandle* navigation_handle) final; + void DidFinishNavigation(content::NavigationHandle* navigation_handle) final; std::unique_ptr<MimeHandlerViewGuestDelegate> delegate_; std::unique_ptr<StreamContainer> stream_;
diff --git a/extensions/browser/renderer_startup_helper.cc b/extensions/browser/renderer_startup_helper.cc index 7f9fce0..8b5eb01 100644 --- a/extensions/browser/renderer_startup_helper.cc +++ b/extensions/browser/renderer_startup_helper.cc
@@ -138,8 +138,7 @@ // partition ID to it. std::string webview_partition_id = WebViewGuest::GetPartitionID(process); if (!webview_partition_id.empty()) { - process->Send(new ExtensionMsg_SetWebViewPartitionID( - WebViewGuest::GetPartitionID(process))); + renderer->SetWebViewPartitionID(webview_partition_id); } BrowserContext* renderer_context = process->GetBrowserContext();
diff --git a/extensions/browser/renderer_startup_helper_unittest.cc b/extensions/browser/renderer_startup_helper_unittest.cc index 9be3c1a..9ef927c 100644 --- a/extensions/browser/renderer_startup_helper_unittest.cc +++ b/extensions/browser/renderer_startup_helper_unittest.cc
@@ -57,6 +57,8 @@ void SetSystemFont(const std::string& font_family, const std::string& font_size) override {} + void SetWebViewPartitionID(const std::string& partition_id) override {} + std::vector<std::string> activated_extensions_; std::vector<std::string> unloaded_extensions_; mojo::AssociatedReceiverSet<mojom::Renderer> receivers_;
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h index 45f92c7..17bb559 100644 --- a/extensions/common/extension_messages.h +++ b/extensions/common/extension_messages.h
@@ -720,10 +720,6 @@ IPC_MESSAGE_CONTROL1(ExtensionMsg_TransferBlobs, std::vector<std::string> /* blob_uuids */) -// Report the WebView partition ID to the WebView guest renderer process. -IPC_MESSAGE_CONTROL1(ExtensionMsg_SetWebViewPartitionID, - std::string /* webview_partition_id */) - // Enable or disable spatial navigation. IPC_MESSAGE_ROUTED1(ExtensionMsg_SetSpatialNavigationEnabled, bool /* spatial_nav_enabled */)
diff --git a/extensions/common/mojom/renderer.mojom b/extensions/common/mojom/renderer.mojom index 7b09a73..273d828 100644 --- a/extensions/common/mojom/renderer.mojom +++ b/extensions/common/mojom/renderer.mojom
@@ -33,4 +33,7 @@ // Tells the renderer process the platform's system font. SetSystemFont(string font_family, string font_size); + + // Reports the WebView partition ID to the WebView guest renderer process. + SetWebViewPartitionID(string partition_id); };
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 9dd2d9e..2ad828ee 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -876,8 +876,6 @@ IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchEvent, OnDispatchEvent) IPC_MESSAGE_HANDLER(ExtensionMsg_SetScriptingAllowlist, OnSetScriptingAllowlist) - IPC_MESSAGE_HANDLER(ExtensionMsg_SetWebViewPartitionID, - OnSetWebViewPartitionID) IPC_MESSAGE_HANDLER(ExtensionMsg_ShouldSuspend, OnShouldSuspend) IPC_MESSAGE_HANDLER(ExtensionMsg_Suspend, OnSuspend) IPC_MESSAGE_HANDLER(ExtensionMsg_TransferBlobs, OnTransferBlobs) @@ -1014,6 +1012,12 @@ system_font_size_ = font_size; } +void Dispatcher::SetWebViewPartitionID(const std::string& partition_id) { + // |webview_partition_id_| cannot be changed once set. + CHECK(webview_partition_id_.empty() || webview_partition_id_ == partition_id); + webview_partition_id_ = partition_id; +} + void Dispatcher::OnCancelSuspend(const std::string& extension_id) { DispatchEvent(extension_id, kOnSuspendCanceledEvent, base::ListValue(), nullptr); @@ -1185,12 +1189,6 @@ ExtensionsClient::Get()->SetScriptingAllowlist(extension_ids); } -void Dispatcher::OnSetWebViewPartitionID(const std::string& partition_id) { - // |webview_partition_id_| cannot be changed once set. - CHECK(webview_partition_id_.empty() || webview_partition_id_ == partition_id); - webview_partition_id_ = partition_id; -} - void Dispatcher::OnShouldSuspend(const std::string& extension_id, uint64_t sequence_id) { RenderThread::Get()->Send(
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h index 517422d..a784c3f 100644 --- a/extensions/renderer/dispatcher.h +++ b/extensions/renderer/dispatcher.h
@@ -222,6 +222,7 @@ bool lock_screen_context) override; void SetSystemFont(const std::string& font_family, const std::string& font_size) override; + void SetWebViewPartitionID(const std::string& partition_id) override; void OnRendererAssociatedRequest( mojo::PendingAssociatedReceiver<mojom::Renderer> receiver); void OnCancelSuspend(const std::string& extension_id); @@ -246,7 +247,6 @@ const base::ListValue& event_args); void OnSetScriptingAllowlist( const ExtensionsClient::ScriptingAllowlist& extension_ids); - void OnSetWebViewPartitionID(const std::string& partition_id); void OnShouldSuspend(const std::string& extension_id, uint64_t sequence_id); void OnSuspend(const std::string& extension_id); void OnTransferBlobs(const std::vector<std::string>& blob_uuids);
diff --git a/gpu/OWNERS b/gpu/OWNERS index 1a2f997..6aeb7ec 100644 --- a/gpu/OWNERS +++ b/gpu/OWNERS
@@ -1,6 +1,5 @@ backer@chromium.org kbr@chromium.org -khushalsagar@chromium.org vasilyt@chromium.org vmiura@chromium.org zmo@chromium.org
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm index 2adfdc7..320f71b 100644 --- a/ios/chrome/app/application_delegate/app_state.mm +++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -435,6 +435,8 @@ } _appIsTerminating = YES; + [_appCommandDispatcher prepareForShutdown]; + // Cancel any in-flight distribution notifications. CHECK(ios::GetChromeBrowserProvider()); ios::GetChromeBrowserProvider() @@ -468,6 +470,19 @@ API_AVAILABLE(ios(13)) { NSMutableArray<NSString*>* sessionIDs = [NSMutableArray arrayWithCapacity:sceneSessions.count]; + // This method is invoked by iOS to inform the application that the sessions + // for "closed windows" is garbage collected and that any data associated with + // them by the application needs to be deleted. + // + // Usually Chrome uses -[SceneState sceneSessionID] as identifier to properly + // support devices that do not support multi-window (and which use a constant + // identifier). For devices that do not support multi-window the session is + // saved at a constant path, so it is harmnless to delete files at a path + // derived from -persistentIdentifier (since there won't be files deleted). + // For devices that do support multi-window, there is data to delete once the + // session is garbage collected. + // + // Thus it is always correct to use -persistentIdentifier here. for (UISceneSession* session in sceneSessions) { [sessionIDs addObject:session.persistentIdentifier]; }
diff --git a/ios/chrome/browser/ui/commands/command_dispatcher.h b/ios/chrome/browser/ui/commands/command_dispatcher.h index f9241719..e977b4d 100644 --- a/ios/chrome/browser/ui/commands/command_dispatcher.h +++ b/ios/chrome/browser/ui/commands/command_dispatcher.h
@@ -65,6 +65,13 @@ // otherwise. - (CommandDispatcher*)strictCallableForProtocol:(Protocol*)protocol; +// After this method is called, -stopDispatching methods will stop dispatching, +// but this object will continue to respond to registered selectors by silently +// failing. This method should be called on -applicationWillTerminate. It helps +// avoid untangling the dispatcher chains in the correct order, which sometimes +// can be very hard. +- (void)prepareForShutdown; + @end #endif // IOS_CHROME_BROWSER_UI_COMMANDS_COMMAND_DISPATCHER_H_
diff --git a/ios/chrome/browser/ui/commands/command_dispatcher.mm b/ios/chrome/browser/ui/commands/command_dispatcher.mm index 5e569fca..df679270 100644 --- a/ios/chrome/browser/ui/commands/command_dispatcher.mm +++ b/ios/chrome/browser/ui/commands/command_dispatcher.mm
@@ -15,13 +15,48 @@ #error "This file requires ARC support." #endif +#pragma mark - SilentlyFailingObject + +// Object that responds to any selector and does nothing when its called. +// Used as a "nice OCMock" equivalent for CommandDispatcher that's preparing for +// shutdown. +@interface SilentlyFailingObject : NSProxy +@end +@implementation SilentlyFailingObject + +- (instancetype)init { + return self; +} + +- (void)forwardInvocation:(NSInvocation*)invocation { +} + +- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector { + // Return some method signature to silence errors. + // Here it's (void)(self, _cmd). + return [NSMethodSignature signatureWithObjCTypes:"v@:"]; +} + +@end + +#pragma mark - CommandDispatcher + @implementation CommandDispatcher { // Stores which target to forward to for a given selector. std::unordered_map<SEL, __weak id> _forwardingTargets; + + // Stores remembered targets while preparing for shutdown. + std::unordered_map<SEL, __weak id> _silentlyFailingTargets; + + // Tracks if preparing for shutdown has been requested. + // This is an ivar, not a property, to avoid having synthesized getter/setter + // methods. + BOOL _preparingForShutdown; } - (void)startDispatchingToTarget:(id)target forSelector:(SEL)selector { DCHECK(![self targetForSelector:selector]); + DCHECK(![self shouldFailSilentlyForSelector:selector]); _forwardingTargets[selector] = target; } @@ -40,6 +75,10 @@ } - (void)stopDispatchingForSelector:(SEL)selector { + if (_preparingForShutdown) { + id target = _forwardingTargets[selector]; + _silentlyFailingTargets[selector] = target; + } _forwardingTargets.erase(selector); } @@ -85,7 +124,9 @@ BOOL conforming = YES; for (unsigned int i = 0; i < methodCount; i++) { SEL selector = requiredInstanceMethods[i].name; - if (_forwardingTargets.find(selector) == _forwardingTargets.end()) { + BOOL targetFound = + _forwardingTargets.find(selector) != _forwardingTargets.end(); + if (!targetFound && ![self shouldFailSilentlyForSelector:selector]) { conforming = NO; break; } @@ -114,6 +155,10 @@ return self; } +- (void)prepareForShutdown { + _preparingForShutdown = YES; +} + #pragma mark - NSObject // Overridden to forward messages to registered handlers. @@ -149,9 +194,18 @@ // Returns the target registered to receive messeages for |selector|. - (id)targetForSelector:(SEL)selector { auto target = _forwardingTargets.find(selector); - if (target == _forwardingTargets.end()) + if (target == _forwardingTargets.end()) { + if ([self shouldFailSilentlyForSelector:selector]) { + return [[SilentlyFailingObject alloc] init]; + } return nil; + } return target->second; } +- (BOOL)shouldFailSilentlyForSelector:(SEL)selector { + return _preparingForShutdown && _silentlyFailingTargets.find(selector) != + _silentlyFailingTargets.end(); +} + @end
diff --git a/ios/chrome/browser/ui/commands/command_dispatcher_unittest.mm b/ios/chrome/browser/ui/commands/command_dispatcher_unittest.mm index cee63cd..79d615f 100644 --- a/ios/chrome/browser/ui/commands/command_dispatcher_unittest.mm +++ b/ios/chrome/browser/ui/commands/command_dispatcher_unittest.mm
@@ -355,6 +355,70 @@ EXPECT_TRUE(exception_caught); } +// Tests that an exception is not thrown when prepareForShutdown was called +// before the target was removed. +TEST_F(CommandDispatcherTest, + PrepareForShutdownLetsStopDispatchingForSelectorFailSilently) { + id dispatcher = [[CommandDispatcher alloc] init]; + CommandDispatcherTestSimpleTarget* target = + [[CommandDispatcherTestSimpleTarget alloc] init]; + + // Check stopDispatchingForSelector: + [dispatcher startDispatchingToTarget:target forSelector:@selector(show)]; + [dispatcher prepareForShutdown]; + [dispatcher stopDispatchingForSelector:@selector(show)]; + bool exception_caught = false; + @try { + [dispatcher show]; + } @catch (NSException* exception) { + exception_caught = true; + } + + EXPECT_FALSE(exception_caught); +} + +TEST_F(CommandDispatcherTest, + PrepareForShutdownLetsStopDispatchingForProtocolFailSilently) { + id dispatcher = [[CommandDispatcher alloc] init]; + CommandDispatcherTestSimpleTarget* target = + [[CommandDispatcherTestSimpleTarget alloc] init]; + + // Check stopDispatchingForProtocol: + [dispatcher startDispatchingToTarget:target + forProtocol:@protocol(HideProtocol)]; + [dispatcher prepareForShutdown]; + [dispatcher stopDispatchingForProtocol:@protocol(HideProtocol)]; + bool exception_caught = false; + @try { + [dispatcher hide]; + } @catch (NSException* exception) { + exception_caught = true; + } + + EXPECT_FALSE(exception_caught); +} + +TEST_F(CommandDispatcherTest, + PrepareForShutdownLetsStopDispatchingToTargetFailSilently) { + id dispatcher = [[CommandDispatcher alloc] init]; + CommandDispatcherTestSimpleTarget* target = + [[CommandDispatcherTestSimpleTarget alloc] init]; + + // Check stopDispatchingToTarget: + [dispatcher startDispatchingToTarget:target + forProtocol:@protocol(HideProtocol)]; + [dispatcher prepareForShutdown]; + [dispatcher stopDispatchingToTarget:target]; + bool exception_caught = false; + @try { + [dispatcher hide]; + } @catch (NSException* exception) { + exception_caught = true; + } + + EXPECT_FALSE(exception_caught); +} + // Tests that -respondsToSelector returns YES for methods once they are // dispatched for. // Tests handler methods with no arguments.
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler.mm b/ios/chrome/browser/ui/main/browser_view_wrangler.mm index 9f47e2e..6c57b5f9 100644 --- a/ios/chrome/browser/ui/main/browser_view_wrangler.mm +++ b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
@@ -105,9 +105,6 @@ std::unique_ptr<Browser> _otrBrowser; } -// Opaque session ID from _sceneState, nil when multi-window isn't enabled. -@property(nonatomic, readonly) NSString* sessionID; - @property(nonatomic, strong, readwrite) WrangledBrowser* mainInterface; @property(nonatomic, strong, readwrite) WrangledBrowser* incognitoInterface; @@ -171,16 +168,6 @@ #pragma mark - BrowserViewInformation property implementations -- (NSString*)sessionID { - NSString* sessionID = nil; - if (IsMultiwindowSupported()) { - if (@available(iOS 13, *)) { - sessionID = _sceneState.scene.session.persistentIdentifier; - } - } - return sessionID; -} - - (void)setCurrentInterface:(WrangledBrowser*)interface { DCHECK(interface); // |interface| must be one of the interfaces this class already owns. @@ -325,6 +312,11 @@ DCHECK(!_isShutdown); _isShutdown = YES; + [self.mainBrowser->GetCommandDispatcher() prepareForShutdown]; + if ([self hasIncognitoInterface]) { + [self.otrBrowser->GetCommandDispatcher() prepareForShutdown]; + } + // At this stage, new BrowserCoordinators shouldn't be lazily constructed by // calling their property getters. [_mainBrowserCoordinator stop]; @@ -415,7 +407,7 @@ - (void)setSessionIDForBrowser:(Browser*)browser restoreSession:(BOOL)restoreSession { SnapshotBrowserAgent::FromBrowser(browser)->SetSessionID( - base::SysNSStringToUTF8(self.sessionID)); + base::SysNSStringToUTF8(_sceneState.sceneSessionID)); SessionRestorationBrowserAgent* restorationAgent = SessionRestorationBrowserAgent::FromBrowser(browser); @@ -443,12 +435,13 @@ NSString* previousSessionID = _sceneState.appState.previousSingleWindowSessionID; if (previousSessionID && - ![self.sessionID isEqualToString:previousSessionID]) { + ![_sceneState.sceneSessionID isEqualToString:previousSessionID]) { restorationAgent->SetSessionID( base::SysNSStringToUTF8(previousSessionID)); restorationAgent->RestoreSession(); - restorationAgent->SetSessionID(base::SysNSStringToUTF8(self.sessionID)); + restorationAgent->SetSessionID( + base::SysNSStringToUTF8(_sceneState.sceneSessionID)); restorationAgent->SaveSession(true); // Fallback to the normal codepath. It will set the session identifier @@ -458,7 +451,8 @@ } } - restorationAgent->SetSessionID(base::SysNSStringToUTF8(self.sessionID)); + restorationAgent->SetSessionID( + base::SysNSStringToUTF8(_sceneState.sceneSessionID)); if (restoreSession) restorationAgent->RestoreSession(); }
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index ea407ba..5f3c18a 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -348,7 +348,7 @@ // Add the scene to the list of connected scene, to restore in case of // crashes. [[PreviousSessionInfo sharedInstance] - addSceneSessionID:sceneState.scene.session.persistentIdentifier]; + addSceneSessionID:sceneState.sceneSessionID]; } } } @@ -396,8 +396,7 @@ // If Multiple scenes are not supported, the session shouldn't be // removed as it can be used for normal restoration. [[PreviousSessionInfo sharedInstance] - removeSceneSessionID:sceneState.scene.session - .persistentIdentifier]; + removeSceneSessionID:sceneState.sceneSessionID]; } } }
diff --git a/ios/chrome/browser/ui/main/scene_state.h b/ios/chrome/browser/ui/main/scene_state.h index 2dce073f..b9ece91 100644 --- a/ios/chrome/browser/ui/main/scene_state.h +++ b/ios/chrome/browser/ui/main/scene_state.h
@@ -76,7 +76,8 @@ @property(nonatomic, strong, readonly) id<BrowserInterfaceProvider> interfaceProvider; -// The persistent identifier for the scene session. +// The persistent identifier for the scene session. This should be used instead +// of -[UISceneSession persistentIdentifier]. @property(nonatomic, readonly) NSString* sceneSessionID; // True if First Run UI (terms of service & sync sign-in) is being presented
diff --git a/ios/chrome/browser/ui/main/scene_state.mm b/ios/chrome/browser/ui/main/scene_state.mm index 7af9df66..86b0a12 100644 --- a/ios/chrome/browser/ui/main/scene_state.mm +++ b/ios/chrome/browser/ui/main/scene_state.mm
@@ -130,7 +130,9 @@ - (NSString*)sceneSessionID { NSString* sessionID = nil; if (@available(ios 13, *)) { - sessionID = _scene.session.persistentIdentifier; + if (IsMultiwindowSupported()) { + sessionID = _scene.session.persistentIdentifier; + } } return sessionID; }
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn index 153627e..8d0147a 100644 --- a/media/capture/BUILD.gn +++ b/media/capture/BUILD.gn
@@ -190,6 +190,8 @@ "video/mac/video_capture_device_factory_mac.mm", "video/mac/video_capture_device_mac.h", "video/mac/video_capture_device_mac.mm", + "video/mac/video_capture_metrics_mac.h", + "video/mac/video_capture_metrics_mac.mm", ] deps += [ "//services/video_capture/public/uma", @@ -493,6 +495,7 @@ "video/mac/video_capture_device_avfoundation_mac_unittest.mm", "video/mac/video_capture_device_factory_mac_unittest.mm", "video/mac/video_capture_device_mac_unittest.mm", + "video/mac/video_capture_metrics_mac_unittest.mm", ] frameworks = [ "AVFoundation.framework", @@ -500,6 +503,7 @@ "CoreVideo.framework", "IOSurface.framework", ] + deps += [ "//third_party/ocmock" ] } if (is_win) {
diff --git a/media/capture/video/mac/DEPS b/media/capture/video/mac/DEPS index 577e795b..b17486db 100644 --- a/media/capture/video/mac/DEPS +++ b/media/capture/video/mac/DEPS
@@ -2,3 +2,9 @@ "+third_party/decklink", "+services/video_capture/public/uma", ] + +specific_include_rules = { +"video_capture_metrics_mac_unittest.mm": [ + "+third_party/ocmock" +] +}
diff --git a/media/capture/video/mac/video_capture_device_avfoundation_mac.h b/media/capture/video/mac/video_capture_device_avfoundation_mac.h index 120f8c6..4e8f82c6 100644 --- a/media/capture/video/mac/video_capture_device_avfoundation_mac.h +++ b/media/capture/video/mac/video_capture_device_avfoundation_mac.h
@@ -53,6 +53,7 @@ base::Lock _lock; media::VideoCaptureDeviceAVFoundationFrameReceiver* _frameReceiver GUARDED_BY(_lock); // weak. + bool _capturedFirstFrame GUARDED_BY(_lock); base::scoped_nsobject<AVCaptureSession> _captureSession;
diff --git a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm index 1ea68ad..f7574a1 100644 --- a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm +++ b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
@@ -23,6 +23,7 @@ #import "media/capture/video/mac/video_capture_device_avfoundation_utils_mac.h" #include "media/capture/video/mac/video_capture_device_factory_mac.h" #include "media/capture/video/mac/video_capture_device_mac.h" +#import "media/capture/video/mac/video_capture_metrics_mac.h" #include "media/capture/video_capture_types.h" #include "services/video_capture/public/uma/video_capture_service_event.h" #include "ui/gfx/geometry/size.h" @@ -162,6 +163,7 @@ DISPATCH_QUEUE_SERIAL), base::scoped_policy::ASSUME); DCHECK(frameReceiver); + _capturedFirstFrame = false; _weakPtrFactoryForTakePhoto = std::make_unique<base::WeakPtrFactory<VideoCaptureDeviceAVFoundation>>( self); @@ -350,6 +352,8 @@ } } + base::AutoLock lock(_lock); + _capturedFirstFrame = false; return YES; } @@ -692,6 +696,10 @@ return; const base::TimeDelta timestamp = GetCMSampleBufferTimestamp(sampleBuffer); + bool logUma = !std::exchange(_capturedFirstFrame, true); + if (logUma) { + media::LogFirstCapturedVideoFrame(_bestCaptureFormat, sampleBuffer); + } // The SampleBufferTransformer CHECK-crashes if the sample buffer is not MJPEG // and does not have a pixel buffer (https://crbug.com/1160647) so we fall
diff --git a/media/capture/video/mac/video_capture_metrics_mac.h b/media/capture/video/mac/video_capture_metrics_mac.h new file mode 100644 index 0000000..c56789a --- /dev/null +++ b/media/capture/video/mac/video_capture_metrics_mac.h
@@ -0,0 +1,23 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_CAPTURE_VIDEO_MAC_VIDEO_CAPTURE_METRICS_MAC_H_ +#define MEDIA_CAPTURE_VIDEO_MAC_VIDEO_CAPTURE_METRICS_MAC_H_ + +#import <AVFoundation/AVFoundation.h> +#include <CoreMedia/CoreMedia.h> +#import <Foundation/Foundation.h> + +#include "media/capture/capture_export.h" +#include "ui/gfx/geometry/size.h" + +namespace media { + +CAPTURE_EXPORT +void LogFirstCapturedVideoFrame(const AVCaptureDeviceFormat* bestCaptureFormat, + const CMSampleBufferRef buffer); + +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_MAC_VIDEO_CAPTURE_METRICS_MAC_H_ \ No newline at end of file
diff --git a/media/capture/video/mac/video_capture_metrics_mac.mm b/media/capture/video/mac/video_capture_metrics_mac.mm new file mode 100644 index 0000000..9c6a64d --- /dev/null +++ b/media/capture/video/mac/video_capture_metrics_mac.mm
@@ -0,0 +1,88 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "media/capture/video/mac/video_capture_metrics_mac.h" + +#include "base/metrics/histogram_functions.h" +#import "media/capture/video/mac/video_capture_device_avfoundation_mac.h" +#include "media/capture/video/video_capture_device_info.h" + +namespace media { + +namespace { + +enum class ResolutionComparison { + kWidthGtHeightEq = 0, + kWidthLtHeightEq = 1, + kWidthEqHeightGt = 2, + kWidthEqHeightLt = 3, + kEq = 4, + kWidthGtHeightGt = 5, + kWidthLtHeightGt = 6, + kWidthGtHeightLt = 7, + kWidthLtHeightLt = 8, + kMaxValue = kWidthLtHeightLt, +}; + +ResolutionComparison CompareDimensions(const CMVideoDimensions& requested, + const CMVideoDimensions& captured) { + if (requested.width > captured.width) { + if (requested.height > captured.height) + return ResolutionComparison::kWidthGtHeightGt; + if (requested.height < captured.height) + return ResolutionComparison::kWidthGtHeightLt; + return ResolutionComparison::kWidthGtHeightEq; + } else if (requested.width < captured.width) { + if (requested.height > captured.height) + return ResolutionComparison::kWidthLtHeightGt; + if (requested.height < captured.height) + return ResolutionComparison::kWidthLtHeightLt; + return ResolutionComparison::kWidthLtHeightEq; + } else { + if (requested.height > captured.height) + return ResolutionComparison::kWidthEqHeightGt; + if (requested.height < captured.height) + return ResolutionComparison::kWidthEqHeightLt; + return ResolutionComparison::kEq; + } +} + +} // namespace + +void LogFirstCapturedVideoFrame(const AVCaptureDeviceFormat* bestCaptureFormat, + const CMSampleBufferRef buffer) { + if (bestCaptureFormat) { + const CMFormatDescriptionRef requestedFormat = + [bestCaptureFormat formatDescription]; + base::UmaHistogramEnumeration( + "Media.VideoCapture.Mac.Device.RequestedPixelFormat", + [VideoCaptureDeviceAVFoundation + FourCCToChromiumPixelFormat:CMFormatDescriptionGetMediaSubType( + requestedFormat)], + media::VideoPixelFormat::PIXEL_FORMAT_MAX); + + if (buffer) { + const CMFormatDescriptionRef capturedFormat = + CMSampleBufferGetFormatDescription(buffer); + base::UmaHistogramBoolean( + "Media.VideoCapture.Mac.Device.CapturedWithRequestedPixelFormat", + CMFormatDescriptionGetMediaSubType(capturedFormat) == + CMFormatDescriptionGetMediaSubType(requestedFormat)); + base::UmaHistogramEnumeration( + "Media.VideoCapture.Mac.Device.CapturedWithRequestedResolution", + CompareDimensions( + CMVideoFormatDescriptionGetDimensions(requestedFormat), + CMVideoFormatDescriptionGetDimensions(capturedFormat))); + + const CVPixelBufferRef pixelBufferRef = + CMSampleBufferGetImageBuffer(buffer); + bool is_io_sufrace = + pixelBufferRef && CVPixelBufferGetIOSurface(pixelBufferRef); + base::UmaHistogramBoolean( + "Media.VideoCapture.Mac.Device.CapturedIOSurface", is_io_sufrace); + } + } +} + +} // namespace media \ No newline at end of file
diff --git a/media/capture/video/mac/video_capture_metrics_mac_unittest.mm b/media/capture/video/mac/video_capture_metrics_mac_unittest.mm new file mode 100644 index 0000000..205b20e --- /dev/null +++ b/media/capture/video/mac/video_capture_metrics_mac_unittest.mm
@@ -0,0 +1,87 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "media/capture/video/mac/video_capture_metrics_mac.h" + +#import <AVFoundation/AVFoundation.h> +#include <CoreMedia/CoreMedia.h> +#import <Foundation/Foundation.h> + +#include "base/mac/scoped_cftyperef.h" +#include "base/test/metrics/histogram_tester.h" +#include "media/base/video_types.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#import "third_party/ocmock/OCMock/OCMock.h" +#include "third_party/ocmock/gtest_support.h" + +namespace media { + +namespace {} // namespace + +TEST(VideoCaptureMetricsMacTest, NoMetricsLoggedIfNullRequestedCaptureFormat) { + base::HistogramTester histogram_tester; + LogFirstCapturedVideoFrame(nullptr, nullptr); + EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix("Media."), + testing::IsEmpty()); +} + +TEST(VideoCaptureMetricsMacTest, LogRequestedPixelFormat) { + base::HistogramTester histogram_tester; + + base::ScopedCFTypeRef<CMFormatDescriptionRef> requested_format; + OSStatus status = CMVideoFormatDescriptionCreate( + kCFAllocatorDefault, + kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange /*NV12*/, 320, 180, + nullptr, requested_format.InitializeInto()); + ASSERT_EQ(0, status); + id capture_format = OCMClassMock([AVCaptureDeviceFormat class]); + OCMStub([capture_format formatDescription]).andReturn(requested_format.get()); + + LogFirstCapturedVideoFrame(capture_format, nullptr); + EXPECT_THAT(histogram_tester.GetAllSamples( + "Media.VideoCapture.Mac.Device.RequestedPixelFormat"), + testing::UnorderedElementsAre( + base::Bucket(VideoPixelFormat::PIXEL_FORMAT_NV12, 1))); +} + +TEST(VideoCaptureMetricsMacTest, LogFirstFrameWhenAsRequested) { + base::HistogramTester histogram_tester; + + base::ScopedCFTypeRef<CMFormatDescriptionRef> requested_format; + OSStatus status = CMVideoFormatDescriptionCreate( + kCFAllocatorDefault, + kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange /*NV12*/, 320, 180, + nullptr, requested_format.InitializeInto()); + ASSERT_EQ(0, status); + id capture_format = OCMClassMock([AVCaptureDeviceFormat class]); + OCMStub([capture_format formatDescription]).andReturn(requested_format.get()); + + // First frame equal. + base::ScopedCFTypeRef<CMSampleBufferRef> first_frame; + status = CMSampleBufferCreate(kCFAllocatorDefault, nullptr, false, nullptr, + nullptr, requested_format, 0, 0, nullptr, 0, + nullptr, first_frame.InitializeInto()); + ASSERT_EQ(0, status); + + LogFirstCapturedVideoFrame(capture_format, first_frame); + + EXPECT_THAT(histogram_tester.GetAllSamples( + "Media.VideoCapture.Mac.Device.RequestedPixelFormat"), + testing::UnorderedElementsAre( + base::Bucket(VideoPixelFormat::PIXEL_FORMAT_NV12, 1))); + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Media.VideoCapture.Mac.Device.CapturedWithRequestedPixelFormat"), + testing::UnorderedElementsAre(base::Bucket(1, 1))); + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Media.VideoCapture.Mac.Device.CapturedWithRequestedResolution"), + testing::UnorderedElementsAre(base::Bucket(4, 1))); + EXPECT_THAT(histogram_tester.GetAllSamples( + "Media.VideoCapture.Mac.Device.CapturedIOSurface"), + testing::UnorderedElementsAre(base::Bucket(0, 1))); +} + +} // namespace media
diff --git a/net/dns/dns_config_service.cc b/net/dns/dns_config_service.cc index 88ba349a..3ae325c 100644 --- a/net/dns/dns_config_service.cc +++ b/net/dns/dns_config_service.cc
@@ -70,8 +70,8 @@ NOTREACHED(); } -DnsConfigService::Watcher::Watcher(DnsConfigService* service) - : service_(service) {} +DnsConfigService::Watcher::Watcher(DnsConfigService& service) + : service_(&service) {} DnsConfigService::Watcher::~Watcher() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -92,31 +92,41 @@ } DnsConfigService::HostsReader::HostsReader( - DnsConfigService* service, - base::FilePath::StringPieceType hosts_file_path) - : service_(service), hosts_file_path_(hosts_file_path) {} + base::FilePath::StringPieceType hosts_file_path, + DnsConfigService& service) + : service_(&service), hosts_file_path_(hosts_file_path) {} DnsConfigService::HostsReader::~HostsReader() = default; -bool DnsConfigService::HostsReader::ReadHosts(DnsHosts* out_dns_hosts) { +base::Optional<DnsHosts> DnsConfigService::HostsReader::ReadHosts() { base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::MAY_BLOCK); DCHECK(!hosts_file_path_.empty()); - return ParseHostsFile(hosts_file_path_, out_dns_hosts); + DnsHosts dns_hosts; + if (!ParseHostsFile(hosts_file_path_, &dns_hosts)) + return base::nullopt; + + return dns_hosts; } -bool DnsConfigService::HostsReader::AddAdditionalHostsTo(DnsHosts& dns_hosts) { +bool DnsConfigService::HostsReader::AddAdditionalHostsTo( + DnsHosts& in_out_dns_hosts) { // Nothing to add in base implementation. return true; } void DnsConfigService::HostsReader::DoWork() { - success_ = ReadHosts(&hosts_) && AddAdditionalHostsTo(hosts_); + hosts_ = ReadHosts(); + if (!hosts_.has_value()) + return; + + if (!AddAdditionalHostsTo(hosts_.value())) + hosts_.reset(); } void DnsConfigService::HostsReader::OnWorkFinished() { - if (success_) { - service_->OnHostsRead(hosts_); + if (hosts_.has_value()) { + service_->OnHostsRead(std::move(hosts_).value()); } else { LOG(WARNING) << "Failed to read DnsHosts."; } @@ -128,7 +138,7 @@ if (!hosts_reader_) { DCHECK(!hosts_file_path_.empty()); hosts_reader_ = - base::MakeRefCounted<HostsReader>(this, hosts_file_path_.value()); + base::MakeRefCounted<HostsReader>(hosts_file_path_.value(), *this); } hosts_reader_->WorkNow(); } @@ -149,7 +159,7 @@ StartTimer(); } -void DnsConfigService::OnConfigRead(const DnsConfig& config) { +void DnsConfigService::OnConfigRead(DnsConfig config) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(config.IsValid()); @@ -163,11 +173,11 @@ OnCompleteConfig(); } -void DnsConfigService::OnHostsRead(const DnsHosts& hosts) { +void DnsConfigService::OnHostsRead(DnsHosts hosts) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (hosts != dns_config_.hosts) { - dns_config_.hosts = hosts; + dns_config_.hosts = std::move(hosts); need_update_ = true; }
diff --git a/net/dns/dns_config_service.h b/net/dns/dns_config_service.h index 3e953c8..d674225 100644 --- a/net/dns/dns_config_service.h +++ b/net/dns/dns_config_service.h
@@ -80,7 +80,7 @@ public: // `service` is expected to own the created Watcher and thus stay valid for // the lifetime of the created Watcher. - explicit Watcher(DnsConfigService* service); + explicit Watcher(DnsConfigService& service); virtual ~Watcher(); Watcher(const Watcher&) = delete; @@ -108,11 +108,13 @@ // Reader of HOSTS files. In this base implementation, uses standard logic // appropriate to most platforms to read the HOSTS file located at - // `service->GetHostsFilePath()`. + // `hosts_file_path`. class HostsReader : public SerialWorker { public: - HostsReader(DnsConfigService* service, - base::FilePath::StringPieceType hosts_file_path); + // `service` is expected to own the created reader and thus stay valid for + // the lifetime of the created reader. + HostsReader(base::FilePath::StringPieceType hosts_file_path, + DnsConfigService& service); HostsReader(const HostsReader&) = delete; HostsReader& operator=(const HostsReader&) = delete; @@ -120,19 +122,19 @@ protected: ~HostsReader() override; - // Reads the HOSTS file and parses to a `DnsHosts`. Returns false on + // Reads the HOSTS file and parses to a `DnsHosts`. Returns nullopt on // failure. Will be called on a separate blockable ThreadPool thread. // // Override if needed to implement platform-specific behavior, e.g. for a // platform-specific HOSTS format. - virtual bool ReadHosts(DnsHosts* out_dns_hosts); + virtual base::Optional<DnsHosts> ReadHosts(); // Adds any necessary additional entries to the given `DnsHosts`. Returns // false on failure. Will be called on a separate blockable ThreadPool // thread. // // Override if needed to implement platform-specific behavior. - virtual bool AddAdditionalHostsTo(DnsHosts& dns_hosts); + virtual bool AddAdditionalHostsTo(DnsHosts& in_out_dns_hosts); // SerialWorker: void DoWork() final; @@ -144,8 +146,7 @@ // running on worker thread. DnsConfigService* const service_; // Written in DoWork, read in OnWorkFinished, no locking necessary. - DnsHosts hosts_; - bool success_ = false; + base::Optional<DnsHosts> hosts_; const base::FilePath hosts_file_path_; }; @@ -162,9 +163,9 @@ void InvalidateHosts(); // Called with new config. |config|.hosts is ignored. - void OnConfigRead(const DnsConfig& config); + void OnConfigRead(DnsConfig config); // Called with new hosts. Rest of the config is assumed unchanged. - void OnHostsRead(const DnsHosts& hosts); + void OnHostsRead(DnsHosts hosts); SEQUENCE_CHECKER(sequence_checker_);
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc index b50f468..3ab9e10 100644 --- a/net/dns/dns_config_service_posix.cc +++ b/net/dns/dns_config_service_posix.cc
@@ -7,6 +7,7 @@ #include <memory> #include <string> #include <type_traits> +#include <utility> #include "base/bind.h" #include "base/files/file.h" @@ -15,6 +16,7 @@ #include "base/lazy_instance.h" #include "base/location.h" #include "base/logging.h" +#include "base/optional.h" #include "base/sequence_checker.h" #include "base/single_thread_task_runner.h" #include "base/threading/scoped_blocking_call.h" @@ -143,24 +145,24 @@ } #endif // defined(OS_ANDROID) -bool ReadDnsConfig(DnsConfig* dns_config) { +base::Optional<DnsConfig> ReadDnsConfig() { base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::MAY_BLOCK); - dns_config->unhandled_options = false; + #if !defined(OS_ANDROID) - bool success = false; + base::Optional<DnsConfig> dns_config; // TODO(fuchsia): Use res_ninit() when it's implemented on Fuchsia. #if defined(OS_OPENBSD) || defined(OS_FUCHSIA) // Note: res_ninit in glibc always returns 0 and sets RES_INIT. // res_init behaves the same way. memset(&_res, 0, sizeof(_res)); if (res_init() == 0) - success = ConvertResStateToDnsConfig(_res, dns_config); + dns_config = ConvertResStateToDnsConfig(_res); #else // all other OS_POSIX struct __res_state res; memset(&res, 0, sizeof(res)); if (res_ninit(&res) == 0) - success = ConvertResStateToDnsConfig(res, dns_config); + dns_config = ConvertResStateToDnsConfig(res); // Prefer res_ndestroy where available. #if defined(OS_APPLE) || defined(OS_FREEBSD) res_ndestroy(&res); @@ -169,26 +171,34 @@ #endif // defined(OS_APPLE) || defined(OS_FREEBSD) #endif // defined(OS_OPENBSD) + if (!dns_config.has_value()) + return dns_config; + #if defined(OS_MAC) - if (!DnsConfigWatcher::CheckDnsConfig(&dns_config->unhandled_options)) - return false; + if (!DnsConfigWatcher::CheckDnsConfig( + dns_config->unhandled_options /* out_unhandled_options */)) { + return base::nullopt; + } #endif // defined(OS_MAC) // Override |fallback_period| value to match default setting on Windows. dns_config->fallback_period = kDnsDefaultFallbackPeriod; - return success; + return dns_config; #else // defined(OS_ANDROID) - dns_config->nameservers.clear(); + DnsConfig dns_config; if (base::android::BuildInfo::GetInstance()->sdk_int() >= base::android::SDK_VERSION_MARSHMALLOW) { - return net::android::GetDnsServers(&dns_config->nameservers, - &dns_config->dns_over_tls_active, - &dns_config->dns_over_tls_hostname); + if (net::android::GetDnsServers(&dns_config.nameservers, + &dns_config.dns_over_tls_active, + &dns_config.dns_over_tls_hostname)) { + return dns_config; + } + return base::nullopt; } if (IsVpnPresent()) { - dns_config->unhandled_options = true; - return true; + dns_config.unhandled_options = true; + return dns_config; } // NOTE(pauljensen): __system_property_get and the net.dns1/2 properties are @@ -200,25 +210,25 @@ __system_property_get("net.dns2", property_value); std::string dns2_string = property_value; if (dns1_string.empty() && dns2_string.empty()) - return false; + return base::nullopt; IPAddress dns1_address; IPAddress dns2_address; bool parsed1 = dns1_address.AssignFromIPLiteral(dns1_string); bool parsed2 = dns2_address.AssignFromIPLiteral(dns2_string); if (!parsed1 && !parsed2) - return false; + return base::nullopt; if (parsed1) { IPEndPoint dns1(dns1_address, dns_protocol::kDefaultPort); - dns_config->nameservers.push_back(dns1); + dns_config.nameservers.push_back(dns1); } if (parsed2) { IPEndPoint dns2(dns2_address, dns_protocol::kDefaultPort); - dns_config->nameservers.push_back(dns2); + dns_config.nameservers.push_back(dns2); } - return true; + return dns_config; #endif // !defined(OS_ANDROID) } @@ -226,7 +236,7 @@ class DnsConfigServicePosix::Watcher : public DnsConfigService::Watcher { public: - explicit Watcher(DnsConfigServicePosix* service) + explicit Watcher(DnsConfigServicePosix& service) : DnsConfigService::Watcher(service) {} ~Watcher() override = default; @@ -274,19 +284,18 @@ // net.dns1 and net.dns2; see #if around ReadDnsConfig above.) class DnsConfigServicePosix::ConfigReader : public SerialWorker { public: - explicit ConfigReader(DnsConfigServicePosix* service) - : service_(service), success_(false) { + explicit ConfigReader(DnsConfigServicePosix& service) : service_(&service) { // Allow execution on another thread; nothing thread-specific about // constructor. DETACH_FROM_SEQUENCE(sequence_checker_); } - void DoWork() override { success_ = ReadDnsConfig(&dns_config_); } + void DoWork() override { dns_config_ = ReadDnsConfig(); } void OnWorkFinished() override { DCHECK(!IsCancelled()); - if (success_) { - service_->OnConfigRead(dns_config_); + if (dns_config_.has_value()) { + service_->OnConfigRead(std::move(dns_config_).value()); } else { LOG(WARNING) << "Failed to read DnsConfig."; } @@ -300,8 +309,7 @@ // on worker thread. DnsConfigServicePosix* const service_; // Written in DoWork, read in OnWorkFinished, no locking necessary. - DnsConfig dns_config_; - bool success_; + base::Optional<DnsConfig> dns_config_; DISALLOW_COPY_AND_ASSIGN(ConfigReader); }; @@ -330,25 +338,24 @@ bool DnsConfigServicePosix::StartWatching() { CreateReader(); // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 - watcher_.reset(new Watcher(this)); + watcher_ = std::make_unique<Watcher>(*this); return watcher_->Watch(); } void DnsConfigServicePosix::CreateReader() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!config_reader_); - config_reader_ = base::MakeRefCounted<ConfigReader>(this); + config_reader_ = base::MakeRefCounted<ConfigReader>(*this); } #if !defined(OS_ANDROID) -bool ConvertResStateToDnsConfig(const struct __res_state& res, - DnsConfig* dns_config) { - DCHECK(dns_config); +base::Optional<DnsConfig> ConvertResStateToDnsConfig( + const struct __res_state& res) { + DnsConfig dns_config; + dns_config.unhandled_options = false; if (!(res.options & RES_INIT)) - return false; - - dns_config->nameservers.clear(); + return base::nullopt; #if defined(OS_APPLE) || defined(OS_FREEBSD) union res_sockaddr_union addresses[MAXNS]; @@ -360,9 +367,9 @@ if (!ipe.FromSockAddr( reinterpret_cast<const struct sockaddr*>(&addresses[i]), sizeof addresses[i])) { - return false; + return base::nullopt; } - dns_config->nameservers.push_back(ipe); + dns_config.nameservers.push_back(ipe); } #elif defined(OS_LINUX) || defined(OS_CHROMEOS) static_assert(std::extent<decltype(res.nsaddr_list)>() >= MAXNS && @@ -383,11 +390,11 @@ addr = reinterpret_cast<const struct sockaddr*>(res._u._ext.nsaddrs[i]); addr_len = sizeof *res._u._ext.nsaddrs[i]; } else { - return false; + return base::nullopt; } if (!ipe.FromSockAddr(addr, addr_len)) - return false; - dns_config->nameservers.push_back(ipe); + return base::nullopt; + dns_config.nameservers.push_back(ipe); } #else // !(defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_APPLE) || // defined(OS_FREEBSD)) @@ -397,22 +404,22 @@ if (!ipe.FromSockAddr( reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]), sizeof res.nsaddr_list[i])) { - return false; + return base::nullopt; } - dns_config->nameservers.push_back(ipe); + dns_config.nameservers.push_back(ipe); } #endif // defined(OS_APPLE) || defined(OS_FREEBSD) - dns_config->search.clear(); + dns_config.search.clear(); for (int i = 0; (i < MAXDNSRCH) && res.dnsrch[i]; ++i) { - dns_config->search.push_back(std::string(res.dnsrch[i])); + dns_config.search.emplace_back(res.dnsrch[i]); } - dns_config->ndots = res.ndots; - dns_config->fallback_period = base::TimeDelta::FromSeconds(res.retrans); - dns_config->attempts = res.retry; + dns_config.ndots = res.ndots; + dns_config.fallback_period = base::TimeDelta::FromSeconds(res.retrans); + dns_config.attempts = res.retry; #if defined(RES_ROTATE) - dns_config->rotate = res.options & RES_ROTATE; + dns_config.rotate = res.options & RES_ROTATE; #endif #if !defined(RES_USE_DNSSEC) // Some versions of libresolv don't have support for the DO bit. In this @@ -424,26 +431,26 @@ // cannot be overwritten by /etc/resolv.conf const unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH; if ((res.options & kRequiredOptions) != kRequiredOptions) { - dns_config->unhandled_options = true; - return true; + dns_config.unhandled_options = true; + return dns_config; } const unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC; if (res.options & kUnhandledOptions) { - dns_config->unhandled_options = true; - return true; + dns_config.unhandled_options = true; + return dns_config; } - if (dns_config->nameservers.empty()) - return false; + if (dns_config.nameservers.empty()) + return base::nullopt; // If any name server is 0.0.0.0, assume the configuration is invalid. // TODO(szym): Measure how often this happens. http://crbug.com/125599 - for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) { - if (dns_config->nameservers[i].address().IsZero()) - return false; + for (const IPEndPoint& nameserver : dns_config.nameservers) { + if (nameserver.address().IsZero()) + return base::nullopt; } - return true; + return dns_config; } #endif // !defined(OS_ANDROID)
diff --git a/net/dns/dns_config_service_posix.h b/net/dns/dns_config_service_posix.h index 3f31069a..16e83422 100644 --- a/net/dns/dns_config_service_posix.h +++ b/net/dns/dns_config_service_posix.h
@@ -59,11 +59,9 @@ }; #if !defined(OS_ANDROID) -// Fills in |dns_config| from |res|. Returns false iff a valid config could not -// be determined. -bool NET_EXPORT_PRIVATE -ConvertResStateToDnsConfig(const struct __res_state& res, - DnsConfig* dns_config); +// Returns nullopt iff a valid config could not be determined. +base::Optional<DnsConfig> NET_EXPORT_PRIVATE +ConvertResStateToDnsConfig(const struct __res_state& res); #endif } // namespace internal
diff --git a/net/dns/dns_config_service_posix_unittest.cc b/net/dns/dns_config_service_posix_unittest.cc index da0c68e..af6b58c 100644 --- a/net/dns/dns_config_service_posix_unittest.cc +++ b/net/dns/dns_config_service_posix_unittest.cc
@@ -8,6 +8,7 @@ #include "base/cancelable_callback.h" #include "base/files/file_util.h" +#include "base/optional.h" #include "base/run_loop.h" #include "base/sequenced_task_runner.h" #include "base/stl_util.h" @@ -146,17 +147,16 @@ TEST(DnsConfigServicePosixTest, ConvertResStateToDnsConfig) { struct __res_state res; - DnsConfig config; - EXPECT_FALSE(config.IsValid()); InitializeResState(&res); - ASSERT_TRUE(internal::ConvertResStateToDnsConfig(res, &config)); + base::Optional<DnsConfig> config = internal::ConvertResStateToDnsConfig(res); CloseResState(&res); - EXPECT_TRUE(config.IsValid()); + ASSERT_TRUE(config.has_value()); + EXPECT_TRUE(config->IsValid()); DnsConfig expected_config; - EXPECT_FALSE(expected_config.EqualsIgnoreHosts(config)); + EXPECT_FALSE(expected_config.EqualsIgnoreHosts(config.value())); InitializeExpectedConfig(&expected_config); - EXPECT_TRUE(expected_config.EqualsIgnoreHosts(config)); + EXPECT_TRUE(expected_config.EqualsIgnoreHosts(config.value())); } TEST(DnsConfigServicePosixTest, RejectEmptyNameserver) { @@ -175,12 +175,11 @@ res.nsaddr_list[1] = sa; res.nscount = 2; - DnsConfig config; - EXPECT_FALSE(internal::ConvertResStateToDnsConfig(res, &config)); + EXPECT_FALSE(internal::ConvertResStateToDnsConfig(res)); sa.sin_addr.s_addr = 0xDEADBEEF; res.nsaddr_list[0] = sa; - EXPECT_TRUE(internal::ConvertResStateToDnsConfig(res, &config)); + EXPECT_TRUE(internal::ConvertResStateToDnsConfig(res)); } TEST(DnsConfigServicePosixTest, DestroyWhileJobsWorking) {
diff --git a/net/dns/dns_config_service_win.cc b/net/dns/dns_config_service_win.cc index e06fb4c..f073bd1 100644 --- a/net/dns/dns_config_service_win.cc +++ b/net/dns/dns_config_service_win.cc
@@ -74,42 +74,53 @@ // Convenience for reading values using RegKey. class RegistryReader { public: - explicit RegistryReader(const wchar_t* key) { + explicit RegistryReader(const wchar_t key[]) { // Ignoring the result. |key_.Valid()| will catch failures. key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE); } ~RegistryReader() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } - bool ReadString(const wchar_t* name, - DnsSystemSettings::RegString* out) const { + base::Optional<DnsSystemSettings::RegString> ReadString( + const wchar_t name[]) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - out->set = false; + DnsSystemSettings::RegString reg_string; + reg_string.set = false; if (!key_.Valid()) { // Assume that if the |key_| is invalid then the key is missing. - return true; + return reg_string; } - LONG result = key_.ReadValue(name, &out->value); + LONG result = key_.ReadValue(name, ®_string.value); if (result == ERROR_SUCCESS) { - out->set = true; - return true; + reg_string.set = true; + return reg_string; } - return (result == ERROR_FILE_NOT_FOUND); + + if (result == ERROR_FILE_NOT_FOUND) + return reg_string; + + return base::nullopt; } - bool ReadDword(const wchar_t* name, DnsSystemSettings::RegDword* out) const { + base::Optional<DnsSystemSettings::RegDword> ReadDword( + const wchar_t name[]) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - out->set = false; + DnsSystemSettings::RegDword reg_dword; + reg_dword.set = false; if (!key_.Valid()) { // Assume that if the |key_| is invalid then the key is missing. - return true; + return reg_dword; } - LONG result = key_.ReadValueDW(name, &out->value); + LONG result = key_.ReadValueDW(name, ®_dword.value); if (result == ERROR_SUCCESS) { - out->set = true; - return true; + reg_dword.set = true; + return reg_dword; } - return (result == ERROR_FILE_NOT_FOUND); + + if (result == ERROR_FILE_NOT_FOUND) + return reg_dword; + + return base::nullopt; } private: @@ -141,22 +152,35 @@ return out; } -bool ReadDevolutionSetting(const RegistryReader& reader, - DnsSystemSettings::DevolutionSetting* setting) { - return reader.ReadDword(L"UseDomainNameDevolution", &setting->enabled) && - reader.ReadDword(L"DomainNameDevolutionLevel", &setting->level); +base::Optional<DnsSystemSettings::DevolutionSetting> ReadDevolutionSetting( + const RegistryReader& reader) { + DnsSystemSettings::DevolutionSetting setting; + + base::Optional<DnsSystemSettings::RegDword> reg_value = + reader.ReadDword(L"UseDomainNameDevolution"); + if (!reg_value) + return base::nullopt; + setting.enabled = reg_value.value(); + + reg_value = reader.ReadDword(L"DomainNameDevolutionLevel"); + if (!reg_value) + return base::nullopt; + setting.level = reg_value.value(); + + return setting; } // Reads DnsSystemSettings from IpHelper and registry. -bool ReadSystemSettings(DnsSystemSettings* settings) { +base::Optional<DnsSystemSettings> ReadSystemSettings() { base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::MAY_BLOCK); - settings->addresses = ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | - GAA_FLAG_SKIP_UNICAST | - GAA_FLAG_SKIP_MULTICAST | - GAA_FLAG_SKIP_FRIENDLY_NAME); - if (!settings->addresses.get()) - return false; + DnsSystemSettings settings; + + settings.addresses = + ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_UNICAST | + GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_FRIENDLY_NAME); + if (!settings.addresses.get()) + return base::nullopt; RegistryReader tcpip_reader(kTcpipPath); RegistryReader tcpip6_reader(kTcpip6Path); @@ -164,76 +188,91 @@ RegistryReader policy_reader(kPolicyPath); RegistryReader primary_dns_suffix_reader(kPrimaryDnsSuffixPath); - if (!policy_reader.ReadString(L"SearchList", &settings->policy_search_list)) { - return false; + base::Optional<DnsSystemSettings::RegString> reg_string = + policy_reader.ReadString(L"SearchList"); + if (!reg_string) + return base::nullopt; + settings.policy_search_list = std::move(reg_string).value(); + + reg_string = tcpip_reader.ReadString(L"SearchList"); + if (!reg_string) + return base::nullopt; + settings.tcpip_search_list = std::move(reg_string).value(); + + reg_string = tcpip_reader.ReadString(L"Domain"); + if (!reg_string) + return base::nullopt; + settings.tcpip_domain = std::move(reg_string).value(); + + base::Optional<DnsSystemSettings::DevolutionSetting> devolution_setting = + ReadDevolutionSetting(policy_reader); + if (!devolution_setting) + return base::nullopt; + settings.policy_devolution = devolution_setting.value(); + + devolution_setting = ReadDevolutionSetting(dnscache_reader); + if (!devolution_setting) + return base::nullopt; + settings.dnscache_devolution = devolution_setting.value(); + + devolution_setting = ReadDevolutionSetting(tcpip_reader); + if (!devolution_setting) + return base::nullopt; + settings.tcpip_devolution = devolution_setting.value(); + + base::Optional<DnsSystemSettings::RegDword> reg_dword = + policy_reader.ReadDword(L"AppendToMultiLabelName"); + if (!reg_dword) + return base::nullopt; + settings.append_to_multi_label_name = reg_dword.value(); + + reg_string = primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix"); + if (!reg_string) { + return base::nullopt; } - - if (!tcpip_reader.ReadString(L"SearchList", &settings->tcpip_search_list)) - return false; - - if (!tcpip_reader.ReadString(L"Domain", &settings->tcpip_domain)) - return false; - - if (!ReadDevolutionSetting(policy_reader, &settings->policy_devolution)) - return false; - - if (!ReadDevolutionSetting(dnscache_reader, &settings->dnscache_devolution)) - return false; - - if (!ReadDevolutionSetting(tcpip_reader, &settings->tcpip_devolution)) - return false; - - if (!policy_reader.ReadDword(L"AppendToMultiLabelName", - &settings->append_to_multi_label_name)) { - return false; - } - - if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix", - &settings->primary_dns_suffix)) { - return false; - } + settings.primary_dns_suffix = std::move(reg_string).value(); base::win::RegistryKeyIterator nrpt_rules(HKEY_LOCAL_MACHINE, kNrptPath); base::win::RegistryKeyIterator cs_nrpt_rules(HKEY_LOCAL_MACHINE, kControlSetNrptPath); - settings->have_name_resolution_policy = + settings.have_name_resolution_policy = (nrpt_rules.SubkeyCount() > 0 || cs_nrpt_rules.SubkeyCount() > 0); base::win::RegistryKeyIterator dns_connections(HKEY_LOCAL_MACHINE, kDnsConnectionsPath); base::win::RegistryKeyIterator dns_connections_proxies( HKEY_LOCAL_MACHINE, kDnsConnectionsProxies); - settings->have_proxy = (dns_connections.SubkeyCount() > 0 || - dns_connections_proxies.SubkeyCount() > 0); + settings.have_proxy = (dns_connections.SubkeyCount() > 0 || + dns_connections_proxies.SubkeyCount() > 0); - return true; + return settings; } // Default address of "localhost" and local computer name can be overridden // by the HOSTS file, but if it's not there, then we need to fill it in. -bool AddLocalhostEntries(DnsHosts* hosts) { +bool AddLocalhostEntriesTo(DnsHosts& in_out_hosts) { IPAddress loopback_ipv4 = IPAddress::IPv4Localhost(); IPAddress loopback_ipv6 = IPAddress::IPv6Localhost(); // This does not override any pre-existing entries from the HOSTS file. - hosts->insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4), - loopback_ipv4)); - hosts->insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6), - loopback_ipv6)); + in_out_hosts.insert(std::make_pair( + DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4), loopback_ipv4)); + in_out_hosts.insert(std::make_pair( + DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6), loopback_ipv6)); wchar_t buffer[MAX_PATH]; DWORD size = MAX_PATH; - std::string localname; - if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size) || - !ParseDomainASCII(buffer, &localname)) { + if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size)) return false; - } + std::string localname = ParseDomainASCII(buffer); + if (localname.empty()) + return false; localname = base::ToLowerASCII(localname); bool have_ipv4 = - hosts->count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)) > 0; + in_out_hosts.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)) > 0; bool have_ipv6 = - hosts->count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)) > 0; + in_out_hosts.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)) > 0; if (have_ipv4 && have_ipv6) return true; @@ -264,10 +303,12 @@ } if (!have_ipv4 && (ipe.GetFamily() == ADDRESS_FAMILY_IPV4)) { have_ipv4 = true; - (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = ipe.address(); + in_out_hosts[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = + ipe.address(); } else if (!have_ipv6 && (ipe.GetFamily() == ADDRESS_FAMILY_IPV6)) { have_ipv6 = true; - (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = ipe.address(); + in_out_hosts[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = + ipe.address(); } } } @@ -282,7 +323,7 @@ ~RegistryWatcher() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } - bool Watch(const wchar_t* key, const CallbackType& callback) { + bool Watch(const wchar_t key[], const CallbackType& callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback.is_null()); DCHECK(callback_.is_null()); @@ -336,19 +377,21 @@ } void ConfigureSuffixSearch(const DnsSystemSettings& settings, - DnsConfig* config) { + DnsConfig& in_out_config) { // SearchList takes precedence, so check it first. if (settings.policy_search_list.set) { - std::vector<std::string> search; - if (ParseSearchList(settings.policy_search_list.value, &search)) { - config->search.swap(search); + std::vector<std::string> search = + ParseSearchList(settings.policy_search_list.value); + if (!search.empty()) { + in_out_config.search = std::move(search); return; } // Even if invalid, the policy disables the user-specified setting below. } else if (settings.tcpip_search_list.set) { - std::vector<std::string> search; - if (ParseSearchList(settings.tcpip_search_list.value, &search)) { - config->search.swap(search); + std::vector<std::string> search = + ParseSearchList(settings.tcpip_search_list.value); + if (!search.empty()) { + in_out_config.search = std::move(search); return; } } @@ -365,15 +408,14 @@ // The user setting (tcpip_domain) can be configurred at Computer Name in // System Settings std::string primary_suffix; - if ((settings.primary_dns_suffix.set && - ParseDomainASCII(settings.primary_dns_suffix.value, &primary_suffix)) || - (settings.tcpip_domain.set && - ParseDomainASCII(settings.tcpip_domain.value, &primary_suffix))) { - // Primary suffix goes in front. - config->search.insert(config->search.begin(), primary_suffix); - } else { + if (settings.primary_dns_suffix.set) + primary_suffix = ParseDomainASCII(settings.primary_dns_suffix.value); + if (primary_suffix.empty() && settings.tcpip_domain.set) + primary_suffix = ParseDomainASCII(settings.tcpip_domain.value); + if (primary_suffix.empty()) return; // No primary suffix, hence no devolution. - } + // Primary suffix goes in front. + in_out_config.search.insert(in_out_config.search.begin(), primary_suffix); // Devolution is determined by precedence: policy > dnscache > tcpip. // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel @@ -415,7 +457,7 @@ for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { offset = primary_suffix.find('.', offset + 1); - config->search.push_back(primary_suffix.substr(offset + 1)); + in_out_config.search.push_back(primary_suffix.substr(offset + 1)); } } @@ -448,39 +490,40 @@ DnsSystemSettings::~DnsSystemSettings() { } -bool ParseDomainASCII(base::WStringPiece widestr, std::string* domain) { - DCHECK(domain); +DnsSystemSettings::DnsSystemSettings(DnsSystemSettings&&) = default; +DnsSystemSettings& DnsSystemSettings::operator=(DnsSystemSettings&&) = default; + +std::string ParseDomainASCII(base::WStringPiece widestr) { if (widestr.empty()) - return false; + return ""; // Check if already ASCII. if (base::IsStringASCII(base::AsStringPiece16(widestr))) { - domain->assign(widestr.begin(), widestr.end()); - return true; + return std::string(widestr.begin(), widestr.end()); } // Otherwise try to convert it from IDN to punycode. const int kInitialBufferSize = 256; url::RawCanonOutputT<base::char16, kInitialBufferSize> punycode; if (!url::IDNToASCII(base::as_u16cstr(widestr), widestr.length(), &punycode)) - return false; + return ""; // |punycode_output| should now be ASCII; convert it to a std::string. // (We could use UTF16ToASCII() instead, but that requires an extra string // copy. Since ASCII is a subset of UTF8 the following is equivalent). - bool success = base::UTF16ToUTF8(punycode.data(), punycode.length(), domain); + std::string converted; + bool success = + base::UTF16ToUTF8(punycode.data(), punycode.length(), &converted); DCHECK(success); - DCHECK(base::IsStringASCII(*domain)); - return success && !domain->empty(); + DCHECK(base::IsStringASCII(converted)); + return converted; } -bool ParseSearchList(const std::wstring& value, - std::vector<std::string>* output) { - DCHECK(output); +std::vector<std::string> ParseSearchList(base::WStringPiece value) { if (value.empty()) - return false; + return {}; - output->clear(); + std::vector<std::string> output; // If the list includes an empty hostname (",," or ", ,"), it is terminated. // Although nslookup and network connection property tab ignore such @@ -490,18 +533,19 @@ value, L",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { // Convert non-ASCII to punycode, although getaddrinfo does not properly // handle such suffixes. - std::string parsed; - if (!ParseDomainASCII(t, &parsed)) + std::string parsed = ParseDomainASCII(t); + if (parsed.empty()) break; - output->push_back(parsed); + output.push_back(std::move(parsed)); } - return !output->empty(); + return output; } -bool ConvertSettingsToDnsConfig(const DnsSystemSettings& settings, - DnsConfig* config) { +base::Optional<DnsConfig> ConvertSettingsToDnsConfig( + const DnsSystemSettings& settings) { bool uses_vpn = false; - *config = DnsConfig(); + + DnsConfig dns_config; // Use GetAdapterAddresses to get effective DNS server order and // connection-specific DNS suffix. Ignore disconnected and loopback adapters. @@ -519,7 +563,7 @@ // previously found, skip processing another adapter. if (adapter->OperStatus != IfOperStatusUp || adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK || - !config->nameservers.empty()) + !dns_config.nameservers.empty()) continue; for (const IP_ADAPTER_DNS_SERVER_ADDRESS* address = @@ -533,9 +577,9 @@ // Override unset port. if (!ipe.port()) ipe = IPEndPoint(ipe.address(), dns_protocol::kDefaultPort); - config->nameservers.push_back(ipe); + dns_config.nameservers.push_back(ipe); } else { - return false; + return base::nullopt; } } @@ -544,34 +588,34 @@ // |DnsSuffix| stores the effective connection-specific suffix, which is // obtained via DHCP (regkey: Tcpip\Parameters\Interfaces\{XXX}\DhcpDomain) // or specified by the user (regkey: Tcpip\Parameters\Domain). - std::string dns_suffix; - if (ParseDomainASCII(adapter->DnsSuffix, &dns_suffix)) - config->search.push_back(dns_suffix); + std::string dns_suffix = ParseDomainASCII(adapter->DnsSuffix); + if (!dns_suffix.empty()) + dns_config.search.push_back(std::move(dns_suffix)); } - if (config->nameservers.empty()) - return false; // No point continuing. + if (dns_config.nameservers.empty()) + return base::nullopt; // No point continuing. // Windows always tries a multi-label name "as is" before using suffixes. - config->ndots = 1; + dns_config.ndots = 1; if (!settings.append_to_multi_label_name.set) { - config->append_to_multi_label_name = false; + dns_config.append_to_multi_label_name = false; } else { - config->append_to_multi_label_name = + dns_config.append_to_multi_label_name = (settings.append_to_multi_label_name.value != 0); } if (settings.have_name_resolution_policy) { // TODO(szym): only set this to true if NRPT has DirectAccess rules. - config->use_local_ipv6 = true; + dns_config.use_local_ipv6 = true; } if (settings.have_name_resolution_policy || settings.have_proxy || uses_vpn) - config->unhandled_options = true; + dns_config.unhandled_options = true; - ConfigureSuffixSearch(settings, config); - return true; + ConfigureSuffixSearch(settings, dns_config); + return dns_config; } // Watches registry and HOSTS file for changes. Must live on a sequence which @@ -580,7 +624,7 @@ : public NetworkChangeNotifier::IPAddressObserver, public DnsConfigService::Watcher { public: - explicit Watcher(DnsConfigServiceWin* service) + explicit Watcher(DnsConfigServiceWin& service) : DnsConfigService::Watcher(service) {} ~Watcher() override { NetworkChangeNotifier::RemoveIPAddressObserver(this); } @@ -648,25 +692,22 @@ // Reads config from registry and IpHelper. All work performed in ThreadPool. class DnsConfigServiceWin::ConfigReader : public SerialWorker { public: - explicit ConfigReader(DnsConfigServiceWin* service) - : service_(service), - success_(false) {} + explicit ConfigReader(DnsConfigServiceWin& service) : service_(&service) {} private: ~ConfigReader() override {} void DoWork() override { - DnsSystemSettings settings = {}; - success_ = false; - if (ReadSystemSettings(&settings)) - success_ = ConvertSettingsToDnsConfig(settings, &dns_config_); + base::Optional<DnsSystemSettings> settings = ReadSystemSettings(); + if (settings.has_value()) + dns_config_ = ConvertSettingsToDnsConfig(settings.value()); } void OnWorkFinished() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!IsCancelled()); - if (success_) { - service_->OnConfigRead(dns_config_); + if (dns_config_.has_value()) { + service_->OnConfigRead(std::move(dns_config_).value()); } else { LOG(WARNING) << "Failed to read DnsConfig."; // Try again in a while in case DnsConfigWatcher missed the signal. @@ -678,25 +719,24 @@ DnsConfigServiceWin* service_; // Written in DoWork(), read in OnWorkFinished(). No locking required. - DnsConfig dns_config_; - bool success_; + base::Optional<DnsConfig> dns_config_; }; // Extension of DnsConfigService::HostsReader that fills in localhost and local // computer name if necessary. class DnsConfigServiceWin::HostsReader : public DnsConfigService::HostsReader { public: - explicit HostsReader(DnsConfigServiceWin* service) - : DnsConfigService::HostsReader(service, GetHostsPath().value()) {} + explicit HostsReader(DnsConfigServiceWin& service) + : DnsConfigService::HostsReader(GetHostsPath().value(), service) {} HostsReader(const HostsReader&) = delete; HostsReader& operator=(const HostsReader&) = delete; protected: - bool AddAdditionalHostsTo(DnsHosts& dns_hosts) override { + bool AddAdditionalHostsTo(DnsHosts& in_out_dns_hosts) override { base::ScopedBlockingCall scoped_blocking_call( FROM_HERE, base::BlockingType::MAY_BLOCK); - return AddLocalhostEntries(&dns_hosts); + return AddLocalhostEntriesTo(in_out_dns_hosts); } private: @@ -727,11 +767,11 @@ bool DnsConfigServiceWin::StartWatching() { if (!config_reader_) - config_reader_ = base::MakeRefCounted<ConfigReader>(this); + config_reader_ = base::MakeRefCounted<ConfigReader>(*this); if (!hosts_reader_) - hosts_reader_ = base::MakeRefCounted<HostsReader>(this); + hosts_reader_ = base::MakeRefCounted<HostsReader>(*this); // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 - watcher_.reset(new Watcher(this)); + watcher_.reset(new Watcher(*this)); return watcher_->Watch(); }
diff --git a/net/dns/dns_config_service_win.h b/net/dns/dns_config_service_win.h index 97dcfb6..59967bf 100644 --- a/net/dns/dns_config_service_win.h +++ b/net/dns/dns_config_service_win.h
@@ -39,17 +39,15 @@ namespace internal { // Converts a UTF-16 domain name to ASCII, possibly using punycode. -// Returns true if the conversion succeeds and output is not empty. In case of -// failure, |domain| might become dirty. -bool NET_EXPORT_PRIVATE ParseDomainASCII(base::WStringPiece widestr, - std::string* domain); +// Returns empty string on failure. +std::string NET_EXPORT_PRIVATE ParseDomainASCII(base::WStringPiece widestr); // Parses |value| as search list (comma-delimited list of domain names) from -// a registry key and stores it in |out|. Returns true on success. Empty +// a registry key and stores it in |out|. Returns empty vector on failure. Empty // entries (e.g., "chromium.org,,org") terminate the list. Non-ascii hostnames // are converted to punycode. -bool NET_EXPORT_PRIVATE ParseSearchList(const std::wstring& value, - std::vector<std::string>* out); +std::vector<std::string> NET_EXPORT_PRIVATE +ParseSearchList(base::WStringPiece value); // All relevant settings read from registry and IP Helper. This isolates our // logic from system calls and is exposed for unit tests. Keep it an aggregate @@ -76,6 +74,9 @@ DnsSystemSettings(); ~DnsSystemSettings(); + DnsSystemSettings(DnsSystemSettings&&); + DnsSystemSettings& operator=(DnsSystemSettings&&); + // Filled in by GetAdapterAddresses. Note that the alternative // GetNetworkParams does not include IPv6 addresses. std::unique_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> addresses; @@ -114,11 +115,10 @@ bool have_proxy = false; }; -// Fills in |dns_config| from |settings|. Exposed for tests. Returns false if a -// valid config could not be determined. -bool NET_EXPORT_PRIVATE -ConvertSettingsToDnsConfig(const DnsSystemSettings& settings, - DnsConfig* dns_config); +// Fills in |dns_config| from |settings|. Exposed for tests. Returns nullopt if +// a valid config could not be determined. +base::Optional<DnsConfig> NET_EXPORT_PRIVATE +ConvertSettingsToDnsConfig(const DnsSystemSettings& settings); // Service for reading and watching Windows system DNS settings. This object is // not thread-safe and methods may perform blocking I/O so methods must be
diff --git a/net/dns/dns_config_service_win_unittest.cc b/net/dns/dns_config_service_win_unittest.cc index 4ab74766..7b99086 100644 --- a/net/dns/dns_config_service_win_unittest.cc +++ b/net/dns/dns_config_service_win_unittest.cc
@@ -4,11 +4,16 @@ #include "net/dns/dns_config_service_win.h" +#include <string> +#include <vector> + #include "base/check.h" #include "base/memory/free_deleter.h" +#include "base/optional.h" #include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" #include "net/dns/public/dns_protocol.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -18,33 +23,22 @@ TEST(DnsConfigServiceWinTest, ParseSearchList) { const struct TestCase { const wchar_t* input; - const char* output[4]; // NULL-terminated, empty if expected false + std::vector<std::string> expected; } cases[] = { - {L"chromium.org", {"chromium.org", nullptr}}, - {L"chromium.org,org", {"chromium.org", "org", nullptr}}, + {L"chromium.org", {"chromium.org"}}, + {L"chromium.org,org", {"chromium.org", "org"}}, // Empty suffixes terminate the list - {L"crbug.com,com,,org", {"crbug.com", "com", nullptr}}, + {L"crbug.com,com,,org", {"crbug.com", "com"}}, // IDN are converted to punycode {L"\u017c\xf3\u0142ta.pi\u0119\u015b\u0107.pl,pl", - {"xn--ta-4ja03asj.xn--pi-wla5e0q.pl", "pl", nullptr}}, + {"xn--ta-4ja03asj.xn--pi-wla5e0q.pl", "pl"}}, // Empty search list is invalid - {L"", {nullptr}}, - {L",,", {nullptr}}, + {L"", {}}, + {L",,", {}}, }; for (const auto& t : cases) { - std::vector<std::string> actual_output, expected_output; - actual_output.push_back("UNSET"); - for (const char* const* output = t.output; *output; ++output) { - expected_output.push_back(*output); - } - bool result = internal::ParseSearchList(t.input, &actual_output); - if (!expected_output.empty()) { - EXPECT_TRUE(result); - EXPECT_EQ(expected_output, actual_output); - } else { - EXPECT_FALSE(result) << "Unexpected parse success on " << t.input; - } + EXPECT_EQ(internal::ParseSearchList(t.input), t.expected); } } @@ -183,14 +177,13 @@ expected_nameservers.push_back(IPEndPoint(ip, port)); } - DnsConfig config; - bool success = internal::ConvertSettingsToDnsConfig(settings, &config); + base::Optional<DnsConfig> config = + internal::ConvertSettingsToDnsConfig(settings); bool expected_success = !expected_nameservers.empty(); - EXPECT_EQ(expected_success, success); - EXPECT_EQ(expected_nameservers, config.nameservers); - if (success) { - ASSERT_EQ(1u, config.search.size()); - EXPECT_EQ(t.expected_suffix, config.search[0]); + EXPECT_EQ(expected_success, config.has_value()); + if (config.has_value()) { + EXPECT_EQ(expected_nameservers, config->nameservers); + EXPECT_THAT(config->search, testing::ElementsAre(t.expected_suffix)); } } } @@ -211,7 +204,7 @@ internal::DnsSystemSettings::DevolutionSetting dnscache_devolution; internal::DnsSystemSettings::DevolutionSetting tcpip_devolution; } input_settings; - std::string expected_search[5]; + std::vector<std::string> expected_search; } cases[] = { { // Policy SearchList override. @@ -389,13 +382,10 @@ settings.dnscache_devolution = t.input_settings.dnscache_devolution; settings.tcpip_devolution = t.input_settings.tcpip_devolution; - DnsConfig config; - EXPECT_TRUE(internal::ConvertSettingsToDnsConfig(settings, &config)); - std::vector<std::string> expected_search; - for (size_t j = 0; !t.expected_search[j].empty(); ++j) { - expected_search.push_back(t.expected_search[j]); - } - EXPECT_EQ(expected_search, config.search); + EXPECT_THAT( + internal::ConvertSettingsToDnsConfig(settings), + testing::Optional(testing::Field( + &DnsConfig::search, testing::ElementsAreArray(t.expected_search)))); } } @@ -416,9 +406,10 @@ internal::DnsSystemSettings settings; settings.addresses = CreateAdapterAddresses(infos); settings.append_to_multi_label_name = t.input; - DnsConfig config; - EXPECT_TRUE(internal::ConvertSettingsToDnsConfig(settings, &config)); - EXPECT_EQ(t.expected_output, config.append_to_multi_label_name); + EXPECT_THAT( + internal::ConvertSettingsToDnsConfig(settings), + testing::Optional(testing::Field(&DnsConfig::append_to_multi_label_name, + testing::Eq(t.expected_output)))); } } @@ -441,10 +432,11 @@ internal::DnsSystemSettings settings; settings.addresses = CreateAdapterAddresses(infos); settings.have_name_resolution_policy = t.have_nrpt; - DnsConfig config; - EXPECT_TRUE(internal::ConvertSettingsToDnsConfig(settings, &config)); - EXPECT_EQ(t.unhandled_options, config.unhandled_options); - EXPECT_EQ(t.have_nrpt, config.use_local_ipv6); + base::Optional<DnsConfig> config = + internal::ConvertSettingsToDnsConfig(settings); + ASSERT_TRUE(config.has_value()); + EXPECT_EQ(t.unhandled_options, config->unhandled_options); + EXPECT_EQ(t.have_nrpt, config->use_local_ipv6); } } @@ -467,9 +459,10 @@ internal::DnsSystemSettings settings; settings.addresses = CreateAdapterAddresses(infos); settings.have_proxy = t.have_proxy; - DnsConfig config; - EXPECT_TRUE(internal::ConvertSettingsToDnsConfig(settings, &config)); - EXPECT_EQ(t.unhandled_options, config.unhandled_options); + EXPECT_THAT( + internal::ConvertSettingsToDnsConfig(settings), + testing::Optional(testing::Field(&DnsConfig::unhandled_options, + testing::Eq(t.unhandled_options)))); } } @@ -483,9 +476,9 @@ internal::DnsSystemSettings settings; settings.addresses = CreateAdapterAddresses(infos); - DnsConfig config; - EXPECT_TRUE(internal::ConvertSettingsToDnsConfig(settings, &config)); - EXPECT_TRUE(config.unhandled_options); + EXPECT_THAT(internal::ConvertSettingsToDnsConfig(settings), + testing::Optional(testing::Field(&DnsConfig::unhandled_options, + testing::IsTrue()))); } } // namespace
diff --git a/net/dns/dns_config_watcher_mac.cc b/net/dns/dns_config_watcher_mac.cc index bb175d7..f48dc70 100644 --- a/net/dns/dns_config_watcher_mac.cc +++ b/net/dns/dns_config_watcher_mac.cc
@@ -78,9 +78,7 @@ } // static -bool DnsConfigWatcher::CheckDnsConfig(bool* out_unhandled_options) { - DCHECK(out_unhandled_options); - +bool DnsConfigWatcher::CheckDnsConfig(bool& out_unhandled_options) { if (!GetDnsInfoApi().dns_configuration_copy) return false; std::unique_ptr<dns_config_t, DnsConfigTDeleter> dns_config( @@ -100,7 +98,7 @@ ++num_resolvers; } - *out_unhandled_options = num_resolvers > 1; + out_unhandled_options = num_resolvers > 1; return true; }
diff --git a/net/dns/dns_config_watcher_mac.h b/net/dns/dns_config_watcher_mac.h index 9151a52..86dbe5a 100644 --- a/net/dns/dns_config_watcher_mac.h +++ b/net/dns/dns_config_watcher_mac.h
@@ -17,7 +17,7 @@ bool Watch(const base::RepeatingCallback<void(bool succeeded)>& callback); // Returns false iff a valid config could not be determined. - static bool CheckDnsConfig(bool* out_unhandled_options); + static bool CheckDnsConfig(bool& out_unhandled_options); private: NotifyWatcherMac watcher_;
diff --git a/net/dns/dns_parse_domain_ascii_win_fuzzer.cc b/net/dns/dns_parse_domain_ascii_win_fuzzer.cc index bc675dc..aa89afb 100644 --- a/net/dns/dns_parse_domain_ascii_win_fuzzer.cc +++ b/net/dns/dns_parse_domain_ascii_win_fuzzer.cc
@@ -18,9 +18,9 @@ base::StringPiece16 widestr( reinterpret_cast<const base::StringPiece16::value_type*>(data), size / 2); - std::string result; + std::string result = net::internal::ParseDomainASCII(widestr); - if (net::internal::ParseDomainASCII(widestr, &result)) + if (!result.empty()) // Call base::ToLowerASCII to get some additional code coverage signal. result = base::ToLowerASCII(result);
diff --git a/net/quic/quic_test_packet_maker.cc b/net/quic/quic_test_packet_maker.cc index b5072c9..fe9e6a2 100644 --- a/net/quic/quic_test_packet_maker.cc +++ b/net/quic/quic_test_packet_maker.cc
@@ -1194,7 +1194,8 @@ const std::string& quic_error_details, uint64_t frame_type) { auto* close_frame = new quic::QuicConnectionCloseFrame( - version_.transport_version, quic_error, quic_error_details, frame_type); + version_.transport_version, quic_error, quic::NO_IETF_QUIC_ERROR, + quic_error_details, frame_type); frames_.push_back(quic::QuicFrame(close_frame)); DVLOG(1) << "Adding frame: " << frames_.back(); }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 94d0675..e1bd17dd 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1774,25 +1774,6 @@ ] } ], - "CodeCacheDeletionWithoutFilter": [ - { - "platforms": [ - "android", - "chromeos", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "CodeCacheDeletionWithoutFilter" - ] - } - ] - } - ], "CompositeCrossOriginIframes": [ { "platforms": [ @@ -4172,24 +4153,6 @@ ] } ], - "MediaFeeds": [ - { - "platforms": [ - "chromeos", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "MediaFeeds" - ] - } - ] - } - ], "MediaFoundationAsyncH264Encoding": [ { "platforms": [ @@ -4220,25 +4183,6 @@ ] } ], - "MediaHistory": [ - { - "platforms": [ - "android", - "chromeos", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "UseMediaHistoryStore" - ] - } - ] - } - ], "MediaLearningSmoothnessExperiment": [ { "platforms": [ @@ -7179,21 +7123,6 @@ ] } ], - "UrgentDiscardingFromPerformanceManager": [ - { - "platforms": [ - "windows" - ], - "experiments": [ - { - "name": "Enabled_20200129", - "enable_features": [ - "UrgentDiscardingFromPerformanceManager" - ] - } - ] - } - ], "UseFluentLanguageModel": [ { "platforms": [ @@ -7284,23 +7213,6 @@ ] } ], - "UserDataSnapshot": [ - { - "platforms": [ - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "UserDataSnapshot", - "enable_features": [ - "UserDataSnapshot" - ] - } - ] - } - ], "UsernameFirstFlow": [ { "platforms": [
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index a1dda79..73dad54 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -3092,6 +3092,7 @@ kAddressSpaceUnknownSecureContextNavigatedToPrivate = 3771, kAddressSpaceUnknownNonSecureContextNavigatedToPrivate = 3772, kRTCPeerConnectionSdpSemanticsPlanB = 3773, + kFetchRespondWithNoResponseWithUsedRequestBody = 3774, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/OWNERS b/third_party/blink/public/platform/OWNERS index a3af200..50f174c 100644 --- a/third_party/blink/public/platform/OWNERS +++ b/third_party/blink/public/platform/OWNERS
@@ -8,7 +8,6 @@ per-file web_application_cache_*=pwnall@chromium.org per-file web_graphics_context_3d_provider.h=kbr@chromium.org -per-file web_graphics_context_3d_provider.h=khushalsagar@chromium.org per-file web_rtc_*=hbos@chromium.org per-file web_media_player*=mlamouri@chromium.org
diff --git a/third_party/blink/renderer/core/accessibility/ax_object_cache_base.h b/third_party/blink/renderer/core/accessibility/ax_object_cache_base.h index d3290f1..1ea08910 100644 --- a/third_party/blink/renderer/core/accessibility/ax_object_cache_base.h +++ b/third_party/blink/renderer/core/accessibility/ax_object_cache_base.h
@@ -28,7 +28,8 @@ ~AXObjectCacheBase() override = default; virtual AXObject* Get(const Node*) = 0; - virtual AXObject* GetOrCreate(LayoutObject*) = 0; + virtual AXObject* GetOrCreate(LayoutObject*, + AXObject* parent_if_known = nullptr) = 0; protected: AXObjectCacheBase() = default;
diff --git a/third_party/blink/renderer/core/css/container_query_test.cc b/third_party/blink/renderer/core/css/container_query_test.cc index ac1add2..168602c7 100644 --- a/third_party/blink/renderer/core/css/container_query_test.cc +++ b/third_party/blink/renderer/core/css/container_query_test.cc
@@ -114,25 +114,45 @@ } TEST_F(ContainerQueryTest, ContainerQueryEvaluation) { - // TODO(crbug.com/1145970): This test relies on the temporary fixed container - // size in ElementRuleCollector::CollectMatchingRulesForList. SetBodyInnerHTML(R"HTML( <style> + #container { + contain: size layout; + width: 500px; + height: 500px; + } + #container.adjust { + width: 600px; + } + div { z-index:1; } /* Should apply: */ @container (min-width: 500px) { div { z-index:2; } } - /* Should not apply: */ + /* Should initially not apply: */ @container (min-width: 600px) { div { z-index:3; } } </style> - <div id=div></div> + <div id=container> + <div id=div></div> + </div> )HTML"); Element* div = GetDocument().getElementById("div"); ASSERT_TRUE(div); EXPECT_EQ(2, div->ComputedStyleRef().ZIndex()); + + // Check that dependent elements are responsive to changes: + Element* container = GetDocument().getElementById("container"); + ASSERT_TRUE(container); + container->setAttribute(html_names::kClassAttr, "adjust"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_EQ(3, div->ComputedStyleRef().ZIndex()); + + container->setAttribute(html_names::kClassAttr, ""); + UpdateAllLifecyclePhasesForTest(); + EXPECT_EQ(2, div->ComputedStyleRef().ZIndex()); } } // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_selector_test.cc b/third_party/blink/renderer/core/css/css_selector_test.cc index 4ae3dca..777fabc 100644 --- a/third_party/blink/renderer/core/css/css_selector_test.cc +++ b/third_party/blink/renderer/core/css/css_selector_test.cc
@@ -165,4 +165,25 @@ EXPECT_TRUE(HasLinkOrVisited(":host-context(:link)")); } +TEST(CSSSelector, CueDefaultNamespace) { + css_test_helpers::TestStyleSheet sheet; + + sheet.AddCSSRules(R"HTML( + @namespace "http://www.w3.org/1999/xhtml"; + video::cue(b) {} + )HTML"); + + const CSSSelector& cue_selector = + (*sheet.GetRuleSet().CuePseudoRules())[0]->Selector(); + EXPECT_EQ(cue_selector.GetPseudoType(), CSSSelector::kPseudoCue); + + const CSSSelectorList* cue_arguments = cue_selector.SelectorList(); + ASSERT_TRUE(cue_arguments); + const CSSSelector* vtt_type_selector = cue_arguments->First(); + ASSERT_TRUE(vtt_type_selector); + EXPECT_EQ(vtt_type_selector->TagQName().LocalName(), "b"); + // Default namespace should not affect VTT node type selector. + EXPECT_EQ(vtt_type_selector->TagQName().NamespaceURI(), g_star_atom); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/css/element_rule_collector.cc b/third_party/blink/renderer/core/css/element_rule_collector.cc index fe63272..cf4c597 100644 --- a/third_party/blink/renderer/core/css/element_rule_collector.cc +++ b/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -206,12 +206,9 @@ if (auto* container_query = rule_data->GetContainerQuery()) { result_.SetDependsOnContainerQueries(); - // TODO(crbug.com/1145970): Propagate actual ContainerQueryEvaluator - // instance from the container. - // For now a fixed container size of 500x500 is used. - auto* eval = MakeGarbageCollected<ContainerQueryEvaluator>(500.0, 500.0); + auto* evaluator = style_recalc_context_.cq_evaluator; - if (!eval->Eval(*container_query)) { + if (!evaluator || !evaluator->Eval(*container_query)) { rejected++; continue; }
diff --git a/third_party/blink/renderer/core/css/parser/css_selector_parser.cc b/third_party/blink/renderer/core/css/parser/css_selector_parser.cc index c9163dc..c385aef 100644 --- a/third_party/blink/renderer/core/css/parser/css_selector_parser.cc +++ b/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
@@ -34,7 +34,7 @@ return range.MakeSubRange(&first, &range.Peek()); } -bool AtEndIgnoringWhitepace(CSSParserTokenRange range) { +bool AtEndIgnoringWhitespace(CSSParserTokenRange range) { range.ConsumeWhitespace(); return range.AtEnd(); } @@ -427,8 +427,9 @@ // [1] https://drafts.csswg.org/selectors/#matches // [2] https://drafts.csswg.org/selectors/#selector-subject base::AutoReset<bool> ignore_namespace( - &ignore_default_namespace_, resist_default_namespace_ && !has_q_name && - AtEndIgnoringWhitepace(range)); + &ignore_default_namespace_, + ignore_default_namespace_ || (resist_default_namespace_ && !has_q_name && + AtEndIgnoringWhitespace(range))); if (!compound_selector) { AtomicString namespace_uri = DetermineNamespace(namespace_prefix); @@ -699,6 +700,10 @@ case CSSSelector::kPseudoCue: { DisallowPseudoElementsScope scope(this); base::AutoReset<bool> inside_compound(&inside_compound_pseudo_, true); + base::AutoReset<bool> ignore_namespace( + &ignore_default_namespace_, + ignore_default_namespace_ || + selector->GetPseudoType() == CSSSelector::kPseudoCue); std::unique_ptr<CSSSelectorList> selector_list = std::make_unique<CSSSelectorList>();
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc index 9845ba0..edfed5ff 100644 --- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc +++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -861,9 +861,6 @@ MatchAllRules(state, collector, matching_behavior != kMatchAllRulesExcludingSMIL); - if (collector.MatchedResult().DependsOnContainerQueries()) - state.Style()->SetDependsOnContainerQueries(true); - if (tracker_) AddMatchedRulesToTracker(collector); @@ -883,6 +880,9 @@ CascadeAndApplyMatchedProperties(state, cascade); + if (collector.MatchedResult().DependsOnContainerQueries()) + state.Style()->SetDependsOnContainerQueries(true); + ApplyCallbackSelectors(state); // Cache our original display.
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc index a84798e..805e627 100644 --- a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc +++ b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
@@ -1122,4 +1122,41 @@ EXPECT_FALSE(e->ComputedStyleRef().DependsOnContainerQueries()); } +// Verify that the ComputedStyle::DependsOnContainerQuery flag does +// not end up in the MatchedPropertiesCache (MPC). +TEST_F(StyleResolverTest, DependsOnContainerQueriesMPC) { + ScopedCSSContainerQueriesForTest scoped_feature(true); + + GetDocument().documentElement()->setInnerHTML(R"HTML( + <style> + @container (min-width: 9999999px) { + #a { color: green; } + } + </style> + <div id=a></div> + <div id=b></div> + )HTML"); + + // In the above example, both <div id=a> and <div id=b> match the same + // rules (i.e. whatever is provided by UA style). The selector inside + // the @container rule does ultimately _not_ match <div id=a> (because the + // container query evaluates to 'false'), however, it _does_ cause the + // ComputedStyle::DependsOnContainerQuery flag to be set on #a. + // + // We must ensure that we don't add the DependsOnContainerQuery-flagged + // style to the MPC, otherwise the subsequent cache hit for #b would result + // in the flag being (incorrectly) set for that element. + + UpdateAllLifecyclePhasesForTest(); + + auto* a = GetDocument().getElementById("a"); + auto* b = GetDocument().getElementById("b"); + + ASSERT_TRUE(a); + ASSERT_TRUE(b); + + EXPECT_TRUE(a->ComputedStyleRef().DependsOnContainerQueries()); + EXPECT_FALSE(b->ComputedStyleRef().DependsOnContainerQueries()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc index c1777f6..a5d55b3c 100644 --- a/third_party/blink/renderer/core/css/style_engine.cc +++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -32,6 +32,7 @@ #include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_theme_engine.h" +#include "third_party/blink/renderer/core/css/container_query_evaluator.h" #include "third_party/blink/renderer/core/css/counter_style_map.h" #include "third_party/blink/renderer/core/css/css_default_style_sheets.h" #include "third_party/blink/renderer/core/css/css_font_family_value.h" @@ -76,6 +77,8 @@ #include "third_party/blink/renderer/core/html/html_slot_element.h" #include "third_party/blink/renderer/core/html/imports/html_imports_controller.h" #include "third_party/blink/renderer/core/html_names.h" +#include "third_party/blink/renderer/core/layout/geometry/logical_size.h" +#include "third_party/blink/renderer/core/layout/geometry/physical_size.h" #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_theme.h" #include "third_party/blink/renderer/core/layout/layout_view.h" @@ -1971,17 +1974,23 @@ return initial_data_; } -void StyleEngine::UpdateStyleAndLayoutTreeForContainer(Element& container) { +void StyleEngine::UpdateStyleAndLayoutTreeForContainer( + Element& container, + const LogicalSize& logical_size) { DCHECK(!style_recalc_root_.GetRootNode()); DCHECK(!container.NeedsStyleRecalc()); DCHECK(!in_container_query_style_recalc_); base::AutoReset<bool> cq_recalc(&in_container_query_style_recalc_, true); - // TODO(crbug.com/1145970): Populate this context with a - // ContainerQueryEvaluator. StyleRecalcContext style_recalc_context; + PhysicalSize physical_size = ToPhysicalSize( + logical_size, container.ComputedStyleRef().GetWritingMode()); + style_recalc_context.cq_evaluator = + MakeGarbageCollected<ContainerQueryEvaluator>(physical_size.width, + physical_size.height); + style_recalc_root_.Update(nullptr, &container); RecalcStyle({StyleRecalcChange::kRecalcContainerQueryDependent}, style_recalc_context);
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h index 8dc67432..7c0ee0d 100644 --- a/third_party/blink/renderer/core/css/style_engine.h +++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -77,6 +77,7 @@ class StyleSheetContents; class StyleInitialData; class ViewportStyleResolver; +struct LogicalSize; enum InvalidationScope { kInvalidateCurrentScope, kInvalidateAllScopes }; @@ -400,7 +401,8 @@ void UpdateViewportStyle(); void UpdateStyleAndLayoutTree(); // To be called from layout when container queries change for the container. - void UpdateStyleAndLayoutTreeForContainer(Element& container); + void UpdateStyleAndLayoutTreeForContainer(Element& container, + const LogicalSize&); void RecalcStyle() { RecalcStyle({}, StyleRecalcContext()); } void ClearEnsuredDescendantStyles(Element& element);
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc index 26d2267..1801dc36 100644 --- a/third_party/blink/renderer/core/css/style_engine_test.cc +++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -3792,13 +3792,15 @@ SetDependsOnContainerQueries(*affected); unsigned start_count = GetStyleEngine().StyleForElementCount(); - GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container1); + GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container1, + LogicalSize()); // The first span.affected child and #container2 EXPECT_EQ(2u, GetStyleEngine().StyleForElementCount() - start_count); start_count = GetStyleEngine().StyleForElementCount(); - GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container2); + GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container2, + LogicalSize()); // Three direct span.affected children, and the two display:none elements. EXPECT_EQ(6u, GetStyleEngine().StyleForElementCount() - start_count); @@ -3845,7 +3847,8 @@ SetDependsOnContainerQueries(*affected); unsigned start_count = GetStyleEngine().StyleForElementCount(); - GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container); + GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container, + LogicalSize()); // span.affected is updated because containment does not apply to the display // types on the element styled with containment. All marked as affected are @@ -3881,7 +3884,8 @@ SetDependsOnContainerQueries(*before); unsigned start_count = GetStyleEngine().StyleForElementCount(); - GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container); + GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container, + LogicalSize()); EXPECT_EQ(2u, GetStyleEngine().StyleForElementCount() - start_count); } @@ -3910,7 +3914,8 @@ EXPECT_TRUE(old_inner_style); unsigned start_count = GetStyleEngine().StyleForElementCount(); - GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container); + GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container, + LogicalSize()); // Input elements mark their InnerEditorElement() style-dirty when they are // recalculated. That means the UpdateStyleAndLayoutTreeForContainer() call
diff --git a/third_party/blink/renderer/core/css/style_recalc.h b/third_party/blink/renderer/core/css/style_recalc.h index 5e1810e..c88f44e8 100644 --- a/third_party/blink/renderer/core/css/style_recalc.h +++ b/third_party/blink/renderer/core/css/style_recalc.h
@@ -9,6 +9,7 @@ namespace blink { +class ContainerQueryEvaluator; class Element; class Node; class PseudoElement; @@ -107,6 +108,9 @@ // TODO(crbug.com/1145970): Populate this class. class StyleRecalcContext { STACK_ALLOCATED(); + + public: + ContainerQueryEvaluator* cq_evaluator = nullptr; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc index 5b8ac42..c3ccabd 100644 --- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
@@ -53,6 +53,13 @@ recorder_(recorder), clock_(base::DefaultTickClock::GetInstance()), event_name_("Blink.UpdateTime") { + // All of these are assumed to have one entry per sub-metric. + DCHECK_EQ(base::size(absolute_metric_records_), metrics_data().size()); + DCHECK_EQ(base::size(current_sample_.sub_metrics_durations), + metrics_data().size()); + DCHECK_EQ(base::size(current_sample_.sub_main_frame_durations), + metrics_data().size()); + // Record average and worst case for the primary metric. primary_metric_.reset(); @@ -72,13 +79,13 @@ const char* const uma_pre_fcp_aggregated_postscript = ".AggregatedPreFCP"; // Populate all the sub-metrics. - absolute_metric_records_.ReserveInitialCapacity(kCount); + size_t metric_index = 0; for (const MetricInitializationData& metric_data : metrics_data()) { // Absolute records report the absolute time for each metric per frame. // They also aggregate the time spent in each stage between navigation // (LocalFrameView resets) and First Contentful Paint. // They have an associated UMA too that we own and allocate here. - auto& absolute_record = absolute_metric_records_.emplace_back(); + auto& absolute_record = absolute_metric_records_[metric_index]; absolute_record.reset(); absolute_record.pre_fcp_aggregate = base::TimeDelta(); if (metric_data.has_uma) { @@ -102,12 +109,9 @@ absolute_record.uma_aggregate_counter.reset(new CustomCountHistogram( aggregated_uma_name.ToString().Utf8().c_str(), 0, 10000000, 50)); } - } - // Make space in the current sample. - current_sample_.sub_metrics_durations.Grow(static_cast<wtf_size_t>(kCount)); - current_sample_.sub_main_frame_durations.Grow( - static_cast<wtf_size_t>(kCount)); + metric_index++; + } } LocalFrameUkmAggregator::~LocalFrameUkmAggregator() { @@ -198,7 +202,7 @@ bool is_pre_fcp = (fcp_state_ != kHavePassedFCP); // Accumulate for UKM and record the UMA - DCHECK_LT(metric_index, absolute_metric_records_.size()); + DCHECK_LT(metric_index, base::size(absolute_metric_records_)); auto& record = absolute_metric_records_[metric_index]; record.interval_duration += duration; if (in_main_frame_update_) @@ -421,7 +425,7 @@ void LocalFrameUkmAggregator::UpdateSample( cc::ActiveFrameSequenceTrackers trackers) { current_sample_.primary_metric_duration = primary_metric_.interval_duration; - for (unsigned i = 0; i < static_cast<unsigned>(kCount); ++i) { + for (size_t i = 0; i < metrics_data().size(); ++i) { current_sample_.sub_metrics_durations[i] = absolute_metric_records_[i].interval_duration; current_sample_.sub_main_frame_durations[i] = @@ -440,7 +444,7 @@ builder.SetMainFrame(primary_metric_.pre_fcp_aggregate.InMicroseconds()); primary_metric_.uma_aggregate_counter->CountMicroseconds( primary_metric_.pre_fcp_aggregate); - for (unsigned i = 0; i < static_cast<unsigned>(kCount); ++i) { + for (size_t i = 0; i < metrics_data().size(); ++i) { auto& absolute_record = absolute_metric_records_[i]; if (absolute_record.uma_aggregate_counter) { absolute_record.uma_aggregate_counter->CountMicroseconds( @@ -502,7 +506,7 @@ current_sample_.primary_metric_duration.InMicroseconds()); builder.SetMainFrameIsBeforeFCP(fcp_state_ != kHavePassedFCP); builder.SetMainFrameReasons(current_sample_.trackers); - for (unsigned i = 0; i < static_cast<unsigned>(kCount); ++i) { + for (size_t i = 0; i < metrics_data().size(); ++i) { switch (static_cast<MetricId>(i)) { CASE_FOR_ID(CompositingAssignments, i); CASE_FOR_ID(CompositingCommit, i); @@ -549,13 +553,13 @@ } bool LocalFrameUkmAggregator::AllMetricsAreZero() { - if (primary_metric_.interval_duration.InMicroseconds()) + if (!primary_metric_.interval_duration.is_zero()) return false; for (auto& record : absolute_metric_records_) { - if (record.interval_duration.InMicroseconds()) { + if (!record.interval_duration.is_zero()) { return false; } - if (record.main_frame_duration.InMicroseconds()) { + if (!record.main_frame_duration.is_zero()) { return false; } }
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h index 7332abcd..13019c9 100644 --- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
@@ -299,8 +299,8 @@ struct SampleToRecord { base::TimeDelta primary_metric_duration; - Vector<base::TimeDelta> sub_metrics_durations; - Vector<base::TimeDelta> sub_main_frame_durations; + std::array<base::TimeDelta, kCount> sub_metrics_durations; + std::array<base::TimeDelta, kCount> sub_main_frame_durations; cc::ActiveFrameSequenceTrackers trackers; }; @@ -338,7 +338,7 @@ // Event and metric data const char* const event_name_; AbsoluteMetricRecord primary_metric_; - Vector<AbsoluteMetricRecord> absolute_metric_records_; + std::array<AbsoluteMetricRecord, kCount> absolute_metric_records_; // The current sample to report. When RecordEvent() is called we // check for uniform_random[0,1) < 1 / n where n is the number of frames
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index 7df196b..cc5d3ffc 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -1262,10 +1262,10 @@ // SVGGraphicsElement::getBBox(). // NOTE: Markers are not specifically ignored here by SVG 1.1 spec, but we // ignore them since stroke-width is ignored (and marker size can depend on - // stroke-width). objectBoundingBox is returned local coordinates. + // stroke-width). objectBoundingBox is returned in local coordinates and + // always unzoomed. // The name objectBoundingBox is taken from the SVG 1.1 spec. virtual FloatRect ObjectBoundingBox() const; - virtual FloatRect StrokeBoundingBox() const; // Returns the smallest rectangle enclosing all of the painted content // respecting clipping, masking, filters, opacity, stroke-width and markers. @@ -1275,6 +1275,11 @@ // coordinate space is the viewport space. virtual FloatRect VisualRectInLocalSVGCoordinates() const; + // Like VisualRectInLocalSVGCoordinates() but does not include visual overflow + // (name is misleading). May be zoomed (currently only for <foreignObject>, + // which represents this via its LocalToSVGParentTransform()). + virtual FloatRect StrokeBoundingBox() const; + // This returns the transform applying to the local SVG coordinate space, // which combines the CSS transform properties and animation motion transform. // See SVGElement::calculateTransform().
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc index 7ebc8511..01823b8 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -438,6 +438,17 @@ CalculateInitialFragmentGeometry(constraint_space, *this); } + if (RuntimeEnabledFeatures::CSSContainerQueriesEnabled() && + IsContainerForContainerQueries()) { + if (auto* element = DynamicTo<Element>(GetDOMNode())) { + LogicalSize available_size = CalculateChildAvailableSize( + constraint_space, *this, fragment_geometry->border_box_size, + fragment_geometry->border + fragment_geometry->padding); + GetDocument().GetStyleEngine().UpdateStyleAndLayoutTreeForContainer( + *element, available_size); + } + } + TextAutosizer::NGLayoutScope text_autosizer_layout_scope( box_, fragment_geometry->border_box_size.inline_size);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h index f6f8d0e..9d1dfed 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h +++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -237,6 +237,10 @@ return box_->ShouldApplySizeContainment(); } + bool IsContainerForContainerQueries() const { + return box_->IsContainerForContainerQueries(); + } + // CSS defines certain cases to synthesize inline block baselines from box. // See comments in UseLogicalBottomMarginEdgeForInlineBlockBaseline(). bool UseBlockEndMarginEdgeForInlineBlockBaseline() const {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h index 2cddf75..e35a3367 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
@@ -72,7 +72,7 @@ } FloatRect StrokeBoundingBox() const override { NOT_DESTROYED(); - return ObjectBoundingBox(); + return VisualRectInLocalSVGCoordinates(); } FloatRect VisualRectInLocalSVGCoordinates() const override { NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc index ecbe99c32..40ddbbf 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
@@ -387,4 +387,25 @@ EXPECT_EQ(PhysicalOffset(450, 450), result.PointInInnerNodeFrame()); } +TEST_F(LayoutSVGForeignObjectTest, BBoxPropagationZoomed) { + GetFrame().SetPageZoomFactor(2); + SetBodyInnerHTML(R"HTML( + <svg> + <g> + <foreignObject x="6" y="5" width="100" height="50" id="target"/> + </g> + </svg> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + + const auto& target = *GetLayoutObjectByElementId("target"); + ASSERT_EQ(target.StyleRef().EffectiveZoom(), 2); + + EXPECT_EQ(target.ObjectBoundingBox(), FloatRect(6, 5, 100, 50)); + EXPECT_EQ(target.StrokeBoundingBox(), FloatRect(12, 10, 200, 100)); + const auto& parent_g = *target.Parent(); + EXPECT_EQ(parent_g.ObjectBoundingBox(), FloatRect(6, 5, 100, 50)); + EXPECT_EQ(parent_g.StrokeBoundingBox(), FloatRect(6, 5, 100, 50)); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/svg_content_container.cc b/third_party/blink/renderer/core/layout/svg/svg_content_container.cc index 37814c8..9decb97f 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_content_container.cc +++ b/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
@@ -143,6 +143,16 @@ return false; } +static FloatRect ObjectBoundsForPropagation(const LayoutObject& object) { + FloatRect bounds = object.ObjectBoundingBox(); + // The local-to-parent transform for <foreignObject> contains a zoom inverse, + // so we need to apply zoom to the bounding box that we use for propagation to + // be in the correct coordinate space. + if (IsA<LayoutSVGForeignObject>(object)) + bounds.Scale(object.StyleRef().EffectiveZoom()); + return bounds; +} + bool SVGContentContainer::UpdateBoundingBoxes(bool& object_bounding_box_valid) { object_bounding_box_valid = false; @@ -154,8 +164,9 @@ if (!HasValidBoundingBoxForContainer(*current)) continue; const AffineTransform& transform = current->LocalToSVGParentTransform(); - UpdateObjectBoundingBox(object_bounding_box, object_bounding_box_valid, - transform.MapRect(current->ObjectBoundingBox())); + UpdateObjectBoundingBox( + object_bounding_box, object_bounding_box_valid, + transform.MapRect(ObjectBoundsForPropagation(*current))); stroke_bounding_box.Unite(transform.MapRect(current->StrokeBoundingBox())); }
diff --git a/third_party/blink/renderer/core/loader/address_space_feature.cc b/third_party/blink/renderer/core/loader/address_space_feature.cc index 3df2c4a..8848c33 100644 --- a/third_party/blink/renderer/core/loader/address_space_feature.cc +++ b/third_party/blink/renderer/core/loader/address_space_feature.cc
@@ -30,6 +30,8 @@ #include "third_party/blink/renderer/core/loader/address_space_feature.h" +#include <tuple> + #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-forward.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" @@ -41,130 +43,104 @@ using AddressSpace = network::mojom::blink::IPAddressSpace; using Feature = mojom::blink::WebFeature; -// Returns the kAddressSpaceLocal* WebFeature enum value corresponding to the -// given client loading a resource from the local address space, if any. -base::Optional<Feature> AddressSpaceLocalFeatureForSubresource( - AddressSpace client_address_space, - bool client_is_secure_context) { - switch (client_address_space) { - case AddressSpace::kUnknown: - return client_is_secure_context - ? Feature::kAddressSpaceUnknownSecureContextEmbeddedLocal - : Feature::kAddressSpaceUnknownNonSecureContextEmbeddedLocal; - case AddressSpace::kPublic: - return client_is_secure_context - ? Feature::kAddressSpacePublicSecureContextEmbeddedLocal - : Feature::kAddressSpacePublicNonSecureContextEmbeddedLocal; - case AddressSpace::kPrivate: - return client_is_secure_context - ? Feature::kAddressSpacePrivateSecureContextEmbeddedLocal - : Feature::kAddressSpacePrivateNonSecureContextEmbeddedLocal; - case AddressSpace::kLocal: - return base::nullopt; // Local to local is fine, we do not track it. - } +// A key in |kFeatureMap|. +// +// Mirrors the arguments to |AddressSpaceFeature()| except for |fetch_type|. +struct FeatureKey { + AddressSpace client_address_space; + bool client_is_secure_context; + AddressSpace response_address_space; +}; + +// FeatureKey instances are comparable for equality. +bool operator==(const FeatureKey& lhs, const FeatureKey& rhs) { + return std::tie(lhs.client_address_space, lhs.client_is_secure_context, + lhs.response_address_space) == + std::tie(rhs.client_address_space, rhs.client_is_secure_context, + rhs.response_address_space); } -// Returns the kAddressSpacePrivate* WebFeature enum value corresponding to the -// given client loading a resource from the private address space, if any. -base::Optional<Feature> AddressSpacePrivateFeatureForSubresource( - AddressSpace client_address_space, - bool client_is_secure_context) { - switch (client_address_space) { - case AddressSpace::kUnknown: - return client_is_secure_context - ? Feature::kAddressSpaceUnknownSecureContextEmbeddedPrivate - : Feature::kAddressSpaceUnknownNonSecureContextEmbeddedPrivate; - case AddressSpace::kPublic: - return client_is_secure_context - ? Feature::kAddressSpacePublicSecureContextEmbeddedPrivate - : Feature::kAddressSpacePublicNonSecureContextEmbeddedPrivate; - case AddressSpace::kPrivate: - case AddressSpace::kLocal: - // Private or local to local is fine, we do not track it. - return base::nullopt; - } -} +// An entry in |kFeatureMap|. +// +// A single key maps to features for all |fetch_type| values. We could instead +// have two maps, one for subresources and one for navigations, but they would +// have the exact same set of keys. Hence it is simpler to have a single map. +struct FeatureEntry { + // The key to this entry. + FeatureKey key; -base::Optional<Feature> AddressSpaceFeatureForSubresource( - AddressSpace client_address_space, - bool client_is_secure_context, - AddressSpace resource_address_space) { - switch (resource_address_space) { - case AddressSpace::kUnknown: - case AddressSpace::kPublic: - return base::nullopt; - case AddressSpace::kPrivate: - return AddressSpacePrivateFeatureForSubresource(client_address_space, - client_is_secure_context); - case AddressSpace::kLocal: - return AddressSpaceLocalFeatureForSubresource(client_address_space, - client_is_secure_context); - } -} + // The corresponding feature for |kSubresource| fetch types. + Feature subresource_feature; -// Returns the kAddressSpaceLocal* WebFeature enum value corresponding to the -// given client loading a resource from the local address space, if any. -base::Optional<Feature> AddressSpaceLocalFeatureForNavigation( - AddressSpace client_address_space, - bool is_secure_context) { - switch (client_address_space) { - case AddressSpace::kUnknown: - return is_secure_context - ? Feature::kAddressSpaceUnknownSecureContextNavigatedToLocal - : Feature:: - kAddressSpaceUnknownNonSecureContextNavigatedToLocal; - case AddressSpace::kPublic: - return is_secure_context - ? Feature::kAddressSpacePublicSecureContextNavigatedToLocal - : Feature::kAddressSpacePublicNonSecureContextNavigatedToLocal; - case AddressSpace::kPrivate: - return is_secure_context - ? Feature::kAddressSpacePrivateSecureContextNavigatedToLocal - : Feature:: - kAddressSpacePrivateNonSecureContextNavigatedToLocal; - case AddressSpace::kLocal: - return base::nullopt; // Local to local is fine, we do not track it. - } -} + // The corresponding feature for |kNavigation| fetch types. + Feature navigation_feature; +}; -// Returns the kAddressSpacePrivate* WebFeature enum value corresponding to the -// given client loading a resource from the private address space, if any. -base::Optional<Feature> AddressSpacePrivateFeatureForNavigation( - AddressSpace client_address_space, - bool is_secure_context) { - switch (client_address_space) { - case AddressSpace::kUnknown: - return is_secure_context - ? Feature::kAddressSpaceUnknownSecureContextNavigatedToPrivate - : Feature:: - kAddressSpaceUnknownNonSecureContextNavigatedToPrivate; - case AddressSpace::kPublic: - return is_secure_context - ? Feature::kAddressSpacePublicSecureContextNavigatedToPrivate - : Feature:: - kAddressSpacePublicNonSecureContextNavigatedToPrivate; - case AddressSpace::kPrivate: - case AddressSpace::kLocal: - // Private or local to local is fine, we do not track it. - return base::nullopt; - } -} +constexpr bool kNonSecureContext = false; +constexpr bool kSecureContext = true; -base::Optional<Feature> AddressSpaceFeatureForNavigation( - AddressSpace client_address_space, - bool is_secure_context, - AddressSpace response_address_space) { - switch (response_address_space) { - case AddressSpace::kUnknown: - case AddressSpace::kPublic: - return base::nullopt; - case AddressSpace::kPrivate: - return AddressSpacePrivateFeatureForNavigation(client_address_space, - is_secure_context); - case AddressSpace::kLocal: - return AddressSpaceLocalFeatureForNavigation(client_address_space, - is_secure_context); +constexpr struct FeatureEntry kFeatureMap[]{ + { + {AddressSpace::kPrivate, kNonSecureContext, AddressSpace::kLocal}, + Feature::kAddressSpacePrivateNonSecureContextEmbeddedLocal, + Feature::kAddressSpacePrivateNonSecureContextNavigatedToLocal, + }, + { + {AddressSpace::kPrivate, kSecureContext, AddressSpace::kLocal}, + Feature::kAddressSpacePrivateSecureContextEmbeddedLocal, + Feature::kAddressSpacePrivateSecureContextNavigatedToLocal, + }, + { + {AddressSpace::kPublic, kNonSecureContext, AddressSpace::kLocal}, + Feature::kAddressSpacePublicNonSecureContextEmbeddedLocal, + Feature::kAddressSpacePublicNonSecureContextNavigatedToLocal, + }, + { + {AddressSpace::kPublic, kSecureContext, AddressSpace::kLocal}, + Feature::kAddressSpacePublicSecureContextEmbeddedLocal, + Feature::kAddressSpacePublicSecureContextNavigatedToLocal, + }, + { + {AddressSpace::kPublic, kNonSecureContext, AddressSpace::kPrivate}, + Feature::kAddressSpacePublicNonSecureContextEmbeddedPrivate, + Feature::kAddressSpacePublicNonSecureContextNavigatedToPrivate, + }, + { + {AddressSpace::kPublic, kSecureContext, AddressSpace::kPrivate}, + Feature::kAddressSpacePublicSecureContextEmbeddedPrivate, + Feature::kAddressSpacePublicSecureContextNavigatedToPrivate, + }, + { + {AddressSpace::kUnknown, kNonSecureContext, AddressSpace::kLocal}, + Feature::kAddressSpaceUnknownNonSecureContextEmbeddedLocal, + Feature::kAddressSpaceUnknownNonSecureContextNavigatedToLocal, + }, + { + {AddressSpace::kUnknown, kSecureContext, AddressSpace::kLocal}, + Feature::kAddressSpaceUnknownSecureContextEmbeddedLocal, + Feature::kAddressSpaceUnknownSecureContextNavigatedToLocal, + }, + { + {AddressSpace::kUnknown, kNonSecureContext, AddressSpace::kPrivate}, + Feature::kAddressSpaceUnknownNonSecureContextEmbeddedPrivate, + Feature::kAddressSpaceUnknownNonSecureContextNavigatedToPrivate, + }, + { + {AddressSpace::kUnknown, kSecureContext, AddressSpace::kPrivate}, + Feature::kAddressSpaceUnknownSecureContextEmbeddedPrivate, + Feature::kAddressSpaceUnknownSecureContextNavigatedToPrivate, + }, +}; + +// Attempts to find an entry matching |key| in |kFeatureMap|. +// Returns a pointer to the entry if successful, nullptr otherwise. +const FeatureEntry* FindFeatureEntry(const FeatureKey& key) { + for (const FeatureEntry& entry : kFeatureMap) { + if (key == entry.key) { + return &entry; + } } + return nullptr; } base::Optional<Feature> AddressSpaceFeature( @@ -172,15 +148,21 @@ AddressSpace client_address_space, bool client_is_secure_context, AddressSpace response_address_space) { + FeatureKey key; + key.client_address_space = client_address_space; + key.client_is_secure_context = client_is_secure_context; + key.response_address_space = response_address_space; + + const FeatureEntry* entry = FindFeatureEntry(key); + if (!entry) { + return base::nullopt; + } + switch (fetch_type) { case FetchType::kSubresource: - return AddressSpaceFeatureForSubresource(client_address_space, - client_is_secure_context, - response_address_space); + return entry->subresource_feature; case FetchType::kNavigation: - return AddressSpaceFeatureForNavigation(client_address_space, - client_is_secure_context, - response_address_space); + return entry->navigation_feature; } }
diff --git a/third_party/blink/renderer/core/loader/address_space_feature.h b/third_party/blink/renderer/core/loader/address_space_feature.h index 35d5d384..d7fd01a 100644 --- a/third_party/blink/renderer/core/loader/address_space_feature.h +++ b/third_party/blink/renderer/core/loader/address_space_feature.h
@@ -66,7 +66,7 @@ FetchType fetch_type, network::mojom::blink::IPAddressSpace client_address_space, bool client_is_secure_context, - network::mojom::blink::IPAddressSpace resource_address_space); + network::mojom::blink::IPAddressSpace response_address_space); // Increments the correct kAddressSpace* WebFeature UseCounter corresponding to // the given |client_frame| performing a fetch of type |fetch_type| and
diff --git a/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc b/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc index dfdd18c..3b38ea9 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc
@@ -50,15 +50,14 @@ return Traversal<HTMLMapElement>::FirstAncestor(*area); } -AXObject* AXImageMapLink::ComputeParent() const { - DCHECK(!IsDetached()); - if (parent_) - return parent_; - - if (!MapElement()) - return nullptr; - - return AXObjectCache().GetOrCreate(MapElement()->GetLayoutObject()); +AXObject* AXImageMapLink::ComputeParentImpl() const { + if (MapElement()) { + AXObject* ax_parent = + AXObjectCache().GetOrCreate(MapElement()->GetLayoutObject()); + if (ax_parent) + return ax_parent; + } + return AXNodeObject::ComputeParentImpl(); } ax::mojom::blink::Role AXImageMapLink::DetermineAccessibilityRole() {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h b/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h index e1c75b3c..e7bd0f3 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h +++ b/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h
@@ -57,7 +57,7 @@ Element* ActionElement() const override; KURL Url() const override; bool IsLinked() const override { return true; } - AXObject* ComputeParent() const override; + AXObject* ComputeParentImpl() const override; void GetRelativeBounds(AXObject** out_container, FloatRect& out_bounds_in_container, SkMatrix44& out_container_transform,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc index 8e05e56..572d4f0 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
@@ -163,17 +163,6 @@ return inline_text_box_->GetText(); } -AXObject* AXInlineTextBox::ComputeParent() const { - DCHECK(!IsDetached()); - if (!inline_text_box_ || !ax_object_cache_) - return nullptr; - LineLayoutText line_layout_text = inline_text_box_->GetLineLayoutItem(); - if (!line_layout_text) - return nullptr; - return ax_object_cache_->GetOrCreate( - LineLayoutAPIShim::LayoutObjectFrom(line_layout_text)); -} - // In addition to LTR and RTL direction, edit fields also support // top to bottom and bottom to top via the CSS writing-mode property. ax::mojom::blink::WritingDirection AXInlineTextBox::GetTextDirection() const { @@ -211,7 +200,7 @@ scoped_refptr<AbstractInlineTextBox> next_on_line = inline_text_box_->NextOnLine(); if (next_on_line) - return ax_object_cache_->GetOrCreate(next_on_line.get()); + return AXObjectCache().GetOrCreate(next_on_line.get(), parent_); return nullptr; } @@ -226,7 +215,7 @@ scoped_refptr<AbstractInlineTextBox> previous_on_line = inline_text_box_->PreviousOnLine(); if (previous_on_line) - return ax_object_cache_->GetOrCreate(previous_on_line.get()); + return AXObjectCache().GetOrCreate(previous_on_line.get(), parent_); return nullptr; } @@ -234,6 +223,15 @@ void AXInlineTextBox::GetDocumentMarkers( Vector<DocumentMarker::MarkerType>* marker_types, Vector<AXRange>* marker_ranges) const { + // TODO(nektar) Address 20% performance degredation and restore code. + // It may be necessary to add document markers as part of tree data instead + // of computing for every node. To measure current performance, create a + // release build without DCHECKs, and then run command similar to: + // tools/perf/run_benchmark blink_perf.accessibility --browser=exact \ + // --browser-executable=path/to/chrome --story-filter="accessibility.*" + // --results-label="[my-branch-name]" + // Pay attention only to rows with ProcessDeferredAccessibilityEvents + // and RenderAccessibilityImpl::SendPendingAccessibilityEvents. if (!RuntimeEnabledFeatures:: AccessibilityUseAXPositionForDocumentMarkersEnabled()) return; @@ -272,6 +270,14 @@ if (dom_range_start.IsNull() || dom_range_end.IsNull()) return; + // TODO(nektar) Figure out why the start > end sometimes. + // To see error, comment out below early return and run command similar to: + // run_web_tests.py --driver-logging -t linux-debug + // --additional-driver-flag=--force-renderer-accessibility + // external/wpt/css/css-ui/text-overflow-006.html + if (dom_range_start > dom_range_end) + return; // Temporary until above TODO is resolved. + DCHECK_LE(dom_range_start, dom_range_end); const EphemeralRangeInFlatTree dom_range( ToPositionInFlatTree(dom_range_start), ToPositionInFlatTree(dom_range_end)); @@ -321,8 +327,11 @@ } } -void AXInlineTextBox::Init() { +void AXInlineTextBox::Init(AXObject* parent) { role_ = ax::mojom::blink::Role::kInlineTextBox; + DCHECK(parent); + SetParent(parent); + UpdateCachedAttributeValuesIfNeeded(false); } void AXInlineTextBox::Detach() {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h index cce5d63..60ad0c8e 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h +++ b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h
@@ -57,7 +57,6 @@ FloatRect& out_bounds_in_container, SkMatrix44& out_container_transform, bool* clips_children = nullptr) const override; - AXObject* ComputeParent() const override; ax::mojom::blink::WritingDirection GetTextDirection() const override; Node* GetNode() const override; AXObject* NextOnLine() const override; @@ -66,7 +65,7 @@ Vector<AXRange>* marker_ranges) const override; protected: - void Init() override; + void Init(AXObject* parent) override; void Detach() override; bool IsDetached() const override; bool IsAXInlineTextBox() const override;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc index 931603f..ffac50da 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -223,8 +223,10 @@ } ax::mojom::blink::Role AXLayoutObject::DetermineAccessibilityRole() { - if (!layout_object_) + if (!layout_object_) { + NOTREACHED(); return ax::mojom::blink::Role::kUnknown; + } if (GetCSSAltText(GetNode())) { const ComputedStyle* style = GetNode()->GetComputedStyle(); ContentData* content_data = style->GetContentData(); @@ -282,10 +284,6 @@ return GetNode(); } -void AXLayoutObject::Init() { - AXNodeObject::Init(); -} - void AXLayoutObject::Detach() { AXNodeObject::Detach(); @@ -1415,7 +1413,7 @@ // No visible rendered text -- must be whitespace. // Either it is useful whitespace for separating words or not. if (layout_text->IsAllCollapsibleWhitespace()) { - if (cached_is_ignored_) + if (LastKnownIsIgnoredValue()) return ""; // If no textboxes, this was whitespace at the line's end. text_alternative = " "; @@ -1527,179 +1525,6 @@ return result; } -// -// Low-level accessibility tree exploration, only for use within the -// accessibility module. -// -// LAYOUT TREE WALKING ALGORITHM -// -// The fundamental types of elements in the Blink layout tree are block -// elements and inline elements. It can get a little confusing when -// an inline element has both inline and block children, for example: -// -// <a href="#"> -// Before Block -// <div> -// In Block -// </div> -// Outside Block -// </a> -// -// Blink wants to maintain the invariant that all of the children of a node -// are either all block or all inline, so it creates three anonymous blocks: -// -// #1 LayoutBlockFlow (anonymous) -// #2 LayoutInline A continuation=#4 -// #3 LayoutText "Before Block" -// #4 LayoutBlockFlow (anonymous) continuation=#8 -// #5 LayoutBlockFlow DIV -// #6 LayoutText "In Block" -// #7 LayoutBlockFlow (anonymous) -// #8 LayoutInline A is_continuation -// #9 LayoutText "Outside Block" -// -// For a good explanation of why this is done, see this blog entry. It's -// describing WebKit in 2007, but the fundamentals haven't changed much. -// -// https://webkit.org/blog/115/webcore-rendering-ii-blocks-and-inlines/ -// -// Now, it's important to understand that we couldn't just use the layout -// tree as the accessibility tree as-is, because the div is no longer -// inside the link! In fact, the link has been split into two different -// nodes, #2 and #8. Luckily, the layout tree contains continuations to -// help us untangle situations like this. -// -// Here's the algorithm we use to walk the layout tree in order to build -// the accessibility tree: -// -// 1. When computing the first child or next sibling of a node, skip over any -// LayoutObjects that are continuations. -// -// 2. When computing the next sibling of a node and there are no more siblings -// in the layout tree, see if the parent node has a continuation, and if -// so follow it and make that the next sibling. -// -// 3. When computing the first child of a node that has a continuation but -// no children in the layout tree, the continuation is the first child. -// -// The end result is this tree, which we use as the basis for the -// accessibility tree. -// -// #1 LayoutBlockFlow (anonymous) -// #2 LayoutInline A -// #3 LayoutText "Before Block" -// #4 LayoutBlockFlow (anonymous) -// #5 LayoutBlockFlow DIV -// #6 LayoutText "In Block" -// #8 LayoutInline A is_continuation -// #9 LayoutText "Outside Block" -// #7 LayoutBlockFlow (anonymous) -// -// This algorithm results in an accessibility tree that preserves containment -// (i.e. the contents of the link in the example above are descendants of the -// link node) while including all of the rich layout detail from the layout -// tree. -// -// There are just a couple of other corner cases to walking the layout tree: -// -// * Walk tables in table order (thead, tbody, tfoot), which may not match -// layout order. -// * Skip CSS first-letter nodes. -// - -// Given a layout object, return the start of the continuation chain. -static inline LayoutInline* StartOfContinuations(LayoutObject* layout_object) { - // See LAYOUT TREE WALKING ALGORITHM, above, for more context as to why - // we need to do this. - - // For inline elements, if it's a continuation, the start of the chain - // is always the primary layout object associated with the node. - if (layout_object->IsInlineElementContinuation()) - return To<LayoutInline>(layout_object->GetNode()->GetLayoutObject()); - - // Blocks with a previous continuation always have a next continuation, - // so we can get the next continuation and do the same trick to get - // the primary layout object associated with the node. - auto* layout_block_flow = DynamicTo<LayoutBlockFlow>(layout_object); - if (layout_block_flow && layout_block_flow->InlineElementContinuation()) { - auto* result = - To<LayoutInline>(layout_block_flow->InlineElementContinuation() - ->GetNode() - ->GetLayoutObject()); - DCHECK_NE(result, layout_object); - return result; - } - - return nullptr; -} - -// See LAYOUT TREE WALKING ALGORITHM, above, for details. -static inline LayoutObject* ParentLayoutObject(LayoutObject* layout_object) { - if (!layout_object) - return nullptr; - - // If the node is a continuation, the parent is the start of the continuation - // chain. See LAYOUT TREE WALKING ALGORITHM, above, for more context as to - // why we need to do this. - LayoutObject* start_of_conts = StartOfContinuations(layout_object); - if (start_of_conts) - return start_of_conts; - - // Otherwise just return the parent in the layout tree. - return layout_object->Parent(); -} - -// -// High-level accessibility tree access. -// - -AXObject* AXLayoutObject::ComputeParent() const { - DCHECK(!IsDetached()); - if (!layout_object_) - return nullptr; - - if (AriaRoleAttribute() == ax::mojom::blink::Role::kMenuBar) - return AXObjectCache().GetOrCreate(layout_object_->Parent()); - - if (GetNode()) - return AXNodeObject::ComputeParent(); - - LayoutObject* parent_layout_obj = ParentLayoutObject(layout_object_); - if (parent_layout_obj) - return AXObjectCache().GetOrCreate(parent_layout_obj); - - // A WebArea's parent should be the page popup owner, if any, otherwise null. - if (IsWebArea()) { - LocalFrame* frame = layout_object_->GetFrame(); - return AXObjectCache().GetOrCreate(frame->PagePopupOwner()); - } - - return nullptr; -} - -AXObject* AXLayoutObject::ComputeParentIfExists() const { - if (!layout_object_) - return nullptr; - - if (AriaRoleAttribute() == ax::mojom::blink::Role::kMenuBar) - return AXObjectCache().Get(layout_object_->Parent()); - - if (GetNode()) - return AXNodeObject::ComputeParentIfExists(); - - LayoutObject* parent_layout_obj = ParentLayoutObject(layout_object_); - if (parent_layout_obj) - return AXObjectCache().Get(parent_layout_obj); - - // A WebArea's parent should be the page popup owner, if any, otherwise null. - if (IsWebArea()) { - LocalFrame* frame = layout_object_->GetFrame(); - return AXObjectCache().Get(frame->PagePopupOwner()); - } - - return nullptr; -} - bool AXLayoutObject::CanHaveChildren() const { if (!layout_object_) return false;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h index aefa84c..5770989 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
@@ -76,7 +76,6 @@ // Overridden from AXObject. // - void Init() override; void Detach() override; bool IsDetached() const override; bool IsAXLayoutObject() const final; @@ -136,11 +135,6 @@ // Hit testing. AXObject* AccessibilityHitTest(const IntPoint&) const override; - // High-level accessibility tree access. Other modules should only use these - // functions. - AXObject* ComputeParent() const override; - AXObject* ComputeParentIfExists() const override; - bool CanHaveChildren() const override; // Notifications that this object may have changed.
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc b/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc index 52fa5ad..4a6df3e 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc
@@ -64,19 +64,31 @@ // There's no reason to clear our AXMenuListPopup child. If we get a // call to clearChildren, it's because the options might have changed, - // so call it on our popup. - DCHECK_EQ(ChildCountIncludingIgnored(), 1); + // so call it on our popup. Clearing the AXMenuListPopup child would cause + // additional thrashing and events that the AT would need to process, + // potentially causing the AT to believe that the popup had closed and a + // new popup and reopened. + DCHECK_EQ(children_.size(), 1U); children_[0]->ClearChildren(); } void AXMenuList::AddChildren() { +#if DCHECK_IS_ON() DCHECK(!IsDetached()); + DCHECK(!is_adding_children_) << " Reentering method on " << GetNode(); + base::AutoReset<bool> reentrancy_protector(&is_adding_children_, true); + DCHECK_EQ(children_.size(), 0U) + << "Parent still has " << children_.size() << " children before adding:" + << "\nParent is " << ToString(true, true) << "\nFirst child is " + << children_[0]->ToString(true, true); +#endif have_children_ = true; AXObjectCacheImpl& cache = AXObjectCache(); - AXObject* popup = cache.GetOrCreate(ax::mojom::Role::kMenuListPopup); + AXObject* popup = + cache.CreateAndInit(ax::mojom::blink::Role::kMenuListPopup, this); DCHECK(popup); - To<AXMockObject>(popup)->SetParent(this); + DCHECK(!popup->IsDetached()); children_.push_back(popup); popup->AddChildren(); }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc b/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc index decf019e..57e1be17 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc
@@ -57,7 +57,7 @@ return element_; } -AXObject* AXMenuListOption::ComputeParent() const { +AXObject* AXMenuListOption::ComputeParentImpl() const { Node* node = GetNode(); if (!node) return nullptr; @@ -73,17 +73,20 @@ if (!menu_list) return select_ax_object; - if (menu_list->HasChildren()) { - const auto& child_objects = menu_list->ChildrenIncludingIgnored(); - if (child_objects.IsEmpty()) - return nullptr; - DCHECK_EQ(child_objects.size(), 1UL); - DCHECK(IsA<AXMenuListPopup>(child_objects[0].Get())); - To<AXMenuListPopup>(child_objects[0].Get())->UpdateChildrenIfNecessary(); - } else { + if (!menu_list->HasChildren()) { menu_list->UpdateChildrenIfNecessary(); } - return parent_.Get(); + + const auto& child_objects = menu_list->ChildrenIncludingIgnored(); + if (child_objects.IsEmpty()) + return nullptr; + DCHECK_EQ(child_objects.size(), 1UL) + << "A menulist must have a single popup child"; + DCHECK(IsA<AXMenuListPopup>(child_objects[0].Get())); + To<AXMenuListPopup>(child_objects[0].Get())->UpdateChildrenIfNecessary(); + + // Return the popup child, which is the parent of this AXMenuListOption. + return child_objects[0]; } bool AXMenuListOption::IsVisible() const {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h b/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h index 1caea39..93aff6c 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h +++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h
@@ -38,6 +38,7 @@ public: AXMenuListOption(HTMLOptionElement*, AXObjectCacheImpl&); ~AXMenuListOption() override; + bool IsDetached() const override { return !element_; } private: void Trace(Visitor*) const override; @@ -46,10 +47,9 @@ Node* GetNode() const override { return element_; } void Detach() override; - bool IsDetached() const override { return !element_; } LocalFrameView* DocumentFrameView() const override; bool CanHaveChildren() const override { return false; } - AXObject* ComputeParent() const override; + AXObject* ComputeParentImpl() const override; Element* ActionElement() const override; bool IsVisible() const override;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc b/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc index b4823a35..595053f 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc
@@ -61,17 +61,14 @@ } AXMenuListOption* AXMenuListPopup::MenuListOptionAXObject( - HTMLElement* element) const { + HTMLElement* element) { DCHECK(element); if (!IsA<HTMLOptionElement>(*element)) return nullptr; - auto* ax_object = - DynamicTo<AXMenuListOption>(AXObjectCache().GetOrCreate(element)); - if (!ax_object) - return nullptr; + AXObject* ax_object = AXObjectCache().GetOrCreate(element, this); - return ax_object; + return DynamicTo<AXMenuListOption>(ax_object); } int AXMenuListPopup::GetSelectedIndex() const { @@ -93,7 +90,16 @@ } void AXMenuListPopup::AddChildren() { +#if DCHECK_IS_ON() DCHECK(!IsDetached()); + DCHECK(!is_adding_children_) << " Reentering method on " << GetNode(); + base::AutoReset<bool> reentrancy_protector(&is_adding_children_, true); + DCHECK_EQ(children_.size(), 0U) + << "Parent still has " << children_.size() << " children before adding:" + << "\nParent is " << ToString(true, true) << "\nFirst child is " + << children_[0]->ToString(true, true); +#endif + if (!parent_) return; @@ -109,8 +115,8 @@ for (auto* const option_element : html_select_element->GetOptionList()) { AXMenuListOption* option = MenuListOptionAXObject(option_element); if (option) { + DCHECK(!option->IsDetached()); children_.push_back(option); - option->SetParent(this); } } }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h b/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h index baa1149..fc180737 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h +++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h
@@ -60,7 +60,7 @@ void AddChildren() override; bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override; - AXMenuListOption* MenuListOptionAXObject(HTMLElement*) const; + AXMenuListOption* MenuListOptionAXObject(HTMLElement*); int GetSelectedIndex() const; // Note that this may be -1 if nothing is selected.
diff --git a/third_party/blink/renderer/modules/accessibility/ax_mock_object.h b/third_party/blink/renderer/modules/accessibility/ax_mock_object.h index 5e409c07..5c87a4c 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_mock_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_mock_object.h
@@ -42,7 +42,6 @@ ~AXMockObject() override; // AXObject overrides. - AXObject* ComputeParent() const override { return parent_; } AXRestriction Restriction() const override { return kRestrictionNone; } bool IsMockObject() const final { return true; }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index a8a8c32..1067d1cd 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -89,6 +89,7 @@ #include "third_party/blink/renderer/core/layout/layout_block_flow.h" #include "third_party/blink/renderer/core/layout/layout_box_model_object.h" #include "third_party/blink/renderer/core/layout/layout_image.h" +#include "third_party/blink/renderer/core/layout/layout_inline.h" #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_table.h" #include "third_party/blink/renderer/core/layout/layout_view.h" @@ -126,6 +127,31 @@ role == ax::mojom::blink::Role::kRowGroup; } +// Within a table, provide the accessible, semantic parent of |node|, +// by traversing the DOM tree, ignoring elements that are neutral in a table. +// Return the AXObject for the ancestor. +blink::AXObject* GetDOMTableAXAncestor(blink::Node* node, + blink::AXObjectCacheImpl& cache) { + // Used by code to determine roles of elements inside of an HTML table, + // Use DOM to get parent since parent_ is not initialized yet when role is + // being computed, and because HTML table structure should not take into + // account aria-owns. + if (!node) + return nullptr; + + while (true) { + node = blink::NodeTraversal::Parent(*node); + if (!node) + return nullptr; + + blink::AXObject* ax_object = cache.GetOrCreate(node); + if (ax_object && !IsNeutralWithinTable(ax_object)) + return ax_object; + } + + return nullptr; +} + enum class AXAction { kActionIncrement = 0, kActionDecrement, @@ -682,7 +708,7 @@ if (!GetElement()) return ax::mojom::blink::Role::kUnknown; - AXObject* parent = ParentObject(); + AXObject* parent = GetDOMTableAXAncestor(GetNode(), AXObjectCache()); if (!parent || !parent->IsTableLikeRole()) return ax::mojom::blink::Role::kGenericContainer; @@ -693,9 +719,7 @@ } ax::mojom::blink::Role AXNodeObject::DetermineTableRowRole() const { - AXObject* parent = ParentObject(); - while (IsNeutralWithinTable(parent)) - parent = parent->ParentObject(); + AXObject* parent = GetDOMTableAXAncestor(GetNode(), AXObjectCache()); if (!parent || !parent->IsTableLikeRole()) return ax::mojom::blink::Role::kGenericContainer; @@ -710,14 +734,13 @@ } ax::mojom::blink::Role AXNodeObject::DetermineTableCellRole() const { - AXObject* parent = ParentObject(); + AXObject* parent = GetDOMTableAXAncestor(GetNode(), AXObjectCache()); if (!parent || !parent->IsTableRowLikeRole()) return ax::mojom::blink::Role::kGenericContainer; // Ensure table container. - AXObject* grandparent = parent->ParentObject(); - while (IsNeutralWithinTable(grandparent)) - grandparent = grandparent->ParentObject(); + AXObject* grandparent = + GetDOMTableAXAncestor(parent->GetNode(), AXObjectCache()); if (!grandparent || !grandparent->IsTableLikeRole()) return ax::mojom::blink::Role::kGenericContainer; @@ -1018,8 +1041,10 @@ } ax::mojom::blink::Role AXNodeObject::DetermineAccessibilityRole() { - if (!GetNode()) + if (!GetNode()) { + NOTREACHED(); return ax::mojom::blink::Role::kUnknown; + } native_role_ = NativeRoleIgnoringAria(); @@ -1158,12 +1183,12 @@ return nullptr; } -void AXNodeObject::Init() { +void AXNodeObject::Init(AXObject* parent_if_known) { #if DCHECK_IS_ON() DCHECK(!initialized_); initialized_ = true; #endif - AXObject::Init(); + AXObject::Init(parent_if_known); } void AXNodeObject::Detach() { @@ -1636,6 +1661,9 @@ return String(); } +// TODO(nektar): Consider removing this method in favor of +// AXInlineTextBox::GetDocumentMarkers, or add document markers to the tree data +// instead of nodes objects. void AXNodeObject::GetDocumentMarkers( Vector<DocumentMarker::MarkerType>* marker_types, Vector<AXRange>* marker_ranges) const { @@ -2751,6 +2779,8 @@ HeapVector<Member<AXObject>> owned_children; AXObjectCache().GetAriaOwnedChildren(this, owned_children); + // TODO(aleventhal) Why isn't this just using cached children? + AXNodeObject* parent = const_cast<AXNodeObject*>(this); for (Node* child = LayoutTreeBuilderTraversal::FirstChild(*node_); child; child = LayoutTreeBuilderTraversal::NextSibling(*child)) { auto* child_text_node = DynamicTo<Text>(child); @@ -2759,7 +2789,7 @@ // skip over empty text nodes continue; } - AXObject* child_obj = AXObjectCache().GetOrCreate(child); + AXObject* child_obj = AXObjectCache().GetOrCreate(child, parent); if (child_obj && !AXObjectCache().IsAriaOwned(child_obj)) children.push_back(child_obj); } @@ -2942,28 +2972,6 @@ } } -static Node* GetParentNodeForComputeParent(Node* node) { - if (!node) - return nullptr; - - return LayoutTreeBuilderTraversal::Parent(*node); -} - -AXObject* AXNodeObject::ComputeParent() const { - DCHECK(!IsDetached()); - if (Node* parent_node = GetParentNodeForComputeParent(GetNode())) - return AXObjectCache().GetOrCreate(parent_node); - - return nullptr; -} - -AXObject* AXNodeObject::ComputeParentIfExists() const { - if (Node* parent_node = GetParentNodeForComputeParent(GetNode())) - return AXObjectCache().Get(parent_node); - - return nullptr; -} - bool AXNodeObject::IsHtmlTable() const { return IsTableLikeRole() && GetLayoutObject() && GetLayoutObject()->IsTable() && IsA<HTMLTableElement>(GetNode()); @@ -3092,6 +3100,7 @@ if (GetLayoutObject()->IsText()) { ClearChildren(); AddInlineTextBoxChildren(true); + have_children_ = true; // Avoid adding these children twice. return; } @@ -3121,20 +3130,22 @@ return; } + if (LastKnownIsIgnoredValue()) { + // Inline textboxes are included if and only if the parent is unignored. + // If the parent is ignored but included in tree, the inline textbox is + // still withheld. + return; + } + auto* layout_text = To<LayoutText>(GetLayoutObject()); for (scoped_refptr<AbstractInlineTextBox> box = layout_text->FirstAbstractInlineTextBox(); box.get(); box = box->NextInlineTextBox()) { - AXObject* ax_box = AXObjectCache().GetOrCreate(box.get()); - if (!ax_box || !ax_box->AccessibilityIsIncludedInTree()) + AXObject* ax_box = AXObjectCache().GetOrCreate(box.get(), this); + if (!ax_box) continue; children_.push_back(ax_box); - // If |force| is set to true, it means that we are forcing the children to - // be added without going through the normal tree building mechanism, which - // would have also set the parent of each child to |this|. - if (force) - ax_box->SetParent(this); } } @@ -3155,7 +3166,7 @@ for (HTMLAreaElement& area : Traversal<HTMLAreaElement>::DescendantsOf(*map)) { // add an <area> element for this child if it has a link - AddChild(AXObjectCache().GetOrCreate(&area)); + AddChild(AXObjectCache().GetOrCreate(&area, this)); } } @@ -3177,7 +3188,7 @@ DCHECK(GetLayoutObject()); LayoutObject* child = GetLayoutObject()->SlowFirstChild(); while (child) { - AddChild(AXObjectCache().GetOrCreate(child)); + AddChild(AXObjectCache().GetOrCreate(child, this)); child = child->NextSibling(); } } @@ -3188,7 +3199,8 @@ for (Node* child = LayoutTreeBuilderTraversal::FirstChild(*node_); child; child = LayoutTreeBuilderTraversal::NextSibling(*child)) { - AXObject* child_obj = AXObjectCache().GetOrCreate(child); + AXObject* child_obj = AXObjectCache().GetOrCreate(child, this); + if (RuntimeEnabledFeatures::AccessibilityExposeIgnoredNodesEnabled() && child_obj && child_obj->RoleValue() == ax::mojom::blink::Role::kStaticText && @@ -3203,9 +3215,28 @@ } } +void AXNodeObject::AddOwnedChildren() { + AXObjectVector owned_children; + AXObjectCache().GetAriaOwnedChildren(this, owned_children); + + for (const auto& owned_child : owned_children) { + owned_child->SetParent(this); + AddChild(owned_child, true); + } +} + void AXNodeObject::AddChildren() { - if (IsDetached()) - return; +#if DCHECK_IS_ON() + DCHECK(!IsDetached()); + DCHECK(!is_adding_children_) << " Reentering method on " << GetNode(); + base::AutoReset<bool> reentrancy_protector(&is_adding_children_, true); + DCHECK_EQ(children_.size(), 0U) + << "\nParent still has " << children_.size() << " children before adding:" + << "\nParent is " << ToString(true, true) << "\nFirst child is " + << children_[0]->ToString(true, true); +#endif +#define CHECK_ATTACHED() \ + DCHECK(!IsDetached()) << "Detached adding children: " << ToString(true, true) // If the need to add more children in addition to existing children arises, // childrenChanged should have been called, leaving the object with no @@ -3213,40 +3244,47 @@ DCHECK(!have_children_); have_children_ = true; - AXObjectVector owned_children; - AXObjectCache().GetAriaOwnedChildren(this, owned_children); - if (IsHtmlTable()) AddTableChildren(); else if (ShouldUseLayoutObjectTraversalForChildren()) AddLayoutChildren(); else AddNodeChildren(); - - // TODO(crbug.com/1158511) This shouldn't be needed! - if (IsDetached()) - return; + CHECK_ATTACHED(); AddPopupChildren(); + CHECK_ATTACHED(); + AddImageMapChildren(); - AddInlineTextBoxChildren(false); + CHECK_ATTACHED(); + + AddInlineTextBoxChildren(); + CHECK_ATTACHED(); + AddValidationMessageChild(); + CHECK_ATTACHED(); + AddAccessibleNodeChildren(); + CHECK_ATTACHED(); - for (const auto& owned_child : owned_children) - AddChild(owned_child, true); + AddOwnedChildren(); + CHECK_ATTACHED(); +#if DCHECK_IS_ON() + // All added children must be attached. for (const auto& child : children_) { - if (!child->CachedParentObject()) - child->SetParent(this); + DCHECK(!child->IsDetached()) + << "A brand new child was detached: " << child->ToString(true, true) + << "\n ... of parent " << ToString(true, true); } +#endif } void AXNodeObject::AddNodeChild(Node* node) { if (!node) return; - AddChild(AXObjectCache().GetOrCreate(node)); + AddChild(AXObjectCache().GetOrCreate(node, this)); } void AXNodeObject::AddChild(AXObject* child, bool is_from_aria_owns) { @@ -3263,6 +3301,8 @@ if (!child || !CanHaveChildren()) return; + DCHECK(!child->IsDetached()) + << "Cannot add a detached child: " << child->ToString(true, true); if (is_from_aria_owns) { DCHECK(AXObjectCache().IsAriaOwned(child)); } else { @@ -3272,11 +3312,29 @@ return; } - if (!child->AccessibilityIsIncludedInTree()) { - DCHECK(!is_from_aria_owns) << "Owned elements smust be in tree"; + // Set the parent: + // - For a new object it will have already been set. + // - For a reused, older object, it may need to be changed to a new parent. + child->SetParent(this); + +#if DCHECK_IS_ON() + child->EnsureCorrectParentComputation(); +#endif + + // Update cached values preemptively, but don't allow children changed to be + // called if ignored change, we are already recomputing children and don't + // want to recurse. + child->UpdateCachedAttributeValuesIfNeeded(false); + + if (!child->LastKnownIsIncludedInTreeValue()) { + DCHECK(!is_from_aria_owns) + << "Owned elements must be in tree: " << child->ToString(true, true) + << "\nRecompute included in tree: " + << child->ComputeAccessibilityIsIgnoredButIncludedInTree(); // Child is ignored and not in the tree. // Recompute the child's children now as we skip over the ignored object. child->SetNeedsToUpdateChildren(); + // Get the ignored child's children and add to children of ancestor // included in tree. This will recurse if necessary, skipping levels of // unignored descendants as it goes. @@ -3287,11 +3345,16 @@ // If the child was owned, it will be added elsewhere as a direct // child of the object owning it, and not as an indirect child under // an object not included in the tree. - if (!AXObjectCache().IsAriaOwned(children[i])) + if (!AXObjectCache().IsAriaOwned(children[i])) { + DCHECK(!children[i]->IsDetached()) << "Cannot add a detached child: " + << children[i]->ToString(true, true); children_.insert(new_index++, children[i]); + } } } else if (!child->IsMenuListOption()) { // MenuListOptions must only be added in AXMenuListPopup::AddChildren. + DCHECK(!child->IsDetached()) + << "Cannot add a detached child: " << child->ToString(true, true); children_.insert(index, child); } } @@ -3655,6 +3718,21 @@ if (!GetNode() && !GetLayoutObject()) return; + // When children changed on a <map> that means we need to forward the + // children changed to the <img> that parents the <area> elements. + // TODO(accessibility) Consider treating <img usemap> as aria-owns so that + // we get implementation "for free" vai relation cache, etc. + if (HTMLMapElement* map_element = DynamicTo<HTMLMapElement>(GetNode())) { + HTMLImageElement* image_element = map_element->ImageElement(); + if (image_element) { + AXObject* ax_image = AXObjectCache().Get(image_element); + if (ax_image) { + ax_image->ChildrenChanged(); + return; + } + } + } + // Always update current object, in case it wasn't included in the tree but // now is. In that case, the LastKnownIsIncludedInTreeValue() won't have been // updated yet, so we can't use that. Unfortunately, this is not a safe time @@ -3672,7 +3750,6 @@ node_to_update->SetNeedsToUpdateChildren(); } - // If this node's children are not part of the accessibility tree then // skip notification and walking up the ancestors. // Cases where this happens: @@ -3680,7 +3757,7 @@ // - this or an ancestor is a leaf node // Uses |cached_is_descendant_of_leaf_node_| to avoid updating cached // attributes for eachc change via | UpdateCachedAttributeValuesIfNeeded()|. - if (!CanHaveChildren() || cached_is_descendant_of_leaf_node_) + if (!CanHaveChildren() || LastKnownIsDescendantOfLeafNode()) return; // Calling CanHaveChildren(), above, can occasionally detach |this|. @@ -3692,10 +3769,70 @@ } void AXNodeObject::UpdateChildrenIfNecessary() { - if (NeedsToUpdateChildren()) +#if DCHECK_IS_ON() + DCHECK(GetDocument()); + DCHECK(GetDocument()->IsActive()); + DCHECK(!GetDocument()->IsDetached()); + DCHECK(GetDocument()->GetPage()); + DCHECK(GetDocument()->View()); + DCHECK(!AXObjectCache().HasBeenDisposed()); + + // Store previous children for DCHECK to ensure no lost children, left + // without parents. + HashSet<AXID> prev_children_axids; + for (const auto& child : children_) { + if (!child->IsDetached()) { + AXID prev_child_axid = child->AXObjectID(); + prev_children_axids.insert(prev_child_axid); + DCHECK(AXObjectCache().ObjectFromAXID(prev_child_axid)); + } + } +#endif + + // Clear current children and get new children. + // TODO(accessibility) is it necessary to have a separate + // NeedsToUpdateChildren() from HasChildren()? + if (NeedsToUpdateChildren()) { ClearChildren(); + if (!IsMenuList()) { // AXMenuList is special and keeps its popup child. + // Ensure children have been correctly cleared. + DCHECK(!HasChildren()) + << GetNode() << " with " << children_.size() << " children"; + DCHECK_EQ(children_.size(), 0U); + } + } else if (HasChildren()) { + return; // Keep existing children. + } else { + // Will update children even though NeedsToUpdateChildren() was not true. + // Cannot have children otherwise will end up adding to them. + DCHECK_EQ(children_.size(), 0U); + } AXObject::UpdateChildrenIfNecessary(); + +#if DCHECK_IS_ON() + // Remove current children's AXIDs from set so that we can see what children + // have been lost. + for (const auto& child : children_) + prev_children_axids.erase(child->AXObjectID()); + + // Report lost children. These are children that had |this| as a parent at + // the start of this method, but no longer do, yet the cache still considers + // them alive. + bool has_last_children = false; + for (AXID prev_child_axid : prev_children_axids) { + AXObject* prev_child = nullptr; + if (prev_child_axid) + AXObjectCache().ObjectFromAXID(prev_child_axid); + if (prev_child) { + has_last_children = true; + LOG(ERROR) << "Lost child: " << prev_child->ToString(true, true) + << "\nThis: " << ToString(true, true); + } + } + + DCHECK(!has_last_children); +#endif } void AXNodeObject::SelectedOptions(AXObjectVector& options) const { @@ -4276,7 +4413,8 @@ } Element* title_element = document->TitleElement(); - AXObject* title_ax_object = AXObjectCache().GetOrCreate(title_element); + AXObject* title_ax_object = AXObjectCache().GetOrCreate( + title_element, AXObjectCache().Get(document)); if (title_ax_object) { if (related_objects) { local_related_objects.push_back(
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.h b/third_party/blink/renderer/modules/accessibility/ax_node_object.h index 5416390..bf122550 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_node_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
@@ -85,7 +85,7 @@ // Overridden from AXObject. // - void Init() override; + void Init(AXObject* parent_if_known) override; void Detach() override; bool IsDetached() const override; bool IsAXNodeObject() const final; @@ -208,10 +208,6 @@ SkMatrix44& out_container_transform, bool* clips_children = nullptr) const override; - // High-level accessibility tree access. - AXObject* ComputeParent() const override; - AXObject* ComputeParentIfExists() const override; - void AddChildren() override; bool CanHaveChildren() const override; @@ -306,12 +302,14 @@ void AddNodeChildren(); void AddLayoutChildren(); - void AddInlineTextBoxChildren(bool force); + void AddInlineTextBoxChildren(bool force = false); void AddImageMapChildren(); void AddPopupChildren(); bool IsHtmlTable() const; void AddTableChildren(); void AddValidationMessageChild(); + void AddOwnedChildren(); + ax::mojom::blink::Dropeffect ParseDropeffect(String& dropeffect) const; DISALLOW_COPY_AND_ASSIGN(AXNodeObject);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index 0e8ad53..400d6b1a 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -85,6 +85,20 @@ namespace { +Node* GetParentNodeForComputeParent(Node* node) { + if (!node) + return nullptr; + + // Prefer LayoutTreeBuilderTraversal::Parent(), which handles pseudo content. + Node* parent = LayoutTreeBuilderTraversal::Parent(*node); + if (parent) + return parent; + + // Unfortunately, LayoutTreeBuilderTraversal::Parent() can return nullptr for + // a text node, such as inside a text area. Fall back on DOM parentNode(). + return node->parentNode(); +} + struct RoleHashTraits : HashTraits<ax::mojom::blink::Role> { static const bool kEmptyValueIsZero = true; static ax::mojom::blink::Role EmptyValue() { @@ -566,8 +580,6 @@ have_children_(false), role_(ax::mojom::blink::Role::kUnknown), aria_role_(ax::mojom::blink::Role::kUnknown), - last_known_is_ignored_value_(kDefaultBehavior), - last_known_is_ignored_but_included_in_tree_value_(kDefaultBehavior), explicit_container_id_(0), parent_(nullptr), last_modification_count_(-1), @@ -590,22 +602,45 @@ --number_of_live_ax_objects_; } -void AXObject::Init() { +void AXObject::Init(AXObject* parent_if_known) { +#if DCHECK_IS_ON() + DCHECK(!parent_); + DCHECK(!is_initializing_); + base::AutoReset<bool> reentrancy_protector(&is_initializing_, true); +#endif + + // The role must be determined immedediately. + // Note: in order to avoid reentrancy, the role computation cannot use the + // ParentObject(), although it can use the DOM parent. role_ = DetermineAccessibilityRole(); DCHECK(role_ != ax::mojom::blink::Role::kUnknown) - << "Illegal Role::kUnknown for " << GetNode(); + << "Illegal Role::kUnknown for " << GetNode() << " " << GetLayoutObject(); + + // Determine the parent as soon as possible. + // Every AXObject must have a parent unless it's the root. + SetParent(parent_if_known ? parent_if_known : ComputeParent()); + DCHECK(parent_ || IsA<Document>(GetNode())) + << "The following node should have a parent: " << GetNode(); + + // Initialize all other cached values. + UpdateCachedAttributeValuesIfNeeded(false); } void AXObject::Detach() { +#if DCHECK_IS_ON() + DCHECK(!is_adding_children_) << ToString(true, true); DCHECK(ax_object_cache_); DCHECK(!ax_object_cache_->IsFrozen()) << "Do not detach children while the tree is frozen, in order to avoid " "an object detaching itself in the middle of computing its own " "accessibility properties."; +#endif + // Clear any children and call detachFromParent on them so that // no children are left with dangling pointers to their parent. ClearChildren(); + parent_ = nullptr; ax_object_cache_ = nullptr; } @@ -614,9 +649,125 @@ } void AXObject::SetParent(AXObject* parent) { + DCHECK(parent || IsA<Document>(GetNode())) + << "Parent cannot be null, except at the root, was null at " << GetNode() + << " " << GetLayoutObject(); parent_ = parent; } +// In many cases, ComputeParent() is not called, because the parent adding +// the child will pass itself into AXObject::Init() via parent_if_known. +// ComputeParent() is still necessary because some parts of the code, +// especially web tests, result in AXObjects being created in the middle of +// the tree before their parents are created. +// TODO(accessibility) Consider forcing all ax objects to be created from +// the top down, eliminating the need for ComputeParent(). +AXObject* AXObject::ComputeParent() const { + DCHECK(!IsDetached()); + + DCHECK(!parent_ || parent_->IsDetached()) + << "Should use cached parent unless it's detached, and should not " + "attempt to recompute it, occurred on " + << GetNode(); + + DCHECK(GetNode() || GetLayoutObject()) + << "Can't compute parent on AXObjects that don't have a backing Node or " + "LayoutObject. Objects without those must set the parent in Init()."; + + return ComputeParentImpl(); +} + +AXObject* AXObject::ComputeParentImpl() const { + if (AXObjectCache().IsAriaOwned(this)) + return AXObjectCache().GetAriaOwnedParent(this); + + Node* current_node = GetNode(); + + // A WebArea's parent should be the page popup owner, if any, otherwise null. + if (IsA<Document>(current_node)) { + LocalFrame* frame = GetLayoutObject()->GetFrame(); + return AXObjectCache().GetOrCreate(frame->PagePopupOwner()); + } + + // If no node, or a pseudo element, use the layout parent. + if (!current_node) { + LayoutObject* current_layout_obj = GetLayoutObject(); + DCHECK(current_layout_obj); + // If no DOM node and no parent, this must be an anonymous layout object. + DCHECK(current_layout_obj->IsAnonymous()); + LayoutObject* parent_layout_obj = current_layout_obj->Parent(); + if (!parent_layout_obj) + return nullptr; + if (AXObject* ax_parent = AXObjectCache().GetOrCreate(parent_layout_obj)) { + DCHECK(!ax_parent->IsDetached()); + return ax_parent; + } + // Switch to using DOM nodes. The only cases that should occur do not have + // chains of multiple parents without DOM nodes. + Node* parent_node = parent_layout_obj->GetNode(); + DCHECK(parent_node) << "Computing an accessible parent from the layout " + "parent did not yield an accessible object nor a " + "DOM node to walk up from, current_layout_obj = " + << current_layout_obj; + if (!parent_node) + return nullptr; + } + + while (true) { + current_node = GetParentNodeForComputeParent(current_node); + if (!current_node) + break; + AXObject* ax_parent = AXObjectCache().GetOrCreate(current_node); + if (ax_parent) { + DCHECK(!ax_parent->IsDetached()); + return ax_parent; + } + } + + return nullptr; +} + +#if DCHECK_IS_ON() +void AXObject::EnsureCorrectParentComputation() { + if (!parent_) + return; + + DCHECK(!parent_->IsDetached()); + + // Don't check the computed parent if the cached parent is a mock object. + // It is expected that a computed parent could never be a mock object, + // which has no backing DOM node or layout object, and therefore cannot be + // found by traversing DOM/layout ancestors. + if (parent_->IsMockObject()) + return; + + // Cannot compute a parent for an object that has no backing node or layout + // object to start from. + if (!GetNode() || !GetLayoutObject()) + return; + + // Don't check the computed parent if the cached parent is an image map: + // <area> children's location in the DOM and HTML hierarchy does not match. + // TODO(aleventhal) Try to remove this rule, it may be unnecessary now. + if (parent_->RoleValue() == ax::mojom::blink::Role::kImageMap) + return; + + // TODO(aleventhal) Different in test fast/css/first-letter-removed-added.html + // when run with --force-renderer-accessibility. + if (GetNode() && GetNode()->IsPseudoElement()) + return; + + // Verify that the algorithm in ComputeParentImpl() provides same results as + // parents that init their children with themselvs as the parent_if_known. + // Inconsistency indicates a problem could potentially exist where a child's + // parent does not include the child in its children. + DCHECK_EQ(ComputeParentImpl(), parent_) + << "\n**** ComputeParent should have provided the same result as " + "the known parent.\n**** Child was " + << this; +} +#endif + const AtomicString& AXObject::GetAOMPropertyOrARIAAttribute( AOMStringProperty property) const { Element* element = this->GetElement(); @@ -1532,7 +1683,8 @@ return !AccessibilityIsIgnored() || AccessibilityIsIgnoredButIncludedInTree(); } -void AXObject::UpdateCachedAttributeValuesIfNeeded() const { +void AXObject::UpdateCachedAttributeValuesIfNeeded( + bool notify_parent_of_ignored_changes) const { if (IsDetached()) return; @@ -1541,79 +1693,94 @@ if (cache.ModificationCount() == last_modification_count_) return; + last_modification_count_ = cache.ModificationCount(); + #if DCHECK_IS_ON() // Required in order to get Lifecycle().ToString() + DCHECK(!is_updating_cached_values_) + << "Reentering UpdateCachedAttributeValuesIfNeeded() on same node: " + << GetNode(); + + base::AutoReset<bool> reentrancy_protector(&is_updating_cached_values_, true); + DCHECK(!GetDocument() || GetDocument()->Lifecycle().GetState() >= DocumentLifecycle::kAfterPerformLayout) << "Unclean document at lifecycle " << GetDocument()->Lifecycle().ToString(); #endif - last_modification_count_ = cache.ModificationCount(); + // TODO(accessibility) Every AXObject must have a parent except the root. + // Sometimes the parent is detached and a new parent isn't yet reattached. + if (!parent_) + parent_ = ComputeParent(); - cached_background_color_ = ComputeBackgroundColor(); cached_is_hidden_via_style = ComputeIsHiddenViaStyle(); cached_is_inert_or_aria_hidden_ = ComputeIsInertOrAriaHidden(); + cached_background_color_ = ComputeBackgroundColor(); cached_is_descendant_of_leaf_node_ = !!LeafNodeAncestor(); cached_is_descendant_of_disabled_node_ = !!DisabledAncestor(); cached_has_inherited_presentational_role_ = !!InheritsPresentationalRoleFrom(); - cached_is_ignored_ = ComputeAccessibilityIsIgnored(); - cached_is_ignored_but_included_in_tree_ = - cached_is_ignored_ && ComputeAccessibilityIsIgnoredButIncludedInTree(); + bool is_ignored = ComputeAccessibilityIsIgnored(); + bool is_ignored_but_included_in_tree = + is_ignored && ComputeAccessibilityIsIgnoredButIncludedInTree(); #if DCHECK_IS_ON() // Ensure that display-locked text is pruned from the tree. This means that // they will be missed in the virtual buffer; therefore, it may be a rule // subject to change. Note that changing the rule would potentially cause a // lot of display-locked whitespace to be exposed. - if (cached_is_ignored_ && - RoleValue() == ax::mojom::blink::Role::kStaticText && GetNode() && + if (is_ignored && RoleValue() == ax::mojom::blink::Role::kStaticText && + GetNode() && DisplayLockUtilities::NearestLockedExclusiveAncestor(*GetNode())) { DCHECK(!cached_is_ignored_but_included_in_tree_) << "Display locked text should not be included in the tree (subject to " "future rule change)"; } #endif + bool included_in_tree_changed = false; + + // If the child's "included in tree" state changes, we will be notifying the + // parent to recompute it's children. + // Exceptions: + // - Caller passes in |notify_parent_of_ignored_changes = false| -- this + // occurs when this is a new child, or when a parent is in the middle of + // adding this child, and doing this would be redundant. + // - Inline text boxes: their "included in tree" state is entirely dependent + // on their static text parent. + if (notify_parent_of_ignored_changes && + RoleValue() != ax::mojom::blink::Role::kInlineTextBox) { + bool is_included_in_tree = !is_ignored || is_ignored_but_included_in_tree; + if (is_included_in_tree != LastKnownIsIncludedInTreeValue()) + included_in_tree_changed = true; + } + + cached_is_ignored_ = is_ignored; + cached_is_ignored_but_included_in_tree_ = is_ignored_but_included_in_tree; cached_is_editable_root_ = ComputeIsEditableRoot(); // Compute live region root, which can be from any ARIA live value, including // "off", or from an automatic ARIA live value, e.g. from role="status". // TODO(dmazzoni): remove this const_cast. AtomicString aria_live; if (GetNode() && IsA<Document>(GetNode())) { - // The document is never a live region root. This extra bit of logic also - // protects against going up the parent chain from a popup document, into - // a parent document with unclean layout. + // The document root is never a live region root. cached_live_region_root_ = nullptr; } else if (RoleValue() == ax::mojom::blink::Role::kInlineTextBox) { // Inline text boxes do not need live region properties. cached_live_region_root_ = nullptr; } else { - cached_live_region_root_ = - IsLiveRegionRoot() - ? const_cast<AXObject*>(this) - : (ParentObjectIfExists() ? ParentObjectIfExists()->LiveRegionRoot() - : nullptr); + // Is a live region root if this or an ancestor is a live region. + DCHECK(parent_); + cached_live_region_root_ = IsLiveRegionRoot() ? const_cast<AXObject*>(this) + : parent_->LiveRegionRoot(); } cached_aria_column_index_ = ComputeAriaColumnIndex(); cached_aria_row_index_ = ComputeAriaRowIndex(); - bool ignored_states_changed = false; - if (cached_is_ignored_ != LastKnownIsIgnoredValue()) { - last_known_is_ignored_value_ = - cached_is_ignored_ ? kIgnoreObject : kIncludeObject; - ignored_states_changed = true; - } - - if (cached_is_ignored_but_included_in_tree_ != - LastKnownIsIgnoredButIncludedInTreeValue()) { - last_known_is_ignored_but_included_in_tree_value_ = - cached_is_ignored_but_included_in_tree_ ? kIncludeObject - : kIgnoreObject; - ignored_states_changed = true; - } - - if (ignored_states_changed) { - if (AXObject* parent = ParentObjectIfExists()) - parent->ChildrenChanged(); + if (included_in_tree_changed) { + if (AXObject* parent = CachedParentObject()) { + // Defer this ChildrenChanged(), otherwise it can cause reentry into + // UpdateCachedAttributeValuesIfNeeded() on |this|. + AXObjectCache().ChildrenChanged(parent); + } } if (GetLayoutObject() && GetLayoutObject()->IsText()) { @@ -1998,32 +2165,11 @@ } bool AXObject::LastKnownIsIgnoredValue() const { - if (last_known_is_ignored_value_ == kDefaultBehavior) { - last_known_is_ignored_value_ = - AccessibilityIsIgnored() ? kIgnoreObject : kIncludeObject; - } - - return last_known_is_ignored_value_ == kIgnoreObject; -} - -void AXObject::SetLastKnownIsIgnoredValue(bool is_ignored) { - last_known_is_ignored_value_ = is_ignored ? kIgnoreObject : kIncludeObject; + return cached_is_ignored_; } bool AXObject::LastKnownIsIgnoredButIncludedInTreeValue() const { - if (last_known_is_ignored_but_included_in_tree_value_ == kDefaultBehavior) { - last_known_is_ignored_but_included_in_tree_value_ = - AccessibilityIsIgnoredButIncludedInTree() ? kIncludeObject - : kIgnoreObject; - } - - return last_known_is_ignored_but_included_in_tree_value_ == kIncludeObject; -} - -void AXObject::SetLastKnownIsIgnoredButIncludedInTreeValue( - bool is_ignored_but_included_in_tree) { - last_known_is_ignored_but_included_in_tree_value_ = - is_ignored_but_included_in_tree ? kIncludeObject : kIgnoreObject; + return cached_is_ignored_but_included_in_tree_; } bool AXObject::LastKnownIsIncludedInTreeValue() const { @@ -3123,14 +3269,14 @@ } const AXObject::AXObjectVector AXObject::UnignoredChildren() { + UpdateChildrenIfNecessary(); + if (!AccessibilityIsIncludedInTree()) { NOTREACHED() << "We don't support finding the unignored children of " "objects excluded from the accessibility tree."; return {}; } - UpdateChildrenIfNecessary(); - // Capture only descendants that are not accessibility ignored, and that are // one level deeper than the current object after flattening any accessibility // ignored descendants. @@ -3428,23 +3574,17 @@ if (IsDetached()) return nullptr; - if (parent_) - return parent_; + // This can happen when an object in the middle of the tree is suddenly + // detached, but the children still exist. One example of this is when + // a <select size="1"> changes to <select size="2">, where the + // Role::kMenuListPopup is detached. + if (!parent_) { + parent_ = ComputeParent(); + DCHECK(parent_ || IsA<Document>(GetNode())) + << "The following node should have a parent: " << GetNode(); + } - if (AXObjectCache().IsAriaOwned(this)) - return AXObjectCache().GetAriaOwnedParent(this); - - return ComputeParent(); -} - -AXObject* AXObject::ParentObjectIfExists() const { - if (IsDetached()) - return nullptr; - - if (parent_) - return parent_; - - return ComputeParentIfExists(); + return parent_; } AXObject* AXObject::ParentObjectUnignored() const { @@ -3502,10 +3642,28 @@ } void AXObject::ClearChildren() { - // Detach all weak pointers from objects to their parents. + // Detach all weak pointers from immediate children to their parents. + // First check to make sure the child's parent wasn't already reassigned. + // In addition, the immediate children are different from children_, and are + // the objects where the parent_ points to this. For example: + // Parent (this) + // Child not included in tree (immediate child) + // Child included in tree (an item in |children_|) + // Therefore, for each child in |children_|, we may need to go up one or + // more ancestors to find the actual immediate child. This is accomplished via + // an additional inner loop. + // TODO(accessibility) This ugly extra inner loop can be removed if we remove + // "not included in tree" holes from the tree, and there will no longer be + // any difference between children_ and immediate children. for (const auto& child : children_) { - if (child->parent_ == this) - child->DetachFromParent(); + AXObject* immediate_child = child; + while (immediate_child) { + if (immediate_child->parent_ == this) { + immediate_child->parent_ = nullptr; + break; + } + immediate_child = immediate_child->parent_; + } } children_.clear(); @@ -3522,7 +3680,7 @@ return; for (const auto& child : accessible_node->GetChildren()) - children_.push_back(AXObjectCache().GetOrCreate(child)); + children_.push_back(AXObjectCache().GetOrCreate(child, this)); } Element* AXObject::GetElement() const { @@ -4305,7 +4463,7 @@ } void AXObject::SelectionChanged() { - if (AXObject* parent = ParentObjectIfExists()) + if (AXObject* parent = CachedParentObject()) parent->SelectionChanged(); } @@ -4635,7 +4793,7 @@ } case ax::mojom::blink::Role::kUnknown: - NOTREACHED() << "Illegal Role::kUnknown for " << GetNode(); + NOTREACHED() << "Illegal Role::kUnknown for " << ToString(true, true); break; } @@ -4729,7 +4887,7 @@ return common_ancestor; } -String AXObject::ToString(bool verbose) const { +String AXObject::ToString(bool verbose, bool cached_values_only) const { // Build a friendly name for debugging the object. // If verbose, build a longer name name in the form of: // CheckBox axid#28 <input.someClass#cbox1> name="checkbox" @@ -4737,12 +4895,16 @@ AXObject::InternalRoleName(RoleValue()).GetString().EncodeForDebugging(); if (verbose) { + if (IsDetached()) + string_builder = string_builder + " (detached)"; string_builder = string_builder + " axid#" + String::Number(AXObjectID()); // Add useful HTML element info, like <div.myClass#myId>. if (GetElement()) { string_builder = string_builder + " <" + GetElement()->tagName().LowerASCII(); - if (GetElement()->FastHasAttribute(html_names::kClassAttr)) { + // Cannot safely get @class from SVG elements. + if (!GetElement()->IsSVGElement() && + GetElement()->FastHasAttribute(html_names::kClassAttr)) { string_builder = string_builder + "." + GetElement()->FastGetAttribute(html_names::kClassAttr); } @@ -4754,17 +4916,25 @@ } // Add properties of interest that often contribute to errors: - if (HasARIAOwns(GetElement())) - string_builder = string_builder + " @aria-owns"; - if (GetAOMPropertyOrARIAAttribute(AOMRelationProperty::kActiveDescendant)) - string_builder = string_builder + " @aria-activedescendant"; + if (HasARIAOwns(GetElement())) { + string_builder = + string_builder + " aria-owns=" + + GetElement()->FastGetAttribute(html_names::kAriaOwnsAttr); + } + if (GetAOMPropertyOrARIAAttribute(AOMRelationProperty::kActiveDescendant)) { + string_builder = + string_builder + " aria-activedescendant=" + + GetElement()->FastGetAttribute(html_names::kAriaOwnsAttr); + } if (IsFocused()) string_builder = string_builder + " focused"; - if (AXObjectCache().IsAriaOwned(this)) + if (!IsDetached() && AXObjectCache().IsAriaOwned(this)) string_builder = string_builder + " isAriaOwned"; - if (AccessibilityIsIgnored()) { + if (cached_values_only ? LastKnownIsIgnoredValue() + : AccessibilityIsIgnored()) { string_builder = string_builder + " isIgnored"; - if (!AccessibilityIsIncludedInTree()) + if (cached_values_only ? !LastKnownIsIncludedInTreeValue() + : !AccessibilityIsIncludedInTree()) string_builder = string_builder + " isRemovedFromTree"; } if (GetNode() && @@ -4778,6 +4948,10 @@ string_builder = string_builder + " isHiddenViaCSS"; if (GetNode() && GetNode()->IsInert()) string_builder = string_builder + " isInert"; + if (NeedsToUpdateChildren()) + string_builder = string_builder + " needsToUpdateChildren"; + if (IsAXLayoutObject() && !GetLayoutObject()) + string_builder = string_builder + " missingLayout"; string_builder = string_builder + " name="; } else { @@ -4785,7 +4959,10 @@ } // Append name last, in case it is long. - return string_builder + ComputedName().EncodeForDebugging(); + if (!cached_values_only) + string_builder = string_builder + ComputedName().EncodeForDebugging(); + + return string_builder; } bool operator==(const AXObject& first, const AXObject& second) { @@ -4838,6 +5015,13 @@ return first == second || first > second; } +std::ostream& operator<<(std::ostream& stream, const AXObject* obj) { + if (obj) + return stream << obj->ToString(true).Utf8(); + else + return stream << "<AXObject nullptr>"; +} + std::ostream& operator<<(std::ostream& stream, const AXObject& obj) { return stream << obj.ToString(true).Utf8(); }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.h b/third_party/blink/renderer/modules/accessibility/ax_object.h index 12bf7d25..3c40ba6 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -336,6 +336,12 @@ protected: explicit AXObject(AXObjectCacheImpl&); +#if DCHECK_IS_ON() + bool is_initializing_ = false; + mutable bool is_updating_cached_values_ = false; + bool is_adding_children_ = false; +#endif + public: virtual ~AXObject(); virtual void Trace(Visitor*) const; @@ -346,16 +352,21 @@ // unique ID, then added to AXObjectCacheImpl, and finally init() must // be called last. void SetAXObjectID(AXID ax_object_id) { id_ = ax_object_id; } - virtual void Init(); + virtual void Init(AXObject* parent_if_known); // When the corresponding WebCore object that this AXObject // wraps is deleted, it must be detached. virtual void Detach(); virtual bool IsDetached() const; - // Sets the parent AXObject directly. If the parent of this object is known, - // this can be faster than using computeParent(). - virtual void SetParent(AXObject* parent); + // Updates the cached attribute values. This may be recursive, so to prevent + // deadlocks, functions called here may only search up the tree (ancestors), + // not down. + // Fires children change on the parent if the node's ignored or included in + // tree status changes. Use |notify_parent_of_ignored_changes = false| to + // prevent this. + void UpdateCachedAttributeValuesIfNeeded( + bool notify_parent_of_ignored_changes = true) const; // The AXObjectCacheImpl that owns this object, and its unique ID within this // cache. @@ -519,6 +530,9 @@ bool ComputeIsInertOrAriaHidden(IgnoredReasons* = nullptr) const; bool IsBlockedByAriaModalDialog(IgnoredReasons* = nullptr) const; bool IsDescendantOfLeafNode() const; + bool LastKnownIsDescendantOfLeafNode() const { + return cached_is_descendant_of_leaf_node_; + } AXObject* LeafNodeAncestor() const; bool IsDescendantOfDisabledNode() const; bool ComputeAccessibilityIsIgnoredButIncludedInTree() const; @@ -527,10 +541,8 @@ const AXObject* DatetimeAncestor(int max_levels_to_check = 3) const; const AXObject* DisabledAncestor() const; bool LastKnownIsIgnoredValue() const; - void SetLastKnownIsIgnoredValue(bool); bool LastKnownIsIgnoredButIncludedInTreeValue() const; bool LastKnownIsIncludedInTreeValue() const; - void SetLastKnownIsIgnoredButIncludedInTreeValue(bool); bool HasInheritedPresentationalRole() const; bool IsPresentationalChild() const; bool CanBeActiveDescendant() const; @@ -913,6 +925,8 @@ // // Can be called on all nodes that are included in the accessibility tree, // including those that are accessibility ignored. + // TODO(accessibility) This actually returns ignored children when they are + // included in the tree. A better name would be ChildrenIncludedInTree(). const AXObjectVector UnignoredChildren() const; const AXObjectVector UnignoredChildren(); @@ -1032,15 +1046,29 @@ AXObject* ParentObject() const; // Get the parent of this object if it has already been created. - // // Works for all nodes, and may return nodes that are accessibility ignored, // including nodes that might not be in the tree. - AXObject* ParentObjectIfExists() const; - - virtual AXObject* ComputeParent() const = 0; - virtual AXObject* ComputeParentIfExists() const { return nullptr; } AXObject* CachedParentObject() const { return parent_; } + // Sets the parent AXObject directly. If the parent of this object is known, + // this can be faster than using ComputeParent(). + void SetParent(AXObject* parent); + + // If parent was not initialized during AddChildren() it can be computed by + // walking the DOM (or layout for nodeless aka anonymous layout object). + // ComputeParent() adds DCHECKs to ensure that it is not being called when + // an attached parent_ is already cached, and that it is possible to compute + // the parent. It calls ComputeParentImpl() for the actual work. + AXObject* ComputeParent() const; + // Subclasses override ComputeParentImpl() to change parent computation. + virtual AXObject* ComputeParentImpl() const; + +#if DCHECK_IS_ON() + // When the parent on children during AddChildren(), take the opportunity to + // check out ComputeParent() implementation. It should match. + void EnsureCorrectParentComputation(); +#endif + // Get or create the first ancestor that's not accessibility ignored. // Works for all nodes. AXObject* ParentObjectUnignored() const; @@ -1215,16 +1243,17 @@ bool IsHiddenForTextAlternativeCalculation() const; // Returns a string representation of this object. - String ToString(bool verbose = false) const; + // |cached_values_only| avoids recomputing cached values, and thus can be + // used during UpdateCachedValuesIfNecessary() without causing recursion. + String ToString(bool verbose = false, bool cached_values_only = false) const; protected: AXID id_; + // Only children that are included in tree, maybe rename to children_in_tree_. AXObjectVector children_; mutable bool have_children_; ax::mojom::blink::Role role_; ax::mojom::blink::Role aria_role_; - mutable AXObjectInclusion last_known_is_ignored_value_; - mutable AXObjectInclusion last_known_is_ignored_but_included_in_tree_value_; LayoutRect explicit_element_rect_; AXID explicit_container_id_; @@ -1281,16 +1310,25 @@ const AXObject* TableRowParent() const; const AXObject* TableParent() const; + // Any parent, regardless of whether it's ignored or not included in the tree. mutable Member<AXObject> parent_; - // The following cached attribute values (the ones starting with m_cached*) - // are only valid if m_lastModificationCount matches - // AXObjectCacheImpl::modificationCount(). + // Helpers for serialization. + void SerializeStyleAttributes(ui::AXNodeData* node_data); + void SerializeSparseAttributes(ui::AXNodeData* node_data); + void SerializeTableAttributes(ui::AXNodeData* node_data); + void SerializeListAttributes(ui::AXNodeData* node_data); + void SerializeScrollAttributes(ui::AXNodeData* node_data); + + private: mutable int last_modification_count_; + + // The following cached attribute values (the ones starting with m_cached*) + // are only valid if last_modification_count_ matches + // AXObjectCacheImpl::ModificationCount(). mutable RGBA32 cached_background_color_; mutable bool cached_is_ignored_ : 1; mutable bool cached_is_ignored_but_included_in_tree_ : 1; - mutable bool cached_is_inert_or_aria_hidden_ : 1; mutable bool cached_is_hidden_via_style : 1; mutable bool cached_is_descendant_of_leaf_node_ : 1; @@ -1304,18 +1342,6 @@ Member<AXObjectCacheImpl> ax_object_cache_; - // Updates the cached attribute values. This may be recursive, so to prevent - // deadlocks, - // functions called here may only search up the tree (ancestors), not down. - void UpdateCachedAttributeValuesIfNeeded() const; - - // Helpers for serialization. - void SerializeStyleAttributes(ui::AXNodeData* node_data); - void SerializeSparseAttributes(ui::AXNodeData* node_data); - void SerializeTableAttributes(ui::AXNodeData* node_data); - void SerializeListAttributes(ui::AXNodeData* node_data); - void SerializeScrollAttributes(ui::AXNodeData* node_data); - private: void UpdateDistributionForFlatTreeTraversal() const; bool IsARIAControlledByTextboxWithActiveDescendant() const; @@ -1362,6 +1388,7 @@ MODULES_EXPORT bool operator>(const AXObject& first, const AXObject& second); MODULES_EXPORT bool operator>=(const AXObject& first, const AXObject& second); MODULES_EXPORT std::ostream& operator<<(std::ostream&, const AXObject&); +MODULES_EXPORT std::ostream& operator<<(std::ostream&, const AXObject*); } // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 5201d0d..2ab6f28 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -470,7 +470,8 @@ return MakeGarbageCollected<AXInlineTextBox>(inline_text_box, *this); } -AXObject* AXObjectCacheImpl::GetOrCreate(AccessibleNode* accessible_node) { +AXObject* AXObjectCacheImpl::GetOrCreate(AccessibleNode* accessible_node, + AXObject* parent_if_known) { if (AXObject* obj = Get(accessible_node)) return obj; @@ -479,25 +480,37 @@ const AXID ax_id = AssociateAXID(new_obj); accessible_node_mapping_.Set(accessible_node, ax_id); - new_obj->Init(); + new_obj->Init(parent_if_known); return new_obj; } AXObject* AXObjectCacheImpl::GetOrCreate(const Node* node) { - return GetOrCreate(const_cast<Node*>(node)); + return GetOrCreate(node, nullptr); } AXObject* AXObjectCacheImpl::GetOrCreate(Node* node) { + return GetOrCreate(node, nullptr); +} + +AXObject* AXObjectCacheImpl::GetOrCreate(const Node* node, + AXObject* parent_if_known) { + return GetOrCreate(const_cast<Node*>(node), parent_if_known); +} + +AXObject* AXObjectCacheImpl::GetOrCreate(Node* node, + AXObject* parent_if_known) { if (!IsNodeRelevantForAccessibility(node)) return nullptr; if (AXObject* obj = Get(node)) return obj; - return CreateAndInit(node); + return CreateAndInit(node, parent_if_known); } -AXObject* AXObjectCacheImpl::CreateAndInit(Node* node, AXID use_axid) { +AXObject* AXObjectCacheImpl::CreateAndInit(Node* node, + AXObject* parent_if_known, + AXID use_axid) { #if DCHECK_IS_ON() DCHECK(node); DCHECK(node->isConnected()); @@ -514,7 +527,21 @@ // a locked subtree, which are created based on its node. if (node->GetLayoutObject() && IsLayoutObjectRelevantForAccessibility(node) && !DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) { - return CreateAndInit(node->GetLayoutObject(), use_axid); + return CreateAndInit(node->GetLayoutObject(), parent_if_known, use_axid); + } + + // Return null if inside a shadow tree of something that can't have children, + // for example, an <img> has a user agent shadow root containing a <span> for + // the alt text. Do not create an accessible for that as it would be unable + // to have a parent that has it as a child. + // TODO(aleventhal) There may be similar cases for content inside a <head>, + // <style> or <script> -- for style/script the inner text might change. + // In those cases the nodes are most likely display:none, but if they are + // display locked we may not know that they are display:none. + if (node->IsInShadowTree()) { + AXObject* shadow_host = Get(node->OwnerShadowHost()); + if (shadow_host && !shadow_host->CanHaveChildren()) + return nullptr; } AXObject* new_obj = CreateFromNode(node); @@ -526,26 +553,29 @@ const AXID ax_id = AssociateAXID(new_obj, use_axid); DCHECK(!HashTraits<AXID>::IsDeletedValue(ax_id)); node_object_mapping_.Set(node, ax_id); - new_obj->Init(); - new_obj->SetLastKnownIsIgnoredValue(new_obj->AccessibilityIsIgnored()); - new_obj->SetLastKnownIsIgnoredButIncludedInTreeValue( - new_obj->AccessibilityIsIgnoredButIncludedInTree()); - MaybeNewRelationTarget(node, new_obj); + new_obj->Init(parent_if_known); + MaybeNewRelationTarget(*node, new_obj); return new_obj; } AXObject* AXObjectCacheImpl::GetOrCreate(LayoutObject* layout_object) { + return GetOrCreate(layout_object, nullptr); +} + +AXObject* AXObjectCacheImpl::GetOrCreate(LayoutObject* layout_object, + AXObject* parent_if_known) { if (!layout_object) return nullptr; if (AXObject* obj = Get(layout_object)) return obj; - return CreateAndInit(layout_object); + return CreateAndInit(layout_object, parent_if_known); } AXObject* AXObjectCacheImpl::CreateAndInit(LayoutObject* layout_object, + AXObject* parent_if_known, AXID use_axid) { #if DCHECK_IS_ON() DCHECK(layout_object); @@ -560,6 +590,16 @@ DCHECK(!node || IsLayoutObjectRelevantForAccessibility(node)) << "Shouldn't get here if the layout object is not relevant for a11y"; + // Return null if inside a shadow tree of something that can't have children, + // for example, an <img> has a user agent shadow root containing a <span> for + // the alt text. Do not create an accessible for that as it would be unable + // to have a parent that has it as a child. + if (node && node->IsInShadowTree()) { + AXObject* shadow_host = Get(node->OwnerShadowHost()); + if (shadow_host && !shadow_host->CanHaveChildren()) + return nullptr; + } + // Prefer creating AXNodeObjects over AXLayoutObjects in locked subtrees // (e.g. content-visibility: auto), even if a LayoutObject is available, // because the LayoutObject is not guaranteed to be up-to-date (it might come @@ -579,7 +619,7 @@ // when there isn't. The locked subtree should not have AXLayoutObjects. return nullptr; } - return CreateAndInit(node, use_axid); + return CreateAndInit(node, parent_if_known, use_axid); } AXObject* new_obj = CreateFromRenderer(layout_object); @@ -590,23 +630,29 @@ const AXID axid = AssociateAXID(new_obj, use_axid); layout_object_mapping_.Set(layout_object, axid); - new_obj->Init(); - new_obj->SetLastKnownIsIgnoredValue(new_obj->AccessibilityIsIgnored()); - new_obj->SetLastKnownIsIgnoredButIncludedInTreeValue( - new_obj->AccessibilityIsIgnoredButIncludedInTree()); - if (node) - MaybeNewRelationTarget(node, new_obj); + new_obj->Init(parent_if_known); + if (node) // There may not be a node, e.g. for an anonymous block. + MaybeNewRelationTarget(*node, new_obj); return new_obj; } -AXObject* AXObjectCacheImpl::GetOrCreate( - AbstractInlineTextBox* inline_text_box) { +AXObject* AXObjectCacheImpl::GetOrCreate(AbstractInlineTextBox* inline_text_box, + AXObject* parent) { if (!inline_text_box) return nullptr; - if (AXObject* obj = Get(inline_text_box)) + DCHECK(parent); + if (AXObject* obj = Get(inline_text_box)) { + if (obj->CachedParentObject()) { + // It is possible that the parent AXObject has changed, but the related + // text node will be the same. + // TODO(alventhal) When is the cached parent different? + DCHECK_EQ(obj->CachedParentObject()->GetNode(), parent->GetNode()); + } + obj->SetParent(parent); return obj; + } AXObject* new_obj = CreateFromInlineTextBox(inline_text_box); @@ -616,18 +662,17 @@ const AXID axid = AssociateAXID(new_obj); inline_text_box_object_mapping_.Set(inline_text_box, axid); - new_obj->Init(); - new_obj->SetLastKnownIsIgnoredValue(new_obj->AccessibilityIsIgnored()); - new_obj->SetLastKnownIsIgnoredButIncludedInTreeValue( - new_obj->AccessibilityIsIgnoredButIncludedInTree()); + new_obj->Init(parent); return new_obj; } -AXObject* AXObjectCacheImpl::GetOrCreate(ax::mojom::blink::Role role) { +AXObject* AXObjectCacheImpl::CreateAndInit(ax::mojom::blink::Role role, + AXObject* parent) { + DCHECK(parent); AXObject* obj = nullptr; switch (role) { - case ax::mojom::Role::kMenuListPopup: + case ax::mojom::blink::Role::kMenuListPopup: DCHECK(use_ax_menu_list_); obj = MakeGarbageCollected<AXMenuListPopup>(*this); break; @@ -640,7 +685,7 @@ AssociateAXID(obj); - obj->Init(); + obj->Init(parent); return obj; } @@ -869,12 +914,18 @@ return; } +#if DCHECK_IS_ON() DCHECK(!tree_update_document->GetPage()->Animator().IsServicingAnimations() || (tree_update_document->Lifecycle().GetState() < DocumentLifecycle::kInAccessibility || tree_update_document->Lifecycle().StateAllowsDetach())) << "DeferTreeUpdateInternal should only be outside of the lifecycle or " - "before the accessibility state."; + "before the accessibility state:" + << "\n* IsServicingAnimations: " + << tree_update_document->GetPage()->Animator().IsServicingAnimations() + << "\n* Lifecycle: " << tree_update_document->Lifecycle().ToString(); +#endif + tree_update_callback_queue_.push_back(MakeGarbageCollected<TreeUpdateParams>( obj->GetNode(), obj->AXObjectID(), ComputeEventFrom(), ActiveEventIntents(), std::move(callback))); @@ -905,12 +956,18 @@ return; } +#if DCHECK_IS_ON() DCHECK(!tree_update_document.GetPage()->Animator().IsServicingAnimations() || (tree_update_document.Lifecycle().GetState() < DocumentLifecycle::kInAccessibility || tree_update_document.Lifecycle().StateAllowsDetach())) << "DeferTreeUpdateInternal should only be outside of the lifecycle or " - "before the accessibility state."; + "before the accessibility state:" + << "\n* IsServicingAnimations: " + << tree_update_document.GetPage()->Animator().IsServicingAnimations() + << "\n* Lifecycle: " << tree_update_document.Lifecycle().ToString(); +#endif + tree_update_callback_queue_.push_back(MakeGarbageCollected<TreeUpdateParams>( node, 0, ComputeEventFrom(), ActiveEventIntents(), std::move(callback))); @@ -1095,7 +1152,7 @@ } if (optional_node_for_relation_update) - relation_cache_->UpdateRelatedTree(optional_node_for_relation_update); + relation_cache_->UpdateRelatedTree(optional_node_for_relation_update, obj); } void AXObjectCacheImpl::TextChangedWithCleanLayout(Node* node) { @@ -1167,7 +1224,7 @@ if (AXObject::HasARIAOwns(element)) HandleAttributeChangedWithCleanLayout(html_names::kAriaOwnsAttr, element); - MaybeNewRelationTarget(node, Get(node)); + MaybeNewRelationTarget(*node, Get(node)); // Even if the node or parent are ignored, an ancestor may need to include // descendants of the attached node, thus ChildrenChangedWithCleanLayout() @@ -1190,6 +1247,11 @@ } } +void AXObjectCacheImpl::ChildrenChanged(AXObject* obj) { + DeferTreeUpdate(&AXObjectCacheImpl::ChildrenChangedWithCleanLayout, + obj->GetNode(), obj); +} + void AXObjectCacheImpl::ChildrenChanged(Node* node) { if (!node) return; @@ -1302,7 +1364,7 @@ if (optional_node) { ContainingTableRowsOrColsMaybeChanged(optional_node); - relation_cache_->UpdateRelatedTree(optional_node); + relation_cache_->UpdateRelatedTree(optional_node, obj); } } @@ -1362,19 +1424,27 @@ // Returns the new object. auto refresh = [this](AXObject* current) { Node* node = current->GetNode(); + AXObject* cached_parent = current->CachedParentObject(); DCHECK(node) << "Refresh() is currently only supported for objects " "with a backing node"; AXID retained_axid = current->AXObjectID(); // Remove from relevant maps, but not from relation cache, as the relations // between AXIDs will still the same. node_object_mapping_.erase(node); - if (current->GetLayoutObject()) + if (current->GetLayoutObject()) { layout_object_mapping_.erase(current->GetLayoutObject()); + } else if (node->GetLayoutObject()) { + DCHECK(!layout_object_mapping_.at(node->GetLayoutObject())) + << node << " " << node->GetLayoutObject(); + } current->Detach(); // TODO(accessibility) We don't use the return value, can we use .erase() // and it will still make sure that the object is cleaned up? objects_.Take(retained_axid); - return CreateAndInit(node, retained_axid); + AXObject* new_object = CreateAndInit(node, cached_parent, retained_axid); + if (!new_object) + RemoveAXID(current); // Failed to create, so remove object completely. + return new_object; }; while (!invalidated_ids_.IsEmpty()) { @@ -1389,25 +1459,50 @@ if (object->GetDocument() != &document) { // Wrong document -- this AXObjectCache processes the current popup // document too. Keep the ID around until its document is processed. + DCHECK(!HashTraits<AXID>::IsDeletedValue(ax_id)); wrong_document_invalidated_ids.insert(ax_id); continue; } bool did_use_layout_object_traversal = object->ShouldUseLayoutObjectTraversalForChildren(); - AXObject* parent = object->ParentObjectIncludedInTree(); + + // Invalidate children on the first available non-detached parent that is + // included in the tree. Sometimes a cached parent is detached because + // an object was detached in the middle of the tree, and cached parents + // are not corrected until the call to UpdateChildrenIfNecessary() below. + AXObject* parent = object; + while (true) { + AXObject* candidate_parent = parent->CachedParentObject(); + if (!candidate_parent || candidate_parent->IsDetached()) { + // The cached parent pointed to a detached AXObject. Compute a new + // candidate parent and repair the cached parent now, so that + // refreshing and initializing the new object can occur (a parent is + // required). + candidate_parent = parent->ComputeParent(); + parent->SetParent(candidate_parent); + } + + if (!candidate_parent) + break; // No higher candidate parent found, will invalidate |parent|. + + parent = candidate_parent; + // Queue up a ChildrenChanged() call for this parent. + pending_children_changed_ids.insert(parent->AXObjectID()); + if (parent->LastKnownIsIncludedInTreeValue()) + break; // Stop here (otherwise continue to higher ancestor). + } + AXObject* new_object = refresh(object); // Children might change because child traversal style changed. - if (new_object->ShouldUseLayoutObjectTraversalForChildren() != - did_use_layout_object_traversal) { - // TODO(accessibility) Need test for this, e.g. for continuations. + if (new_object && + new_object->ShouldUseLayoutObjectTraversalForChildren() != + did_use_layout_object_traversal) { + // TODO(accessibility) Need test for this. + DCHECK(!HashTraits<AXID>::IsDeletedValue(ax_id)); pending_children_changed_ids.insert(ax_id); } - - // Queue up a ChildrenChanged() call for this parent. - if (parent && parent != object) - pending_children_changed_ids.insert(parent->AXObjectID()); } // Update parents' children. for (AXID parent_id : pending_children_changed_ids) { @@ -1606,13 +1701,12 @@ if (event_type == ax::mojom::blink::Event::kChildrenChanged && obj->CachedParentObject()) { const bool was_ignored = obj->LastKnownIsIgnoredValue(); - const bool was_ignored_but_included_in_tree = - obj->LastKnownIsIgnoredButIncludedInTreeValue(); - bool is_ignored_changed = - was_ignored != obj->AccessibilityIsIgnored() || - was_ignored_but_included_in_tree != - obj->AccessibilityIsIgnoredButIncludedInTree(); - if (is_ignored_changed) + const bool was_in_tree = obj->LastKnownIsIncludedInTreeValue(); + obj->UpdateCachedAttributeValuesIfNeeded(false); + const bool is_ignored = obj->LastKnownIsIgnoredValue(); + const bool is_in_tree = obj->LastKnownIsIncludedInTreeValue(); + + if (is_ignored != was_ignored || was_in_tree != is_in_tree) ChildrenChangedWithCleanLayout(nullptr, obj->CachedParentObject()); } } @@ -1769,23 +1863,28 @@ } // This might be the new target of a relation. Handle all possible cases. -void AXObjectCacheImpl::MaybeNewRelationTarget(Node* node, AXObject* obj) { +void AXObjectCacheImpl::MaybeNewRelationTarget(Node& node, AXObject* obj) { // Track reverse relations - relation_cache_->UpdateRelatedTree(node); + relation_cache_->UpdateRelatedTree(&node, obj); if (!obj) return; - // Check whether aria-activedescendant on a focused object points to |obj|. - // If so, fire activedescendantchanged event now. - // This is only for ARIA active descendants, not in a native control like a - // listbox, which has its own initial active descendant handling. + DCHECK_EQ(obj->GetNode(), &node); + + // Check whether aria-activedescendant on the focused object points to + // |obj|. If so, fire activedescendantchanged event now. This is only for + // ARIA active descendants, not in a native control like a listbox, which + // has its own initial active descendant handling. Node* focused_node = document_->FocusedElement(); if (focused_node) { AXObject* focus = Get(focused_node); - if (focus && focus->ActiveDescendant() == obj && - obj->CanBeActiveDescendant()) + if (focus && + focus->GetAOMPropertyOrARIAAttribute( + AOMRelationProperty::kActiveDescendant) == &node && + obj->CanBeActiveDescendant()) { focus->HandleActiveDescendantChanged(); + } } } @@ -1861,7 +1960,7 @@ IsA<HTMLLabelElement>(*element)) { LabelChangedWithCleanLayout(element); } else if (attr_name == html_names::kIdAttr) { - MaybeNewRelationTarget(element, Get(element)); + MaybeNewRelationTarget(*element, Get(element)); } else if (attr_name == html_names::kTabindexAttr) { FocusableChangedWithCleanLayout(element); } else if (attr_name == html_names::kDisabledAttr || @@ -1924,7 +2023,7 @@ DCHECK(message_ax_object); // Cache the validation message container for reuse. validation_message_axid_ = AssociateAXID(message_ax_object); - message_ax_object->Init(); + message_ax_object->Init(Root()); // Validation message alert object is a child of the document, as not all // form controls can have a child. Also, there are form controls such as // listbox that technically can have children, but they are probably not
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h index 8b1fe88..71a2867 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -93,6 +93,7 @@ void SelectionChanged(Node*) override; void UpdateReverseRelations(const AXObject* relation_source, const Vector<String>& target_ids); + void ChildrenChanged(AXObject*); void ChildrenChanged(Node*) override; void ChildrenChanged(const LayoutObject*) override; void ChildrenChanged(AccessibleNode*) override; @@ -184,14 +185,17 @@ AXObject* ObjectFromAXID(AXID id) const { return objects_.at(id); } AXObject* Root(); - // Used for objects without backing elements. - AXObject* GetOrCreate(ax::mojom::blink::Role); + // Used for objects without backing DOM nodes, layout objects, etc. + AXObject* CreateAndInit(ax::mojom::blink::Role, AXObject* parent); - AXObject* GetOrCreate(AccessibleNode*); - AXObject* GetOrCreate(LayoutObject*) override; - AXObject* GetOrCreate(const Node*); + AXObject* GetOrCreate(AccessibleNode*, AXObject* parent_if_known); + AXObject* GetOrCreate(LayoutObject*, AXObject* parent_if_known) override; + AXObject* GetOrCreate(LayoutObject* layout_object); + AXObject* GetOrCreate(const Node*, AXObject* parent_if_known); + AXObject* GetOrCreate(Node*, AXObject* parent_if_known); AXObject* GetOrCreate(Node*); - AXObject* GetOrCreate(AbstractInlineTextBox*); + AXObject* GetOrCreate(const Node*); + AXObject* GetOrCreate(AbstractInlineTextBox*, AXObject* parent); AXID GetAXID(Node*) override; Element* GetElementFromAXID(AXID) override; @@ -207,7 +211,9 @@ void ChildrenChangedWithCleanLayout(Node* optional_node_for_relation_update, AXObject*); - void MaybeNewRelationTarget(Node* node, AXObject* obj); + // When an object is created or its id changes, this must be called so that + // the relation cache is updated. + void MaybeNewRelationTarget(Node& node, AXObject* obj); void HandleActiveDescendantChangedWithCleanLayout(Node*); void HandleRoleChangeWithCleanLayout(Node*); @@ -292,6 +298,10 @@ static bool UseAXMenuList() { return use_ax_menu_list_; } +#if DCHECK_IS_ON() + bool HasBeenDisposed() { return has_been_disposed_; } +#endif + // Retrieves a vector of all AXObjects whose bounding boxes may have changed // since the last query. Clears the vector so that the next time it's // called, it will only retrieve objects that have changed since now. @@ -313,8 +323,10 @@ // Create an AXObject, and do not check if a previous one exists. // Also, initialize the object and add it to maps for later retrieval. - AXObject* CreateAndInit(Node*, AXID use_axid = 0); - AXObject* CreateAndInit(LayoutObject*, AXID use_axid = 0); + AXObject* CreateAndInit(Node*, AXObject* parent_if_known, AXID use_axid = 0); + AXObject* CreateAndInit(LayoutObject*, + AXObject* parent_if_known, + AXID use_axid = 0); // Mark object as invalid and needing to be refreshed when layout is clean. // Will result in a new object with the same AXID, and will also call
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc index c6a8edc8..33dd355 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc
@@ -64,7 +64,7 @@ static unsigned num_children_changed_calls_; void ChildrenChanged() final { num_children_changed_calls_++; } - AXObject* ComputeParent() const final { return nullptr; } + AXObject* ComputeParentImpl() const final { return nullptr; } Document* GetDocument() const final { return &AXObjectCache().GetDocument(); } };
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc index 01bb417f..9d74433 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
@@ -33,7 +33,7 @@ << "Unclean document at lifecycle " << document.Lifecycle().ToString(); #endif if (element.FastHasAttribute(html_names::kAriaOwnsAttr)) { - if (AXObject* owner = GetOrCreate(&element)) { + if (AXObject* owner = GetOrCreate(&element, nullptr)) { owner_ids_to_update_.insert(owner->AXObjectID()); } } @@ -141,8 +141,8 @@ // back to its real parent in the tree by detaching it from its current // parent and calling childrenChanged on its real parent. removed_child->DetachFromParent(); - AXObject* real_parent = removed_child->ParentObjectIncludedInTree(); - + // Recompute the real parent and cache it. + AXObject* real_parent = removed_child->ParentObject(); ChildrenChanged(real_parent); } } @@ -160,6 +160,7 @@ // on the original parent so that it can recompute its list of children. AXObject* original_parent = added_child->ParentObject(); added_child->DetachFromParent(); + added_child->SetParent(const_cast<AXObject*>(owner)); ChildrenChanged(original_parent); } } @@ -174,14 +175,14 @@ Vector<String> owned_id_vector; for (const auto& element : attr_associated_elements) { - AXObject* child = GetOrCreate(element); + AXObject* child = GetOrCreate(element, owner); // TODO(meredithl): Determine how to update reverse relations for elements // without an id. if (element->GetIdAttribute()) owned_id_vector.push_back(element->GetIdAttribute()); if (IsValidOwnsRelation(const_cast<AXObject*>(owner), child)) - validated_owned_children_result.push_back(GetOrCreate(element)); + validated_owned_children_result.push_back(GetOrCreate(element, owner)); } // Track reverse relations for future tree updates. @@ -243,7 +244,7 @@ Vector<AXID> validated_owned_child_axids; for (const String& id_name : owned_id_vector) { Element* child_element = scope.getElementById(AtomicString(id_name)); - AXObject* child = GetOrCreate(child_element); + AXObject* child = GetOrCreate(child_element, owner); if (IsValidOwnsRelation(const_cast<AXObject*>(owner), child)) owned_children.push_back(child); } @@ -274,18 +275,22 @@ UnmapOwnedChildren(owner, current_child_axids); MapOwnedChildren(owner, validated_owned_child_axids); +#if DCHECK_IS_ON() + // Owned children must be in tree to avoid serialization issues. + for (AXObject* child : validated_owned_children_result) { + DCHECK(child->AccessibilityIsIncludedInTree()) + << "Owned child not in tree: " << child->ToString(true, false) + << "\nRecompute included in tree: " + << child->ComputeAccessibilityIsIgnoredButIncludedInTree(); + } +#endif + // Finally, update the mapping from the owner to the list of child IDs. aria_owner_to_children_mapping_.Set(owner->AXObjectID(), validated_owned_child_axids); ChildrenChanged(owner); - -#if DCHECK_IS_ON() - // Owned children must be in tree to avoid serialization issues. - for (AXObject* child : validated_owned_children_result) { - DCHECK(child->AccessibilityIsIncludedInTree()); - } -#endif + owner->UpdateChildrenIfNecessary(); } bool AXRelationCache::MayHaveHTMLLabelViaForAttribute( @@ -318,9 +323,11 @@ } } -void AXRelationCache::UpdateRelatedTree(Node* node) { +void AXRelationCache::UpdateRelatedTree(Node* node, AXObject* obj) { HeapVector<Member<AXObject>> related_sources; - AXObject* related_target = Get(node); + DCHECK(node); + DCHECK(!obj || Get(node) == obj); + AXObject* related_target = obj ? obj : Get(node); // If it's already owned, schedule an update on the owner. if (related_target && IsAriaOwned(related_target)) { AXObject* owned_parent = GetAriaOwnedParent(related_target); @@ -407,8 +414,8 @@ return object_cache_->Get(node); } -AXObject* AXRelationCache::GetOrCreate(Node* node) { - return object_cache_->GetOrCreate(node); +AXObject* AXRelationCache::GetOrCreate(Node* node, const AXObject* owner) { + return object_cache_->GetOrCreate(node, const_cast<AXObject*>(owner)); } void AXRelationCache::ChildrenChanged(AXObject* object) {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h index a7619b7..6fce88df 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h +++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
@@ -45,7 +45,9 @@ // just changed, check to see if another object wants to be its parent due to // aria-owns. If so, add it to a queue of ids to process later during // ProcessUpdatesWithCleanLayout. - void UpdateRelatedTree(Node*); + // |node| is not optional. + // |obj| is optional. If provided, it must match the AXObject for |node|. + void UpdateRelatedTree(Node* node, AXObject* obj); // Remove given AXID from cache. void RemoveAXID(AXID); @@ -146,7 +148,7 @@ // Helpers that call back into object cache AXObject* ObjectFromAXID(AXID) const; - AXObject* GetOrCreate(Node*); + AXObject* GetOrCreate(Node*, const AXObject* owner); AXObject* Get(Node*); void ChildrenChanged(AXObject*);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc b/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc index 9458d0b..15eed4a 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc
@@ -18,10 +18,6 @@ AXValidationMessage::~AXValidationMessage() {} -AXObject* AXValidationMessage::ComputeParent() const { - return AXObjectCache().Root(); -} - bool AXValidationMessage::ComputeAccessibilityIsIgnored( IgnoredReasons* ignored_reasons) const { return false;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_validation_message.h b/third_party/blink/renderer/modules/accessibility/ax_validation_message.h index a589c4e6..fd174fdb 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_validation_message.h +++ b/third_party/blink/renderer/modules/accessibility/ax_validation_message.h
@@ -26,7 +26,6 @@ // AXObject: bool CanHaveChildren() const override { return false; } bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override; - AXObject* ComputeParent() const override; void GetRelativeBounds(AXObject** out_container, FloatRect& out_bounds_in_container, SkMatrix44& out_container_transform,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc index 977db453..b31a2e63 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
@@ -27,6 +27,15 @@ } void AXVirtualObject::AddChildren() { +#if DCHECK_IS_ON() + DCHECK(!IsDetached()); + DCHECK(!is_adding_children_) << " Reentering method on " << GetNode(); + base::AutoReset<bool> reentrancy_protector(&is_adding_children_, true); + DCHECK_EQ(children_.size(), 0U) + << "Parent still has " << children_.size() << " children before adding:" + << "\nParent is " << ToString(true, true) << "\nFirst child is " + << children_[0]->ToString(true, true); +#endif if (!accessible_node_) return; @@ -34,12 +43,13 @@ have_children_ = true; for (const auto& child : accessible_node_->GetChildren()) { - AXObject* ax_child = AXObjectCache().GetOrCreate(child); + AXObject* ax_child = AXObjectCache().GetOrCreate(child, this); if (!ax_child) continue; + DCHECK(!ax_child->IsDetached()); + DCHECK(ax_child->AccessibilityIsIncludedInTree()); children_.push_back(ax_child); - ax_child->SetParent(this); } }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h index 4049d30..e03b75fe 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h
@@ -21,7 +21,6 @@ // AXObject overrides. void Detach() override; - AXObject* ComputeParent() const override { return parent_; } bool IsVirtualObject() const override { return true; } void AddChildren() override; void ChildrenChanged() override;
diff --git a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc index 071f5584..9861aa6b 100644 --- a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc +++ b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
@@ -24,6 +24,7 @@ #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fetch/body_stream_buffer.h" #include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/core/streams/readable_stream.h" #include "third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.h" #include "third_party/blink/renderer/modules/service_worker/fetch_event.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h" @@ -375,6 +376,11 @@ void FetchRespondWithObserver::OnNoResponse() { DCHECK(GetExecutionContext()); + if (request_body_stream_ && (request_body_stream_->IsLocked() || + request_body_stream_->IsDisturbed())) { + GetExecutionContext()->CountUse( + WebFeature::kFetchRespondWithNoResponseWithUsedRequestBody); + } ServiceWorkerGlobalScope* service_worker_global_scope = To<ServiceWorkerGlobalScope>(GetExecutionContext()); service_worker_global_scope->RespondToFetchEventWithNoResponse( @@ -382,6 +388,17 @@ event_->ResolveHandledPromise(); } +void FetchRespondWithObserver::SetEvent(FetchEvent* event) { + DCHECK(!event_); + DCHECK(!request_body_stream_); + event_ = event; + // We don't use Body::body() in order to avoid accidental CountUse calls. + BodyStreamBuffer* body_buffer = event_->request()->BodyBuffer(); + if (body_buffer) { + request_body_stream_ = body_buffer->Stream(); + } +} + FetchRespondWithObserver::FetchRespondWithObserver( ExecutionContext* context, int fetch_event_id, @@ -399,6 +416,7 @@ void FetchRespondWithObserver::Trace(Visitor* visitor) const { visitor->Trace(event_); + visitor->Trace(request_body_stream_); RespondWithObserver::Trace(visitor); }
diff --git a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h index 2de7884..0ba6bf6 100644 --- a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h +++ b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h
@@ -18,6 +18,7 @@ class CrossOriginResourcePolicyChecker; class ExecutionContext; class FetchEvent; +class ReadableStream; class ScriptValue; class WaitUntilObserver; @@ -47,10 +48,7 @@ const char* property_name) override; void OnNoResponse() override; - void SetEvent(FetchEvent* event) { - DCHECK(!event_); - event_ = event; - } + void SetEvent(FetchEvent* event); void Trace(Visitor*) const override; @@ -61,6 +59,7 @@ const mojom::RequestContextFrameType frame_type_; const network::mojom::RequestDestination request_destination_; Member<FetchEvent> event_; + Member<ReadableStream> request_body_stream_; base::WeakPtr<CrossOriginResourcePolicyChecker> corp_checker_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; };
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.cc b/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.cc index d4f8ece8..8b7afe0 100644 --- a/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.cc +++ b/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.cc
@@ -32,8 +32,12 @@ // TODO(crbug.com/1022888): The worklet thread priority is always NORMAL on // Linux and Chrome OS regardless of this thread priority setting. params.thread_priority = base::ThreadPriority::REALTIME_AUDIO; + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"), + "RealtimeAudioWorkletThread() - REALTIME_AUDIO"); } else { params.thread_priority = base::ThreadPriority::NORMAL; + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"), + "RealtimeAudioWorkletThread() - NORMAL"); } if (++s_ref_count_ == 1)
diff --git a/third_party/blink/renderer/platform/graphics/OWNERS b/third_party/blink/renderer/platform/graphics/OWNERS index 8f1c634..457035c 100644 --- a/third_party/blink/renderer/platform/graphics/OWNERS +++ b/third_party/blink/renderer/platform/graphics/OWNERS
@@ -18,14 +18,10 @@ # lowLatency canvas mcasas@chromium.org -# canvas resources and images -khushalsagar@chromium.org - - # Video SurfaceLayer functionality. per-file video_frame*=file://media/OWNERS per-file video_frame*=mlamouri@chromium.org per-file video_frame*=lethalantidote@chromium.org per-file surface_layer_bridge*=file://media/OWNERS per-file surface_layer_bridge*=mlamouri@chromium.org -per-file surface_layer_bridge*=lethalantidote@chromium.org \ No newline at end of file +per-file surface_layer_bridge*=lethalantidote@chromium.org
diff --git a/third_party/blink/renderer/platform/graphics/gpu/OWNERS b/third_party/blink/renderer/platform/graphics/gpu/OWNERS index 10e108e..1bac549 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/OWNERS +++ b/third_party/blink/renderer/platform/graphics/gpu/OWNERS
@@ -12,4 +12,4 @@ klausw@chromium.org # SharedGpuContext, ImageLayerBridge, etc. -khushalsagar@chromium.org \ No newline at end of file +sunnyps@chromium.org
diff --git a/third_party/blink/renderer/platform/heap/impl/persistent.h b/third_party/blink/renderer/platform/heap/impl/persistent.h index 0c12b71..40388bd 100644 --- a/third_party/blink/renderer/platform/heap/impl/persistent.h +++ b/third_party/blink/renderer/platform/heap/impl/persistent.h
@@ -39,19 +39,11 @@ base::Location location_; }; -#if !BUILDFLAG(FROM_HERE_USES_LOCATION_BUILTINS) && \ - BUILDFLAG(RAW_HEAP_SNAPSHOTS) -#if !BUILDFLAG(ENABLE_LOCATION_SOURCE) -#define PERSISTENT_FROM_HERE \ - PersistentLocation(::base::Location::CreateFromHere(__FILE__)) -#else -#define PERSISTENT_FROM_HERE \ - PersistentLocation( \ - ::base::Location::CreateFromHere(__func__, __FILE__, __LINE__)) -#endif -#else +#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) +#define PERSISTENT_FROM_HERE PersistentLocation(base::Location::Current()) +#else // !RAW_HEAP_SNAPSHOTS #define PERSISTENT_FROM_HERE PersistentLocation() -#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) +#endif // !RAW_HEAP_SNAPSHOTS template <typename T, WeaknessPersistentConfiguration weaknessConfiguration,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 3f7f5e5..5dbe6093 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -922,9 +922,7 @@ // For simulating Android's overlay fullscreen video in web tests on Linux. { name: "ForcedColors", - // No status because this blink runtime feature doesn't work by itself. - // It's controlled by the corresponding Chromium feature which needs to - // be enabled to make the whole feature work. + status: "stable", }, { name: "ForceDeferScriptIntervention", @@ -1068,7 +1066,7 @@ // provides a convenient way for testing legacy layout code path in blink // unit tests. name: "LayoutNG", - implied_by: ["LayoutNGGrid", "BidiCaretAffinity"], + implied_by: ["LayoutNGGrid", "BidiCaretAffinity", "CSSContainerQueries"], status: "stable", }, {
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin.cc b/third_party/blink/renderer/platform/weborigin/security_origin.cc index 6153335..0fd156a1 100644 --- a/third_party/blink/renderer/platform/weborigin/security_origin.cc +++ b/third_party/blink/renderer/platform/weborigin/security_origin.cc
@@ -438,48 +438,9 @@ // //services/network/public/cpp/is_potentially_trustworthy.h). DCHECK_NE(protocol_, "data"); - - // The code below is based on the specification at - // https://w3c.github.io/webappsec-secure-contexts/#potentially-trustworthy-origin - - // 1. If origin is an opaque origin, return "Not Trustworthy". if (IsOpaque()) return is_opaque_origin_potentially_trustworthy_; - - // 2. Assert: origin is a tuple origin. - DCHECK(!IsOpaque()); - - // 3. If origin’s scheme is either "https" or "wss", return "Potentially - // Trustworthy". - // This is handled by the url::GetSecureSchemes() call below. - - // 4. If origin’s host component matches one of the CIDR notations 127.0.0.0/8 - // or ::1/128 [RFC4632], return "Potentially Trustworthy". - // 5. If origin’s host component is "localhost" or falls within ".localhost", - // and the user agent conforms to the name resolution rules in - // [let-localhost-be-localhost], return "Potentially Trustworthy". - if (IsLocalhost()) - return true; - - // 6. If origin’s scheme component is file, return "Potentially Trustworthy". - // This is handled by the IsLocal() call below. - - // 7. If origin’s scheme component is one which the user agent considers to be - // authenticated, return "Potentially Trustworthy". - // Note: See §7.1 Packaged Applications for detail here. - // - if (base::Contains(url::GetSecureSchemes(), protocol_.Ascii()) || IsLocal()) - return true; - - // 8. If origin has been configured as a trustworthy origin, return - // "Potentially Trustworthy". - // Note: See §7.2 Development Environments for detail here. - if (network::SecureOriginAllowlist::GetInstance().IsOriginAllowlisted( - ToUrlOrigin())) - return true; - - // 9. Return "Not Trustworthy". - return false; + return network::IsOriginPotentiallyTrustworthy(ToUrlOrigin()); } // static
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index 438881c..8265e425 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -670,7 +670,6 @@ crbug.com/1035582 paint/invalidation/invalidate-caret-before-text-node-update.html [ Failure ] crbug.com/1035582 paint/invalidation/outline/focus-continuations.html [ Failure ] crbug.com/1035582 paint/invalidation/outline/focus-enable-continuations.html [ Failure ] -crbug.com/1035582 paint/invalidation/outline/focus-ring-on-child-move.html [ Failure ] crbug.com/1035582 paint/invalidation/outline/focus-ring-on-continuation-move.html [ Failure ] crbug.com/1035582 paint/invalidation/outline/focus-ring-on-inline-continuation-move.html [ Failure ] crbug.com/1035582 paint/invalidation/outline/outline-become-affected-by-descendant.html [ Failure ]
diff --git a/third_party/blink/web_tests/FlagExpectations/force-renderer-accessibility b/third_party/blink/web_tests/FlagExpectations/force-renderer-accessibility index 130e8a3..77a402f 100644 --- a/third_party/blink/web_tests/FlagExpectations/force-renderer-accessibility +++ b/third_party/blink/web_tests/FlagExpectations/force-renderer-accessibility
@@ -40,17 +40,6 @@ fast/css-generated-content/after-with-first-letter-float-crash.html [ Crash ] fast/css-generated-content/table-row-after-no-crash.html [ Crash ] fast/css-generated-content/positioned-div-with-floating-after-content-crash.html [ Crash ] -fast/css/text-overflow-ellipsis-text-align-right.html [ Crash ] -fast/css/text-overflow-ellipsis-strict.html [ Crash ] -fast/css/text-overflow-ellipsis-block-with-border-and-padding.html [ Crash ] -fast/css/vertical-text-overflow-ellipsis-text-align-justify.html [ Crash ] -fast/css/vertical-text-overflow-ellipsis-text-align-center.html [ Crash ] -fast/css/text-overflow-ellipsis.html [ Crash ] -fast/css/text-overflow-ellipsis-text-align-left.html [ Crash ] -fast/css/vertical-text-overflow-ellipsis-text-align-right.html [ Crash ] -fast/css/text-overflow-ellipsis-text-align-center.html [ Crash ] -fast/css/vertical-text-overflow-ellipsis-text-align-left.html [ Crash ] -fast/css/text-overflow-ellipsis-text-align-justify.html [ Crash ] paint/markers/inline-spelling-markers-hidpi-composited.html [ Crash ] paint/markers/inline_spelling_markers.html [ Crash ] paint/markers/composition-marker-split.html [ Crash ] @@ -63,10 +52,6 @@ external/wpt/css/css-text/text-transform/text-transform-upperlower-044.html [ Crash ] external/wpt/css/css-text/text-transform/text-transform-upperlower-041.html [ Crash ] external/wpt/css/css-text/text-transform/text-transform-upperlower-043.html [ Crash ] -external/wpt/css/css-ui/text-overflow-006.html [ Crash ] -external/wpt/css/css-ui/text-overflow-013.html [ Crash ] -external/wpt/css/css-ui/text-overflow-028.html [ Crash ] -external/wpt/css/css-ui/text-overflow-027.html [ Crash ] external/wpt/css/css-overflow/webkit-line-clamp-031.html [ Crash ] external/wpt/css/css-overflow/webkit-line-clamp-034.html [ Crash ] external/wpt/css/css-overflow/webkit-line-clamp-025.html [ Crash ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index a7e05259..cf7d92fe 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -5879,3 +5879,6 @@ crbug.com/1147859 external/wpt/css/css-pseudo/highlight-painting-order.html [ Failure ] crbug.com/1060837 virtual/plz-dedicated-worker/external/wpt/html/cross-origin-embedder-policy/dedicated-worker.https.html [ Timeout ] + +# Sheriff 2021-01-15 +crbug.com/1167210 [ Mac ] virtual/forced-high-contrast-colors/fast/css/forced-colors-mode/forced-colors-mode-15.html [ Pass Failure ] \ No newline at end of file
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 2dab837..45ec3916 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -567,11 +567,6 @@ "--disable-features=CookiesWithoutSameSiteMustBeSecure"] }, { - "prefix": "forced-colors", - "bases": ["external/wpt/css/css-forced-color-adjust"], - "args": ["--enable-blink-features=ForcedColors"] - }, - { "prefix": "forced-high-contrast-colors", "bases": ["external/wpt/forced-colors-mode", "html/details_summary/color-scheme-validation"],
diff --git a/third_party/blink/web_tests/accessibility/canvas-fallback-content.html b/third_party/blink/web_tests/accessibility/canvas-fallback-content.html index 6b3c61d..aad37166 100644 --- a/third_party/blink/web_tests/accessibility/canvas-fallback-content.html +++ b/third_party/blink/web_tests/accessibility/canvas-fallback-content.html
@@ -1,4 +1,4 @@ -<!DOCTYPE HTML> +pc<!DOCTYPE HTML> <html> <body> <script src="../resources/testharness.js"></script> @@ -39,7 +39,10 @@ <div id="console"></div> <script> function check(id, expectedRole) { + console.log('Checking for ' + expectedRole + ' at #' + id); var axElement = accessibilityController.accessibleElementById(id); + assert_true(Boolean(axElement)); + assert_equals(axElement.role, expectedRole, id); var element = document.getElementById(id); // TODO(crbug.com/930327): focus() triggers a lifecycle update without updating observers. // Make sure to get the axElement before calling focus(), to trigger a full update cycle. @@ -77,10 +80,12 @@ // Check that the role is updated when the element changes. document.getElementById('focusable1').setAttribute('role', 'button'); - check("focusable1", "AXRole: AXButton", t); - document.getElementById('focusable2').setAttribute('role', 'button'); - check("focusable2", "AXRole: AXButton", t, true); + // Role changes do not take effect immediately. + requestAnimationFrame(() => { + check("focusable1", "AXRole: AXButton", t); + check("focusable2", "AXRole: AXButton", t,); + }); }, "This test makes sure that focusable elements in canvas fallback content are accessible.");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-forced-color-adjust/inheritance-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-forced-color-adjust/inheritance-expected.txt deleted file mode 100644 index 2711c74..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-forced-color-adjust/inheritance-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -FAIL Property forced-color-adjust has initial value auto assert_true: forced-color-adjust doesn't seem to be supported in the computed style expected true got false -FAIL Property forced-color-adjust inherits assert_true: forced-color-adjust doesn't seem to be supported in the computed style expected true got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-computed-expected.txt deleted file mode 100644 index 109a375145f6..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-computed-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -FAIL Property forced-color-adjust value 'auto' assert_true: forced-color-adjust doesn't seem to be supported in the computed style expected true got false -FAIL Property forced-color-adjust value 'none' assert_true: forced-color-adjust doesn't seem to be supported in the computed style expected true got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-valid-expected.txt deleted file mode 100644 index d488b40..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-valid-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -FAIL e.style['forced-color-adjust'] = "none" should set the property value assert_not_equals: property should be set got disallowed value "" -FAIL e.style['forced-color-adjust'] = "auto" should set the property value assert_not_equals: property should be set got disallowed value "" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/forced-colors-expected.txt b/third_party/blink/web_tests/external/wpt/css/mediaqueries/forced-colors-expected.txt deleted file mode 100644 index 8f3a9b998..0000000 --- a/third_party/blink/web_tests/external/wpt/css/mediaqueries/forced-colors-expected.txt +++ /dev/null
@@ -1,22 +0,0 @@ -This is a testharness.js-based test. -FAIL Should be parseable in a CSS stylesheet: '(forced-colors)' assert_true: expected true got false -FAIL Should be parseable in a CSS stylesheet: '(forced-colors: none)' assert_true: expected true got false -FAIL Should be parseable in a CSS stylesheet: '(forced-colors: active)' assert_true: expected true got false -PASS Should not be parseable in a CSS stylesheet: '(forced-colors: 0)' -PASS Should not be parseable in a CSS stylesheet: '(forced-colors: no-preference)' -PASS Should not be parseable in a CSS stylesheet: '(forced-colors: 10px)' -PASS Should not be parseable in a CSS stylesheet: '(forced-colors: active 0)' -PASS Should not be parseable in a CSS stylesheet: '(forced-colors: none active)' -PASS Should not be parseable in a CSS stylesheet: '(forced-colors: active/none)' -FAIL Should be parseable in JS: '(forced-colors)' assert_true: expected true got false -FAIL Should be parseable in JS: '(forced-colors: none)' assert_true: expected true got false -FAIL Should be parseable in JS: '(forced-colors: active)' assert_true: expected true got false -PASS Should not be parseable in JS: '(forced-colors: 0)' -PASS Should not be parseable in JS: '(forced-colors: no-preference)' -PASS Should not be parseable in JS: '(forced-colors: 10px)' -PASS Should not be parseable in JS: '(forced-colors: active 0)' -PASS Should not be parseable in JS: '(forced-colors: none active)' -PASS Should not be parseable in JS: '(forced-colors: active/none)' -FAIL Check that none evaluates to false in the boolean context assert_equals: expected true but got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https-expected.txt new file mode 100644 index 0000000..0065aa4a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Test Clients.matchAll() with a blob URL worker client. assert_equals: expected 1 but got 0 +FAIL Test Clients.matchAll() with an uncontrolled blob URL worker client. assert_equals: expected 1 but got 0 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https.html new file mode 100644 index 0000000..c29bac8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https.html
@@ -0,0 +1,85 @@ +<!DOCTYPE html> +<title>Service Worker: Clients.matchAll with a blob URL worker client</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/test-helpers.sub.js"></script> +<script> +const SCRIPT = 'resources/clients-matchall-worker.js'; + +promise_test(async (t) => { + const scope = 'resources/clients-matchall-blob-url-worker.html'; + + const reg = await service_worker_unregister_and_register(t, SCRIPT, scope); + t.add_cleanup(_ => reg.unregister()); + await wait_for_state(t, reg.installing, 'activated'); + + const frame = await with_iframe(scope); + t.add_cleanup(_ => frame.remove()); + + { + const message = await frame.contentWindow.waitForWorker(); + assert_equals(message.data, 'Worker is ready.', + 'Worker should reply to the message.'); + } + + const channel = new MessageChannel(); + const message = await new Promise(resolve => { + channel.port1.onmessage = resolve; + frame.contentWindow.navigator.serviceWorker.controller.postMessage( + {port: channel.port2, options: {type: 'worker'}}, [channel.port2]); + }); + + checkMessageEvent(message); + +}, 'Test Clients.matchAll() with a blob URL worker client.'); + +promise_test(async (t) => { + const scope = 'resources/blank.html'; + + const reg = await service_worker_unregister_and_register(t, SCRIPT, scope); + t.add_cleanup(_ => reg.unregister()); + await wait_for_state(t, reg.installing, 'activated'); + + const workerScript = ` + self.onmessage = (e) => { + self.postMessage("Worker is ready."); + }; + `; + const blob = new Blob([workerScript], { type: 'text/javascript' }); + const blobUrl = URL.createObjectURL(blob); + const worker = new Worker(blobUrl); + + { + const message = await new Promise(resolve => { + worker.onmessage = resolve; + worker.postMessage("Ping to worker."); + }); + assert_equals(message.data, 'Worker is ready.', + 'Worker should reply to the message.'); + } + + const channel = new MessageChannel(); + const message = await new Promise(resolve => { + channel.port1.onmessage = resolve; + reg.active.postMessage( + {port: channel.port2, + options: {includeUncontrolled: true, type: 'worker'}}, + [channel.port2] + ); + }); + + checkMessageEvent(message); + +}, 'Test Clients.matchAll() with an uncontrolled blob URL worker client.'); + +function checkMessageEvent(e) { + assert_equals(e.data.length, 1); + + const workerClient = e.data[0]; + assert_equals(workerClient[0], undefined); // visibilityState + assert_equals(workerClient[1], undefined); // focused + assert_true(workerClient[2].includes('blob:')); // url + assert_equals(workerClient[3], 'worker'); // type + assert_equals(workerClient[4], 'none'); // frameType +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/clients-matchall-blob-url-worker.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/clients-matchall-blob-url-worker.html new file mode 100644 index 0000000..ee89a0d8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/clients-matchall-blob-url-worker.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> +<script> +const workerScript = ` + self.onmessage = (e) => { + self.postMessage("Worker is ready."); + }; +`; +const blob = new Blob([workerScript], { type: 'text/javascript' }); +const blobUrl = URL.createObjectURL(blob); +const worker = new Worker(blobUrl); + +function waitForWorker() { + return new Promise(resolve => { + worker.onmessage = resolve; + worker.postMessage("Ping to worker."); + }); +} +</script> +</html>
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/outline/focus-ring-on-child-move-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/outline/focus-ring-on-child-move-expected.txt deleted file mode 100644 index 2777e49..0000000 --- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/outline/focus-ring-on-child-move-expected.txt +++ /dev/null
@@ -1,28 +0,0 @@ -{ - "layers": [ - { - "name": "Scrolling Contents Layer", - "bounds": [800, 600], - "contentsOpaque": true, - "backgroundColor": "#FFFFFF", - "paintInvalidations": [ - { - "object": "LayoutBlockFlow (positioned) DIV", - "rect": [99, 49, 302, 302], - "reason": "outline" - }, - { - "object": "LayoutBlockFlow (positioned) DIV id='child'", - "rect": [300, 50, 20, 300], - "reason": "geometry" - }, - { - "object": "LayoutBlockFlow (positioned) DIV id='child'", - "rect": [150, 50, 20, 300], - "reason": "geometry" - } - ] - } - ] -} -
diff --git a/third_party/blink/web_tests/paint/invalidation/outline/focus-ring-on-child-move-expected.txt b/third_party/blink/web_tests/paint/invalidation/outline/focus-ring-on-child-move-expected.txt index 4959aa2..c9d5757 100644 --- a/third_party/blink/web_tests/paint/invalidation/outline/focus-ring-on-child-move-expected.txt +++ b/third_party/blink/web_tests/paint/invalidation/outline/focus-ring-on-child-move-expected.txt
@@ -6,8 +6,7 @@ "contentsOpaque": true, "backgroundColor": "#FFFFFF", "invalidations": [ - [300, 50, 20, 300], - [150, 50, 20, 300] + [98, 48, 304, 304] ] } ]
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/outline/focus-ring-on-child-move-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/outline/focus-ring-on-child-move-expected.txt deleted file mode 100644 index c9d5757..0000000 --- a/third_party/blink/web_tests/platform/linux/paint/invalidation/outline/focus-ring-on-child-move-expected.txt +++ /dev/null
@@ -1,14 +0,0 @@ -{ - "layers": [ - { - "name": "Scrolling Contents Layer", - "bounds": [800, 600], - "contentsOpaque": true, - "backgroundColor": "#FFFFFF", - "invalidations": [ - [98, 48, 304, 304] - ] - } - ] -} -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/paint/invalidation/outline/focus-ring-on-child-move-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.14/paint/invalidation/outline/focus-ring-on-child-move-expected.txt deleted file mode 100644 index c9d5757..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.14/paint/invalidation/outline/focus-ring-on-child-move-expected.txt +++ /dev/null
@@ -1,14 +0,0 @@ -{ - "layers": [ - { - "name": "Scrolling Contents Layer", - "bounds": [800, 600], - "contentsOpaque": true, - "backgroundColor": "#FFFFFF", - "invalidations": [ - [98, 48, 304, 304] - ] - } - ] -} -
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/outline/focus-ring-on-child-move-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/outline/focus-ring-on-child-move-expected.txt deleted file mode 100644 index c9d5757..0000000 --- a/third_party/blink/web_tests/platform/mac/paint/invalidation/outline/focus-ring-on-child-move-expected.txt +++ /dev/null
@@ -1,14 +0,0 @@ -{ - "layers": [ - { - "name": "Scrolling Contents Layer", - "bounds": [800, 600], - "contentsOpaque": true, - "backgroundColor": "#FFFFFF", - "invalidations": [ - [98, 48, 304, 304] - ] - } - ] -} -
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/outline/focus-ring-on-child-move-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/outline/focus-ring-on-child-move-expected.txt deleted file mode 100644 index c9d5757..0000000 --- a/third_party/blink/web_tests/platform/win/paint/invalidation/outline/focus-ring-on-child-move-expected.txt +++ /dev/null
@@ -1,14 +0,0 @@ -{ - "layers": [ - { - "name": "Scrolling Contents Layer", - "bounds": [800, 600], - "contentsOpaque": true, - "backgroundColor": "#FFFFFF", - "invalidations": [ - [98, 48, 304, 304] - ] - } - ] -} -
diff --git a/third_party/blink/web_tests/virtual/forced-colors/README.md b/third_party/blink/web_tests/virtual/forced-colors/README.md deleted file mode 100644 index de185c88..0000000 --- a/third_party/blink/web_tests/virtual/forced-colors/README.md +++ /dev/null
@@ -1 +0,0 @@ -This directory is for testing Forced Colors mode implementation.
diff --git a/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/README.txt b/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/README.txt deleted file mode 100644 index de185c88..0000000 --- a/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/README.txt +++ /dev/null
@@ -1 +0,0 @@ -This directory is for testing Forced Colors mode implementation.
diff --git a/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/inheritance-expected.txt b/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/inheritance-expected.txt deleted file mode 100644 index 80e63c66..0000000 --- a/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/inheritance-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -PASS Property forced-color-adjust has initial value auto -PASS Property forced-color-adjust inherits -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-computed-expected.txt b/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-computed-expected.txt deleted file mode 100644 index d988ed8..0000000 --- a/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-computed-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -PASS Property forced-color-adjust value 'auto' -PASS Property forced-color-adjust value 'none' -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-valid-expected.txt b/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-valid-expected.txt deleted file mode 100644 index 8a0eba0..0000000 --- a/third_party/blink/web_tests/virtual/forced-colors/external/wpt/css/css-forced-color-adjust/parsing/forced-color-adjust-valid-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -PASS e.style['forced-color-adjust'] = "none" should set the property value -PASS e.style['forced-color-adjust'] = "auto" should set the property value -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/plz-dedicated-worker/external/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https-expected.txt b/third_party/blink/web_tests/virtual/plz-dedicated-worker/external/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https-expected.txt new file mode 100644 index 0000000..4b89cc4 --- /dev/null +++ b/third_party/blink/web_tests/virtual/plz-dedicated-worker/external/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +PASS Test Clients.matchAll() with a blob URL worker client. +PASS Test Clients.matchAll() with an uncontrolled blob URL worker client. +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt index 6c271cb..f5edaf826 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt
@@ -173,6 +173,7 @@ fontVariantNumeric fontVariationSettings fontWeight +forcedColorAdjust gap getPropertyPriority getPropertyValue
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt index 6e2de31..288cc68c 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt
@@ -190,6 +190,7 @@ font-variant-numeric font-variation-settings font-weight + forced-color-adjust grid-auto-columns grid-auto-flow grid-auto-rows
diff --git a/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt b/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt index 280292379..8c40cef 100644 --- a/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt +++ b/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt
@@ -180,6 +180,7 @@ fontVariantNumeric fontVariationSettings fontWeight +forcedColorAdjust gap getPropertyPriority getPropertyValue
diff --git a/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt index 9cce4c6..fd1e2f5 100644 --- a/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt
@@ -192,6 +192,7 @@ font-variant-numeric font-variation-settings font-weight + forced-color-adjust grid-auto-columns grid-auto-flow grid-auto-rows
diff --git a/third_party/r8/README.chromium b/third_party/r8/README.chromium index 5b2d55d4..2cc564e 100644 --- a/third_party/r8/README.chromium +++ b/third_party/r8/README.chromium
@@ -1,7 +1,7 @@ Name: R8 URL: https://r8.googlesource.com/r8 -Revision: 1d0cad3ec27fc88a1ca4ffc4d3d4d5d0b3f80f5b -Version: Unknown +Revision: 120900065d05300341e1dbd89feee4354f525468 +Version: 3.0.12-dev License: BSD 3-Clause License File: NOT_SHIPPED Security Critical: no
diff --git a/third_party/r8/patches/0001-Desugaring-Make-all-lambdas-stateless-fix-naming-sch.patch b/third_party/r8/patches/0001-Desugaring-Make-all-lambdas-stateless-fix-naming-sch.patch index b6b1dd2..55440801b 100644 --- a/third_party/r8/patches/0001-Desugaring-Make-all-lambdas-stateless-fix-naming-sch.patch +++ b/third_party/r8/patches/0001-Desugaring-Make-all-lambdas-stateless-fix-naming-sch.patch
@@ -1,4 +1,4 @@ -From 43c8250f2420c41640305d68b9d4512d69b850b0 Mon Sep 17 00:00:00 2001 +From 5a248a7f422c11f6e41e1c8684d207f3c2953b3b Mon Sep 17 00:00:00 2001 From: Sam Maier <smaier@chromium.org> Date: Tue, 19 May 2020 15:55:44 -0400 Subject: [PATCH 1/3] Desugaring: Make all lambdas stateless & fix naming @@ -12,10 +12,10 @@ 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java -index c9e47c259..b5b72c0ab 100644 +index a50581ee0..0d166d275 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java -@@ -130,7 +130,8 @@ public final class LambdaClass { +@@ -134,7 +134,8 @@ public final class LambdaClass { // If the lambda class should match 1:1 the class it is accessed from, we // just add the name of this type to make lambda class name unique. // It also helps link the class lambda originated from in some cases. @@ -25,7 +25,7 @@ lambdaClassDescriptor.append(accessedFrom.getHolderType().getName()).append('$'); } -@@ -209,7 +210,7 @@ public final class LambdaClass { +@@ -213,7 +214,7 @@ public final class LambdaClass { } public final boolean isStateless() { @@ -35,5 +35,5 @@ void addSynthesizedFrom(DexProgramClass clazz) { -- -2.29.2.299.gdc1121823c-goog +2.30.0.284.gd98b1dd5eaa7-goog
diff --git a/third_party/r8/patches/0002-Command-line-flags-for-class-merging-and-outlining.patch b/third_party/r8/patches/0002-Command-line-flags-for-class-merging-and-outlining.patch index 3be15d19..9d6ac91 100644 --- a/third_party/r8/patches/0002-Command-line-flags-for-class-merging-and-outlining.patch +++ b/third_party/r8/patches/0002-Command-line-flags-for-class-merging-and-outlining.patch
@@ -1,4 +1,4 @@ -From 81210f660e8b86116e7b512ae25c44c44cb1e1e7 Mon Sep 17 00:00:00 2001 +From bfb105aec6d8e20aa91f23652b148cda5d800211 Mon Sep 17 00:00:00 2001 From: Andrew Grieve <agrieve@chromium.org> Date: Mon, 28 Sep 2020 15:51:32 -0400 Subject: [PATCH 2/3] Command-line flags for class merging and outlining @@ -8,25 +8,21 @@ 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java -index 47c084e22..a7b1fc0eb 100644 +index 985090a37..64daa52a6 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java -@@ -236,11 +236,11 @@ public class InternalOptions implements GlobalKeepInfoConfiguration { +@@ -240,8 +240,8 @@ public class InternalOptions implements GlobalKeepInfoConfiguration { public boolean enableFieldAssignmentTracker = true; public boolean enableFieldBitAccessAnalysis = System.getProperty("com.android.tools.r8.fieldBitAccessAnalysis") != null; - public boolean enableStaticClassMerging = true; -- public boolean enableHorizontalClassMerging = true; -+ public boolean enableStaticClassMerging = System.getProperty("com.android.tools.r8.staticClassMerging") != null; -+ public boolean enableHorizontalClassMerging = System.getProperty("com.android.tools.r8.horizontalClassMerging") != null; - public int horizontalClassMergingMaxGroupSize = 30; - public boolean enableHorizontalClassMergingOfKotlinLambdas = true; - public boolean enableVerticalClassMerging = true; ++ public boolean enableStaticClassMerging = System.getProperty("com.android.tools.r8.staticClassMerging") != null; + public boolean enableVerticalClassMerging = System.getProperty("com.android.tools.r8.verticalClassMerging") != null; public boolean enableArgumentRemoval = true; public boolean enableUnusedInterfaceRemoval = true; public boolean enableDevirtualization = true; -@@ -1167,7 +1167,7 @@ public class InternalOptions implements GlobalKeepInfoConfiguration { +@@ -1202,7 +1202,7 @@ public class InternalOptions implements GlobalKeepInfoConfiguration { public static final String CLASS_NAME = "com.android.tools.r8.GeneratedOutlineSupport"; public static final String METHOD_PREFIX = "outline"; @@ -35,6 +31,15 @@ public int minSize = 3; public int maxSize = 99; public int threshold = 20; +@@ -1273,7 +1273,7 @@ public class InternalOptions implements GlobalKeepInfoConfiguration { + + public static class HorizontalClassMergerOptions { + +- public boolean enable = true; ++ public boolean enable = System.getProperty("com.android.tools.r8.horizontalClassMerging") != null; + public boolean enableConstructorMerging = true; + public boolean enableJavaLambdaMerging = false; + public boolean enableKotlinLambdaMerging = true; -- -2.29.2.299.gdc1121823c-goog +2.30.0.284.gd98b1dd5eaa7-goog
diff --git a/third_party/r8/patches/0003-Allow-access-modification-everywhere.patch b/third_party/r8/patches/0003-Allow-access-modification-everywhere.patch index 86c7279f..b6effe5 100644 --- a/third_party/r8/patches/0003-Allow-access-modification-everywhere.patch +++ b/third_party/r8/patches/0003-Allow-access-modification-everywhere.patch
@@ -1,4 +1,4 @@ -From eaf26704d9d5143d3cd5a8aa96ebff225bdf6747 Mon Sep 17 00:00:00 2001 +From 9d6a4562f1bdde941dcef77c311bcb9beb47313c Mon Sep 17 00:00:00 2001 From: Andrew Grieve <agrieve@chromium.org> Date: Wed, 21 Oct 2020 10:59:42 -0400 Subject: [PATCH 3/3] Allow access modification everywhere @@ -11,10 +11,10 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java -index bdda13be7..7553cbfa6 100644 +index b374e5843..999fd8307 100644 --- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java +++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java -@@ -881,7 +881,7 @@ public class AppInfoWithLiveness extends AppInfoWithClassHierarchy +@@ -900,7 +900,7 @@ public class AppInfoWithLiveness extends AppInfoWithClassHierarchy public boolean isAccessModificationAllowed(DexReference reference) { assert options().getProguardConfiguration().isAccessModificationAllowed(); @@ -24,5 +24,5 @@ public boolean isRepackagingAllowed(DexProgramClass clazz) { -- -2.29.2.299.gdc1121823c-goog +2.30.0.284.gd98b1dd5eaa7-goog
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 34126a5..a2b804a 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -30998,6 +30998,7 @@ <int value="3772" label="AddressSpaceUnknownNonSecureContextNavigatedToPrivate"/> <int value="3773" label="RTCPeerConnectionSdpSemanticsPlanB"/> + <int value="3774" label="FetchRespondWithNoResponseWithUsedRequestBody"/> </enum> <enum name="FeaturePolicyAllowlistType"> @@ -65103,6 +65104,20 @@ <int value="5" label="RESOLVE_SPECULATIVE_ABORT"/> </enum> +<enum name="ResolutionComparison"> + <int value="0" label="Requested width larger than capture"/> + <int value="1" label="Requested width smaller than capture"/> + <int value="2" label="Requested height larger than capture"/> + <int value="3" label="Requested height smaller than capture"/> + <int value="4" label="Requested resolution equals capture"/> + <int value="5" label="Requested width and height larger than capture"/> + <int value="6" + label="Requested width smaller, and height larger than capture"/> + <int value="7" + label="Requested width larger and height smaller than capture"/> + <int value="8" label="Requested width and height smaller than capture"/> +</enum> + <enum name="ResolutionUnspecWasteCategory"> <int value="0" label="AF_WASTE_IPV4_ONLY"> Running in a IPv4-only configuration. No waste.
diff --git a/tools/metrics/histograms/expand_owners.py b/tools/metrics/histograms/expand_owners.py index 566f8d56..f3de3e9 100644 --- a/tools/metrics/histograms/expand_owners.py +++ b/tools/metrics/histograms/expand_owners.py
@@ -17,8 +17,8 @@ # module's directory, histograms, and the directory above tools, which may or # may not be src depending on the machine running the code, is up three # directory levels from the histograms directory. -_DIR_ABOVE_TOOLS = [os.path.dirname(__file__), '..', '..', '..'] -_SRC = 'src/' +DIR_ABOVE_TOOLS = [os.path.dirname(__file__), '..', '..', '..'] +SRC = 'src/' class Error(Exception): @@ -91,7 +91,7 @@ Args: path: The path to an OWNERS file, e.g. 'src/gin/OWNERS'. """ - return path.startswith(_SRC) and path.endswith(_OWNERS) + return path.startswith(SRC) and path.endswith(_OWNERS) def _GetHigherLevelOwnersFilePath(path): @@ -111,7 +111,7 @@ # The highest directory that is searched for component information is one # directory lower than the directory above tools. Depending on the machine # running this code, the directory above tools may or may not be src. - path_to_limiting_dir = os.path.abspath(os.path.join(*_DIR_ABOVE_TOOLS)) + path_to_limiting_dir = os.path.abspath(os.path.join(*DIR_ABOVE_TOOLS)) limiting_dir = path_to_limiting_dir.split(os.sep)[-1] owners_file_limit = (os.sep).join([limiting_dir, _OWNERS]) if path.endswith(owners_file_limit): @@ -138,10 +138,10 @@ if _IsWellFormattedFilePath(path): # _SRC is removed because the file system on the machine running the code # may not have a(n) src directory. - path_without_src = path[len(_SRC):] + path_without_src = path[len(SRC):] return os.path.abspath( - os.path.join(*(_DIR_ABOVE_TOOLS + path_without_src.split(os.sep)))) + os.path.join(*(DIR_ABOVE_TOOLS + path_without_src.split(os.sep)))) raise Error( 'The given path {} is not well-formatted. Well-formatted paths begin ' @@ -184,7 +184,7 @@ elif first_word.startswith(directive): next_path = _GetOwnersFilePath( - os.path.join(_SRC, first_word[len(directive):])) + os.path.join(SRC, first_word[len(directive):])) if os.path.exists(next_path) and os.path.isfile(next_path): extracted_emails.extend( @@ -241,7 +241,7 @@ """ # Verify that the paths are absolute and the root is a parent of the # passed in path. - root_path = os.path.abspath(os.path.join(*_DIR_ABOVE_TOOLS)) + root_path = os.path.abspath(os.path.join(*DIR_ABOVE_TOOLS)) path = os.path.abspath(path) if not path.startswith(root_path): raise Error('Path {} is not a subpath of the root path {}.'.format( @@ -250,7 +250,7 @@ dirmd_exe = 'dirmd' if sys.platform == 'win32': dirmd_exe = 'dirmd.bat' - dirmd_path = os.path.join(*(_DIR_ABOVE_TOOLS + + dirmd_path = os.path.join(*(DIR_ABOVE_TOOLS + ['third_party', 'depot_tools', dirmd_exe])) dirmd = subprocess.Popen([dirmd_path, 'compute', '--root', root_path, path], stdout=subprocess.PIPE)
diff --git a/tools/metrics/histograms/expand_owners_unittest.py b/tools/metrics/histograms/expand_owners_unittest.py index 5beb49e7..76203b35 100644 --- a/tools/metrics/histograms/expand_owners_unittest.py +++ b/tools/metrics/histograms/expand_owners_unittest.py
@@ -5,6 +5,7 @@ import unittest import expand_owners +import mock import os import shutil import tempfile @@ -13,43 +14,38 @@ _DEFAULT_COMPONENT = '# COMPONENT: Default>Component' -def _DirnameN(path, n): - """Calls os.path.dirname() on the argument n times.""" - path = os.path.abspath(path) - for _ in range(n): - path = os.path.dirname(path) - return path +def _GetToolsParentDir(): + """Returns an absolute path to the the tools directory's parent directory. - -assert __file__.endswith('tools/metrics/histograms/expand_owners_unittest.py') - -_PATH_TO_CHROMIUM_DIR = _DirnameN(__file__, 5) + Example: 'C:\a\n\ff\' or '/opt/n/ff/'. + """ + return os.path.abspath(os.path.join(*expand_owners.DIR_ABOVE_TOOLS)) def _GetFileDirective(path): """Returns a file directive line. Args: - path: An absolute path, e.g. '/some/directory/chromium/src/tools/OWNERS'. + path: An absolute path, e.g. '/some/directory/subdirectory/tools/OWNERS'. Returns: A file directive that can be used in an OWNERS file, e.g. file://tools/OWNERS. """ - return ''.join(['file://', path.split('src/')[1]]) + return ''.join(['file://', path[len(_GetToolsParentDir()) + 1:]]) def _GetSrcRelativePath(path): """Returns a(n) src-relative path for the given file path. Args: - path: An absolute path, e.g. '/some/directory/chromium/src/tools/OWNERS'. + path: An absolute path, e.g. '/some/directory/subdirectory/tools/OWNERS'. Returns: A src-relative path, e.g.'src/tools/OWNERS'. """ - assert path.startswith(_PATH_TO_CHROMIUM_DIR) - return path[len(_PATH_TO_CHROMIUM_DIR) + 1:] + assert path.startswith(_GetToolsParentDir()) + return expand_owners.SRC + path[len(_GetToolsParentDir()) + 1:] def _MakeOwnersFile(filename, directory): @@ -75,10 +71,17 @@ self.temp_dir = tempfile.mkdtemp( dir=os.path.abspath(os.path.join(os.path.dirname(__file__)))) + # The below construction is used rather than __file__.endswith() because + # the file extension could be .py or .pyc. + assert os.sep.join( + ['tools', 'metrics', 'histograms', + 'expand_owners_unittest.py']) in __file__ + def tearDown(self): super(ExpandOwnersTest, self).tearDown() shutil.rmtree(self.temp_dir) + @unittest.skip("http://crbug.com/1164985") def testExpandOwnersUsesMetadataOverOwners(self): """Checks that DIR_METADATA is used if available""" with open(os.path.join(self.temp_dir, 'DIR_METADATA'), "w+") as md: @@ -134,8 +137,10 @@ expand_owners.ExpandHistogramsOWNERS(histograms) self.assertMultiLineEqual(histograms.toxml(), expected_histograms.toxml()) - def testExpandOwnersWithSimpleOWNERSFilePath(self): + @mock.patch('expand_owners._ExtractComponentViaDirmd') + def testExpandOwnersWithSimpleOWNERSFilePath(self, mock_dirmd_extract): """Checks that OWNERS files are expanded.""" + mock_dirmd_extract.return_value = None absolute_path = _MakeOwnersFile('simple_OWNERS', self.temp_dir) src_relative_path = _GetSrcRelativePath(absolute_path) @@ -188,11 +193,15 @@ expand_owners.ExpandHistogramsOWNERS(histograms) self.assertMultiLineEqual(histograms.toxml(), expected_histograms.toxml()) - def testExpandOwnersWithLongFilePath(self): + @mock.patch('expand_owners._ExtractComponentViaDirmd') + def testExpandOwnersWithLongFilePath(self, mock_dirmd_extract): + """Checks that long OWNERS file paths are supported. + + Most OWNERS file paths appear between owners tags on the same line, e.g. + <owner>src/chrome/browser</owner>. However, especially long paths may appear + on their own line between the tags. """ - Check that long file path which forces <owner> tags to separate lines is - supported. - """ + mock_dirmd_extract.return_value = None absolute_path = _MakeOwnersFile('simple_OWNERS', self.temp_dir) src_relative_path = _GetSrcRelativePath(absolute_path) @@ -229,8 +238,10 @@ expand_owners.ExpandHistogramsOWNERS(histograms) self.assertMultiLineEqual(histograms.toxml(), expected_histograms.toxml()) - def testExpandOwnersWithDuplicateOwners(self): + @mock.patch('expand_owners._ExtractComponentViaDirmd') + def testExpandOwnersWithDuplicateOwners(self, mock_dirmd_extract): """Checks that owners are unique.""" + mock_dirmd_extract.return_value = None absolute_path = _MakeOwnersFile('simple_OWNERS', self.temp_dir) src_relative_path = _GetSrcRelativePath(absolute_path) @@ -266,8 +277,10 @@ expand_owners.ExpandHistogramsOWNERS(histograms) self.assertMultiLineEqual(histograms.toxml(), expected_histograms.toxml()) - def testExpandOwnersWithFileDirectiveOWNERSFilePath(self): + @mock.patch('expand_owners._ExtractComponentViaDirmd') + def testExpandOwnersWithFileDirectiveOWNERSFilePath(self, mock_dirmd_extract): """Checks that OWNERS files with file directives are expanded.""" + mock_dirmd_extract.return_value = None simple_absolute_path = _MakeOwnersFile('simple_OWNERS', self.temp_dir) with open(simple_absolute_path, 'w') as owners_file: @@ -314,8 +327,11 @@ expand_owners.ExpandHistogramsOWNERS(histograms) self.assertEqual(histograms.toxml(), expected_histograms.toxml()) - def testExpandOwnersForOWNERSFileWithDuplicateComponents(self): + @mock.patch('expand_owners._ExtractComponentViaDirmd') + def testExpandOwnersForOWNERSFileWithDuplicateComponents( + self, mock_dirmd_extract): """Checks that only one component tag is added if there are duplicates.""" + mock_dirmd_extract.return_value = None absolute_path = _MakeOwnersFile('OWNERS', self.temp_dir) src_relative_path = _GetSrcRelativePath(absolute_path) @@ -463,8 +479,7 @@ """) with self.assertRaisesRegexp( - expand_owners.Error, - r'The file at .*src/medium/medium/roast/OWNERS does not exist\.'): + expand_owners.Error, r'The file at .*medium.*OWNERS does not exist\.'): expand_owners.ExpandHistogramsOWNERS(histograms_with_fake_file_path) def testExpandOwnersWithoutOwnersFromFile(self): @@ -595,28 +610,21 @@ expand_owners._ExtractEmailAddressesFromOWNERS( file_directive_absolute_path) + def testGetHigherLevelPath(self): + """Checks that higher directories are recursively checked for OWNERS. -class GetHigherLevelOwnersFilePathTest(unittest.TestCase): - - def testGetHigherLevelPathDerivedPathInSrcDirectory(self): - """Checks that higher directories are recursively checked for OWNERS.""" - path = expand_owners._GetOwnersFilePath('src/banana/chocolate/OWNERS') - self.assertRegexpMatches( - expand_owners._GetHigherLevelOwnersFilePath(path), r'.*src/OWNERS') - - def testGetHigherLevelPathGivenPathInSrcDirectory(self): - """Checks that '' is returned when the last directory is reached. - - If the directory above the tools directory is src, then receiving - 'src/OWNERS' is the point at which recursion stops. However, this directory - may not always be src. + Also, checks that there isn't a recursive loop. """ - path_to_chromium_directory = [ - os.path.dirname(__file__), '..', '..', '..', '..' - ] - path = os.path.abspath( - os.path.join(*(path_to_chromium_directory + ['src/OWNERS']))) - self.assertEqual(expand_owners._GetHigherLevelOwnersFilePath(path), '') + path = expand_owners._GetOwnersFilePath('src/banana/chocolate/OWNERS') + result = expand_owners._GetHigherLevelOwnersFilePath(path) + + # The condition is true when the tools directory's parent directory is src, + # which is generally the case locally. However, the parent directory is not + # always src, e.g. on various testing bots. + if os.path.basename(_GetToolsParentDir()) == 'src': + self.assertRegexpMatches(result, r'.*OWNERS') + else: + self.assertEqual(result, '') if __name__ == '__main__':
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml index 9353e2d5..3757232 100644 --- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -599,6 +599,8 @@ name="PageLoad.AdPaintTiming.NavigationToFirstContentfulPaint"/> <affected-histogram name="PageLoad.AdPaintTiming.NavigationToFirstContentfulPaint2"/> + <affected-histogram + name="PageLoad.AdPaintTiming.NavigationToFirstContentfulPaint3"/> <affected-histogram name="PageLoad.Bytes"/> <affected-histogram name="PageLoad.Cpu"/> <affected-histogram @@ -16603,8 +16605,8 @@ <histogram_suffixes name="SendTabToSelfEntryPoint" separator="." ordering="prefix"> <owner>jeffreycohen@chromium.org</owner> - <owner>sebsg@chromium.org</owner> <owner>tgupta@chromium.org</owner> + <owner>chrome-sharing-core@google.com</owner> <suffix name="ContentMenu" label="Option shown in the content context menu"/> <suffix name="LinkMenu" label="Option shown in the link context menu"/> <suffix name="OmniboxIcon" label="Icon shown in the omnibox"/> @@ -16619,9 +16621,6 @@ <obsolete> The affected histogram is obsolete (5/20). </obsolete> - <owner>jeffreycohen@chromium.org</owner> - <owner>sebsg@chromium.org</owner> - <owner>tgupta@chromium.org</owner> <suffix name="ContentMenu" label="The count of devices shown in the content submenu"/> <suffix name="LinkMenu"
diff --git a/tools/metrics/histograms/histograms_xml/media/histograms.xml b/tools/metrics/histograms/histograms_xml/media/histograms.xml index 10a2ebc..edbb8fe 100644 --- a/tools/metrics/histograms/histograms_xml/media/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/media/histograms.xml
@@ -3877,6 +3877,51 @@ </summary> </histogram> +<histogram name="Media.VideoCapture.Mac.Device.CapturedIOSurface" + enum="Boolean" expires_after="M92"> + <owner>eshr@google.com</owner> + <owner>handellm@google.com</owner> + <summary> + A count of how often the capture device delivers an IOSurface to the capture + pipeline. This is recorded once per opening of the camera, when the first + video frame is captured. + </summary> +</histogram> + +<histogram + name="Media.VideoCapture.Mac.Device.CapturedWithRequestedPixelFormat" + enum="Boolean" expires_after="M92"> + <owner>eshr@google.com</owner> + <owner>handellm@google.com</owner> + <summary> + A boolean count of how often the requested pixel format is the one that was + actually captured. This is recorded once per opening of the camera, when the + first video frame is captured. + </summary> +</histogram> + +<histogram name="Media.VideoCapture.Mac.Device.CapturedWithRequestedResolution" + enum="ResolutionComparison" expires_after="M92"> + <owner>eshr@google.com</owner> + <owner>handellm@google.com</owner> + <summary> + An enumeration count of whether or not the requested resolution equals the + captured resolution, detailing which dimensions differ in the enum. This is + recorded once per opening of the camera, when the first video frame is + captured. + </summary> +</histogram> + +<histogram name="Media.VideoCapture.Mac.Device.RequestedPixelFormat" + enum="VideoResolutionDesignation" expires_after="M92"> + <owner>eshr@google.com</owner> + <owner>handellm@google.com</owner> + <summary> + Counts the pixel formats requested by the VideoCaptureDevice on Mac. This is + recorded when the first video frame is captured. + </summary> +</histogram> + <histogram name="Media.VideoCapture.MacBook.AttemptCountWhenNoCamera" units="attempts" expires_after="2020-03-15"> <owner>chfremer@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index a856efe8..390c69ae 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -13587,17 +13587,18 @@ </histogram> <histogram name="SendTabToSelf.AndroidShareSheet.ClickResult" - enum="SendTabToSelfClickResult" expires_after="M88"> + enum="SendTabToSelfClickResult" expires_after="M97"> <owner>jeffreycohen@chromium.org</owner> <owner>tgupta@chromium.org</owner> + <owner>chrome-sharing-core@google.com</owner> <summary>Tracks the user flow for sending a tab for SendTabToSelf.</summary> </histogram> <histogram base="true" name="SendTabToSelf.ClickResult" - enum="SendTabToSelfClickResult" expires_after="M88"> + enum="SendTabToSelfClickResult" expires_after="M97"> <owner>jeffreycohen@chromium.org</owner> - <owner>sebsg@chromium.org</owner> <owner>tgupta@chromium.org</owner> + <owner>chrome-sharing-core@google.com</owner> <summary> Record whether the user has clicked the item when it is shown. </summary> @@ -14666,12 +14667,18 @@ </histogram> <histogram name="SpellCheck.MisspellRatio" units="%" expires_after="M90"> + <obsolete> + Removed 2021/01: the relevant code path isn't used anymore. + </obsolete> <owner>gujen@google.com</owner> <owner>chrome-language@google.com</owner> <summary>The percentage of misspelled words within checked words.</summary> </histogram> <histogram name="SpellCheck.ReplaceRatio" units="%" expires_after="M90"> + <obsolete> + Removed 2021/01: the relevant code path isn't used anymore. + </obsolete> <owner>gujen@google.com</owner> <owner>chrome-language@google.com</owner> <summary>The percentage of replaced words within misspelled words.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/page/histograms.xml b/tools/metrics/histograms/histograms_xml/page/histograms.xml index 936450c..df73252e 100644 --- a/tools/metrics/histograms/histograms_xml/page/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/page/histograms.xml
@@ -34,6 +34,26 @@ <histogram base="true" name="PageLoad.AdPaintTiming.NavigationToFirstContentfulPaint2" units="ms" expires_after="2021-07-31"> + <obsolete> + Replaced by PageLoad.PaintTiming.NavigationToLargestContentfulPaint3 in Jan + 2021 to increase the bucket range. + </obsolete> + <owner>jkarlin@chromium.org</owner> + <owner>johnidel@chromium.org</owner> + <summary> + Records the time from frame navigation start to FirstContentfulPaint of each + ad frame that receives a FirstContentfulPaint. The time could be quite + large, as some ads don't paint until they're scrolled into view. But the + metric is still useful in aggregate. + + Recorded for all ad frames with non-zero bytes or cpu usage that receive a + FirstContentfulPaint. Recorded when the ad frame or page is destroyed. + </summary> +</histogram> + +<histogram base="true" + name="PageLoad.AdPaintTiming.NavigationToFirstContentfulPaint3" units="ms" + expires_after="2021-12-31"> <owner>jkarlin@chromium.org</owner> <owner>johnidel@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/signin/histograms.xml b/tools/metrics/histograms/histograms_xml/signin/histograms.xml index 07250917..b067699 100644 --- a/tools/metrics/histograms/histograms_xml/signin/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
@@ -521,12 +521,13 @@ </histogram> <histogram name="Signin.InvestigatedScenario" enum="SigninInvestigatedScenario" - expires_after="M90"> + expires_after="M95"> <owner>treib@chromium.org</owner> <owner>mmoskvitin@google.com</owner> <summary> - Records the general type of signin that is occuring in relation to previous - signin and local data. + Recorded when Sync is turned on in a profile. Records whether this is the + first time Sync is turned on in this profile or, if not, whether Sync was + previously turned on for the same or for a different account. </summary> </histogram>
diff --git a/tools/metrics/metrics_python_tests.py b/tools/metrics/metrics_python_tests.py index 5c9cafa..5e31885 100755 --- a/tools/metrics/metrics_python_tests.py +++ b/tools/metrics/metrics_python_tests.py
@@ -23,8 +23,7 @@ sys.exit( typ.main(tests=resolve( 'actions/extract_actions_test.py', - # TODO(crbug/1126653): Turn back on once tests can pass again. - # 'histograms/expand_owners_unittest.py', + 'histograms/expand_owners_unittest.py', 'histograms/extract_histograms_test.py', 'histograms/generate_expired_histograms_array_unittest.py', 'histograms/pretty_print_test.py',
diff --git a/tools/perf/benchmarks/v8_browsing.py b/tools/perf/benchmarks/v8_browsing.py index 1b17073..1b4a116ec 100644 --- a/tools/perf/benchmarks/v8_browsing.py +++ b/tools/perf/benchmarks/v8_browsing.py
@@ -11,19 +11,6 @@ from telemetry.web_perf import timeline_based_measurement import page_sets -V8_BROWSING_BENCHMARK_UMA = [ - 'V8.WasmCompileModuleMicroSeconds.wasm', - 'V8.WasmCompileModuleAsyncMicroSeconds', - 'V8.WasmCompileModuleStreamingMicroSeconds', - 'V8.WasmFinishModuleStreamingMicroSeconds', - 'V8.WasmTierUpModuleMicroSeconds', - 'V8.WasmCompileFunctionMicroSeconds.wasm', - 'V8.WasmInstantiateModuleMicroSeconds.wasm', - 'V8.WasmModuleCodeSizeTopTierMiB', - 'V8.WasmCompileFunctionPeakMemoryBytes', - 'V8.WasmModuleCodeSizeMiB', -] - def AugmentOptionsForV8BrowsingMetrics(options, enable_runtime_call_stats=True): categories = [ @@ -57,9 +44,6 @@ options.config.chrome_trace_config.SetTraceBufferSizeInKb(400 * 1024) - options.config.chrome_trace_config.EnableUMAHistograms( - *V8_BROWSING_BENCHMARK_UMA) - metrics = [ 'blinkGcMetric', 'consoleErrorMetric', @@ -68,7 +52,6 @@ 'memoryMetric', 'pcscanMetric', 'reportedByPageMetric', - 'umaMetric', 'wasmMetric', ] options.ExtendTimelineBasedMetric(metrics)
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 8d5cb13f..fcffa17 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "remote_path": "perfetto_binaries/trace_processor_shell/win/94ca9a9578a7eeb3df93a820955458fb9aff28fd/trace_processor_shell.exe" }, "mac": { - "hash": "19571150217264641baf978653dd92211ef6b268", - "remote_path": "perfetto_binaries/trace_processor_shell/mac/94ca9a9578a7eeb3df93a820955458fb9aff28fd/trace_processor_shell" + "hash": "cef9f6facb62a38a26057262c029aad1fa51bca4", + "remote_path": "perfetto_binaries/trace_processor_shell/mac/2d79f95e908dcbae188e1fedd12e8424cbd14392/trace_processor_shell" }, "linux": { "hash": "240f01ceac4408177109ca356554518088cf0498",
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 5427e8eb..35b14dd 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -254,7 +254,6 @@ crbug.com/1160628 [ android-pixel-2 ] rendering.mobile/idle_power_request_animation_frame [ Skip ] crbug.com/1160628 [ android-pixel-2 ] rendering.mobile/idle_power_set_timeout_long [ Skip ] crbug.com/1160628 [ android-pixel-2 ] rendering.mobile/idle_power_set_timetout [ Skip ] -crbug.com/1166558 [ android-pixel-2 ] rendering.mobile/microgame_fps [ Skip ] # Benchmark: rasterize_and_record_micro.top_25 crbug.com/764543 rasterize_and_record_micro.top_25/file://static_top_25/wikipedia.html [ Skip ]
diff --git a/ui/accessibility/ax_role_properties.cc b/ui/accessibility/ax_role_properties.cc index c09f6364..8b966e2c 100644 --- a/ui/accessibility/ax_role_properties.cc +++ b/ui/accessibility/ax_role_properties.cc
@@ -723,6 +723,17 @@ } } +bool IsComboBox(const ax::mojom::Role role) { + switch (role) { + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kComboBoxGrouping: + case ax::mojom::Role::kTextFieldWithComboBox: + return true; + default: + return false; + } +} + bool ShouldHaveReadonlyStateByDefault(const ax::mojom::Role role) { switch (role) { case ax::mojom::Role::kArticle:
diff --git a/ui/accessibility/ax_role_properties.h b/ui/accessibility/ax_role_properties.h index 1178560..0280412 100644 --- a/ui/accessibility/ax_role_properties.h +++ b/ui/accessibility/ax_role_properties.h
@@ -179,6 +179,9 @@ // break, or inline text box. AX_BASE_EXPORT bool IsText(ax::mojom::Role role); +// Returns true if the provided role is any of the combobox-related roles. +AX_BASE_EXPORT bool IsComboBox(ax::mojom::Role role); + // Returns true if the node should be read only by default AX_BASE_EXPORT bool ShouldHaveReadonlyStateByDefault( const ax::mojom::Role role);
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm index ce50a0a..93a3618 100644 --- a/ui/accessibility/platform/ax_platform_node_mac.mm +++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -57,8 +57,8 @@ {ax::mojom::Role::kColorWell, NSAccessibilityColorWellRole}, {ax::mojom::Role::kColumn, NSAccessibilityColumnRole}, {ax::mojom::Role::kColumnHeader, @"AXCell"}, - {ax::mojom::Role::kComboBoxGrouping, NSAccessibilityGroupRole}, - {ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityPopUpButtonRole}, + {ax::mojom::Role::kComboBoxGrouping, NSAccessibilityComboBoxRole}, + {ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityComboBoxRole}, {ax::mojom::Role::kComment, NSAccessibilityGroupRole}, {ax::mojom::Role::kComplementary, NSAccessibilityGroupRole}, {ax::mojom::Role::kContentDeletion, NSAccessibilityGroupRole},
diff --git a/ui/android/OWNERS b/ui/android/OWNERS index 3dce3d6e..2d96ba4 100644 --- a/ui/android/OWNERS +++ b/ui/android/OWNERS
@@ -8,6 +8,3 @@ # for display/window/view_android boliu@chromium.org jinsukkim@chromium.org - -# for CC and Viz integration -khushalsagar@chromium.org
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc index 0193353..5f8e78b 100644 --- a/ui/base/ui_base_features.cc +++ b/ui/base/ui_base_features.cc
@@ -164,7 +164,7 @@ // Enables forced colors mode for web content. const base::Feature kForcedColors{"ForcedColors", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; bool IsForcedColorsEnabled() { static const bool forced_colors_enabled =
diff --git a/ui/gfx/OWNERS b/ui/gfx/OWNERS index e34675cb..4bbf63b 100644 --- a/ui/gfx/OWNERS +++ b/ui/gfx/OWNERS
@@ -25,7 +25,6 @@ # Overlay transforms. per-file overlay*=alexst@chromium.org -per-file overlay*=khushalsagar@chromium.org per-file overlay*=spang@chromium.org # Transform, interpolated transform and transform util.
diff --git a/ui/gl/OWNERS b/ui/gl/OWNERS index 85860991..1f6eeb2 100644 --- a/ui/gl/OWNERS +++ b/ui/gl/OWNERS
@@ -6,7 +6,7 @@ per-file *_ozone*=alexst@chromium.org per-file *_ozone*=dnicoara@chromium.org per-file *_ozone*=spang@chromium.org -per-file *surface_control*=khushalsagar@chromium.org +per-file *surface_control*=vasilyt@chromium.org # For Windows Direct Composition and Swap Chain magchen@chromium.org
diff --git a/ui/views/accessibility/accessibility_alert_window.cc b/ui/views/accessibility/accessibility_alert_window.cc index 9afdb52..c1b5b43 100644 --- a/ui/views/accessibility/accessibility_alert_window.cc +++ b/ui/views/accessibility/accessibility_alert_window.cc
@@ -23,7 +23,7 @@ alert_window_->Init(ui::LayerType::LAYER_NOT_DRAWN); alert_window_->SetProperty(ui::kAXRoleOverride, ax::mojom::Role::kAlert); parent->AddChild(alert_window_.get()); - observer_.Add(aura::Env::GetInstance()); + observation_.Observe(aura::Env::GetInstance()); } AccessibilityAlertWindow::~AccessibilityAlertWindow() = default; @@ -38,7 +38,7 @@ } void AccessibilityAlertWindow::OnWillDestroyEnv() { - observer_.RemoveAll(); + observation_.Reset(); alert_window_.reset(); }
diff --git a/ui/views/accessibility/accessibility_alert_window.h b/ui/views/accessibility/accessibility_alert_window.h index 5895a71..d64082df 100644 --- a/ui/views/accessibility/accessibility_alert_window.h +++ b/ui/views/accessibility/accessibility_alert_window.h
@@ -9,7 +9,7 @@ #include <string> #include "base/gtest_prod_util.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/aura/env.h" #include "ui/aura/env_observer.h" #include "ui/views/views_export.h" @@ -48,7 +48,7 @@ // The accessibility cache associated with |alert_window_|. views::AXAuraObjCache* cache_; - ScopedObserver<aura::Env, aura::EnvObserver> observer_{this}; + base::ScopedObservation<aura::Env, aura::EnvObserver> observation_{this}; }; } // namespace views
diff --git a/ui/views/accessibility/accessibility_alert_window_unittest.cc b/ui/views/accessibility/accessibility_alert_window_unittest.cc index 60af94e..fe3c5e3 100644 --- a/ui/views/accessibility/accessibility_alert_window_unittest.cc +++ b/ui/views/accessibility/accessibility_alert_window_unittest.cc
@@ -76,7 +76,7 @@ AccessibilityAlertWindow window(parent_.get(), &cache); window.OnWillDestroyEnv(); - EXPECT_FALSE(window.observer_.IsObservingSources()); + EXPECT_FALSE(window.observation_.IsObserving()); EXPECT_FALSE(window.alert_window_); }
diff --git a/ui/views/accessibility/ax_view_obj_wrapper.cc b/ui/views/accessibility/ax_view_obj_wrapper.cc index 5384534..b75370f 100644 --- a/ui/views/accessibility/ax_view_obj_wrapper.cc +++ b/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -4,6 +4,7 @@ #include "ui/views/accessibility/ax_view_obj_wrapper.h" +#include <string> #include <vector> #include "ui/accessibility/ax_action_data.h" @@ -20,7 +21,7 @@ : AXAuraObjWrapper(aura_obj_cache), view_(view) { if (view->GetWidget()) aura_obj_cache_->GetOrCreate(view->GetWidget()); - observer_.Add(view); + observation_.Observe(view); } AXViewObjWrapper::~AXViewObjWrapper() = default; @@ -97,7 +98,7 @@ } void AXViewObjWrapper::OnViewIsDeleting(View* observed_view) { - observer_.RemoveAll(); + observation_.Reset(); view_ = nullptr; }
diff --git a/ui/views/accessibility/ax_view_obj_wrapper.h b/ui/views/accessibility/ax_view_obj_wrapper.h index 758381f..c4ebc6c 100644 --- a/ui/views/accessibility/ax_view_obj_wrapper.h +++ b/ui/views/accessibility/ax_view_obj_wrapper.h
@@ -7,9 +7,10 @@ #include <stdint.h> +#include <string> #include <vector> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/views/accessibility/ax_aura_obj_wrapper.h" #include "ui/views/view.h" #include "ui/views/view_observer.h" @@ -43,7 +44,7 @@ private: View* view_; - ScopedObserver<View, ViewObserver> observer_{this}; + base::ScopedObservation<View, ViewObserver> observation_{this}; }; } // namespace views
diff --git a/ui/views/accessibility/ax_widget_obj_wrapper.cc b/ui/views/accessibility/ax_widget_obj_wrapper.cc index c58811c..a81b7a5 100644 --- a/ui/views/accessibility/ax_widget_obj_wrapper.cc +++ b/ui/views/accessibility/ax_widget_obj_wrapper.cc
@@ -18,7 +18,7 @@ AXWidgetObjWrapper::AXWidgetObjWrapper(AXAuraObjCache* aura_obj_cache, Widget* widget) : AXAuraObjWrapper(aura_obj_cache), widget_(widget) { - widget_observer_.Add(widget); + widget_observation_.Observe(widget); widget->AddRemovalsObserver(this); }
diff --git a/ui/views/accessibility/ax_widget_obj_wrapper.h b/ui/views/accessibility/ax_widget_obj_wrapper.h index 9d768b8..14c735c 100644 --- a/ui/views/accessibility/ax_widget_obj_wrapper.h +++ b/ui/views/accessibility/ax_widget_obj_wrapper.h
@@ -7,9 +7,10 @@ #include <stdint.h> +#include <string> #include <vector> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/accessibility/platform/ax_unique_id.h" #include "ui/views/accessibility/ax_aura_obj_wrapper.h" #include "ui/views/widget/widget.h" @@ -52,7 +53,7 @@ const ui::AXUniqueId unique_id_; - ScopedObserver<Widget, WidgetObserver> widget_observer_{this}; + base::ScopedObservation<Widget, WidgetObserver> widget_observation_{this}; }; } // namespace views
diff --git a/ui/views/accessibility/ax_window_obj_wrapper.cc b/ui/views/accessibility/ax_window_obj_wrapper.cc index bdbe0ec..6576335 100644 --- a/ui/views/accessibility/ax_window_obj_wrapper.cc +++ b/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -81,7 +81,7 @@ : AXAuraObjWrapper(aura_obj_cache), window_(window), is_root_window_(window->IsRootWindow()) { - observer_.Add(window); + observation_.Observe(window); if (is_root_window_) aura_obj_cache_->OnRootWindowObjCreated(window);
diff --git a/ui/views/accessibility/ax_window_obj_wrapper.h b/ui/views/accessibility/ax_window_obj_wrapper.h index 7c5514b..221e5b0 100644 --- a/ui/views/accessibility/ax_window_obj_wrapper.h +++ b/ui/views/accessibility/ax_window_obj_wrapper.h
@@ -7,9 +7,10 @@ #include <stdint.h> +#include <string> #include <vector> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/accessibility/ax_enums.mojom-forward.h" #include "ui/accessibility/platform/ax_unique_id.h" #include "ui/aura/window.h" @@ -69,7 +70,8 @@ // pointer could be left in |aura_obj_cache_|. See https://crbug.com/1091545 bool window_destroying_ = false; - ScopedObserver<aura::Window, aura::WindowObserver> observer_{this}; + base::ScopedObservation<aura::Window, aura::WindowObserver> observation_{ + this}; }; } // namespace views
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc index e644376..3b7c1df 100644 --- a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc +++ b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
@@ -10,7 +10,7 @@ #include "base/containers/contains.h" #include "base/memory/singleton.h" -#include "base/scoped_observer.h" +#include "base/scoped_multi_source_observation.h" #include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" @@ -87,11 +87,11 @@ return; widgets_.push_back(widget); - widget_observer_.Add(widget); + widget_observations_.AddObservation(widget); aura::Window* window = widget->GetNativeWindow(); if (window) - window_observer_.Add(window); + window_observations_.AddObservation(window); } gfx::NativeViewAccessible GetNativeViewAccessible() override { @@ -103,11 +103,11 @@ // WidgetObserver: void OnWidgetDestroying(Widget* widget) override { - widget_observer_.Remove(widget); + widget_observations_.RemoveObservation(widget); aura::Window* window = widget->GetNativeWindow(); - if (window && window_observer_.IsObserving(window)) - window_observer_.Remove(window); + if (window && window_observations_.IsObservingSource(window)) + window_observations_.RemoveObservation(window); auto iter = std::find(widgets_.begin(), widgets_.end(), widget); if (iter != widgets_.end()) @@ -167,8 +167,10 @@ ui::AXNodeData data_; ui::AXUniqueId unique_id_; std::vector<Widget*> widgets_; - ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this}; - ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this}; + base::ScopedMultiSourceObservation<views::Widget, views::WidgetObserver> + widget_observations_{this}; + base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver> + window_observations_{this}; }; } // namespace
diff --git a/ui/views/animation/animation_delegate_views.cc b/ui/views/animation/animation_delegate_views.cc index f379e561..f114d727 100644 --- a/ui/views/animation/animation_delegate_views.cc +++ b/ui/views/animation/animation_delegate_views.cc
@@ -14,7 +14,7 @@ AnimationDelegateViews::AnimationDelegateViews(View* view) : view_(view) { if (view) - scoped_observer_.Add(view); + scoped_observation_.Observe(view); } AnimationDelegateViews::~AnimationDelegateViews() { @@ -46,7 +46,8 @@ } void AnimationDelegateViews::OnViewIsDeleting(View* observed_view) { - scoped_observer_.Remove(view_); + DCHECK(scoped_observation_.IsObservingSource(view_)); + scoped_observation_.Reset(); view_ = nullptr; UpdateAnimationRunner(); }
diff --git a/ui/views/animation/animation_delegate_views.h b/ui/views/animation/animation_delegate_views.h index c8aed39..7edc84d 100644 --- a/ui/views/animation/animation_delegate_views.h +++ b/ui/views/animation/animation_delegate_views.h
@@ -7,7 +7,7 @@ #include <memory> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/gfx/animation/animation_container_observer.h" #include "ui/gfx/animation/animation_delegate.h" #include "ui/views/view.h" @@ -61,7 +61,7 @@ // The animation runner that |container_| uses. CompositorAnimationRunner* compositor_animation_runner_ = nullptr; - ScopedObserver<View, ViewObserver> scoped_observer_{this}; + base::ScopedObservation<View, ViewObserver> scoped_observation_{this}; }; } // namespace views
diff --git a/ui/views/animation/compositor_animation_runner.h b/ui/views/animation/compositor_animation_runner.h index 2f26f8d2..b2e543e 100644 --- a/ui/views/animation/compositor_animation_runner.h +++ b/ui/views/animation/compositor_animation_runner.h
@@ -7,7 +7,6 @@ #include <memory> -#include "base/scoped_observer.h" #include "base/time/time.h" #include "ui/compositor/compositor.h" #include "ui/compositor/compositor_animation_observer.h"
diff --git a/ui/views/animation/ink_drop_event_handler.cc b/ui/views/animation/ink_drop_event_handler.cc index 1247ade..d0771c2 100644 --- a/ui/views/animation/ink_drop_event_handler.cc +++ b/ui/views/animation/ink_drop_event_handler.cc
@@ -18,7 +18,7 @@ std::make_unique<ui::ScopedTargetHandler>(host_view, this)), host_view_(host_view), delegate_(delegate) { - observer_.Add(host_view_); + observation_.Observe(host_view_); } InkDropEventHandler::~InkDropEventHandler() = default;
diff --git a/ui/views/animation/ink_drop_event_handler.h b/ui/views/animation/ink_drop_event_handler.h index 93f1996..ebc95790 100644 --- a/ui/views/animation/ink_drop_event_handler.h +++ b/ui/views/animation/ink_drop_event_handler.h
@@ -7,7 +7,7 @@ #include <memory> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/strings/string_piece.h" #include "ui/events/event_handler.h" #include "ui/views/view.h" @@ -75,7 +75,7 @@ // The last user Event to trigger an InkDrop-ripple animation. std::unique_ptr<ui::LocatedEvent> last_ripple_triggering_event_; - ScopedObserver<View, ViewObserver> observer_{this}; + base::ScopedObservation<View, ViewObserver> observation_{this}; DISALLOW_COPY_AND_ASSIGN(InkDropEventHandler); };
diff --git a/ui/views/background.cc b/ui/views/background.cc index 7ab9015..3cf74b72 100644 --- a/ui/views/background.cc +++ b/ui/views/background.cc
@@ -8,7 +8,7 @@ #include "base/check.h" #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "build/build_config.h" #include "cc/paint/paint_flags.h" #include "ui/gfx/canvas.h" @@ -67,15 +67,18 @@ public: explicit ThemedVectorIconBackground(View* view, const ui::ThemedVectorIcon& icon) - : icon_(icon), observer_(this) { + : icon_(icon) { DCHECK(!icon_.empty()); - observer_.Add(view); + observation_.Observe(view); OnViewThemeChanged(view); } // ViewObserver: void OnViewThemeChanged(View* view) override { view->SchedulePaint(); } - void OnViewIsDeleting(View* view) override { observer_.Remove(view); } + void OnViewIsDeleting(View* view) override { + DCHECK(observation_.IsObservingSource(view)); + observation_.Reset(); + } void Paint(gfx::Canvas* canvas, View* view) const override { canvas->DrawImageInt(icon_.GetImageSkia(view->GetNativeTheme()), 0, 0); @@ -83,7 +86,7 @@ private: const ui::ThemedVectorIcon icon_; - ScopedObserver<View, ViewObserver> observer_; + base::ScopedObservation<View, ViewObserver> observation_{this}; DISALLOW_COPY_AND_ASSIGN(ThemedVectorIconBackground); }; @@ -94,9 +97,8 @@ public: explicit ThemedSolidBackground(View* view, ui::NativeTheme::ColorId color_id) : SolidBackground(gfx::kPlaceholderColor), - observer_(this), color_id_(color_id) { - observer_.Add(view); + observation_.Observe(view); OnViewThemeChanged(view); } ~ThemedSolidBackground() override = default; @@ -106,10 +108,13 @@ SetNativeControlColor(view->GetNativeTheme()->GetSystemColor(color_id_)); view->SchedulePaint(); } - void OnViewIsDeleting(View* view) override { observer_.Remove(view); } + void OnViewIsDeleting(View* view) override { + DCHECK(observation_.IsObservingSource(view)); + observation_.Reset(); + } private: - ScopedObserver<View, ViewObserver> observer_; + base::ScopedObservation<View, ViewObserver> observation_{this}; ui::NativeTheme::ColorId color_id_; DISALLOW_COPY_AND_ASSIGN(ThemedSolidBackground);
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc index 7c19157..6e0f3355 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -195,9 +195,9 @@ public: AnchorWidgetObserver(BubbleDialogDelegate* owner, Widget* widget) : owner_(owner) { - widget_observer_.Add(widget); + widget_observation_.Observe(widget); #if !defined(OS_APPLE) - window_observer_.Add(widget->GetNativeWindow()); + window_observation_.Observe(widget->GetNativeWindow()); #endif } ~AnchorWidgetObserver() override = default; @@ -205,9 +205,11 @@ // WidgetObserver: void OnWidgetDestroying(Widget* widget) override { #if !defined(OS_APPLE) - window_observer_.Remove(widget->GetNativeWindow()); + DCHECK(window_observation_.IsObservingSource(widget->GetNativeWindow())); + window_observation_.Reset(); #endif - widget_observer_.Remove(widget); + DCHECK(widget_observation_.IsObservingSource(widget)); + widget_observation_.Reset(); owner_->OnAnchorWidgetDestroying(); // |this| may be destroyed here! } @@ -238,9 +240,11 @@ private: BubbleDialogDelegate* owner_; - ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this}; + base::ScopedObservation<views::Widget, views::WidgetObserver> + widget_observation_{this}; #if !defined(OS_APPLE) - ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this}; + base::ScopedObservation<aura::Window, aura::WindowObserver> + window_observation_{this}; #endif }; @@ -250,7 +254,7 @@ public: BubbleWidgetObserver(BubbleDialogDelegate* owner, Widget* widget) : owner_(owner) { - observer_.Add(widget); + observation_.Observe(widget); } ~BubbleWidgetObserver() override = default; @@ -264,7 +268,8 @@ } void OnWidgetDestroyed(Widget* widget) override { - observer_.Remove(widget); + DCHECK(observation_.IsObservingSource(widget)); + observation_.Reset(); owner_->OnWidgetDestroyed(widget); } @@ -295,7 +300,8 @@ private: BubbleDialogDelegate* owner_; - ScopedObserver<views::Widget, views::WidgetObserver> observer_{this}; + base::ScopedObservation<views::Widget, views::WidgetObserver> observation_{ + this}; }; BubbleDialogDelegate::BubbleDialogDelegate() = default;
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.h b/ui/views/bubble/bubble_dialog_delegate_view.h index 2f2b186..d335aa4 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.h +++ b/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -9,7 +9,6 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/scoped_observer.h" #include "build/build_config.h" #include "ui/accessibility/ax_enums.mojom-forward.h" #include "ui/base/class_property.h"
diff --git a/ui/views/bubble/tooltip_icon.cc b/ui/views/bubble/tooltip_icon.cc index fa42d321..4a24284a 100644 --- a/ui/views/bubble/tooltip_icon.cc +++ b/ui/views/bubble/tooltip_icon.cc
@@ -98,7 +98,7 @@ bubble_->SetCanActivate(!mouse_inside_); bubble_->Show(); - observer_.Add(bubble_->GetWidget()); + observation_.Observe(bubble_->GetWidget()); if (mouse_inside_) { View* frame = bubble_->GetWidget()->non_client_view()->frame_view(); @@ -117,7 +117,8 @@ } void TooltipIcon::OnWidgetDestroyed(Widget* widget) { - observer_.Remove(widget); + DCHECK(observation_.IsObservingSource(widget)); + observation_.Reset(); SetDrawAsHovered(false); mouse_watcher_.reset();
diff --git a/ui/views/bubble/tooltip_icon.h b/ui/views/bubble/tooltip_icon.h index 80436bd8..7fd90f1 100644 --- a/ui/views/bubble/tooltip_icon.h +++ b/ui/views/bubble/tooltip_icon.h
@@ -8,7 +8,7 @@ #include <memory> #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/strings/string16.h" #include "base/timer/timer.h" #include "ui/views/bubble/bubble_border.h" @@ -102,7 +102,7 @@ // A watcher that keeps |bubble_| open if the user's mouse enters it. std::unique_ptr<MouseWatcher> mouse_watcher_; - ScopedObserver<Widget, WidgetObserver> observer_{this}; + base::ScopedObservation<Widget, WidgetObserver> observation_{this}; base::ObserverList<Observer, /*check_empty=*/true> observers_;
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc index f911fa3..8a1bd561 100644 --- a/ui/views/controls/combobox/combobox.cc +++ b/ui/views/controls/combobox/combobox.cc
@@ -309,14 +309,16 @@ void Combobox::SetModel(ui::ComboboxModel* model) { DCHECK(model) << "After construction, the model must not be null."; - if (model_) - observer_.Remove(model_); + if (model_) { + DCHECK(observation_.IsObservingSource(model_)); + observation_.Reset(); + } model_ = model; if (model_) { menu_model_ = std::make_unique<ComboboxMenuModel>(this, model_); - observer_.Add(model_); + observation_.Observe(model_); SetSelectedIndex(model_->GetDefaultIndex()); OnComboboxModelChanged(model_); }
diff --git a/ui/views/controls/combobox/combobox.h b/ui/views/controls/combobox/combobox.h index 812810c..fa78168 100644 --- a/ui/views/controls/combobox/combobox.h +++ b/ui/views/controls/combobox/combobox.h
@@ -9,7 +9,7 @@ #include <utility> #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/strings/string16.h" #include "base/time/time.h" #include "ui/base/models/combobox_model.h" @@ -224,7 +224,8 @@ // The focus ring for this Combobox. FocusRing* focus_ring_ = nullptr; - ScopedObserver<ui::ComboboxModel, ui::ComboboxModelObserver> observer_{this}; + base::ScopedObservation<ui::ComboboxModel, ui::ComboboxModelObserver> + observation_{this}; DISALLOW_COPY_AND_ASSIGN(Combobox); };
diff --git a/ui/views/controls/editable_combobox/editable_combobox.cc b/ui/views/controls/editable_combobox/editable_combobox.cc index b9203707..f535357 100644 --- a/ui/views/controls/editable_combobox/editable_combobox.cc +++ b/ui/views/controls/editable_combobox/editable_combobox.cc
@@ -136,7 +136,7 @@ filter_on_edit_(filter_on_edit), show_on_empty_(show_on_empty) { UpdateItemsShown(); - observer_.Add(combobox_model_); + observation_.Observe(combobox_model_); } ~EditableComboboxMenuModel() override = default; @@ -252,7 +252,8 @@ // When false, UpdateItemsShown doesn't do anything. bool update_items_shown_enabled_ = true; - ScopedObserver<ui::ComboboxModel, ui::ComboboxModelObserver> observer_{this}; + base::ScopedObservation<ui::ComboboxModel, ui::ComboboxModelObserver> + observation_{this}; DISALLOW_COPY_AND_ASSIGN(EditableComboboxMenuModel); }; @@ -322,7 +323,7 @@ show_on_empty_(show_on_empty), showing_password_text_(type != Type::kPassword) { SetModel(std::move(combobox_model)); - observer_.Add(textfield_); + observation_.Observe(textfield_); textfield_->set_controller(this); textfield_->SetFontList(GetFontList()); textfield_->SetTextInputType((type == Type::kPassword)
diff --git a/ui/views/controls/editable_combobox/editable_combobox.h b/ui/views/controls/editable_combobox/editable_combobox.h index a87863d..551433e 100644 --- a/ui/views/controls/editable_combobox/editable_combobox.h +++ b/ui/views/controls/editable_combobox/editable_combobox.h
@@ -10,7 +10,7 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/strings/string16.h" #include "build/build_config.h" #include "ui/base/ui_base_types.h" @@ -187,7 +187,7 @@ bool dropdown_blocked_for_animation_ = false; - ScopedObserver<View, ViewObserver> observer_{this}; + base::ScopedObservation<View, ViewObserver> observation_{this}; DISALLOW_COPY_AND_ASSIGN(EditableCombobox); };
diff --git a/ui/views/controls/focus_ring.cc b/ui/views/controls/focus_ring.cc index e347131..95d55d5 100644 --- a/ui/views/controls/focus_ring.cc +++ b/ui/views/controls/focus_ring.cc
@@ -113,13 +113,13 @@ if (details.is_add) { // Need to start observing the parent. - view_observer_.Add(details.parent); + view_observation_.Observe(details.parent); RefreshLayer(); - } else if (view_observer_.IsObserving(details.parent)) { + } else if (view_observation_.IsObservingSource(details.parent)) { // This view is being removed from its parent. It needs to remove itself // from its parent's observer list in the case where the FocusView is // removed from its parent but not deleted. - view_observer_.Remove(details.parent); + view_observation_.Reset(); } }
diff --git a/ui/views/controls/focus_ring.h b/ui/views/controls/focus_ring.h index c3e42b6a4..7882505 100644 --- a/ui/views/controls/focus_ring.h +++ b/ui/views/controls/focus_ring.h
@@ -7,7 +7,7 @@ #include <memory> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/native_theme/native_theme.h" #include "ui/views/controls/focusable_border.h" #include "ui/views/view.h" @@ -96,7 +96,7 @@ // The predicate used to determine whether the parent has focus. base::Optional<ViewPredicate> has_focus_predicate_; - ScopedObserver<View, ViewObserver> view_observer_{this}; + base::ScopedObservation<View, ViewObserver> view_observation_{this}; DISALLOW_COPY_AND_ASSIGN(FocusRing); };
diff --git a/ui/views/event_monitor_aura.cc b/ui/views/event_monitor_aura.cc index 69edc44..698f21e 100644 --- a/ui/views/event_monitor_aura.cc +++ b/ui/views/event_monitor_aura.cc
@@ -7,7 +7,7 @@ #include <memory> #include "base/check_op.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/events/event_observer.h" @@ -25,21 +25,23 @@ const std::set<ui::EventType>& types) : EventMonitorAura(event_observer, target_window, types), target_window_(target_window) { - window_observer_.Add(target_window); + window_observation_.Observe(target_window); } ~WindowMonitorAura() override = default; // aura::WindowObserver: void OnWindowDestroying(aura::Window* window) override { DCHECK_EQ(window, target_window_); - window_observer_.Remove(target_window_); + DCHECK(window_observation_.IsObservingSource(target_window_)); + window_observation_.Reset(); target_window_ = nullptr; TearDown(); } private: aura::Window* target_window_; - ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this}; + base::ScopedObservation<aura::Window, aura::WindowObserver> + window_observation_{this}; DISALLOW_COPY_AND_ASSIGN(WindowMonitorAura); };
diff --git a/ui/views/examples/examples_views_delegate_chromeos.cc b/ui/views/examples/examples_views_delegate_chromeos.cc index cc3365f..2a47b1d 100644 --- a/ui/views/examples/examples_views_delegate_chromeos.cc +++ b/ui/views/examples/examples_views_delegate_chromeos.cc
@@ -14,8 +14,7 @@ constexpr gfx::Size kDefaultSize(1024, 768); } // namespace -ExamplesViewsDelegateChromeOS::ExamplesViewsDelegateChromeOS() - : observer_(this) {} +ExamplesViewsDelegateChromeOS::ExamplesViewsDelegateChromeOS() = default; ExamplesViewsDelegateChromeOS::~ExamplesViewsDelegateChromeOS() = default; @@ -28,7 +27,7 @@ wm_helper_ = std::make_unique<wm::WMTestHelper>(kDefaultSize); wm_helper_->host()->Show(); - observer_.Add(wm_helper_->host()); + observation_.Observe(wm_helper_->host()); params->context = wm_helper_->host()->window(); } } @@ -37,7 +36,8 @@ aura::WindowTreeHost* host) { Widget* widget = GetExamplesWidget(); if (widget) { - observer_.Remove(host); + DCHECK(observation_.IsObservingSource(host)); + observation_.Reset(); widget->Close(); } }
diff --git a/ui/views/examples/examples_views_delegate_chromeos.h b/ui/views/examples/examples_views_delegate_chromeos.h index 1bba04f..3933cd5 100644 --- a/ui/views/examples/examples_views_delegate_chromeos.h +++ b/ui/views/examples/examples_views_delegate_chromeos.h
@@ -7,7 +7,7 @@ #include <memory> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/aura/window_tree_host.h" #include "ui/aura/window_tree_host_observer.h" #include "ui/views/test/desktop_test_views_delegate.h" @@ -33,7 +33,8 @@ // aura::WindowTreeHostObserver: void OnHostCloseRequested(aura::WindowTreeHost* host) override; - ScopedObserver<aura::WindowTreeHost, aura::WindowTreeHostObserver> observer_; + base::ScopedObservation<aura::WindowTreeHost, aura::WindowTreeHostObserver> + observation_{this}; std::unique_ptr<wm::WMTestHelper> wm_helper_; };
diff --git a/ui/views/layout/animating_layout_manager.cc b/ui/views/layout/animating_layout_manager.cc index 3e6a87fa..cc67d166 100644 --- a/ui/views/layout/animating_layout_manager.cc +++ b/ui/views/layout/animating_layout_manager.cc
@@ -146,8 +146,7 @@ } void OnViewIsDeleting(View* observed_view) override { - if (animation_delegate_->scoped_observer_.IsObserving(observed_view)) - animation_delegate_->scoped_observer_.Remove(observed_view); + animation_delegate_->scoped_observation_.Reset(); } private: @@ -165,7 +164,8 @@ AnimatingLayoutManager* const target_layout_manager_; std::unique_ptr<gfx::SlideAnimation> animation_; ViewWidgetObserver view_widget_observer_{this}; - ScopedObserver<View, ViewObserver> scoped_observer_{&view_widget_observer_}; + base::ScopedObservation<View, ViewObserver> scoped_observation_{ + &view_widget_observer_}; }; AnimatingLayoutManager::AnimationDelegate::AnimationDelegate( @@ -179,7 +179,7 @@ if (host_view->GetWidget()) MakeReadyForAnimation(); else - scoped_observer_.Add(host_view); + scoped_observation_.Observe(host_view); UpdateAnimationParameters(); } @@ -205,8 +205,7 @@ if (!ready_to_animate_) { target_layout_manager_->ResetLayout(); ready_to_animate_ = true; - if (scoped_observer_.IsObserving(target_layout_manager_->host_view())) - scoped_observer_.Remove(target_layout_manager_->host_view()); + scoped_observation_.Reset(); } }
diff --git a/ui/views/layout/animating_layout_manager_unittest.cc b/ui/views/layout/animating_layout_manager_unittest.cc index d50d50d1..02f66e60 100644 --- a/ui/views/layout/animating_layout_manager_unittest.cc +++ b/ui/views/layout/animating_layout_manager_unittest.cc
@@ -8,7 +8,7 @@ #include <utility> #include <vector> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/test/task_environment.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" @@ -108,7 +108,7 @@ ~AnimationEventLogger() override = default; explicit AnimationEventLogger(AnimatingLayoutManager* layout) { - scoped_observer_.Add(layout); + scoped_observation_.Observe(layout); } void OnLayoutIsAnimatingChanged(AnimatingLayoutManager* source, @@ -120,7 +120,8 @@ private: std::vector<bool> events_; - ScopedObserver<AnimatingLayoutManager, Observer> scoped_observer_{this}; + base::ScopedObservation<AnimatingLayoutManager, Observer> scoped_observation_{ + this}; }; } // anonymous namespace @@ -2879,7 +2880,7 @@ public: explicit AnimationWatcher(AnimatingLayoutManager* layout_manager) : layout_manager_(layout_manager) { - observer_.Add(layout_manager); + observation_.Observe(layout_manager); } void OnLayoutIsAnimatingChanged(AnimatingLayoutManager*, @@ -2901,8 +2902,9 @@ private: AnimatingLayoutManager* const layout_manager_; - ScopedObserver<AnimatingLayoutManager, AnimatingLayoutManager::Observer> - observer_{this}; + base::ScopedObservation<AnimatingLayoutManager, + AnimatingLayoutManager::Observer> + observation_{this}; std::unique_ptr<base::RunLoop> run_loop_; bool waiting_ = false; };
diff --git a/ui/views/test/ax_event_counter.cc b/ui/views/test/ax_event_counter.cc index b1c68ee3..592d9fd0 100644 --- a/ui/views/test/ax_event_counter.cc +++ b/ui/views/test/ax_event_counter.cc
@@ -7,9 +7,8 @@ namespace views { namespace test { -AXEventCounter::AXEventCounter(views::AXEventManager* event_manager) - : tree_observer_(this) { - tree_observer_.Add(event_manager); +AXEventCounter::AXEventCounter(views::AXEventManager* event_manager) { + tree_observation_.Observe(event_manager); } AXEventCounter::~AXEventCounter() = default;
diff --git a/ui/views/test/ax_event_counter.h b/ui/views/test/ax_event_counter.h index be647c1..5cab9fa 100644 --- a/ui/views/test/ax_event_counter.h +++ b/ui/views/test/ax_event_counter.h
@@ -7,7 +7,7 @@ #include "base/containers/flat_map.h" #include "base/run_loop.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/views/accessibility/ax_event_manager.h" #include "ui/views/accessibility/ax_event_observer.h" @@ -39,8 +39,8 @@ base::flat_map<ax::mojom::Event, int> event_counts_; ax::mojom::Event wait_for_event_type_ = ax::mojom::Event::kNone; base::RunLoop* run_loop_ = nullptr; - ScopedObserver<views::AXEventManager, views::AXEventObserver> tree_observer_{ - this}; + base::ScopedObservation<views::AXEventManager, views::AXEventObserver> + tree_observation_{this}; }; } // namespace test
diff --git a/ui/views/test/widget_test.cc b/ui/views/test/widget_test.cc index e6c48cf..1c42693 100644 --- a/ui/views/test/widget_test.cc +++ b/ui/views/test/widget_test.cc
@@ -261,7 +261,7 @@ void WidgetVisibleWaiter::Wait() { if (!widget_->IsVisible()) { - widget_observer_.Add(widget_); + widget_observation_.Observe(widget_); run_loop_.Run(); } } @@ -270,7 +270,8 @@ bool visible) { DCHECK_EQ(widget_, widget); if (visible) { - widget_observer_.Remove(widget); + DCHECK(widget_observation_.IsObservingSource(widget)); + widget_observation_.Reset(); run_loop_.Quit(); } } @@ -280,7 +281,8 @@ ADD_FAILURE() << "Widget destroying before it became visible!"; // Even though the test failed, be polite and remove the observer so we // don't crash with a UAF in the destructor. - widget_observer_.Remove(widget); + DCHECK(widget_observation_.IsObservingSource(widget)); + widget_observation_.Reset(); } } // namespace test
diff --git a/ui/views/test/widget_test.h b/ui/views/test/widget_test.h index 02565096..9743c69 100644 --- a/ui/views/test/widget_test.h +++ b/ui/views/test/widget_test.h
@@ -12,7 +12,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/run_loop.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/test/bind.h" #include "build/build_config.h" #include "ui/gfx/native_widget_types.h" @@ -307,7 +307,7 @@ Widget* const widget_; base::RunLoop run_loop_; - ScopedObserver<Widget, WidgetObserver> widget_observer_{this}; + base::ScopedObservation<Widget, WidgetObserver> widget_observation_{this}; }; } // namespace test
diff --git a/ui/views/view.cc b/ui/views/view.cc index b7a1edbc..ecf38ee 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -17,7 +17,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/notreached.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/trace_event.h" @@ -160,7 +160,7 @@ // views::ViewObserver: void OnViewBoundsChanged(View* observed_view) override; - ScopedObserver<View, ViewObserver> observed_view_{this}; + base::ScopedObservation<View, ViewObserver> observed_view_{this}; SkPath path_; ui::Layer layer_; @@ -171,7 +171,7 @@ layer_.set_delegate(this); layer_.SetFillsBoundsOpaquely(false); layer_.SetName("ViewMaskLayer"); - observed_view_.Add(observed_view); + observed_view_.Observe(observed_view); OnViewBoundsChanged(observed_view); }
diff --git a/ui/views/view_tracker.cc b/ui/views/view_tracker.cc index 7b54e2032..eaa66da 100644 --- a/ui/views/view_tracker.cc +++ b/ui/views/view_tracker.cc
@@ -16,10 +16,10 @@ if (view == view_) return; - observer_.RemoveAll(); + observation_.Reset(); view_ = view; if (view_) - observer_.Add(view_); + observation_.Observe(view_); } void ViewTracker::OnViewIsDeleting(View* observed_view) {
diff --git a/ui/views/view_tracker.h b/ui/views/view_tracker.h index fead2fa1..74886d9 100644 --- a/ui/views/view_tracker.h +++ b/ui/views/view_tracker.h
@@ -5,7 +5,7 @@ #ifndef UI_VIEWS_VIEW_TRACKER_H_ #define UI_VIEWS_VIEW_TRACKER_H_ -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/views/view.h" #include "ui/views/view_observer.h" #include "ui/views/views_export.h" @@ -28,7 +28,7 @@ private: View* view_ = nullptr; - ScopedObserver<View, ViewObserver> observer_{this}; + base::ScopedObservation<View, ViewObserver> observation_{this}; }; } // namespace views
diff --git a/ui/views/widget/unique_widget_ptr.cc b/ui/views/widget/unique_widget_ptr.cc index fe1d260..6e21997 100644 --- a/ui/views/widget/unique_widget_ptr.cc +++ b/ui/views/widget/unique_widget_ptr.cc
@@ -6,7 +6,7 @@ #include <utility> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_observer.h" @@ -32,7 +32,7 @@ // deliberately implicit. UniqueWidgetPtrImpl(std::unique_ptr<Widget> widget) // NOLINT : widget_closer_(widget.release()) { - widget_observer_.Add(widget_closer_.get()); + widget_observation_.Observe(widget_closer_.get()); } UniqueWidgetPtrImpl(const UniqueWidgetPtrImpl&) = delete; @@ -46,19 +46,19 @@ void Reset() { if (!widget_closer_) return; - widget_observer_.RemoveAll(); + widget_observation_.Reset(); widget_closer_.reset(); } // WidgetObserver overrides. void OnWidgetDestroying(Widget* widget) override { DCHECK_EQ(widget, widget_closer_.get()); - widget_observer_.RemoveAll(); + widget_observation_.Reset(); widget_closer_.release(); } private: - ScopedObserver<Widget, WidgetObserver> widget_observer_{this}; + base::ScopedObservation<Widget, WidgetObserver> widget_observation_{this}; WidgetAutoClosePtr widget_closer_; };
diff --git a/ui/views/widget/unique_widget_ptr_unittest.cc b/ui/views/widget/unique_widget_ptr_unittest.cc index df8804ab..3e333ba3 100644 --- a/ui/views/widget/unique_widget_ptr_unittest.cc +++ b/ui/views/widget/unique_widget_ptr_unittest.cc
@@ -5,8 +5,9 @@ #include "ui/views/widget/unique_widget_ptr.h" #include <memory> +#include <utility> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/views/test/views_test_base.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" @@ -29,7 +30,7 @@ std::unique_ptr<Widget> AllocateTestWidget() override { auto widget = ViewsTestBase::AllocateTestWidget(); widget->Init(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS)); - widget_observer_.Add(widget.get()); + widget_observation_.Observe(widget.get()); return widget; } @@ -46,13 +47,14 @@ void OnWidgetDestroying(Widget* widget) override { ASSERT_NE(widget_, nullptr); ASSERT_EQ(widget_, widget); - widget_observer_.Remove(widget_); + ASSERT_TRUE(widget_observation_.IsObservingSource(widget_)); + widget_observation_.Reset(); widget_ = nullptr; } private: Widget* widget_ = nullptr; - ScopedObserver<Widget, WidgetObserver> widget_observer_{this}; + base::ScopedObservation<Widget, WidgetObserver> widget_observation_{this}; }; // Make sure explicitly resetting the |unique_widget_ptr| variable properly
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index 52c1d1e..e8d1afc 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc
@@ -396,7 +396,7 @@ SetInitialBoundsForFramelessWindow(bounds); } - observer_manager_.Add(GetNativeTheme()); + observation_.Observe(GetNativeTheme()); native_widget_initialized_ = true; native_widget_->OnWidgetInitDone(); @@ -1502,16 +1502,16 @@ void Widget::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) { TRACE_EVENT0("ui", "Widget::OnNativeThemeUpdated"); - DCHECK(observer_manager_.IsObserving(observed_theme)); + DCHECK(observation_.IsObservingSource(observed_theme)); #if defined(OS_APPLE) || defined(OS_WIN) ui::NativeTheme* current_native_theme = observed_theme; #else ui::NativeTheme* current_native_theme = GetNativeTheme(); #endif - if (!observer_manager_.IsObserving(current_native_theme)) { - observer_manager_.RemoveAll(); - observer_manager_.Add(current_native_theme); + if (!observation_.IsObservingSource(current_native_theme)) { + observation_.Reset(); + observation_.Observe(current_native_theme); } PropagateNativeThemeChanged();
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index 819ea9a..d85ff8d5 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h
@@ -14,7 +14,7 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/optional.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "build/build_config.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h" #include "ui/base/ui_base_types.h" @@ -1174,8 +1174,8 @@ // Block the widget from closing. bool block_close_ = false; - ScopedObserver<ui::NativeTheme, ui::NativeThemeObserver> observer_manager_{ - this}; + base::ScopedObservation<ui::NativeTheme, ui::NativeThemeObserver> + observation_{this}; base::WeakPtrFactory<Widget> weak_ptr_factory_{this};
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc index c32b7760..113aa30 100644 --- a/ui/views/widget/widget_unittest.cc +++ b/ui/views/widget/widget_unittest.cc
@@ -1493,7 +1493,7 @@ public: explicit DesktopAuraTestValidPaintWidget(Widget::InitParams init_params) : Widget(std::move(init_params)) { - observer_.Add(this); + observation_.Observe(this); } ~DesktopAuraTestValidPaintWidget() override = default; @@ -1536,7 +1536,7 @@ bool expect_paint_ = true; bool received_paint_while_hidden_ = false; base::OnceClosure quit_closure_; - ScopedObserver<Widget, WidgetObserver> observer_{this}; + base::ScopedObservation<Widget, WidgetObserver> observation_{this}; DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget); };
diff --git a/ui/views/widget/widget_utils.cc b/ui/views/widget/widget_utils.cc index 81c67ad1..0675d724 100644 --- a/ui/views/widget/widget_utils.cc +++ b/ui/views/widget/widget_utils.cc
@@ -21,16 +21,16 @@ void WidgetOpenTimer::OnWidgetDestroying(Widget* widget) { DCHECK(open_timer_.has_value()); - DCHECK(observed_widget_.IsObserving(widget)); + DCHECK(observed_widget_.IsObservingSource(widget)); callback_.Run(open_timer_->Elapsed()); open_timer_.reset(); - observed_widget_.Remove(widget); + observed_widget_.Reset(); } void WidgetOpenTimer::Reset(Widget* widget) { DCHECK(!open_timer_.has_value()); - DCHECK(!observed_widget_.IsObserving(widget)); - observed_widget_.Add(widget); + DCHECK(!observed_widget_.IsObservingSource(widget)); + observed_widget_.Observe(widget); open_timer_ = base::ElapsedTimer(); }
diff --git a/ui/views/widget/widget_utils.h b/ui/views/widget/widget_utils.h index cb092fe..ee84051b 100644 --- a/ui/views/widget/widget_utils.h +++ b/ui/views/widget/widget_utils.h
@@ -6,7 +6,7 @@ #define UI_VIEWS_WIDGET_WIDGET_UTILS_H_ #include "base/callback.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" #include "ui/gfx/native_widget_types.h" @@ -39,7 +39,7 @@ // Time the bubble has been open. Used for UMA metrics collection. base::Optional<base::ElapsedTimer> open_timer_; - ScopedObserver<Widget, WidgetObserver> observed_widget_{this}; + base::ScopedObservation<Widget, WidgetObserver> observed_widget_{this}; }; // Returns the root window for |widget|. On non-Aura, this is equivalent to
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index 4c96541..c347d16 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc
@@ -456,7 +456,7 @@ hwnd(), ui::WindowEventTarget::kWin32InputEventTarget, static_cast<ui::WindowEventTarget*>(this)); DCHECK(delegate_->GetHWNDMessageDelegateInputMethod()); - observer_.Add(delegate_->GetHWNDMessageDelegateInputMethod()); + observation_.Observe(delegate_->GetHWNDMessageDelegateInputMethod()); // The usual way for UI Automation to obtain a fragment root is through // WM_GETOBJECT. However, if there's a relation such as "Controller For"
diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h index 3d498de..042392a 100644 --- a/ui/views/win/hwnd_message_handler.h +++ b/ui/views/win/hwnd_message_handler.h
@@ -18,7 +18,7 @@ #include "base/lazy_instance.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/strings/string16.h" #include "base/win/scoped_gdi_object.h" #include "base/win/win_util.h" @@ -819,7 +819,8 @@ // Populated if the cursor position is being mocked for testing purposes. base::Optional<gfx::Point> mock_cursor_position_; - ScopedObserver<ui::InputMethod, ui::InputMethodObserver> observer_{this}; + base::ScopedObservation<ui::InputMethod, ui::InputMethodObserver> + observation_{this}; // The WeakPtrFactories below (one inside the // CR_MSG_MAP_CLASS_DECLARATIONS macro and autohide_factory_) must
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestFactory.java b/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestFactory.java index 6210114..c78d931 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestFactory.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestFactory.java
@@ -25,6 +25,7 @@ import org.chromium.mojo.system.MojoResult; import org.chromium.payments.mojom.PaymentRequest; import org.chromium.services.service_manager.InterfaceFactory; +import org.chromium.url.GURL; import org.chromium.weblayer_private.ProfileImpl; import org.chromium.weblayer_private.TabImpl; @@ -63,7 +64,7 @@ PaymentRequestServiceUtil.getLiveWebContents(mRenderFrameHost); if (webContents == null || webContents.isDestroyed()) return null; - String url = webContents.getLastCommittedUrl(); + GURL url = webContents.getLastCommittedUrl(); if (url == null || !OriginSecurityChecker.isSchemeCryptographic(url)) { return null; }