diff --git a/AUTHORS b/AUTHORS index 31ddb044..9778c49 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -964,6 +964,7 @@ Sergey Shekyan <shekyan@gmail.com> Sergey Talantov <sergey.talantov@gmail.com> Sergio Carlos Morales Angeles <carloschilazo@gmail.com> +Sergio Garcia Murillo <sergio.garcia.murillo@gmail.com> Sergiy Belozorov <rryk.ua@gmail.com> Seshadri Mahalingam <seshadri.mahalingam@gmail.com> Seungkyu Lee <zx6658@gmail.com>
diff --git a/DEPS b/DEPS index ab86b11..51640850 100644 --- a/DEPS +++ b/DEPS
@@ -213,7 +213,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '55e37b474d17543e9a8b6bcba71a1c53b2852da8', + 'v8_revision': '9b373ece78ec52eeee18e248c4d76696ce6e335a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -221,7 +221,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': 'ab3b50bcdeef82814e45cc263b6ccb0e6179dbdf', + 'angle_revision': 'adc9033be9174ca30e65ddd3f8986ddad60de60f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -280,7 +280,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': '7318bc06728f464275b8605e5c0da3f45b56710c', + 'catapult_revision': '1ae270e66814fe4d968ec699f21b75205e2d7a83', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -288,7 +288,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': 'c01495c05ce3b1117b39ab4da19bf226ad7dd6b5', + 'devtools_frontend_revision': '6d08302be136ec5a68f6c7731644ad2c33e511e6', # 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. @@ -328,7 +328,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'a7f1c50f498e8d0655061e1530984449b8eba5e1', + 'dawn_revision': 'c63ac30826671e49173d18afdb9ae4b31bdaa6be', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -384,7 +384,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. - 'libjxl_revision': 'e5ce94456581d43f8a52c8100c726a0d079f65e7', + 'libjxl_revision': '9a8f5195e4d1c45112fd65f184ebe115f4163ba2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -730,7 +730,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'F-KyxlnPsilCF8hZJ4eXLycPHgTbV09Ch5FXUOHjzWMC', + 'version': 'RjeRyfAqXQf6VfPsfovn5_088ot2hkVyL1FaGWMsxI0C', }, ], 'condition': 'checkout_android', @@ -966,7 +966,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6b022d1efb1559ab795a1c91014a2a6fb7efba88', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3da91715d3b7447cc012b3e38901b9e9a54039eb', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1416,7 +1416,7 @@ 'packages': [ { 'package': 'fuchsia/third_party/aemu/linux-amd64', - 'version': 'Q9wrtYCFy4whHc75FrdwzygrqI5DSmX_tuj8UJUcrckC' + 'version': '42zBK32YxEB18xY1NCrwmj25vLkVlpXgaCil3aOhi6EC' }, ], 'condition': 'host_os == "linux" and checkout_fuchsia', @@ -1552,7 +1552,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '239db71432f4e4fe1f6192a7d54717701ef84f66', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'da3dc149b20576a9bae09b0d7a4ecfe819829c1f', + Var('webrtc_git') + '/src.git' + '@' + 'c51ce06208e516ce80539a100a5d1f41ff360c75', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1613,7 +1613,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@4b648bf36750515bb4f2b451924d5535b8ab1e81', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@48aeba5a7e1ef4b213c51d909971831d3278d23a', 'condition': 'checkout_src_internal', }, @@ -1621,7 +1621,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/eche_app/app', - 'version': 'yY4G9__wVxlswvn7cNuQGTFi4WP3FitAGp1I_1AgGagC', + 'version': '6mLyz6teriSC8d5wsJf-A5ZsxuzknycldIZl8mGcJBUC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 76c87f5..159d798 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -327,30 +327,6 @@ ), ) -# Directories that contain deprecated Bind() or Callback types. -# Find sub-directories from a given directory by running: -# for i in `find . -maxdepth 1 -type d|sort`; do -# echo "-- $i" -# (cd $i; git grep -nP \ -# 'base::(Bind\(|(Cancelable)?(Callback<|Closure))'|wc -l) -# done -# -# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list -# when they have been converted to modern callback types (OnceCallback, -# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit -# checks for them and prevent regressions. -_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join(( - '^base/callback.h', # Intentional. - '^base/cancelable_callback.h', # Intentional. - "^docs/callback\\.md", # Intentional - "^docs/process/lsc/large_scale_changes\\.md", # Intentional - '^extensions/browser/api/webcam_private', - '^third_party/blink/PRESUBMIT_test.py', # Intentional. - '^third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py' # Intentional pylint: disable=line-too-long - '^tools/clang/base_bind_rewriters/', # Intentional. - '^tools/gdb/gdb_chrome.py', # Intentional. -)) - # Format: Sequence of tuples containing: # * String pattern or, if starting with a slash, a regular expression. # * Sequence of strings to show when the pattern matches. @@ -763,51 +739,6 @@ (), ), ( - r'/\bbase::Bind\(', - ( - 'Please use base::Bind{Once,Repeating} instead', - 'of base::Bind. (crbug.com/714018)', - ), - False, - (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,), - ), - ( - r'/\bbase::Callback[<:]', - ( - 'Please use base::{Once,Repeating}Callback instead', - 'of base::Callback. (crbug.com/714018)', - ), - False, - (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,), - ), - ( - r'/\bbase::Closure\b', - ( - 'Please use base::{Once,Repeating}Closure instead', - 'of base::Closure. (crbug.com/714018)', - ), - False, - (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,), - ), - ( - r'/\bbase::CancelableCallback[<:]', - ( - 'Please use base::Cancelable{Once,Repeating}Callback instead', - 'of base::CancelableCallback. (crbug.com/714018)', - ), - False, - (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,), - ), - ( - r'/\bbase::CancelableClosure\b', - ( - 'Please use base::Cancelable{Once,Repeating}Closure instead', - 'of base::CancelableClosure. (crbug.com/714018)', - ), - False, - (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,), - ), - ( r'/\bRunMessageLoop\b', ( 'RunMessageLoop is deprecated, use RunLoop instead.',
diff --git a/android_webview/OWNERS b/android_webview/OWNERS index 324db12..6956a3e 100644 --- a/android_webview/OWNERS +++ b/android_webview/OWNERS
@@ -3,6 +3,7 @@ michaelbai@chromium.org ntfschr@chromium.org torne@chromium.org +nator@chromium.org # Documentation changes: per-file *.md=file://android_webview/docs/OWNERS
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc index 717993e..54ad96e8 100644 --- a/android_webview/browser/aw_contents.cc +++ b/android_webview/browser/aw_contents.cc
@@ -63,7 +63,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "components/autofill/android/provider/autofill_provider_android.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" -#include "components/autofill/core/browser/android_autofill_manager.h" +#include "components/autofill/core/browser/browser_autofill_manager.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_features.h" #include "components/navigation_interception/intercept_navigation_delegate.h" @@ -327,8 +327,7 @@ is_download_manager_disabled_for_testing()) ? autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER : autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER, - base::BindRepeating(&autofill::AndroidAutofillManager::Create, - autofill_provider_.get())); + autofill_provider_.get()); } void AwContents::SetAwAutofillClient(const JavaRef<jobject>& client) {
diff --git a/android_webview/docs/test-instructions.md b/android_webview/docs/test-instructions.md index f6b06c2..d2d595e 100644 --- a/android_webview/docs/test-instructions.md +++ b/android_webview/docs/test-instructions.md
@@ -87,19 +87,29 @@ ### Layout tests and page cycler tests -WebView's layout tests and page cycler tests exercise the WebView installed on -the system, instrumenting the WebView shell (`system_webview_shell_apk`, -`org.chromium.webview_shell`). These test cases are defined in +WebView's layout tests and page cycler tests exercise the **WebView installed on +the system** and instrument the [system WebView shell app](webview-shell.md) +(`system_webview_shell_apk`). These test cases are defined in `//android_webview/tools/system_webview_shell/`. +*** note +**Important:** because these tests run against the WebView installed on the +system, both these test targets automatically compile and install +`system_webview_apk` and switch the WebView provider. This means you need to +configure this target to be compatible with your system by following the +[full build instructions](build-instructions.md). + +**Note:** we do not currently support running these tests on the emulator due to +signing key mismatches with the preinstalled WebView shell +(https://crbug.com/1205665 tracks supporting this). +*** + ```sh -# Build +# Build (this also compiles system_webview_shell_apk and system_webview_apk) $ autoninja -C out/Default system_webview_shell_layout_test_apk -# Install the desired WebView APK -... - -# Run layout tests (installs WebView shell): +# Run layout tests (installs the test APK, WebView shell, and +# system_webview_apk, and also switches your WebView provider) $ out/Default/bin/run_system_webview_shell_layout_test_apk # Print both Java and C++ log messages to the console (optional):
diff --git a/ash/capture_mode/capture_mode_controller.cc b/ash/capture_mode/capture_mode_controller.cc index 67bb0b49..fa58ffe 100644 --- a/ash/capture_mode/capture_mode_controller.cc +++ b/ash/capture_mode/capture_mode_controller.cc
@@ -12,7 +12,6 @@ #include "ash/capture_mode/capture_mode_util.h" #include "ash/capture_mode/video_recording_watcher.h" #include "ash/display/window_tree_host_manager.h" -#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/capture_mode_delegate.h" #include "ash/public/cpp/holding_space/holding_space_client.h" #include "ash/public/cpp/holding_space/holding_space_controller.h" @@ -929,11 +928,9 @@ CopyImageToClipboard(image); ShowPreviewNotification(path, image, CaptureModeType::kImage); - if (features::IsTemporaryHoldingSpaceEnabled()) { - HoldingSpaceClient* client = HoldingSpaceController::Get()->client(); - if (client) // May be `nullptr` in tests. - client->AddScreenshot(path); - } + HoldingSpaceClient* client = HoldingSpaceController::Get()->client(); + if (client) // May be `nullptr` in tests. + client->AddScreenshot(path); } void CaptureModeController::OnVideoFileStatus(bool success) { @@ -960,11 +957,9 @@ RecordCaptureModeRecordTime( (base::TimeTicks::Now() - recording_start_time_).InSeconds()); - if (features::IsTemporaryHoldingSpaceEnabled()) { - HoldingSpaceClient* client = HoldingSpaceController::Get()->client(); - if (client) // May be `nullptr` in tests. - client->AddScreenRecording(current_video_file_path_); - } + HoldingSpaceClient* client = HoldingSpaceController::Get()->client(); + if (client) // May be `nullptr` in tests. + client->AddScreenRecording(current_video_file_path_); } if (!on_file_saved_callback_.is_null())
diff --git a/ash/login/ui/OWNERS b/ash/login/ui/OWNERS index 5634885..2d6ea2a 100644 --- a/ash/login/ui/OWNERS +++ b/ash/login/ui/OWNERS
@@ -3,6 +3,8 @@ per-file lock_screen.*=set noparent per-file lock_screen.*=file://ash/login/LOGIN_LOCK_OWNERS +per-file lock_screen.*=tellier@google.com per-file lock_contents_view.*=set noparent per-file lock_contents_view.*=file://ash/login/LOGIN_LOCK_OWNERS +per-file lock_contents_view.*=tellier@google.com
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc index 7046d443..a2ff930b 100644 --- a/ash/public/cpp/ash_features.cc +++ b/ash/public/cpp/ash_features.cc
@@ -126,11 +126,8 @@ const base::Feature kNotificationsInContextMenu{ "NotificationsInContextMenu", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kTemporaryHoldingSpace{"TemporaryHoldingSpace", - base::FEATURE_ENABLED_BY_DEFAULT}; - -const base::Feature kTemporaryHoldingSpaceArcIntegration{ - "TemporaryHoldingSpaceArcIntegration", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kHoldingSpaceArcIntegration{ + "HoldingSpaceArcIntegration", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kDragUnpinnedAppToPin{"DragUnpinnedAppToPin", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -298,13 +295,8 @@ return base::FeatureList::IsEnabled(kNotificationsInContextMenu); } -bool IsTemporaryHoldingSpaceEnabled() { - return base::FeatureList::IsEnabled(kTemporaryHoldingSpace); -} - -bool IsTemporaryHoldingSpaceArcIntegrationEnabled() { - return IsTemporaryHoldingSpaceEnabled() && - base::FeatureList::IsEnabled(kTemporaryHoldingSpaceArcIntegration); +bool IsHoldingSpaceArcIntegrationEnabled() { + return base::FeatureList::IsEnabled(kHoldingSpaceArcIntegration); } bool IsDragUnpinnedAppToPinEnabled() {
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h index 2d54ef5..401b669 100644 --- a/ash/public/cpp/ash_features.h +++ b/ash/public/cpp/ash_features.h
@@ -172,15 +172,10 @@ // Enables notifications to be shown within context menus. ASH_PUBLIC_EXPORT extern const base::Feature kNotificationsInContextMenu; -// Enables the productivity feature that aims to reduce context switching by -// enabling users to collect content and transfer or access it later. -ASH_PUBLIC_EXPORT extern const base::Feature kTemporaryHoldingSpace; - // Enables ARC integration with the productivity feature that aims to reduce // context switching by enabling users to collect content and transfer or access -// it later. Note that this flag has no effect w/o `kTemporaryHoldingSpace`. -ASH_PUBLIC_EXPORT extern const base::Feature - kTemporaryHoldingSpaceArcIntegration; +// it later. +ASH_PUBLIC_EXPORT extern const base::Feature kHoldingSpaceArcIntegration; // Enables dragging an unpinned open app to pinned app side to pin. ASH_PUBLIC_EXPORT extern const base::Feature kDragUnpinnedAppToPin; @@ -261,9 +256,7 @@ ASH_PUBLIC_EXPORT bool IsNotificationsInContextMenuEnabled(); -ASH_PUBLIC_EXPORT bool IsTemporaryHoldingSpaceEnabled(); - -ASH_PUBLIC_EXPORT bool IsTemporaryHoldingSpaceArcIntegrationEnabled(); +ASH_PUBLIC_EXPORT bool IsHoldingSpaceArcIntegrationEnabled(); ASH_PUBLIC_EXPORT bool IsDragUnpinnedAppToPinEnabled();
diff --git a/ash/shell.cc b/ash/shell.cc index 0390850..56e6206 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -1054,8 +1054,7 @@ } // `HoldingSpaceController` must be instantiated before the shelf. - if (features::IsTemporaryHoldingSpaceEnabled()) - holding_space_controller_ = std::make_unique<HoldingSpaceController>(); + holding_space_controller_ = std::make_unique<HoldingSpaceController>(); shelf_config_ = std::make_unique<ShelfConfig>(); shelf_controller_ = std::make_unique<ShelfController>();
diff --git a/ash/system/holding_space/holding_space_tray_unittest.cc b/ash/system/holding_space/holding_space_tray_unittest.cc index 62329979..ea23dbc 100644 --- a/ash/system/holding_space/holding_space_tray_unittest.cc +++ b/ash/system/holding_space/holding_space_tray_unittest.cc
@@ -8,7 +8,6 @@ #include <deque> #include <vector> -#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/holding_space/holding_space_client.h" #include "ash/public/cpp/holding_space/holding_space_constants.h" #include "ash/public/cpp/holding_space/holding_space_controller.h" @@ -35,7 +34,6 @@ #include "base/strings/strcat.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_feature_list.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/compositor/layer.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" @@ -272,9 +270,7 @@ class HoldingSpaceTrayTest : public AshTestBase { public: - HoldingSpaceTrayTest() { - scoped_feature_list_.InitAndEnableFeature(features::kTemporaryHoldingSpace); - } + HoldingSpaceTrayTest() = default; // AshTestBase: void SetUp() override { @@ -413,7 +409,6 @@ std::unique_ptr<HoldingSpaceTestApi> test_api_; testing::NiceMock<MockHoldingSpaceClient> holding_space_client_; HoldingSpaceModel holding_space_model_; - base::test::ScopedFeatureList scoped_feature_list_; }; // Tests -----------------------------------------------------------------------
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc index 21508dc..ca5b54b 100644 --- a/ash/system/status_area_widget.cc +++ b/ash/system/status_area_widget.cc
@@ -102,10 +102,8 @@ std::make_unique<StatusAreaOverflowButtonTray>(shelf_); AddTrayButton(overflow_button_tray_.get()); - if (features::IsTemporaryHoldingSpaceEnabled()) { - holding_space_tray_ = std::make_unique<HoldingSpaceTray>(shelf_); - AddTrayButton(holding_space_tray_.get()); - } + holding_space_tray_ = std::make_unique<HoldingSpaceTray>(shelf_); + AddTrayButton(holding_space_tray_.get()); logout_button_tray_ = std::make_unique<LogoutButtonTray>(shelf_); AddTrayButton(logout_button_tray_.get());
diff --git a/base/allocator/partition_allocator/partition_alloc_perftest.cc b/base/allocator/partition_allocator/partition_alloc_perftest.cc index 2c0bb0ab..0e51fb57 100644 --- a/base/allocator/partition_allocator/partition_alloc_perftest.cc +++ b/base/allocator/partition_allocator/partition_alloc_perftest.cc
@@ -282,6 +282,20 @@ return timer.LapsPerSecond() * kMultiBucketRounds; } +float DirectMapped(Allocator* allocator) { + constexpr size_t kSize = 2 * 1000 * 1000; + + LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval); + do { + void* cur = allocator->Alloc(kSize); + CHECK_NE(cur, nullptr); + allocator->Free(cur); + timer.NextLap(); + } while (!timer.HasTimeLimitExpired()); + + return timer.LapsPerSecond(); +} + std::unique_ptr<Allocator> CreateAllocator(AllocatorType type) { switch (type) { case AllocatorType::kSystem: @@ -305,9 +319,16 @@ void RunTest(int thread_count, AllocatorType alloc_type, float (*test_fn)(Allocator*), + float (*noisy_neighbor_fn)(Allocator*), const char* story_base_name) { auto alloc = CreateAllocator(alloc_type); + std::unique_ptr<TestLoopThread> noisy_neighbor_thread = nullptr; + if (noisy_neighbor_fn) { + noisy_neighbor_thread = std::make_unique<TestLoopThread>( + BindOnce(noisy_neighbor_fn, Unretained(alloc.get()))); + } + std::vector<std::unique_ptr<TestLoopThread>> threads; for (int i = 0; i < thread_count; ++i) { threads.push_back(std::make_unique<TestLoopThread>( @@ -322,6 +343,9 @@ total_laps_per_second += laps_per_second; } + if (noisy_neighbor_thread) + noisy_neighbor_thread->Run(); + char const* alloc_type_str; switch (alloc_type) { case AllocatorType::kSystem: @@ -368,7 +392,7 @@ #if !defined(MEMORY_CONSTRAINED) TEST_P(MemoryAllocationPerfTest, SingleBucket) { auto params = GetParam(); - RunTest(std::get<0>(params), std::get<1>(params), SingleBucket, + RunTest(std::get<0>(params), std::get<1>(params), SingleBucket, nullptr, "SingleBucket"); } #endif // defined(MEMORY_CONSTRAINED) @@ -376,22 +400,37 @@ TEST_P(MemoryAllocationPerfTest, SingleBucketWithFree) { auto params = GetParam(); RunTest(std::get<0>(params), std::get<1>(params), SingleBucketWithFree, - "SingleBucketWithFree"); + nullptr, "SingleBucketWithFree"); } #if !defined(MEMORY_CONSTRAINED) TEST_P(MemoryAllocationPerfTest, MultiBucket) { auto params = GetParam(); - RunTest(std::get<0>(params), std::get<1>(params), MultiBucket, "MultiBucket"); + RunTest(std::get<0>(params), std::get<1>(params), MultiBucket, nullptr, + "MultiBucket"); } #endif // defined(MEMORY_CONSTRAINED) TEST_P(MemoryAllocationPerfTest, MultiBucketWithFree) { auto params = GetParam(); RunTest(std::get<0>(params), std::get<1>(params), MultiBucketWithFree, - "MultiBucketWithFree"); + nullptr, "MultiBucketWithFree"); } +TEST_P(MemoryAllocationPerfTest, DirectMapped) { + auto params = GetParam(); + RunTest(std::get<0>(params), std::get<1>(params), DirectMapped, nullptr, + "DirectMapped"); +} + +#if !defined(MEMORY_CONSTRAINED) +TEST_P(MemoryAllocationPerfTest, MultiBucketWithNoisyNeighbor) { + auto params = GetParam(); + RunTest(std::get<0>(params), std::get<1>(params), MultiBucket, DirectMapped, + "MultiBucketWithNoisyNeighbor"); +} +#endif // !defined(MEMORY_CONSTRAINED) + } // namespace } // namespace base
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc index 7b259f6..d796c0e3 100644 --- a/base/allocator/partition_allocator/partition_bucket.cc +++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -27,10 +27,15 @@ namespace { template <bool thread_safe> -SlotSpanMetadata<thread_safe>* -PartitionDirectMap(PartitionRoot<thread_safe>* root, int flags, size_t raw_size) - EXCLUSIVE_LOCKS_REQUIRED(root->lock_) { - bool return_null = flags & PartitionAllocReturnNull; +SlotSpanMetadata<thread_safe>* PartitionDirectMap( + PartitionRoot<thread_safe>* root, + int flags, + size_t raw_size) { + // No static EXCLUSIVE_LOCKS_REQUIRED(), as the checker doesn't understand + // scoped unlocking. + root->lock_.AssertAcquired(); + + const bool return_null = flags & PartitionAllocReturnNull; if (UNLIKELY(raw_size > MaxDirectMapped())) { if (return_null) return nullptr; @@ -60,110 +65,134 @@ IMMEDIATE_CRASH(); // Not required, kept as documentation. } - size_t slot_size = PartitionRoot<thread_safe>::GetDirectMapSlotSize(raw_size); - size_t reserved_size = root->GetDirectMapReservedSize(raw_size); - size_t map_size = - reserved_size - - PartitionRoot<thread_safe>::GetDirectMapMetadataAndGuardPagesSize(); - PA_DCHECK(slot_size <= map_size); + PartitionDirectMapExtent<thread_safe>* map_extent = nullptr; + PartitionPage<thread_safe>* page = nullptr; - char* ptr = nullptr; - // Allocate from GigaCage, if enabled. In this case, use non-BRP pool, because - // BackupRefPtr isn't supported in direct maps. - bool with_giga_cage = features::IsPartitionAllocGigaCageEnabled(); - if (with_giga_cage) { - ptr = internal::AddressPoolManager::GetInstance()->Reserve( - GetNonBRPPool(), nullptr, reserved_size); - } else { - ptr = reinterpret_cast<char*>( - AllocPages(nullptr, reserved_size, kSuperPageAlignment, - PageInaccessible, PageTag::kPartitionAlloc)); - } - if (UNLIKELY(!ptr)) { - if (return_null) - return nullptr; - - // Crash handling is split on purpose in this function: - // - Crashing here likely means that Chrome is out of address space (on 32 - // bit platforms), or out of GigaCage space (on 64 bit ones). - // - Crashing below would likely mean out of commit charge. + { + // Getting memory for direct-mapped allocations doesn't interact with the + // rest of the allocator, but takes a long time, as it involves several + // system calls. With GigaCage, no mmap() (or equivalent) call is made on 64 + // bit systems, but page permissions are changed with mprotect(), which is a + // syscall. // - // See comment above regarding unlocking, - ScopedUnlockGuard<thread_safe> unlock{root->lock_}; - root->OutOfMemory(raw_size); - IMMEDIATE_CRASH(); // Not required, kept as documentation. - } + // These calls are almost always slow (at least a couple us per syscall on a + // desktop Linux machine), and they also have a very long latency tail, + // possibly from getting descheduled. As a consequence, we should not hold + // the lock when performing a syscall. This is not the only problematic + // location, but since this one doesn't interact with the rest of the + // allocator, we can safely drop and then re-acquire the lock. + // + // Note that this only affects allocations that are not served out of the + // thread cache, but as a simple example the buffer partition in blink is + // frequently used for large allocations (e.g. ArrayBuffer), and frequent, + // small ones (e.g. WTF::String), and does not have a thread cache. + ScopedUnlockGuard<thread_safe> scoped_unlock{root->lock_}; - root->total_size_of_direct_mapped_pages.fetch_add(reserved_size, - std::memory_order_relaxed); + const size_t slot_size = + PartitionRoot<thread_safe>::GetDirectMapSlotSize(raw_size); + const size_t reserved_size = + PartitionRoot<thread_safe>::GetDirectMapReservedSize(raw_size); + const size_t map_size = + reserved_size - + PartitionRoot<thread_safe>::GetDirectMapMetadataAndGuardPagesSize(); + PA_DCHECK(slot_size <= map_size); - char* slot = ptr + PartitionPageSize(); - RecommitSystemPages(ptr + SystemPageSize(), SystemPageSize(), PageReadWrite, - PageUpdatePermissions); - // It is typically possible to map a large range of inaccessible pages, and - // this is leveraged in multiple places, including the GigaCage. However, this - // doesn't mean that we can commit all this memory. For the vast majority of - // allocations, this just means that we crash in a slightly different places, - // but for callers ready to handle failures, we have to return nullptr. - // See crbug.com/1187404. - // - // Note that we didn't check above, because if we cannot even commit a single - // page, then this is likely hopeless anyway, and we will crash very soon. - bool ok = root->TryRecommitSystemPagesForData(slot, slot_size, - PageUpdatePermissions); - if (!ok) { + char* ptr = nullptr; + // Allocate from GigaCage, if enabled. In this case, use non-BRP pool, + // because BackupRefPtr isn't supported in direct maps. + const bool with_giga_cage = features::IsPartitionAllocGigaCageEnabled(); if (with_giga_cage) { - internal::AddressPoolManager::GetInstance()->UnreserveAndDecommit( - GetNonBRPPool(), ptr, reserved_size); + ptr = internal::AddressPoolManager::GetInstance()->Reserve( + GetNonBRPPool(), nullptr, reserved_size); } else { - FreePages(ptr, reserved_size); + ptr = reinterpret_cast<char*>( + AllocPages(nullptr, reserved_size, kSuperPageAlignment, + PageInaccessible, PageTag::kPartitionAlloc)); + } + if (UNLIKELY(!ptr)) { + if (return_null) + return nullptr; + + // Crash handling is split on purpose in this function: + // - Crashing here likely means that Chrome is out of address space (on 32 + // bit platforms), or out of GigaCage space (on 64 bit ones). + // - Crashing below would likely mean out of commit charge. + root->OutOfMemory(raw_size); + IMMEDIATE_CRASH(); // Not required, kept as documentation. } - if (return_null) - return nullptr; + root->total_size_of_direct_mapped_pages.fetch_add( + reserved_size, std::memory_order_relaxed); - // See comment above. - ScopedUnlockGuard<thread_safe> unlock{root->lock_}; - root->OutOfMemory(raw_size); - IMMEDIATE_CRASH(); // Not required, kept as documentation. + char* const slot = ptr + PartitionPageSize(); + RecommitSystemPages(ptr + SystemPageSize(), SystemPageSize(), PageReadWrite, + PageUpdatePermissions); + // It is typically possible to map a large range of inaccessible pages, and + // this is leveraged in multiple places, including the GigaCage. However, + // this doesn't mean that we can commit all this memory. For the vast + // majority of allocations, this just means that we crash in a slightly + // different place, but for callers ready to handle failures, we have to + // return nullptr. See crbug.com/1187404. + // + // Note that we didn't check above, because if we cannot even commit a + // single page, then this is likely hopeless anyway, and we will crash very + // soon. + const bool ok = root->TryRecommitSystemPagesForData(slot, slot_size, + PageUpdatePermissions); + if (!ok) { + if (!return_null) { + root->OutOfMemory(raw_size); + IMMEDIATE_CRASH(); // Not required, kept as documentation. + } + + if (with_giga_cage) { + internal::AddressPoolManager::GetInstance()->UnreserveAndDecommit( + GetNonBRPPool(), ptr, reserved_size); + } else { + FreePages(ptr, reserved_size); + } + return nullptr; + } + + auto* metadata = reinterpret_cast<PartitionDirectMapMetadata<thread_safe>*>( + PartitionSuperPageToMetadataArea(ptr)); + metadata->extent.root = root; + // The new structures are all located inside a fresh system page so they + // will all be zeroed out. These DCHECKs are for documentation and to assert + // our expectations of the kernel. + PA_DCHECK(!metadata->extent.super_page_base); + PA_DCHECK(!metadata->extent.super_pages_end); + PA_DCHECK(!metadata->extent.next); + // Call FromSlotInnerPtr instead of FromSlotStartPtr, because the bucket + // isn't set up yet to properly assert the slot start. + PA_DCHECK(PartitionPage<thread_safe>::FromSlotInnerPtr(slot) == + &metadata->page); + + page = &metadata->page; + PA_DCHECK(!page->slot_span_metadata_offset); + PA_DCHECK(!page->slot_span_metadata.next_slot_span); + PA_DCHECK(!page->slot_span_metadata.num_allocated_slots); + PA_DCHECK(!page->slot_span_metadata.num_unprovisioned_slots); + PA_DCHECK(!page->slot_span_metadata.empty_cache_index); + + PA_DCHECK(!metadata->bucket.active_slot_spans_head); + PA_DCHECK(!metadata->bucket.empty_slot_spans_head); + PA_DCHECK(!metadata->bucket.decommitted_slot_spans_head); + PA_DCHECK(!metadata->bucket.num_system_pages_per_slot_span); + PA_DCHECK(!metadata->bucket.num_full_slot_spans); + metadata->bucket.slot_size = slot_size; + + new (&page->slot_span_metadata) + SlotSpanMetadata<thread_safe>(&metadata->bucket); + auto* next_entry = new (slot) PartitionFreelistEntry(); + page->slot_span_metadata.SetFreelistHead(next_entry); + + map_extent = &metadata->direct_map_extent; + map_extent->map_size = map_size; + map_extent->bucket = &metadata->bucket; } - auto* metadata = reinterpret_cast<PartitionDirectMapMetadata<thread_safe>*>( - PartitionSuperPageToMetadataArea(ptr)); - metadata->extent.root = root; - // The new structures are all located inside a fresh system page so they - // will all be zeroed out. These DCHECKs are for documentation. - PA_DCHECK(!metadata->extent.super_page_base); - PA_DCHECK(!metadata->extent.super_pages_end); - PA_DCHECK(!metadata->extent.next); - // Call FromSlotInnerPtr instead of FromSlotStartPtr, because the bucket isn't - // set up yet to properly assert the slot start. - PA_DCHECK(PartitionPage<thread_safe>::FromSlotInnerPtr(slot) == - &metadata->page); - - auto* page = &metadata->page; - PA_DCHECK(!page->slot_span_metadata_offset); - PA_DCHECK(!page->slot_span_metadata.next_slot_span); - PA_DCHECK(!page->slot_span_metadata.num_allocated_slots); - PA_DCHECK(!page->slot_span_metadata.num_unprovisioned_slots); - PA_DCHECK(!page->slot_span_metadata.empty_cache_index); - - PA_DCHECK(!metadata->bucket.active_slot_spans_head); - PA_DCHECK(!metadata->bucket.empty_slot_spans_head); - PA_DCHECK(!metadata->bucket.decommitted_slot_spans_head); - PA_DCHECK(!metadata->bucket.num_system_pages_per_slot_span); - PA_DCHECK(!metadata->bucket.num_full_slot_spans); - metadata->bucket.slot_size = slot_size; - - new (&page->slot_span_metadata) - SlotSpanMetadata<thread_safe>(&metadata->bucket); - auto* next_entry = new (slot) PartitionFreelistEntry(); - page->slot_span_metadata.SetFreelistHead(next_entry); - - auto* map_extent = &metadata->direct_map_extent; - map_extent->map_size = map_size; - map_extent->bucket = &metadata->bucket; - + root->lock_.AssertAcquired(); // Maintain the doubly-linked list of all direct mappings. map_extent->next_extent = root->direct_map_list; if (map_extent->next_extent)
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h index 582e072..3fc1425 100644 --- a/base/allocator/partition_allocator/partition_root.h +++ b/base/allocator/partition_allocator/partition_root.h
@@ -233,7 +233,7 @@ char* next_partition_page_end = nullptr; SuperPageExtentEntry* current_extent = nullptr; SuperPageExtentEntry* first_extent = nullptr; - DirectMapExtent* direct_map_list = nullptr; + DirectMapExtent* direct_map_list GUARDED_BY(lock_) = nullptr; SlotSpan* global_empty_slot_span_ring[kMaxFreeableSpans] = {}; int16_t global_empty_slot_span_ring_index = 0; @@ -279,8 +279,7 @@ ALWAYS_INLINE bool TryRecommitSystemPagesForData( void* address, size_t length, - PageAccessibilityDisposition accessibility_disposition) - EXCLUSIVE_LOCKS_REQUIRED(lock_); + PageAccessibilityDisposition accessibility_disposition); [[noreturn]] NOINLINE void OutOfMemory(size_t size); @@ -401,7 +400,7 @@ return bits::AlignUp(raw_size, SystemPageSize()); } - ALWAYS_INLINE size_t GetDirectMapReservedSize(size_t raw_size) { + static ALWAYS_INLINE size_t GetDirectMapReservedSize(size_t raw_size) { // Caller must check that the size is not above the MaxDirectMapped() // limit before calling. This also guards against integer overflow in the // calculation here.
diff --git a/base/bind.h b/base/bind.h index 359e3533..c9a5ea8f 100644 --- a/base/bind.h +++ b/base/bind.h
@@ -45,9 +45,6 @@ // auto cb = base::BindOnce(&C::F, instance); // std::move(cb).Run(); // Identical to instance->F() // -// base::Bind is currently a type alias for base::BindRepeating(). In the -// future, we expect to flip this to default to base::BindOnce(). -// // See //docs/callback.md for the full documentation. // // ----------------------------------------------------------------------------- @@ -91,17 +88,6 @@ std::forward<Args>(args)...); } -// Unannotated Bind. -// TODO(tzik): Deprecate this and migrate to OnceCallback and -// RepeatingCallback, once they get ready. -template <typename Functor, typename... Args> -inline Callback<internal::MakeUnboundRunType<Functor, Args...>> Bind( - Functor&& functor, - Args&&... args) { - return base::BindRepeating(std::forward<Functor>(functor), - std::forward<Args>(args)...); -} - // Special cases for binding to a base::Callback without extra bound arguments. // We CHECK() the validity of callback to guard against null pointers // accidentally ending up in posted tasks, causing hard-to-debug crashes. @@ -124,12 +110,6 @@ return callback; } -template <typename Signature> -Callback<Signature> Bind(Callback<Signature> callback) { - CHECK(callback); - return callback; -} - // Unretained() allows binding a non-refcounted class, and to disable // refcounting on arguments that are refcounted objects. //
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc index 7154194a..ec7433a 100644 --- a/base/bind_unittest.cc +++ b/base/bind_unittest.cc
@@ -1282,38 +1282,40 @@ int assigns = 0; CopyCounter counter(&copies, &assigns); - Bind(&VoidPolymorphic<CopyCounter>::Run, counter); + BindRepeating(&VoidPolymorphic<CopyCounter>::Run, counter); EXPECT_EQ(1, copies); EXPECT_EQ(0, assigns); copies = 0; assigns = 0; - Bind(&VoidPolymorphic<CopyCounter>::Run, CopyCounter(&copies, &assigns)); + BindRepeating(&VoidPolymorphic<CopyCounter>::Run, + CopyCounter(&copies, &assigns)); EXPECT_EQ(1, copies); EXPECT_EQ(0, assigns); copies = 0; assigns = 0; - Bind(&VoidPolymorphic<CopyCounter>::Run).Run(counter); + BindRepeating(&VoidPolymorphic<CopyCounter>::Run).Run(counter); EXPECT_EQ(2, copies); EXPECT_EQ(0, assigns); copies = 0; assigns = 0; - Bind(&VoidPolymorphic<CopyCounter>::Run).Run(CopyCounter(&copies, &assigns)); + BindRepeating(&VoidPolymorphic<CopyCounter>::Run) + .Run(CopyCounter(&copies, &assigns)); EXPECT_EQ(1, copies); EXPECT_EQ(0, assigns); copies = 0; assigns = 0; DerivedCopyMoveCounter derived(&copies, &assigns, nullptr, nullptr); - Bind(&VoidPolymorphic<CopyCounter>::Run).Run(CopyCounter(derived)); + BindRepeating(&VoidPolymorphic<CopyCounter>::Run).Run(CopyCounter(derived)); EXPECT_EQ(2, copies); EXPECT_EQ(0, assigns); copies = 0; assigns = 0; - Bind(&VoidPolymorphic<CopyCounter>::Run) + BindRepeating(&VoidPolymorphic<CopyCounter>::Run) .Run(CopyCounter( DerivedCopyMoveCounter(&copies, &assigns, nullptr, nullptr))); EXPECT_EQ(2, copies); @@ -1326,8 +1328,8 @@ int move_constructs = 0; int move_assigns = 0; - Bind(&VoidPolymorphic<const MoveCounter&>::Run, - MoveCounter(&move_constructs, &move_assigns)); + BindRepeating(&VoidPolymorphic<const MoveCounter&>::Run, + MoveCounter(&move_constructs, &move_assigns)); EXPECT_EQ(1, move_constructs); EXPECT_EQ(0, move_assigns); @@ -1336,14 +1338,14 @@ move_constructs = 0; move_assigns = 0; - Bind(&VoidPolymorphic<MoveCounter>::Run) + BindRepeating(&VoidPolymorphic<MoveCounter>::Run) .Run(MoveCounter(&move_constructs, &move_assigns)); EXPECT_EQ(1, move_constructs); EXPECT_EQ(0, move_assigns); move_constructs = 0; move_assigns = 0; - Bind(&VoidPolymorphic<MoveCounter>::Run) + BindRepeating(&VoidPolymorphic<MoveCounter>::Run) .Run(MoveCounter(DerivedCopyMoveCounter( nullptr, nullptr, &move_constructs, &move_assigns))); EXPECT_EQ(2, move_constructs); @@ -1362,7 +1364,7 @@ int move_assigns = 0; CopyMoveCounter counter(&copies, &assigns, &move_constructs, &move_assigns); - Bind(&VoidPolymorphic<CopyMoveCounter>::Run, counter); + BindRepeating(&VoidPolymorphic<CopyMoveCounter>::Run, counter); EXPECT_EQ(1, copies); EXPECT_EQ(0, assigns); EXPECT_EQ(0, move_constructs); @@ -1372,8 +1374,9 @@ assigns = 0; move_constructs = 0; move_assigns = 0; - Bind(&VoidPolymorphic<CopyMoveCounter>::Run, - CopyMoveCounter(&copies, &assigns, &move_constructs, &move_assigns)); + BindRepeating( + &VoidPolymorphic<CopyMoveCounter>::Run, + CopyMoveCounter(&copies, &assigns, &move_constructs, &move_assigns)); EXPECT_EQ(0, copies); EXPECT_EQ(0, assigns); EXPECT_EQ(1, move_constructs); @@ -1383,7 +1386,7 @@ assigns = 0; move_constructs = 0; move_assigns = 0; - Bind(&VoidPolymorphic<CopyMoveCounter>::Run).Run(counter); + BindRepeating(&VoidPolymorphic<CopyMoveCounter>::Run).Run(counter); EXPECT_EQ(1, copies); EXPECT_EQ(0, assigns); EXPECT_EQ(1, move_constructs); @@ -1393,7 +1396,7 @@ assigns = 0; move_constructs = 0; move_assigns = 0; - Bind(&VoidPolymorphic<CopyMoveCounter>::Run) + BindRepeating(&VoidPolymorphic<CopyMoveCounter>::Run) .Run(CopyMoveCounter(&copies, &assigns, &move_constructs, &move_assigns)); EXPECT_EQ(0, copies); EXPECT_EQ(0, assigns); @@ -1406,7 +1409,7 @@ assigns = 0; move_constructs = 0; move_assigns = 0; - Bind(&VoidPolymorphic<CopyMoveCounter>::Run) + BindRepeating(&VoidPolymorphic<CopyMoveCounter>::Run) .Run(CopyMoveCounter(derived_counter)); EXPECT_EQ(1, copies); EXPECT_EQ(0, assigns); @@ -1417,7 +1420,7 @@ assigns = 0; move_constructs = 0; move_assigns = 0; - Bind(&VoidPolymorphic<CopyMoveCounter>::Run) + BindRepeating(&VoidPolymorphic<CopyMoveCounter>::Run) .Run(CopyMoveCounter(DerivedCopyMoveCounter( &copies, &assigns, &move_constructs, &move_assigns))); EXPECT_EQ(0, copies); @@ -1444,8 +1447,8 @@ char(int, double), internal::ExtractCallableRunType<decltype(h)>>::value)); - EXPECT_EQ(42, Bind([] { return 42; }).Run()); - EXPECT_EQ(42, Bind([](int i) { return i * 7; }, 6).Run()); + EXPECT_EQ(42, BindRepeating([] { return 42; }).Run()); + EXPECT_EQ(42, BindRepeating([](int i) { return i * 7; }, 6).Run()); int x = 1; base::RepeatingCallback<void(int)> cb =
diff --git a/base/callback.h b/base/callback.h index b1f4ec4..c7b76c0 100644 --- a/base/callback.h +++ b/base/callback.h
@@ -48,9 +48,6 @@ // will be a no-op. Note that |IsCancelled()| and |is_null()| are distinct: // simply cancelling a callback will not also make it null. // -// base::Callback is currently a type alias for base::RepeatingCallback. In the -// future, we expect to flip this to default to base::OnceCallback. -// // See //docs/callback.md for the full documentation. namespace base {
diff --git a/base/callback_forward.h b/base/callback_forward.h index d0f230c..8435348 100644 --- a/base/callback_forward.h +++ b/base/callback_forward.h
@@ -13,15 +13,11 @@ template <typename Signature> class RepeatingCallback; -template <typename Signature> -using Callback = RepeatingCallback<Signature>; - // Syntactic sugar to make OnceClosure<void()> and RepeatingClosure<void()> // easier to declare since they will be used in a lot of APIs with delayed // execution. using OnceClosure = OnceCallback<void()>; using RepeatingClosure = RepeatingCallback<void()>; -using Closure = Callback<void()>; } // namespace base
diff --git a/base/cancelable_callback.h b/base/cancelable_callback.h index c19e9a36..44ed6ad5 100644 --- a/base/cancelable_callback.h +++ b/base/cancelable_callback.h
@@ -147,10 +147,6 @@ internal::CancelableCallbackImpl<RepeatingCallback<Signature>>; using CancelableRepeatingClosure = CancelableRepeatingCallback<void()>; -template <typename Signature> -using CancelableCallback = CancelableRepeatingCallback<Signature>; -using CancelableClosure = CancelableCallback<void()>; - } // namespace base #endif // BASE_CANCELABLE_CALLBACK_H_
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index 03d4beb..3960226 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc
@@ -7,7 +7,6 @@ #include <algorithm> #include <utility> -#include "base/auto_reset.h" #include "base/base_switches.h" #include "base/command_line.h" #include "base/debug/activity_tracker.h" @@ -18,7 +17,6 @@ #include "base/process/process_handle.h" #include "base/process/process_info.h" #include "base/rand_util.h" -#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" @@ -442,7 +440,9 @@ FieldTrialList::FieldTrialList( std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider) - : entropy_provider_(std::move(entropy_provider)) { + : entropy_provider_(std::move(entropy_provider)), + observer_list_(new ObserverListThreadSafe<FieldTrialList::Observer>( + ObserverListPolicy::EXISTING_ONLY)) { DCHECK(!global_); DCHECK(!used_without_global_); global_ = this; @@ -917,8 +917,7 @@ bool FieldTrialList::AddObserver(Observer* observer) { if (!global_) return false; - AutoLock auto_lock(global_->lock_); - global_->observers_.push_back(observer); + global_->observer_list_->AddObserver(observer); return true; } @@ -926,10 +925,19 @@ void FieldTrialList::RemoveObserver(Observer* observer) { if (!global_) return; - AutoLock auto_lock(global_->lock_); - Erase(global_->observers_, observer); - DCHECK_EQ(global_->num_ongoing_notify_field_trial_group_selection_calls_, 0) - << "Cannot call RemoveObserver while accessing FieldTrial::group()."; + global_->observer_list_->RemoveObserver(observer); +} + +// static +void FieldTrialList::SetSynchronousObserver(Observer* observer) { + DCHECK(!global_->synchronous_observer_); + global_->synchronous_observer_ = observer; +} + +// static +void FieldTrialList::RemoveSynchronousObserver(Observer* observer) { + DCHECK_EQ(global_->synchronous_observer_, observer); + global_->synchronous_observer_ = nullptr; } // static @@ -951,8 +959,6 @@ if (!global_) return; - std::vector<Observer*> local_observers; - { AutoLock auto_lock(global_->lock_); if (field_trial->group_reported_) @@ -962,24 +968,17 @@ if (!field_trial->enable_field_trial_) return; - ++global_->num_ongoing_notify_field_trial_group_selection_calls_; - ActivateFieldTrialEntryWhileLocked(field_trial); - - // Copy observers to a local variable to access outside the scope of the - // lock. Since removing observers concurrently with this method is - // disallowed, pointers should remain valid while observers are notified. - local_observers = global_->observers_; } - for (Observer* observer : local_observers) { - observer->OnFieldTrialGroupFinalized(field_trial->trial_name(), - field_trial->group_name_internal()); + if (global_->synchronous_observer_) { + global_->synchronous_observer_->OnFieldTrialGroupFinalized( + field_trial->trial_name(), field_trial->group_name_internal()); } - int previous_num_ongoing_notify_field_trial_group_selection_calls = - global_->num_ongoing_notify_field_trial_group_selection_calls_--; - DCHECK_GT(previous_num_ongoing_notify_field_trial_group_selection_calls, 0); + global_->observer_list_->NotifySynchronously( + FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized, + field_trial->trial_name(), field_trial->group_name_internal()); } // static
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h index 1c2460c..9b61c1e 100644 --- a/base/metrics/field_trial.h +++ b/base/metrics/field_trial.h
@@ -57,7 +57,6 @@ #include <stddef.h> #include <stdint.h> -#include <atomic> #include <map> #include <memory> #include <string> @@ -269,7 +268,6 @@ FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOn); FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_Default); FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_NonDefault); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ObserveReentrancy); FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes); FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DoesNotSurpassTotalProbability); FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, @@ -610,15 +608,26 @@ // Add an observer to be notified when a field trial is irrevocably committed // to being part of some specific field_group (and hence the group_name is // also finalized for that field_trial). Returns false and does nothing if - // there is no FieldTrialList singleton. The observer can be notified on any - // sequence; it must be thread-safe. + // there is no FieldTrialList singleton. static bool AddObserver(Observer* observer); - // Remove an observer. This cannot be invoked concurrently with - // FieldTrial::group() (typically, this means that no other thread should be - // running when this is invoked). + // Remove an observer. static void RemoveObserver(Observer* observer); + // Similar to AddObserver(), but the passed observer will be notified + // synchronously when a field trial is activated and its group selected. It + // will be notified synchronously on the same thread where the activation and + // group selection happened. It is the responsibility of the observer to make + // sure that this is a safe operation and the operation must be fast, as this + // work is done synchronously as part of group() or related APIs. Only a + // single such observer is supported, exposed specifically for crash + // reporting. Must be called on the main thread before any other threads + // have been started. + static void SetSynchronousObserver(Observer* observer); + + // Removes the single synchronous observer. + static void RemoveSynchronousObserver(Observer* observer); + // Grabs the lock if necessary and adds the field trial to the allocator. This // should only be called from FinalizeGroupChoice(). static void OnGroupFinalized(bool is_locked, FieldTrial* field_trial); @@ -741,7 +750,7 @@ typedef std::map<std::string, FieldTrial*, std::less<>> RegistrationMap; // Helper function should be called only while holding lock_. - FieldTrial* PreLockedFind(StringPiece name) EXCLUSIVE_LOCKS_REQUIRED(lock_); + FieldTrial* PreLockedFind(StringPiece name); // Register() stores a pointer to the given trial in a global map. // This method also AddRef's the indicated trial. @@ -759,22 +768,19 @@ // FieldTrialList is created after that. static bool used_without_global_; - // Lock for access to |registered_|, |observers_| and - // |field_trial_allocator_|. + // Lock for access to registered_ and field_trial_allocator_. Lock lock_; - RegistrationMap registered_ GUARDED_BY(lock_); + RegistrationMap registered_; // Entropy provider to be used for one-time randomized field trials. If NULL, // one-time randomization is not supported. std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider_; // List of observers to be notified when a group is selected for a FieldTrial. - std::vector<Observer*> observers_ GUARDED_BY(lock_); + scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_; - // Counts the ongoing calls to - // FieldTrialList::NotifyFieldTrialGroupSelection(). Used to ensure that - // RemoveObserver() isn't called while notifying observers. - std::atomic_int num_ongoing_notify_field_trial_group_selection_calls_{0}; + // Single synchronous observer to be notified when a trial group is chosen. + Observer* synchronous_observer_ = nullptr; // Allocator in shared memory containing field trial data. Used in both // browser and child processes, but readonly in the child.
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc index 6e70648c..07fbdd2 100644 --- a/base/metrics/field_trial_unittest.cc +++ b/base/metrics/field_trial_unittest.cc
@@ -55,15 +55,29 @@ FieldTrial::SESSION_RANDOMIZED, default_group_number); } -// A FieldTrialList::Observer implementation which stores the trial name and -// group name received via OnFieldTrialGroupFinalized() for later inspection. +// FieldTrialList::Observer implementation for testing. class TestFieldTrialObserver : public FieldTrialList::Observer { public: - TestFieldTrialObserver() { FieldTrialList::AddObserver(this); } + enum Type { + ASYNCHRONOUS, + SYNCHRONOUS, + }; + + explicit TestFieldTrialObserver(Type type) : type_(type) { + if (type == SYNCHRONOUS) + FieldTrialList::SetSynchronousObserver(this); + else + FieldTrialList::AddObserver(this); + } TestFieldTrialObserver(const TestFieldTrialObserver&) = delete; TestFieldTrialObserver& operator=(const TestFieldTrialObserver&) = delete; - ~TestFieldTrialObserver() override { FieldTrialList::RemoveObserver(this); } + ~TestFieldTrialObserver() override { + if (type_ == SYNCHRONOUS) + FieldTrialList::RemoveSynchronousObserver(this); + else + FieldTrialList::RemoveObserver(this); + } void OnFieldTrialGroupFinalized(const std::string& trial, const std::string& group) override { @@ -75,39 +89,11 @@ const std::string& group_name() const { return group_name_; } private: + const Type type_; std::string trial_name_; std::string group_name_; }; -// A FieldTrialList::Observer implementation which accesses the group of a -// FieldTrial from OnFieldTrialGroupFinalized(). Used to test reentrancy. -class FieldTrialObserverAccessingGroup : public FieldTrialList::Observer { - public: - // |trial_to_access| is the FieldTrial on which to invoke group() when - // receiving an OnFieldTrialGroupFinalized() notification. - explicit FieldTrialObserverAccessingGroup( - scoped_refptr<FieldTrial> trial_to_access) - : trial_to_access_(trial_to_access) { - FieldTrialList::AddObserver(this); - } - FieldTrialObserverAccessingGroup(const FieldTrialObserverAccessingGroup&) = - delete; - FieldTrialObserverAccessingGroup& operator=( - const FieldTrialObserverAccessingGroup&) = delete; - - ~FieldTrialObserverAccessingGroup() override { - FieldTrialList::RemoveObserver(this); - } - - void OnFieldTrialGroupFinalized(const std::string& trial, - const std::string& group) override { - trial_to_access_->group(); - } - - private: - scoped_refptr<FieldTrial> trial_to_access_; -}; - std::string MockEscapeQueryParamValue(const std::string& input) { return input; } @@ -628,7 +614,7 @@ TEST_F(FieldTrialTest, CreateTrialsFromStringNotActiveObserver) { ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); - TestFieldTrialObserver observer; + TestFieldTrialObserver observer(TestFieldTrialObserver::ASYNCHRONOUS); ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/")); RunLoop().RunUntilIdle(); // Observer shouldn't be notified. @@ -637,6 +623,7 @@ // Check that the values still get returned and querying them activates them. EXPECT_EQ("def", FieldTrialList::FindFullName("Abc")); + RunLoop().RunUntilIdle(); EXPECT_EQ("Abc", observer.trial_name()); EXPECT_EQ("def", observer.group_name()); } @@ -901,7 +888,26 @@ const char kTrialName[] = "TrialToObserve1"; const char kSecondaryGroupName[] = "SecondaryGroup"; - TestFieldTrialObserver observer; + TestFieldTrialObserver observer(TestFieldTrialObserver::ASYNCHRONOUS); + int default_group = -1; + scoped_refptr<FieldTrial> trial = + CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); + const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50); + const int chosen_group = trial->group(); + EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group); + + EXPECT_EQ(kTrialName, observer.trial_name()); + if (chosen_group == default_group) + EXPECT_EQ(kDefaultGroupName, observer.group_name()); + else + EXPECT_EQ(kSecondaryGroupName, observer.group_name()); +} + +TEST_F(FieldTrialTest, SynchronousObserver) { + const char kTrialName[] = "TrialToObserve1"; + const char kSecondaryGroupName[] = "SecondaryGroup"; + + TestFieldTrialObserver observer(TestFieldTrialObserver::SYNCHRONOUS); int default_group = -1; scoped_refptr<FieldTrial> trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); @@ -917,39 +923,10 @@ EXPECT_EQ(kSecondaryGroupName, observer.group_name()); } -// Verify that no hang occurs when a FieldTrial group is selected from a -// FieldTrialList::Observer::OnFieldTrialGroupFinalized() notification. If the -// FieldTrialList's lock is held when observers are notified, this test will -// hang due to reentrant lock acquisition when selecting the FieldTrial group. -TEST_F(FieldTrialTest, ObserveReentrancy) { - const char kTrialName1[] = "TrialToObserve1"; - const char kTrialName2[] = "TrialToObserve2"; - - int default_group_1 = -1; - scoped_refptr<FieldTrial> trial_1 = - CreateFieldTrial(kTrialName1, 100, kDefaultGroupName, &default_group_1); - - FieldTrialObserverAccessingGroup observer(trial_1); - - int default_group_2 = -1; - scoped_refptr<FieldTrial> trial_2 = - CreateFieldTrial(kTrialName2, 100, kDefaultGroupName, &default_group_2); - - // No group should be selected for |trial_1| yet. - EXPECT_EQ(FieldTrial::kNotFinalized, trial_1->group_); - - // Force selection of a group for |trial_2|. This will notify |observer| which - // will force the selection of a group for |trial_1|. This should not hang. - trial_2->group(); - - // The above call should have selected a group for |trial_1|. - EXPECT_NE(FieldTrial::kNotFinalized, trial_1->group_); -} - TEST_F(FieldTrialTest, ObserveDisabled) { const char kTrialName[] = "TrialToObserve2"; - TestFieldTrialObserver observer; + TestFieldTrialObserver observer(TestFieldTrialObserver::ASYNCHRONOUS); int default_group = -1; scoped_refptr<FieldTrial> trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); @@ -973,7 +950,7 @@ TEST_F(FieldTrialTest, ObserveForcedDisabled) { const char kTrialName[] = "TrialToObserve3"; - TestFieldTrialObserver observer; + TestFieldTrialObserver observer(TestFieldTrialObserver::ASYNCHRONOUS); int default_group = -1; scoped_refptr<FieldTrial> trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); @@ -1069,13 +1046,14 @@ { 0.95, kDefaultGroupName }, }; - for (auto& test_case : test_cases) { - TestFieldTrialObserver observer; - scoped_refptr<FieldTrial> trial(FieldTrial::CreateSimulatedFieldTrial( - kTrialName, 100, kDefaultGroupName, test_case.entropy_value)); + for (size_t i = 0; i < base::size(test_cases); ++i) { + TestFieldTrialObserver observer(TestFieldTrialObserver::ASYNCHRONOUS); + scoped_refptr<FieldTrial> trial( + FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, kDefaultGroupName, + test_cases[i].entropy_value)); trial->AppendGroup("A", 80); trial->AppendGroup("B", 10); - EXPECT_EQ(test_case.expected_group, trial->group_name()); + EXPECT_EQ(test_cases[i].expected_group, trial->group_name()); // Field trial shouldn't have been registered with the list. EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName));
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h index c750bbb0..dc6b7bb9d 100644 --- a/base/observer_list_threadsafe.h +++ b/base/observer_list_threadsafe.h
@@ -7,6 +7,7 @@ #include <unordered_map> #include <utility> +#include <vector> #include "base/base_export.h" #include "base/bind.h" @@ -42,11 +43,7 @@ // The drawback of the threadsafe observer list is that notifications are not // as real-time as the non-threadsafe version of this class. Notifications // will always be done via PostTask() to another sequence, whereas with the -// non-thread-safe ObserverList, notifications happen synchronously. -// -// Note: this class previously supported synchronous notifications for -// same-sequence observers, but it was error-prone and removed in -// crbug.com/1193750, think twice before re-considering this paradigm. +// non-thread-safe observer_list, notifications happen synchronously. // /////////////////////////////////////////////////////////////////////////////// @@ -202,6 +199,49 @@ } } + // Like Notify() but attempts to synchronously invoke callbacks if they are + // associated with this thread. + template <typename Method, typename... Params> + void NotifySynchronously(const Location& from_here, + Method m, + Params&&... params) { + RepeatingCallback<void(ObserverType*)> method = + BindRepeating(&Dispatcher<ObserverType, Method>::Run, m, + std::forward<Params>(params)...); + + // The observers may make reentrant calls (which can be a problem due to the + // lock), so we extract a list to call synchronously. + struct PendingNotificationData { + ObserverType* observer; + size_t observer_id; + }; + std::vector<PendingNotificationData> current_sequence_observers; + + { + AutoLock lock(lock_); + current_sequence_observers.reserve(observers_.size()); + for (const auto& observer : observers_) { + if (observer.second.task_runner->RunsTasksInCurrentSequence()) { + current_sequence_observers.emplace_back(PendingNotificationData{ + observer.first, observer.second.observer_id}); + } else { + observer.second.task_runner->PostTask( + from_here, + BindOnce(&ObserverListThreadSafe<ObserverType>::NotifyWrapper, + this, observer.first, + NotificationData(this, observer.second.observer_id, + from_here, method))); + } + } + } + + for (const auto& pending_notification : current_sequence_observers) { + NotifyWrapper(pending_notification.observer, + NotificationData(this, pending_notification.observer_id, + from_here, method)); + } + } + private: friend class RefCountedThreadSafe<ObserverListThreadSafeBase>;
diff --git a/base/observer_list_threadsafe_unittest.cc b/base/observer_list_threadsafe_unittest.cc index 3dee47f..08f4aa4 100644 --- a/base/observer_list_threadsafe_unittest.cc +++ b/base/observer_list_threadsafe_unittest.cc
@@ -514,4 +514,59 @@ EXPECT_EQ(1, c.total); } +TEST(ObserverListThreadSafeTest, NotifySynchronously) { + test::TaskEnvironment task_environment; + + scoped_refptr<ObserverListThreadSafe<Foo>> observer_list( + new ObserverListThreadSafe<Foo>); + Adder a(1); + Adder b(-1); + Adder c(1); + Adder d(-1); + + observer_list->AddObserver(&a); + observer_list->AddObserver(&b); + + observer_list->NotifySynchronously(FROM_HERE, &Foo::Observe, 10); + + observer_list->AddObserver(&c); + observer_list->AddObserver(&d); + + observer_list->NotifySynchronously(FROM_HERE, &Foo::Observe, 10); + + EXPECT_EQ(20, a.total); + EXPECT_EQ(-20, b.total); + EXPECT_EQ(10, c.total); + EXPECT_EQ(-10, d.total); +} + +TEST(ObserverListThreadSafeTest, NotifySynchronouslyCrossSequence) { + test::TaskEnvironment task_environment; + + scoped_refptr<ObserverListThreadSafe<Foo>> observer_list( + new ObserverListThreadSafe<Foo>); + Adder a(1); + observer_list->AddObserver(&a); + + WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, + WaitableEvent::InitialState::NOT_SIGNALED); + // Call NotifySynchronously on a different sequence. + ThreadPool::PostTask(FROM_HERE, {}, BindLambdaForTesting([&]() { + observer_list->NotifySynchronously(FROM_HERE, + &Foo::Observe, 10); + event.Signal(); + })); + + event.Wait(); + + // Because it was run on a different sequence NotifySynchronously should have + // posted a task which hasn't run yet. + EXPECT_EQ(0, a.total); + + RunLoop().RunUntilIdle(); + + // Verify the task has now run. + EXPECT_EQ(10, a.total); +} + } // namespace base
diff --git a/base/task/sequence_manager/sequence_manager_impl_unittest.cc b/base/task/sequence_manager/sequence_manager_impl_unittest.cc index 618ffb8..254a77e 100644 --- a/base/task/sequence_manager/sequence_manager_impl_unittest.cc +++ b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
@@ -4823,9 +4823,9 @@ std::vector<int> order; - CancelableClosure cancelable_closure1( + CancelableRepeatingClosure cancelable_closure1( BindLambdaForTesting([&]() { order.push_back(10); })); - CancelableClosure cancelable_closure2( + CancelableRepeatingClosure cancelable_closure2( BindLambdaForTesting([&]() { order.push_back(11); })); queue1->task_runner()->PostTask(FROM_HERE, BindLambdaForTesting([&]() { order.push_back(1);
diff --git a/base/task/sequence_manager/thread_controller_impl.h b/base/task/sequence_manager/thread_controller_impl.h index 0276b03..8d40248 100644 --- a/base/task/sequence_manager/thread_controller_impl.h +++ b/base/task/sequence_manager/thread_controller_impl.h
@@ -120,7 +120,7 @@ const TickClock* time_source_; RepeatingClosure immediate_do_work_closure_; RepeatingClosure delayed_do_work_closure_; - CancelableClosure cancelable_delayed_do_work_closure_; + CancelableRepeatingClosure cancelable_delayed_do_work_closure_; SequencedTaskSource* sequence_ = nullptr; // Not owned. TaskAnnotator task_annotator_; WorkDeduplicator work_deduplicator_;
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/CallbackHelper.java b/base/test/android/javatests/src/org/chromium/base/test/util/CallbackHelper.java index 3264014..2f04d86 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/util/CallbackHelper.java +++ b/base/test/android/javatests/src/org/chromium/base/test/util/CallbackHelper.java
@@ -228,6 +228,20 @@ } /** + * Blocks until the next time the callback is called. + * @param msg The error message to use if the callback times out. + * @throws TimeoutException + */ + public void waitForNext(String msg) throws TimeoutException { + waitForCallback(msg, mCallCount, 1, WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS); + } + + /** @see #waitForNext(String) */ + public void waitForNext() throws TimeoutException { + waitForNext(null); + } + + /** * Wait until the callback has been called once. */ public void waitForFirst(String msg, long timeout, TimeUnit unit) throws TimeoutException {
diff --git a/base/test/task_environment_unittest.cc b/base/test/task_environment_unittest.cc index 61c620b..4b813713 100644 --- a/base/test/task_environment_unittest.cc +++ b/base/test/task_environment_unittest.cc
@@ -1147,20 +1147,20 @@ EXPECT_EQ(TimeDelta::Max(), task_environment.NextMainThreadPendingTaskDelay()); - CancelableClosure task2(BindRepeating([]() {})); + CancelableRepeatingClosure task2(BindRepeating([]() {})); ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task2.callback(), TimeDelta::FromSeconds(1)); task2.Cancel(); EXPECT_EQ(0u, task_environment.GetPendingMainThreadTaskCount()); - CancelableClosure task3(BindRepeating([]() {})); + CancelableRepeatingClosure task3(BindRepeating([]() {})); ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task3.callback(), TimeDelta::FromSeconds(1)); task3.Cancel(); EXPECT_EQ(TimeDelta::Max(), task_environment.NextMainThreadPendingTaskDelay()); - CancelableClosure task4(BindRepeating([]() {})); + CancelableRepeatingClosure task4(BindRepeating([]() {})); ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task4.callback(), TimeDelta::FromSeconds(1)); task4.Cancel(); @@ -1185,7 +1185,7 @@ TaskEnvironment::ThreadPoolExecutionMode::QUEUED); TimeTicks start_time = task_environment.NowTicks(); - CancelableClosure task(BindRepeating([]() {})); + CancelableRepeatingClosure task(BindRepeating([]() {})); ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task.callback(), TimeDelta::FromSeconds(1)); EXPECT_EQ(TimeDelta::FromSeconds(1), @@ -1199,7 +1199,7 @@ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME); EXPECT_FALSE(task_environment.NextTaskIsDelayed()); - CancelableClosure task(BindRepeating([]() {})); + CancelableRepeatingClosure task(BindRepeating([]() {})); ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task.callback(), TimeDelta::FromSeconds(1)); EXPECT_TRUE(task_environment.NextTaskIsDelayed());
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 3a15d060..307ecc1 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -4.20210504.3.1 +4.20210505.0.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 3a15d060..307ecc1 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -4.20210504.3.1 +4.20210505.0.1
diff --git a/build/toolchain/apple/toolchain.gni b/build/toolchain/apple/toolchain.gni index 3474a31..4191f9bf 100644 --- a/build/toolchain/apple/toolchain.gni +++ b/build/toolchain/apple/toolchain.gni
@@ -513,10 +513,13 @@ _tool = rebase_path("//build/toolchain/ios/compile_xcassets.py", root_build_dir) + _env_vars = "TOOL_VERSION=${tool_versions.compile_xcassets}" + if (invoker.sdk_developer_dir != "") { + _env_vars += " DEVELOPER_DIR=${toolchain_args.sdk_developer_dir}" + } + command = - "rm -f \"{{output}}\" && " + - "TOOL_VERSION=${tool_versions.compile_xcassets} " + - "$python_path $_tool -p \"${invoker.sdk_name}\" " + + "$_env_vars $python_path $_tool -p \"${invoker.sdk_name}\" " + "-t \"${invoker.deployment_target}\" " + "-T \"{{bundle_product_type}}\" " + "-P \"{{bundle_partial_info_plist}}\" " + "-o {{output}} {{inputs}}"
diff --git a/build/toolchain/ios/compile_xcassets.py b/build/toolchain/ios/compile_xcassets.py index e160665..2241f148 100644 --- a/build/toolchain/ios/compile_xcassets.py +++ b/build/toolchain/ios/compile_xcassets.py
@@ -2,12 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import argparse -import os -import re -import subprocess -import sys -import tempfile """Wrapper around actool to compile assets catalog. The script compile_xcassets.py is a wrapper around actool to compile @@ -22,6 +16,14 @@ an option to fail with non-zero error code when there are warnings. """ +import argparse +import os +import re +import shutil +import subprocess +import sys +import tempfile + # Pattern matching a section header in the output of actool. SECTION_HEADER = re.compile('^/\\* ([^ ]*) \\*/$') @@ -62,6 +64,15 @@ return False +def FixAbsolutePathInLine(line, relative_paths): + """Fix absolute paths present in |line| to relative paths.""" + absolute_path = line.split(':')[0] + relative_path = relative_paths.get(absolute_path, absolute_path) + if absolute_path == relative_path: + return line + return relative_path + line[len(absolute_path):] + + def FilterCompilerOutput(compiler_output, relative_paths): """Filers actool compilation output. @@ -102,14 +113,12 @@ if current_section and current_section != NOTICE_SECTION: if IsSpuriousMessage(line): continue - absolute_path = line.split(':')[0] - relative_path = relative_paths.get(absolute_path, absolute_path) - if absolute_path != relative_path: - line = relative_path + line[len(absolute_path):] if not data_in_section: data_in_section = True filtered_output.append('/* %s */\n' % current_section) - filtered_output.append(line + '\n') + + fixed_line = FixAbsolutePathInLine(line, relative_paths) + filtered_output.append(fixed_line + '\n') return ''.join(filtered_output) @@ -168,7 +177,7 @@ command.extend([ACTOOL_FLAG_FOR_ASSET_TYPE[asset_type], asset_name]) - # Always ask actool to generate a partial Info.plist file. If not path + # Always ask actool to generate a partial Info.plist file. If no path # has been given by the caller, use a temporary file name. temporary_file = None if not partial_info_plist: @@ -202,10 +211,21 @@ stderr=subprocess.STDOUT) stdout, _ = process.communicate() - # Filter the output to remove all garbarge and to fix the paths. - stdout = FilterCompilerOutput(stdout.decode('UTF-8'), relative_paths) + # If the invocation of `actool` failed, copy all the compiler output to + # the standard error stream and exit. See https://crbug.com/1205775 for + # example of compilation that failed with no error message due to filter. + if process.returncode: + for line in stdout.splitlines(): + fixed_line = FixAbsolutePathInLine(line, relative_paths) + sys.stderr.write(fixed_line + '\n') + sys.exit(1) - if process.returncode or stdout: + # Filter the output to remove all garbage and to fix the paths. If the + # output is not empty after filtering, then report the compilation as a + # failure (as some version of `actool` report error to stdout, yet exit + # with an return code of zero). + stdout = FilterCompilerOutput(stdout.decode('UTF-8'), relative_paths) + if stdout: sys.stderr.write(stdout) sys.exit(1) @@ -252,6 +272,12 @@ 'to the containing bundle: %s\n' % (args.output, )) sys.exit(1) + if os.path.exists(args.output): + if os.path.isfile(args.output): + os.unlink(args.output) + else: + shutil.rmtree(args.output) + CompileAssetCatalog(args.output, args.platform, args.product_type, args.minimum_deployment_target, args.inputs, args.compress_pngs, args.partial_info_plist)
diff --git a/cc/trees/frame_rate_estimator.cc b/cc/trees/frame_rate_estimator.cc index 577b6a1..0ba9354 100644 --- a/cc/trees/frame_rate_estimator.cc +++ b/cc/trees/frame_rate_estimator.cc
@@ -49,7 +49,7 @@ // The delta below is to account for minor offsets in frame times. constexpr auto kFudgeDelta = base::TimeDelta::FromMilliseconds(1); constexpr auto kMinDelta = - (viz::BeginFrameArgs::DefaultInterval() * 2) + kFudgeDelta; + (viz::BeginFrameArgs::DefaultInterval() * 2) - kFudgeDelta; if (draw_delta < kMinDelta) num_of_consecutive_frames_with_min_delta_++; else
diff --git a/cc/trees/frame_rate_estimator_unittest.cc b/cc/trees/frame_rate_estimator_unittest.cc index d99fabf8..03df3952 100644 --- a/cc/trees/frame_rate_estimator_unittest.cc +++ b/cc/trees/frame_rate_estimator_unittest.cc
@@ -4,6 +4,7 @@ #include "cc/trees/frame_rate_estimator.h" +#include "base/stl_util.h" #include "base/test/test_simple_task_runner.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "testing/gtest/include/gtest/gtest.h" @@ -69,5 +70,28 @@ EXPECT_NE(estimator_->GetPreferredInterval(), viz::BeginFrameArgs::MinInterval()); } + +TEST_F(FrameRateEstimatorTest, RafAtHalfFps) { + estimator_->SetFrameEstimationEnabled(true); + // Recorded rAF intervals at 30 fps. + const base::TimeDelta kIntervals[] = { + base::TimeDelta::FromMicroseconds(33425), + base::TimeDelta::FromMicroseconds(33298), + base::TimeDelta::FromMicroseconds(33396), + base::TimeDelta::FromMicroseconds(33339), + base::TimeDelta::FromMicroseconds(33431), + base::TimeDelta::FromMicroseconds(33320), + base::TimeDelta::FromMicroseconds(33364), + base::TimeDelta::FromMicroseconds(33360)}; + const base::TimeDelta kIntervalForHalfFps = + viz::BeginFrameArgs::DefaultInterval() * 2; + base::TimeTicks time; + for (size_t i = 0; i <= base::size(kIntervals); ++i) { + estimator_->WillDraw(time); + EXPECT_EQ(kIntervalForHalfFps, estimator_->GetPreferredInterval()); + if (i < base::size(kIntervals)) + time += kIntervals[i]; + } +} } // namespace } // namespace cc
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index 24b4105..d10441c 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -142,6 +142,7 @@ "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabLaunchCauseMetricsTest.java", + "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabPostMessageTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistenceIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicyTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelperTest.java",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn index 867a3b6..019e75d 100644 --- a/chrome/android/features/autofill_assistant/BUILD.gn +++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -316,6 +316,7 @@ "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/BottomSheetOnboardingCoordinatorTest.java", + "javatests/src/org/chromium/chrome/browser/autofill_assistant/InChromeTriggeringTest.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/PasswordChangeFixtureParameters.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/PasswordChangeFixtureTest.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/PasswordChangeFixtureTestUtils.java",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScript.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScript.java index 110f6d0..297447a 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScript.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScript.java
@@ -184,11 +184,6 @@ } @VisibleForTesting - public void disableBottomSheetAnimationsForTesting(boolean disable) { - mAnimateBottomSheet = !disable; - } - - @VisibleForTesting public List<AssistantChip> getLeftAlignedChipsForTest() { return mLeftAlignedChips; } @@ -225,6 +220,7 @@ AssistantHeaderModel.FEEDBACK_BUTTON_CALLBACK, mDelegate::onFeedbackButtonClicked); if (AutofillAssistantServiceInjector.hasServiceRequestSenderToInject()) { mHeaderModel.set(AssistantHeaderModel.DISABLE_ANIMATIONS_FOR_TESTING, true); + mAnimateBottomSheet = false; } return mHeaderModel; }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScriptBridge.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScriptBridge.java index 511cec04..12dd8e2 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScriptBridge.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScriptBridge.java
@@ -9,14 +9,12 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.autofill_assistant.AssistantCoordinator; import org.chromium.chrome.browser.autofill_assistant.AssistantDependenciesImpl; import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiController; import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChip; import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderModel; import org.chromium.chrome.browser.feedback.HelpAndFeedbackLauncherImpl; -import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabUtils; import org.chromium.ui.KeyboardVisibilityDelegate; @@ -33,7 +31,6 @@ private final AssistantTriggerScript mTriggerScript; private long mNativeBridge; private KeyboardVisibilityDelegate.KeyboardVisibilityListener mKeyboardVisibilityListener; - private ActivityTabProvider.ActivityTabTabObserver mActivityTabObserver; @CalledByNative public AssistantTriggerScriptBridge(AssistantDependenciesImpl startupDependencies) { @@ -70,14 +67,6 @@ mStartupDependencies.getBottomInsetProvider()); mKeyboardVisibilityListener = this::safeNativeOnKeyboardVisibilityChanged; - mActivityTabObserver = - new ActivityTabProvider.ActivityTabTabObserver( - mStartupDependencies.getActivityTabProvider(), true) { - @Override - public void onInteractabilityChanged(Tab tab, boolean isInteractable) { - safeNativeOnTabInteractabilityChanged(isInteractable); - } - }; } /** @@ -146,7 +135,6 @@ mTriggerScript.destroy(); mStartupDependencies.getKeyboardVisibilityDelegate().removeKeyboardVisibilityListener( mKeyboardVisibilityListener); - mActivityTabObserver.destroy(); } private void safeNativeOnTriggerScriptAction(int action) { @@ -178,13 +166,6 @@ } } - private void safeNativeOnTabInteractabilityChanged(boolean interactable) { - if (mNativeBridge != 0) { - AssistantTriggerScriptBridgeJni.get().onTabInteractabilityChanged( - mNativeBridge, AssistantTriggerScriptBridge.this, interactable); - } - } - @NativeMethods interface Natives { void onTriggerScriptAction(long nativeTriggerScriptBridgeAndroid, @@ -195,7 +176,5 @@ long nativeTriggerScriptBridgeAndroid, AssistantTriggerScriptBridge caller); void onKeyboardVisibilityChanged(long nativeTriggerScriptBridgeAndroid, AssistantTriggerScriptBridge caller, boolean visible); - void onTabInteractabilityChanged(long nativeTriggerScriptBridgeAndroid, - AssistantTriggerScriptBridge caller, boolean interactable); } }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InChromeTriggeringTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InChromeTriggeringTest.java new file mode 100644 index 0000000..f3391427 --- /dev/null +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InChromeTriggeringTest.java
@@ -0,0 +1,130 @@ +// 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.autofill_assistant; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withText; + +import static org.chromium.base.test.util.CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL; +import static org.chromium.base.test.util.CriteriaHelper.DEFAULT_POLLING_INTERVAL; +import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.createDefaultTriggerScriptUI; +import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewAssertionTrue; +import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; + +import androidx.test.filters.MediumTest; + +import com.google.protobuf.GeneratedMessageLite; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.browser.autofill_assistant.proto.GetTriggerScriptsResponseProto; +import org.chromium.chrome.browser.autofill_assistant.proto.TriggerScriptProto; +import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge; +import org.chromium.chrome.browser.tabmodel.TabModelUtils; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.util.browser.Features; +import org.chromium.content_public.browser.test.util.TestThreadUtils; + +/** + * Tests for TriggerContext. + */ +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +@RunWith(ChromeJUnit4ClassRunner.class) +public class InChromeTriggeringTest { + private static final String HTML_DIRECTORY = "/components/test/data/autofill_assistant/html/"; + private static final String TEST_PAGE_UNSUPPORTED = "autofill_assistant_target_website.html"; + private static final String TEST_PAGE_SUPPORTED = "cart.html"; + + @Rule + public ChromeTabbedActivityTestRule mTestRule = new ChromeTabbedActivityTestRule(); + + private String getTargetWebsiteUrl(String testPage) { + return mTestRule.getTestServer().getURL(HTML_DIRECTORY + testPage); + } + + private void setupTriggerScripts(GetTriggerScriptsResponseProto triggerScripts) { + AutofillAssistantTestServiceRequestSender testServiceRequestSender = + new AutofillAssistantTestServiceRequestSender(); + testServiceRequestSender.setNextResponse(/* httpStatus = */ 200, triggerScripts); + testServiceRequestSender.scheduleForInjection(); + } + + @Before + public void setUp() { + mTestRule.startMainActivityOnBlankPage(); + + // Enable MSBB. + AutofillAssistantPreferencesUtil.setProactiveHelpSwitch(true); + TestThreadUtils.runOnUiThreadBlocking(() -> { + UnifiedConsentServiceBridge.setUrlKeyedAnonymizedDataCollectionEnabled( + AutofillAssistantUiController.getProfile(), true); + + // Force native to pick up the changes we made to Chrome preferences. + AutofillAssistantTabHelper + .get(TabModelUtils.getCurrentTab(mTestRule.getActivity().getCurrentTabModel())) + .forceSettingsChangeNotificationForTesting(); + }); + } + + private GeneratedMessageLite createDefaultTriggerScriptResponse(String statusMessage) { + return GetTriggerScriptsResponseProto.newBuilder() + .addTriggerScripts(TriggerScriptProto.newBuilder().setUserInterface( + createDefaultTriggerScriptUI(statusMessage, + /* bubbleMessage = */ "", + /* withProgressBar = */ false))) + .build(); + } + + @Test + @MediumTest + @Features.EnableFeatures("AutofillAssistantInChromeTriggering") + public void triggerImplicitlyOnSupportedSite() { + AutofillAssistantTestServiceRequestSender testServiceRequestSender = + new AutofillAssistantTestServiceRequestSender(); + testServiceRequestSender.setNextResponse( + /* httpStatus = */ 200, createDefaultTriggerScriptResponse("TriggerScript")); + testServiceRequestSender.scheduleForInjection(); + + mTestRule.loadUrl(getTargetWebsiteUrl(TEST_PAGE_UNSUPPORTED)); + onView(withText("TriggerScript")).check(doesNotExist()); + + mTestRule.loadUrl(getTargetWebsiteUrl(TEST_PAGE_SUPPORTED)); + // Note: allow for some extra time here to account for both the navigation and the start. + waitUntilViewMatchesCondition( + withText("TriggerScript"), isDisplayed(), 2 * DEFAULT_MAX_TIME_TO_POLL); + + // Disabling the proactive help setting should stop the trigger script. + AutofillAssistantPreferencesUtil.setProactiveHelpSwitch(false); + TestThreadUtils.runOnUiThreadBlocking( + () + -> AutofillAssistantTabHelper + .get(TabModelUtils.getCurrentTab( + mTestRule.getActivity().getCurrentTabModel())) + .forceSettingsChangeNotificationForTesting()); + waitUntilViewAssertionTrue( + withText("TriggerScript"), doesNotExist(), DEFAULT_POLLING_INTERVAL); + + // Re-enabling the proactive help setting should restart the trigger script, since we are + // still on a supported URL. + testServiceRequestSender.setNextResponse( + /* httpStatus = */ 200, createDefaultTriggerScriptResponse("TriggerScript")); + AutofillAssistantPreferencesUtil.setProactiveHelpSwitch(true); + TestThreadUtils.runOnUiThreadBlocking( + () + -> AutofillAssistantTabHelper + .get(TabModelUtils.getCurrentTab( + mTestRule.getActivity().getCurrentTabModel())) + .forceSettingsChangeNotificationForTesting()); + waitUntilViewMatchesCondition(withText("TriggerScript"), isDisplayed()); + } +}
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/Starter.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/Starter.java index 2b07e20a..205148f 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/Starter.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/Starter.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.autofill_assistant; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import org.chromium.base.UserData; import org.chromium.base.annotations.CalledByNative; @@ -139,6 +140,15 @@ safeNativeOnInteractabilityChanged(isInteractable); } + /** + * Forces native to re-evaluate the Chrome settings. Integration tests may need to call this to + * ensure that programmatic updates to the Chrome settings are received by the native starter. + */ + @VisibleForTesting + public void forceSettingsChangeNotificationForTesting() { + safeNativeOnInteractabilityChanged(true); + } + private void safeNativeDetach() { if (mNativeStarter == 0) { return;
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java index 40ba6878..f45b9bcf 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -2013,10 +2013,9 @@ } private void waitForOverviewVisible() { - int callCount = mLayoutChangedCallbackHelper.getCallCount(); if (mCurrentlyActiveLayout == LayoutType.TAB_SWITCHER) return; try { - mLayoutChangedCallbackHelper.waitForCallback(callCount); + mLayoutChangedCallbackHelper.waitForNext(); } catch (TimeoutException ex) { assert false : "Timeout waiting for browser to enter tab switcher."; }
diff --git a/chrome/android/java/res/layout/autofill_save_address_profile_prompt.xml b/chrome/android/java/res/layout/autofill_save_address_profile_prompt.xml index dc17d1f..aec3414 100644 --- a/chrome/android/java/res/layout/autofill_save_address_profile_prompt.xml +++ b/chrome/android/java/res/layout/autofill_save_address_profile_prompt.xml
@@ -13,6 +13,7 @@ android:layout_width="48dp" android:layout_height="48dp" android:layout_alignParentEnd="true" + android:layout_marginEnd="8dp" android:padding="12dp" android:background="?attr/selectableItemBackground" android:contentDescription="@string/payments_edit_address"
diff --git a/chrome/android/java/res/layout/autofill_update_address_profile_prompt.xml b/chrome/android/java/res/layout/autofill_update_address_profile_prompt.xml index 2131ada..6d1b634 100644 --- a/chrome/android/java/res/layout/autofill_update_address_profile_prompt.xml +++ b/chrome/android/java/res/layout/autofill_update_address_profile_prompt.xml
@@ -7,13 +7,13 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical"> + android:orientation="vertical" + android:paddingBottom="12dp"> <TextView android:id="@+id/subtitle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="16dp" android:paddingStart="@dimen/dialog_padding_sides" android:paddingEnd="@dimen/dialog_padding_sides" android:ellipsize="end" @@ -25,11 +25,20 @@ android:layout_height="wrap_content" android:paddingStart="@dimen/dialog_padding_sides" tools:ignore="RtlSymmetry"> + + <Space + android:id="@+id/no_header_space" + android:layout_width="match_parent" + android:layout_height="25dp" + tools:visibility="gone" /> + <!-- TODO(crbug.com/1167061): Replace with proper localized string. --> <TextView android:id="@+id/header_new" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:layout_below="@id/no_header_space" android:layout_toStartOf="@id/edit_button" android:text="New" android:textAppearance="@style/TextAppearance.TextMedium.Blue" @@ -40,6 +49,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="12dp" + android:layout_marginTop="3dp" android:layout_below="@id/header_new" android:layout_toStartOf="@id/edit_button" android:textAppearance="@style/TextAppearance.TextLarge.Primary" @@ -50,7 +60,10 @@ android:id="@+id/edit_button" android:layout_width="48dp" android:layout_height="48dp" + android:layout_alignBaseline="@id/details_new" android:layout_alignParentEnd="true" + android:layout_marginEnd="8dp" + android:baseline="32dp" android:padding="12dp" android:background="?attr/selectableItemBackground" android:contentDescription="@string/payments_edit_address" @@ -60,12 +73,6 @@ tools:src="@drawable/edit_icon" /> </RelativeLayout> - <View - android:id="@+id/details_separator" - style="@style/HorizontalDivider" - android:layout_marginStart="@dimen/dialog_padding_sides" - android:layout_marginEnd="@dimen/dialog_padding_sides" /> - <!-- TODO(crbug.com/1167061): Replace with proper localized string. --> <TextView android:id="@+id/header_old" @@ -81,7 +88,7 @@ android:id="@+id/details_old" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="12dp" + android:layout_marginTop="3dp" android:paddingStart="@dimen/dialog_padding_sides" android:paddingEnd="@dimen/dialog_padding_sides" android:textAppearance="@style/TextAppearance.TextLarge.Primary"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveAddressProfilePrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveAddressProfilePrompt.java index 81bf568a..851651f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveAddressProfilePrompt.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveAddressProfilePrompt.java
@@ -129,7 +129,8 @@ } /** - * Displays the details in case an existing address to be updated. + * Displays the details in case an existing address to be updated. If oldDetails are empty, only + * newDetails are shown. * * @param subtitle the text to display below the title. * @param oldDetails details in the existing profile that differ. @@ -137,8 +138,8 @@ */ @CalledByNative private void setUpdateDetails(String subtitle, String oldDetails, String newDetails) { - // TODO(crbug.com/1167061): Properly handle the case when oldDetails is empty. ((TextView) mDialogView.findViewById(R.id.subtitle)).setText(subtitle); + showHeaders(!TextUtils.isEmpty(oldDetails)); showTextIfNotEmpty(mDialogView.findViewById(R.id.details_old), oldDetails); showTextIfNotEmpty(mDialogView.findViewById(R.id.details_new), newDetails); } @@ -181,4 +182,11 @@ textView.setText(text); } } + + private void showHeaders(boolean show) { + mDialogView.findViewById(R.id.header_new).setVisibility(show ? View.VISIBLE : View.GONE); + mDialogView.findViewById(R.id.header_old).setVisibility(show ? View.VISIBLE : View.GONE); + mDialogView.findViewById(R.id.no_header_space) + .setVisibility(show ? View.GONE : View.VISIBLE); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java index fa1f293b..270e63c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
@@ -140,12 +140,9 @@ assert mSheetContent == null; createWebContents(profile); mSheetObserver = new EmptyBottomSheetObserver() { - private int mCloseReason; - @Override public void onSheetContentChanged(BottomSheetContent newContent) { if (newContent != mSheetContent) { - mMetrics.recordMetricsForClosed(mCloseReason); mPeeked = false; destroyWebContents(); } @@ -179,13 +176,6 @@ } @Override - public void onSheetClosed(int reason) { - // "Closed" actually means "Peek" for bottom sheet. Save the reason to - // log when the sheet goes to hidden state. See http://crbug.com/986310. - mCloseReason = reason; - } - - @Override public void onSheetOffsetChanged(float heightFraction, float offsetPx) { if (mSheetContent == null) return; if (mCanPromoteToNewTab) mSheetContent.showOpenInNewTabButton(heightFraction);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabMetrics.java index 66fc0cb1..d0beb5863 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabMetrics.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabMetrics.java
@@ -7,7 +7,6 @@ import org.chromium.base.TimeUtils; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; -import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason; /** * Metrics util class for ephemeral tab. @@ -53,21 +52,19 @@ } /** Records metrics when the panel has been closed. */ - public void recordMetricsForClosed(@StateChangeReason int stateChangeReason) { + private void recordMetricsForClosed() { if (!mIsVisible) return; finishPeekTimer(); finishOpenTimer(); RecordHistogram.recordBooleanHistogram("EphemeralTab.CtrPeek", mIsViewed); RecordHistogram.recordBooleanHistogram("EphemeralTab.Ctr", mDidRecordFirstOpen); - RecordHistogram.recordEnumeratedHistogram("EphemeralTab.BottomSheet.CloseReason", - stateChangeReason, StateChangeReason.MAX_VALUE + 1); reset(); } /** Records a user action that promotes the ephemeral tab to a full tab. */ public void recordOpenInNewTab() { - recordMetricsForClosed(StateChangeReason.PROMOTE_TAB); + recordMetricsForClosed(); RecordUserAction.record("EphemeralTab.OpenInNewTab"); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java index 57eecb45..0db0e7e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java
@@ -21,10 +21,11 @@ */ interface Delegate { /** - * @param {@code true} if the requested history is of forward navigation. + * @param forward {@code true} if the requested history is of forward navigation. + * @param isOffTheRecord {@code true} if the history is called from incognito mode. * @return {@link NavigationHistory} object. */ - NavigationHistory getHistory(boolean forward); + NavigationHistory getHistory(boolean forward, boolean isOffTheRecord); /** * Navigates to the page associated with the given index.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java index b3d1a56..df85d13b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
@@ -114,6 +114,8 @@ // no peek/half state. private boolean mFullyExpand; + private Profile mProfile; + /** * Construct a new NavigationSheet. */ @@ -123,6 +125,7 @@ mBottomSheetController = bottomSheetController; mLayoutInflater = LayoutInflater.from(context); mToolbarView = mLayoutInflater.inflate(R.layout.navigation_sheet_toolbar, null); + mProfile = profile; mMediator = new NavigationSheetMediator(context, mModelList, profile, (position, index) -> { mDelegate.navigateToIndex(index); close(false); @@ -162,7 +165,10 @@ (NavigationSheetView) mLayoutInflater.inflate(R.layout.navigation_sheet, null); ListView listview = (ListView) mContentView.findViewById(R.id.navigation_entries); listview.setAdapter(mModelAdapter); - NavigationHistory history = mDelegate.getHistory(mForward); + NavigationHistory history = mDelegate.getHistory(mForward, mProfile.isOffTheRecord()); + // If there is no entry, the sheet should not be opened. This is the case when in a fresh + // Incognito NTP. + if (history.getEntryCount() == 0) return false; mMediator.populateEntries(history); if (!mBottomSheetController.get().requestShowContent(this, true)) { close(false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetMediator.java index 5658c58e..a6a2fd6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetMediator.java
@@ -14,6 +14,7 @@ import android.view.View; import org.chromium.chrome.R; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.ui.favicon.FaviconHelper; import org.chromium.chrome.browser.ui.favicon.FaviconUtils; @@ -37,6 +38,8 @@ * Mediator class for navigation sheet. */ class NavigationSheetMediator { + private static final String INCOGNITO_HISTORY_ENTRIES_FLAG = + ChromeFeatureList.UPDATE_HISTORY_ENTRY_POINTS_IN_INCOGNITO; private final ClickListener mClickListener; private final FaviconHelper mFaviconHelper; private final RoundedIconGenerator mIconGenerator; @@ -44,7 +47,9 @@ private final ModelList mModelList; private final Drawable mHistoryIcon; private final Drawable mDefaultIcon; + private final Drawable mIncognitoIcon; private final String mNewTabText; + private final String mNewIncognitoTabText; private final Profile mProfile; private NavigationHistory mHistory; @@ -88,7 +93,10 @@ context, R.drawable.ic_history_googblue_24dp, R.color.default_icon_color); mDefaultIcon = TintedDrawable.constructTintedDrawable( context, R.drawable.ic_chrome, R.color.default_icon_color); + mIncognitoIcon = TintedDrawable.constructTintedDrawable( + context, R.drawable.incognito_small, R.color.default_icon_color); mNewTabText = context.getResources().getString(R.string.menu_new_tab); + mNewIncognitoTabText = context.getResources().getString(R.string.menu_new_incognito_tab); } /** @@ -143,7 +151,7 @@ Drawable drawable; if (favicon == null) { drawable = UrlUtilities.isNTPUrl(pageUrl) - ? mDefaultIcon + ? getNTPIcon() : new BitmapDrawable(mIconGenerator.generateIconForUrl(pageUrl)); } else { drawable = new BitmapDrawable(favicon); @@ -155,9 +163,23 @@ private String getEntryText(NavigationEntry entry) { String entryText = entry.getTitle(); - if (UrlUtilities.isNTPUrl(entry.getUrl())) entryText = mNewTabText; + if (UrlUtilities.isNTPUrl(entry.getUrl())) entryText = getNTPText(); if (TextUtils.isEmpty(entryText)) entryText = entry.getVirtualUrl().getSpec(); if (TextUtils.isEmpty(entryText)) entryText = entry.getUrl().getSpec(); return entryText; } + + private Drawable getNTPIcon() { + return mProfile.isOffTheRecord() + && ChromeFeatureList.isEnabled(INCOGNITO_HISTORY_ENTRIES_FLAG) + ? mIncognitoIcon + : mDefaultIcon; + } + + private String getNTPText() { + return mProfile.isOffTheRecord() + && ChromeFeatureList.isEnabled(INCOGNITO_HISTORY_ENTRIES_FLAG) + ? mNewIncognitoTabText + : mNewTabText; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java index 3c107de0..e265a444 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.gesturenav; import org.chromium.base.Consumer; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.tab.Tab; import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.content_public.browser.NavigationEntry; @@ -18,6 +19,8 @@ public class TabbedSheetDelegate implements NavigationSheet.Delegate { private static final int MAXIMUM_HISTORY_ITEMS = 8; private static final int FULL_HISTORY_ENTRY_INDEX = -1; + private static final String INCOGNITO_HISTORY_ENTRIES_FLAG = + ChromeFeatureList.UPDATE_HISTORY_ENTRY_POINTS_IN_INCOGNITO; private final Tab mTab; private final Consumer<Tab> mShowHistoryManager; @@ -30,13 +33,15 @@ } @Override - public NavigationHistory getHistory(boolean forward) { + public NavigationHistory getHistory(boolean forward, boolean isOffTheRecord) { NavigationHistory history = mTab.getWebContents().getNavigationController().getDirectedNavigationHistory( forward, MAXIMUM_HISTORY_ITEMS); - history.addEntry(new NavigationEntry(FULL_HISTORY_ENTRY_INDEX, - new GURL(UrlConstants.HISTORY_URL), GURL.emptyGURL(), GURL.emptyGURL(), - GURL.emptyGURL(), mFullHistoryMenu, null, 0, 0)); + if (!isOffTheRecord || !ChromeFeatureList.isEnabled(INCOGNITO_HISTORY_ENTRIES_FLAG)) { + history.addEntry(new NavigationEntry(FULL_HISTORY_ENTRY_INDEX, + new GURL(UrlConstants.HISTORY_URL), GURL.emptyGURL(), GURL.emptyGURL(), + GURL.emptyGURL(), mFullHistoryMenu, null, 0, 0)); + } return history; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index 93e0e62..ecc7f4c0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -135,7 +135,6 @@ import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.UiThreadTaskTraits; -import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.content_public.browser.test.util.ClickUtils; import org.chromium.content_public.browser.test.util.DOMUtils; import org.chromium.content_public.browser.test.util.JavaScriptUtils; @@ -174,30 +173,6 @@ private static final String FRAGMENT_TEST_PAGE = "/chrome/test/data/android/fragment.html"; private static final String TARGET_BLANK_TEST_PAGE = "/chrome/test/data/android/cct_target_blank.html"; - private static final String JS_MESSAGE = "from_js"; - private static final String TITLE_FROM_POSTMESSAGE_TO_CHANNEL = - "<!DOCTYPE html><html><body>" - + " <script>" - + " var received = '';" - + " onmessage = function (e) {" - + " var myport = e.ports[0];" - + " myport.onmessage = function (f) {" - + " received += f.data;" - + " document.title = received;" - + " }" - + " }" - + " </script>" - + "</body></html>"; - private static final String MESSAGE_FROM_PAGE_TO_CHANNEL = - "<!DOCTYPE html><html><body>" - + " <script>" - + " onmessage = function (e) {" - + " if (e.ports != null && e.ports.length > 0) {" - + " e.ports[0].postMessage(\"" + JS_MESSAGE + "\");" - + " }" - + " }" - + " </script>" - + "</body></html>"; private static final String ONLOAD_TITLE_CHANGE = "<!DOCTYPE html><html><body>" + " <script>" + " window.onload = function () {" @@ -1143,326 +1118,6 @@ } /** - * Tests that basic postMessage functionality works through sending a single postMessage - * request. - */ - @Test - @SmallTest - public void testPostMessageBasic() throws Exception { - final CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait(); - Context context = InstrumentationRegistry.getTargetContext(); - Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage); - final CustomTabsSessionToken token = - CustomTabsSessionToken.getSessionTokenFromIntent(intent); - Assert.assertTrue(connection.newSession(token)); - Assert.assertTrue(connection.requestPostMessageChannel(token, null)); - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); - CriteriaHelper.pollInstrumentationThread(() -> { - final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); - Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(mTestPage)); - }); - Assert.assertTrue( - connection.postMessage(token, "Message", null) == CustomTabsService.RESULT_SUCCESS); - TestThreadUtils.runOnUiThreadBlocking( - (Runnable) () -> mCustomTabActivityTestRule.getActivity().getActivityTab().loadUrl( - new LoadUrlParams(mTestPage2))); - CriteriaHelper.pollUiThread(() -> { - final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); - return ChromeTabUtils.isLoadingAndRenderingDone(currentTab); - }); - Assert.assertTrue(connection.postMessage(token, "Message", null) - == CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR); - } - - /** - * Tests that postMessage channel is not functioning after web contents get destroyed and also - * not breaking things. - */ - @Test - @SmallTest - public void testPostMessageWebContentsDestroyed() throws Exception { - final CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait(); - Context context = InstrumentationRegistry.getTargetContext(); - Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage); - final CustomTabsSessionToken token = - CustomTabsSessionToken.getSessionTokenFromIntent(intent); - Assert.assertTrue(connection.newSession(token)); - Assert.assertTrue(connection.requestPostMessageChannel(token, null)); - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); - CriteriaHelper.pollInstrumentationThread(() -> { - final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); - Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(mTestPage)); - }); - Assert.assertTrue( - connection.postMessage(token, "Message", null) == CustomTabsService.RESULT_SUCCESS); - - final CallbackHelper renderProcessCallback = new CallbackHelper(); - new WebContentsObserver(mCustomTabActivityTestRule.getWebContents()) { - @Override - public void renderProcessGone(boolean wasOomProtected) { - renderProcessCallback.notifyCalled(); - } - }; - PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> { - WebContentsUtils.simulateRendererKilled( - mCustomTabActivityTestRule.getActivity().getActivityTab().getWebContents(), - false); - }); - renderProcessCallback.waitForCallback(0); - Assert.assertTrue(connection.postMessage(token, "Message", null) - == CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR); - } - - /** - * Tests whether validatePostMessageOrigin is necessary for making successful postMessage - * requests. - */ - @Test - @SmallTest - public void testPostMessageRequiresValidation() throws Exception { - final CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait(); - Context context = InstrumentationRegistry.getTargetContext(); - Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage); - final CustomTabsSessionToken token = - CustomTabsSessionToken.getSessionTokenFromIntent(intent); - Assert.assertTrue(connection.newSession(token)); - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); - CriteriaHelper.pollInstrumentationThread(() -> { - final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); - Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(mTestPage)); - }); - Assert.assertTrue(connection.postMessage(token, "Message", null) - == CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR); - } - - /** - * Tests the sent postMessage requests not only return success, but is also received by page. - */ - @Test - @SmallTest - public void testPostMessageReceivedInPage() throws Exception { - final String url = - mWebServer.setResponse("/test.html", TITLE_FROM_POSTMESSAGE_TO_CHANNEL, null); - final CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait(); - Context context = InstrumentationRegistry.getTargetContext(); - Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, url); - final CustomTabsSessionToken token = - CustomTabsSessionToken.getSessionTokenFromIntent(intent); - Assert.assertTrue(connection.newSession(token)); - Assert.assertTrue(connection.requestPostMessageChannel(token, null)); - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); - CriteriaHelper.pollInstrumentationThread(() -> { - final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); - Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(url)); - }); - Assert.assertTrue(connection.postMessage(token, "New title", null) - == CustomTabsService.RESULT_SUCCESS); - waitForTitle("New title"); - } - - /** - * Tests the postMessage requests sent from the page is received on the client side. - */ - @Test - @SmallTest - public void testPostMessageReceivedFromPage() throws Exception { - final CallbackHelper messageChannelHelper = new CallbackHelper(); - final CallbackHelper onPostMessageHelper = new CallbackHelper(); - final String url = mWebServer.setResponse("/test.html", MESSAGE_FROM_PAGE_TO_CHANNEL, null); - CustomTabsTestUtils.warmUpAndWait(); - final CustomTabsSession session = - CustomTabsTestUtils.bindWithCallback(new CustomTabsCallback() { - @Override - public void onMessageChannelReady(Bundle extras) { - messageChannelHelper.notifyCalled(); - } - - @Override - public void onPostMessage(String message, Bundle extras) { - onPostMessageHelper.notifyCalled(); - } - }).session; - session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); - Intent intent = new CustomTabsIntent.Builder(session).build().intent; - intent.setData(Uri.parse(url)); - intent.setComponent(new ComponentName( - InstrumentationRegistry.getTargetContext(), ChromeLauncherActivity.class)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - Assert.assertTrue(session.postMessage("Message", null) - == CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR); - - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); - messageChannelHelper.waitForCallback(0); - onPostMessageHelper.waitForCallback(0); - } - - /** - * Tests the postMessage requests sent from the page is received on the client side even though - * the request is sent after the page is created. - */ - @Test - @SmallTest - @DisabledTest(message = "https://crbug.com/692025") - public void testPostMessageReceivedFromPageWithLateRequest() throws Exception { - final CallbackHelper messageChannelHelper = new CallbackHelper(); - final CallbackHelper onPostMessageHelper = new CallbackHelper(); - final String url = mWebServer.setResponse("/test.html", MESSAGE_FROM_PAGE_TO_CHANNEL, null); - CustomTabsTestUtils.warmUpAndWait(); - final CustomTabsSession session = - CustomTabsTestUtils.bindWithCallback(new CustomTabsCallback() { - @Override - public void onMessageChannelReady(Bundle extras) { - messageChannelHelper.notifyCalled(); - } - - @Override - public void onPostMessage(String message, Bundle extras) { - onPostMessageHelper.notifyCalled(); - } - }).session; - - Intent intent = new CustomTabsIntent.Builder(session).build().intent; - intent.setData(Uri.parse(url)); - intent.setComponent(new ComponentName( - InstrumentationRegistry.getTargetContext(), ChromeLauncherActivity.class)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); - CriteriaHelper.pollInstrumentationThread(() -> { - final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); - Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(url)); - }); - - session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); - - messageChannelHelper.waitForCallback(0); - onPostMessageHelper.waitForCallback(0); - - Assert.assertTrue(session.postMessage("Message", null) == CustomTabsService.RESULT_SUCCESS); - } - - private static final int BEFORE_MAY_LAUNCH_URL = 0; - private static final int BEFORE_INTENT = 1; - private static final int AFTER_INTENT = 2; - - /** - * Tests a postMessage request chain can start while loading a hidden tab and continue - * afterwards. Request sent before the hidden tab start. - */ - @Test - @SmallTest - @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) - public void testPostMessageThroughHiddenTabWithRequestBeforeMayLaunchUrl() throws Exception { - sendPostMessageDuringHiddenTabTransition(BEFORE_MAY_LAUNCH_URL); - } - - /** - * Tests a postMessage request chain can start while loading a hidden tab and continue - * afterwards. Request sent after the hidden tab start and before intent launched. - */ - @Test - @SmallTest - @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) - public void testPostMessageThroughHiddenTabWithRequestBeforeIntent() throws Exception { - sendPostMessageDuringHiddenTabTransition(BEFORE_INTENT); - } - - /** - * Tests a postMessage request chain can start while loading a hidden tab and continue - * afterwards. Request sent after intent received. - */ - @Test - @SmallTest - @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) - public void testPostMessageThroughHiddenTabWithRequestAfterIntent() throws Exception { - sendPostMessageDuringHiddenTabTransition(AFTER_INTENT); - } - - private void sendPostMessageDuringHiddenTabTransition(int requestTime) throws Exception { - final CallbackHelper messageChannelHelper = new CallbackHelper(); - final String url = - mWebServer.setResponse("/test.html", TITLE_FROM_POSTMESSAGE_TO_CHANNEL, null); - final CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait(); - - final CustomTabsSession session = - CustomTabsTestUtils.bindWithCallback(new CustomTabsCallback() { - @Override - public void onMessageChannelReady(Bundle extras) { - messageChannelHelper.notifyCalled(); - } - }).session; - - Intent intent = new CustomTabsIntent.Builder(session).build().intent; - intent.setData(Uri.parse(url)); - intent.setComponent(new ComponentName( - InstrumentationRegistry.getTargetContext(), ChromeLauncherActivity.class)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - CustomTabsSessionToken token = CustomTabsSessionToken.getSessionTokenFromIntent(intent); - - boolean channelRequested = false; - String titleString = ""; - - if (requestTime == BEFORE_MAY_LAUNCH_URL) { - channelRequested = - session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); - Assert.assertTrue(channelRequested); - } - - setCanUseHiddenTabForSession(connection, token, true); - session.mayLaunchUrl(Uri.parse(url), null, null); - ensureCompletedSpeculationForUrl(connection, url); - - if (requestTime == BEFORE_INTENT) { - channelRequested = - session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); - Assert.assertTrue(channelRequested); - } - - if (channelRequested) { - messageChannelHelper.waitForCallback(0); - String currentMessage = "Prerendering "; - // Initial title update during prerender. - assertEquals( - CustomTabsService.RESULT_SUCCESS, session.postMessage(currentMessage, null)); - titleString = currentMessage; - } - - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); - - CriteriaHelper.pollInstrumentationThread(() -> { - final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); - Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(url)); - }); - - if (requestTime == AFTER_INTENT) { - channelRequested = - session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); - Assert.assertTrue(channelRequested); - messageChannelHelper.waitForCallback(0); - } - - String currentMessage = "and loading "; - // Update title again and verify both updates went through with the channel still intact. - assertEquals( - CustomTabsService.RESULT_SUCCESS, session.postMessage(currentMessage, null)); - titleString += currentMessage; - - // Request a new channel, verify it was created. - session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); - messageChannelHelper.waitForCallback(1); - - String newMessage = "and refreshing"; - // Update title again and verify both updates went through with the channel still intact. - assertEquals( - CustomTabsService.RESULT_SUCCESS, session.postMessage(newMessage, null)); - titleString += newMessage; - - final String title = titleString; - waitForTitle(title); - } - - /** * Tests that when we use a pre-created renderer, the page loaded is the * only one in the navigation history. */ @@ -2779,11 +2434,6 @@ return historyObserver.getHistoryQueryResults(); } - private void waitForTitle(String newTitle) { - Tab currentTab = getActivity().getActivityTab(); - ChromeTabUtils.waitForTitle(currentTab, newTitle); - } - private SessionDataHolder getSessionDataHolder() { return ChromeApplicationImpl.getComponent().resolveSessionDataHolder(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabPostMessageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabPostMessageTest.java new file mode 100644 index 0000000..f5e2e92e --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabPostMessageTest.java
@@ -0,0 +1,456 @@ +// 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.customtabs; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; + +import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE; +import static org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule.LONG_TIMEOUT_MS; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.test.InstrumentationRegistry; + +import androidx.browser.customtabs.CustomTabsCallback; +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.browser.customtabs.CustomTabsService; +import androidx.browser.customtabs.CustomTabsSession; +import androidx.browser.customtabs.CustomTabsSessionToken; +import androidx.test.filters.SmallTest; + +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.library_loader.LibraryLoader; +import org.chromium.base.task.PostTask; +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.Criteria; +import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.Restriction; +import org.chromium.chrome.browser.document.ChromeLauncherActivity; +import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.util.ChromeTabUtils; +import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.content_public.browser.UiThreadTaskTraits; +import org.chromium.content_public.browser.WebContentsObserver; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.content_public.browser.test.util.WebContentsUtils; +import org.chromium.net.test.util.TestWebServer; + +/** + * Integration tests for the Custom Tab post message support. + */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class CustomTabPostMessageTest { + private static final int BEFORE_MAY_LAUNCH_URL = 0; + private static final int BEFORE_INTENT = 1; + private static final int AFTER_INTENT = 2; + + private static final String JS_MESSAGE = "from_js"; + private static final String TEST_PAGE = "/chrome/test/data/android/google.html"; + private static final String TEST_PAGE_2 = "/chrome/test/data/android/test.html"; + + private static final String TITLE_FROM_POSTMESSAGE_TO_CHANNEL = "<!DOCTYPE html><html><body>" + + " <script>" + + " var received = '';" + + " onmessage = function (e) {" + + " var myport = e.ports[0];" + + " myport.onmessage = function (f) {" + + " received += f.data;" + + " document.title = received;" + + " }" + + " }" + + " </script>" + + "</body></html>"; + private static final String MESSAGE_FROM_PAGE_TO_CHANNEL = "<!DOCTYPE html><html><body>" + + " <script>" + + " onmessage = function (e) {" + + " if (e.ports != null && e.ports.length > 0) {" + + " e.ports[0].postMessage(\"" + JS_MESSAGE + "\");" + + " }" + + " }" + + " </script>" + + "</body></html>"; + + @Rule + public CustomTabActivityTestRule mCustomTabActivityTestRule = new CustomTabActivityTestRule(); + + private String mTestPage; + private String mTestPage2; + private CustomTabsConnection mConnectionToCleanup; + private TestWebServer mWebServer; + + @Before + public void setUp() throws Exception { + mTestPage = mCustomTabActivityTestRule.getTestServer().getURL(TEST_PAGE); + mTestPage2 = mCustomTabActivityTestRule.getTestServer().getURL(TEST_PAGE_2); + LibraryLoader.getInstance().ensureInitialized(); + mWebServer = TestWebServer.start(); + } + + @After + public void tearDown() { + if (mConnectionToCleanup != null) CustomTabsTestUtils.cleanupSessions(mConnectionToCleanup); + if (mWebServer != null) mWebServer.shutdown(); + } + + private void waitForTitle(String newTitle) { + Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); + ChromeTabUtils.waitForTitle(currentTab, newTitle); + } + + private void setCanUseHiddenTabForSession( + CustomTabsConnection connection, CustomTabsSessionToken token, boolean useHiddenTab) { + assert mConnectionToCleanup == null || mConnectionToCleanup == connection; + // Save the connection. In case the hidden tab is not consumed by the test, ensure that it + // is properly cleaned up after the test. + mConnectionToCleanup = connection; + connection.setCanUseHiddenTabForSession(token, useHiddenTab); + } + + private static void ensureCompletedSpeculationForUrl( + final CustomTabsConnection connection, final String url) { + CriteriaHelper.pollUiThread(() -> { + Criteria.checkThat("Tab was not created", connection.getSpeculationParamsForTesting(), + Matchers.notNullValue()); + }, LONG_TIMEOUT_MS, CriteriaHelper.DEFAULT_POLLING_INTERVAL); + ChromeTabUtils.waitForTabPageLoaded(connection.getSpeculationParamsForTesting().tab, url); + } + + /** + * Tests that basic postMessage functionality works through sending a single postMessage + * request. + */ + @Test + @SmallTest + public void testPostMessageBasic() throws Exception { + final CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait(); + Context context = InstrumentationRegistry.getTargetContext(); + Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage); + final CustomTabsSessionToken token = + CustomTabsSessionToken.getSessionTokenFromIntent(intent); + Assert.assertTrue(connection.newSession(token)); + Assert.assertTrue(connection.requestPostMessageChannel(token, null)); + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + CriteriaHelper.pollInstrumentationThread(() -> { + final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); + Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(mTestPage)); + }); + Assert.assertTrue( + connection.postMessage(token, "Message", null) == CustomTabsService.RESULT_SUCCESS); + TestThreadUtils.runOnUiThreadBlocking( + (Runnable) () + -> mCustomTabActivityTestRule.getActivity().getActivityTab().loadUrl( + new LoadUrlParams(mTestPage2))); + CriteriaHelper.pollUiThread(() -> { + final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); + return ChromeTabUtils.isLoadingAndRenderingDone(currentTab); + }); + Assert.assertTrue(connection.postMessage(token, "Message", null) + == CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR); + } + + /** + * Tests that postMessage channel is not functioning after web contents get destroyed and also + * not breaking things. + */ + @Test + @SmallTest + public void testPostMessageWebContentsDestroyed() throws Exception { + final CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait(); + Context context = InstrumentationRegistry.getTargetContext(); + Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage); + final CustomTabsSessionToken token = + CustomTabsSessionToken.getSessionTokenFromIntent(intent); + Assert.assertTrue(connection.newSession(token)); + Assert.assertTrue(connection.requestPostMessageChannel(token, null)); + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + CriteriaHelper.pollInstrumentationThread(() -> { + final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); + Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(mTestPage)); + }); + Assert.assertTrue( + connection.postMessage(token, "Message", null) == CustomTabsService.RESULT_SUCCESS); + + final CallbackHelper renderProcessCallback = new CallbackHelper(); + new WebContentsObserver(mCustomTabActivityTestRule.getWebContents()) { + @Override + public void renderProcessGone(boolean wasOomProtected) { + renderProcessCallback.notifyCalled(); + } + }; + PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> { + WebContentsUtils.simulateRendererKilled( + mCustomTabActivityTestRule.getActivity().getActivityTab().getWebContents(), + false); + }); + renderProcessCallback.waitForCallback(0); + Assert.assertTrue(connection.postMessage(token, "Message", null) + == CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR); + } + + /** + * Tests whether validatePostMessageOrigin is necessary for making successful postMessage + * requests. + */ + @Test + @SmallTest + public void testPostMessageRequiresValidation() throws Exception { + final CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait(); + Context context = InstrumentationRegistry.getTargetContext(); + Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage); + final CustomTabsSessionToken token = + CustomTabsSessionToken.getSessionTokenFromIntent(intent); + Assert.assertTrue(connection.newSession(token)); + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + CriteriaHelper.pollInstrumentationThread(() -> { + final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); + Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(mTestPage)); + }); + Assert.assertTrue(connection.postMessage(token, "Message", null) + == CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR); + } + + /** + * Tests the sent postMessage requests not only return success, but is also received by page. + */ + @Test + @SmallTest + public void testPostMessageReceivedInPage() throws Exception { + final String url = + mWebServer.setResponse("/test.html", TITLE_FROM_POSTMESSAGE_TO_CHANNEL, null); + final CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait(); + Context context = InstrumentationRegistry.getTargetContext(); + Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, url); + final CustomTabsSessionToken token = + CustomTabsSessionToken.getSessionTokenFromIntent(intent); + Assert.assertTrue(connection.newSession(token)); + Assert.assertTrue(connection.requestPostMessageChannel(token, null)); + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + CriteriaHelper.pollInstrumentationThread(() -> { + final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); + Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(url)); + }); + Assert.assertTrue(connection.postMessage(token, "New title", null) + == CustomTabsService.RESULT_SUCCESS); + waitForTitle("New title"); + } + + /** + * Tests the postMessage requests sent from the page is received on the client side. + */ + @Test + @SmallTest + public void testPostMessageReceivedFromPage() throws Exception { + final CallbackHelper messageChannelHelper = new CallbackHelper(); + final CallbackHelper onPostMessageHelper = new CallbackHelper(); + final String url = mWebServer.setResponse("/test.html", MESSAGE_FROM_PAGE_TO_CHANNEL, null); + CustomTabsTestUtils.warmUpAndWait(); + final CustomTabsSession session = + CustomTabsTestUtils + .bindWithCallback(new CustomTabsCallback() { + @Override + public void onMessageChannelReady(Bundle extras) { + messageChannelHelper.notifyCalled(); + } + + @Override + public void onPostMessage(String message, Bundle extras) { + onPostMessageHelper.notifyCalled(); + } + }) + .session; + session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); + Intent intent = new CustomTabsIntent.Builder(session).build().intent; + intent.setData(Uri.parse(url)); + intent.setComponent(new ComponentName( + InstrumentationRegistry.getTargetContext(), ChromeLauncherActivity.class)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + Assert.assertTrue(session.postMessage("Message", null) + == CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR); + + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + messageChannelHelper.waitForCallback(0); + onPostMessageHelper.waitForCallback(0); + } + + /** + * Tests the postMessage requests sent from the page is received on the client side even though + * the request is sent after the page is created. + */ + @Test + @SmallTest + @DisabledTest(message = "https://crbug.com/692025") + public void testPostMessageReceivedFromPageWithLateRequest() throws Exception { + final CallbackHelper messageChannelHelper = new CallbackHelper(); + final CallbackHelper onPostMessageHelper = new CallbackHelper(); + final String url = mWebServer.setResponse("/test.html", MESSAGE_FROM_PAGE_TO_CHANNEL, null); + CustomTabsTestUtils.warmUpAndWait(); + final CustomTabsSession session = + CustomTabsTestUtils + .bindWithCallback(new CustomTabsCallback() { + @Override + public void onMessageChannelReady(Bundle extras) { + messageChannelHelper.notifyCalled(); + } + + @Override + public void onPostMessage(String message, Bundle extras) { + onPostMessageHelper.notifyCalled(); + } + }) + .session; + + Intent intent = new CustomTabsIntent.Builder(session).build().intent; + intent.setData(Uri.parse(url)); + intent.setComponent(new ComponentName( + InstrumentationRegistry.getTargetContext(), ChromeLauncherActivity.class)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + CriteriaHelper.pollInstrumentationThread(() -> { + final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); + Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(url)); + }); + + session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); + + messageChannelHelper.waitForCallback(0); + onPostMessageHelper.waitForCallback(0); + + Assert.assertTrue(session.postMessage("Message", null) == CustomTabsService.RESULT_SUCCESS); + } + + /** + * Tests a postMessage request chain can start while loading a hidden tab and continue + * afterwards. Request sent before the hidden tab start. + */ + @Test + @SmallTest + @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) + public void testPostMessageThroughHiddenTabWithRequestBeforeMayLaunchUrl() throws Exception { + sendPostMessageDuringHiddenTabTransition(BEFORE_MAY_LAUNCH_URL); + } + + /** + * Tests a postMessage request chain can start while loading a hidden tab and continue + * afterwards. Request sent after the hidden tab start and before intent launched. + */ + @Test + @SmallTest + @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) + public void testPostMessageThroughHiddenTabWithRequestBeforeIntent() throws Exception { + sendPostMessageDuringHiddenTabTransition(BEFORE_INTENT); + } + + /** + * Tests a postMessage request chain can start while loading a hidden tab and continue + * afterwards. Request sent after intent received. + */ + @Test + @SmallTest + @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) + public void testPostMessageThroughHiddenTabWithRequestAfterIntent() throws Exception { + sendPostMessageDuringHiddenTabTransition(AFTER_INTENT); + } + + private void sendPostMessageDuringHiddenTabTransition(int requestTime) throws Exception { + final CallbackHelper messageChannelHelper = new CallbackHelper(); + final String url = + mWebServer.setResponse("/test.html", TITLE_FROM_POSTMESSAGE_TO_CHANNEL, null); + final CustomTabsConnection connection = CustomTabsTestUtils.warmUpAndWait(); + + final CustomTabsSession session = + CustomTabsTestUtils + .bindWithCallback(new CustomTabsCallback() { + @Override + public void onMessageChannelReady(Bundle extras) { + messageChannelHelper.notifyCalled(); + } + }) + .session; + + Intent intent = new CustomTabsIntent.Builder(session).build().intent; + intent.setData(Uri.parse(url)); + intent.setComponent(new ComponentName( + InstrumentationRegistry.getTargetContext(), ChromeLauncherActivity.class)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + CustomTabsSessionToken token = CustomTabsSessionToken.getSessionTokenFromIntent(intent); + + boolean channelRequested = false; + String titleString = ""; + + if (requestTime == BEFORE_MAY_LAUNCH_URL) { + channelRequested = + session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); + Assert.assertTrue(channelRequested); + } + + setCanUseHiddenTabForSession(connection, token, true); + session.mayLaunchUrl(Uri.parse(url), null, null); + ensureCompletedSpeculationForUrl(connection, url); + + if (requestTime == BEFORE_INTENT) { + channelRequested = + session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); + Assert.assertTrue(channelRequested); + } + + if (channelRequested) { + messageChannelHelper.waitForCallback(0); + String currentMessage = "Prerendering "; + // Initial title update during prerender. + assertEquals( + CustomTabsService.RESULT_SUCCESS, session.postMessage(currentMessage, null)); + titleString = currentMessage; + } + + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + + CriteriaHelper.pollInstrumentationThread(() -> { + final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab(); + Criteria.checkThat(ChromeTabUtils.getUrlStringOnUiThread(currentTab), is(url)); + }); + + if (requestTime == AFTER_INTENT) { + channelRequested = + session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); + Assert.assertTrue(channelRequested); + messageChannelHelper.waitForCallback(0); + } + + String currentMessage = "and loading "; + // Update title again and verify both updates went through with the channel still intact. + assertEquals(CustomTabsService.RESULT_SUCCESS, session.postMessage(currentMessage, null)); + titleString += currentMessage; + + // Request a new channel, verify it was created. + session.requestPostMessageChannel(Uri.parse("https://www.example.com/")); + messageChannelHelper.waitForCallback(1); + + String newMessage = "and refreshing"; + // Update title again and verify both updates went through with the channel still intact. + assertEquals(CustomTabsService.RESULT_SUCCESS, session.postMessage(newMessage, null)); + titleString += newMessage; + + final String title = titleString; + waitForTitle(title); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java index 2237d3967..673568a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java
@@ -26,6 +26,7 @@ import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeTabbedActivity; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.gesturenav.NavigationSheetMediator.ItemProperties; import org.chromium.chrome.browser.profiles.Profile; @@ -34,7 +35,9 @@ import org.chromium.chrome.browser.ui.RootUiCoordinator; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.NavigationEntry; import org.chromium.content_public.browser.NavigationHistory; @@ -58,6 +61,8 @@ private static final int INVALID_NAVIGATION_INDEX = -1; private static final int NAVIGATION_INDEX_1 = 1; private static final int NAVIGATION_INDEX_2 = 5; + private static final int NAVIGATION_INDEX_3 = 9; + private static final int FULL_HISTORY_ENTRY_INDEX = 13; private BottomSheetController mBottomSheetController; @@ -88,6 +93,9 @@ mHistory.addEntry(new TestNavigationEntry(NAVIGATION_INDEX_2, new GURL(UrlUtils.encodeHtmlDataUri("<html>1</html>")), GURL.emptyGURL(), GURL.emptyGURL(), null, null, 0, 0)); + mHistory.addEntry( + new TestNavigationEntry(NAVIGATION_INDEX_3, new GURL(UrlConstants.NTP_URL), + GURL.emptyGURL(), GURL.emptyGURL(), null, null, 0, 0)); } @Override @@ -111,9 +119,18 @@ } @Override - public NavigationHistory getHistory(boolean forward) { - return mNavigationController.getDirectedNavigationHistory( + public NavigationHistory getHistory(boolean forward, boolean isOffTheRecord) { + NavigationHistory history = mNavigationController.getDirectedNavigationHistory( forward, MAXIMUM_HISTORY_ITEMS); + if (!isOffTheRecord) { + history.addEntry(new NavigationEntry(FULL_HISTORY_ENTRY_INDEX, + new GURL(UrlConstants.HISTORY_URL), GURL.emptyGURL(), GURL.emptyGURL(), + GURL.emptyGURL(), + mActivityTestRule.getActivity().getResources().getString( + R.string.show_full_history), + null, 0, 0)); + } + return history; } @Override @@ -132,7 +149,8 @@ @MediumTest public void testFaviconFetching() throws ExecutionException { TestNavigationController controller = new TestNavigationController(); - NavigationSheetCoordinator sheet = (NavigationSheetCoordinator) showPopup(controller); + NavigationSheetCoordinator sheet = + (NavigationSheetCoordinator) showPopup(controller, false); ListView listview = sheet.getContentView().findViewById(R.id.navigation_entries); CriteriaHelper.pollUiThread(() -> { @@ -148,7 +166,8 @@ @SmallTest public void testItemSelection() throws ExecutionException { TestNavigationController controller = new TestNavigationController(); - NavigationSheetCoordinator sheet = (NavigationSheetCoordinator) showPopup(controller); + NavigationSheetCoordinator sheet = + (NavigationSheetCoordinator) showPopup(controller, false); ListView listview = sheet.getContentView().findViewById(R.id.navigation_entries); CriteriaHelper.pollUiThread(() -> listview.getChildCount() >= 2); @@ -196,12 +215,75 @@ Assert.assertNull(TestThreadUtils.runOnUiThreadBlocking(this::getNavigationSheet)); } - private NavigationSheet showPopup(NavigationController controller) throws ExecutionException { + @Test + @MediumTest + @EnableFeatures({ChromeFeatureList.UPDATE_HISTORY_ENTRY_POINTS_IN_INCOGNITO}) + public void testFieldsForOffTheRecordProfile() throws ExecutionException { + TestNavigationController controller = new TestNavigationController(); + NavigationSheetCoordinator sheet = (NavigationSheetCoordinator) showPopup(controller, true); + ListView listview = sheet.getContentView().findViewById(R.id.navigation_entries); + + CriteriaHelper.pollUiThread(() -> { + boolean doesNewIncognitoTabItemPresent = false; + boolean doesShowFullHistoryItemPresent = false; + for (int i = 0; i < controller.mHistory.getEntryCount(); i++) { + ListItem item = (ListItem) listview.getAdapter().getItem(i); + String label = item.model.get(ItemProperties.LABEL); + String incognitoNTPText = mActivityTestRule.getActivity().getResources().getString( + R.string.menu_new_incognito_tab); + String fullHistoryText = mActivityTestRule.getActivity().getResources().getString( + R.string.show_full_history); + if (label.equals(incognitoNTPText)) { + doesNewIncognitoTabItemPresent = true; + } else if (label.equals(fullHistoryText)) { + doesShowFullHistoryItemPresent = true; + } + } + Assert.assertTrue(doesNewIncognitoTabItemPresent); + Assert.assertFalse(doesShowFullHistoryItemPresent); + }); + } + + @Test + @MediumTest + @EnableFeatures({ChromeFeatureList.UPDATE_HISTORY_ENTRY_POINTS_IN_INCOGNITO}) + public void testFieldsForRegularProfile() throws ExecutionException { + TestNavigationController controller = new TestNavigationController(); + NavigationSheetCoordinator sheet = + (NavigationSheetCoordinator) showPopup(controller, false); + ListView listview = sheet.getContentView().findViewById(R.id.navigation_entries); + + CriteriaHelper.pollUiThread(() -> { + boolean doesNewTabItemPresent = false; + boolean doesShowFullHisotryItemPresent = false; + for (int i = 0; i < controller.mHistory.getEntryCount(); i++) { + ListItem item = (ListItem) listview.getAdapter().getItem(i); + String label = item.model.get(ItemProperties.LABEL); + String regularNTPText = mActivityTestRule.getActivity().getResources().getString( + R.string.menu_new_tab); + String fullHistoryText = mActivityTestRule.getActivity().getResources().getString( + R.string.show_full_history); + if (label.equals(regularNTPText)) { + doesNewTabItemPresent = true; + } else if (label.equals(fullHistoryText)) { + doesShowFullHisotryItemPresent = true; + } + } + Assert.assertTrue(doesNewTabItemPresent); + Assert.assertTrue(doesShowFullHisotryItemPresent); + }); + } + + private NavigationSheet showPopup(NavigationController controller, boolean isOffTheRecord) + throws ExecutionException { return TestThreadUtils.runOnUiThreadBlocking(() -> { Tab tab = mActivityTestRule.getActivity().getActivityTabProvider().get(); - NavigationSheet navigationSheet = - NavigationSheet.create(tab.getContentView(), mActivityTestRule.getActivity(), - () -> mBottomSheetController, Profile.getLastUsedRegularProfile()); + Profile profile = Profile.getLastUsedRegularProfile(); + if (isOffTheRecord) { + profile = profile.getPrimaryOTRProfile(true); + } + NavigationSheet navigationSheet = NavigationSheet.create(tab.getContentView(), + mActivityTestRule.getActivity(), () -> mBottomSheetController, profile); navigationSheet.setDelegate(new TestSheetDelegate(controller)); navigationSheet.startAndExpand(false, false); return navigationSheet;
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index c235983..7aada7d 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2842,6 +2842,7 @@ "android/seccomp_support_detector.h", "android/send_tab_to_self/android_notification_handler.cc", "android/send_tab_to_self/android_notification_handler.h", + "android/send_tab_to_self/metrics_recorder.cc", "android/send_tab_to_self/send_tab_to_self_android_bridge.cc", "android/send_tab_to_self/send_tab_to_self_entry_bridge.cc", "android/send_tab_to_self/send_tab_to_self_entry_bridge.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index ae453d7..283aafb9 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -6757,12 +6757,6 @@ flag_descriptions::kSyncAutofillWalletOfferDataDescription, kOsAll, FEATURE_VALUE_TYPE(switches::kSyncAutofillWalletOfferData)}, -#if BUILDFLAG(IS_CHROMEOS_ASH) - {"enable-holding-space", flag_descriptions::kHoldingSpaceName, - flag_descriptions::kHoldingSpaceDescription, kOsCrOS, - FEATURE_VALUE_TYPE(ash::features::kTemporaryHoldingSpace)}, -#endif - #if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \ defined(OS_CHROMEOS) {"enable-oop-print-drivers", flag_descriptions::kEnableOopPrintDriversName,
diff --git a/chrome/browser/android/autofill_assistant/starter_android.cc b/chrome/browser/android/autofill_assistant/starter_android.cc index 8f826b3..2803029 100644 --- a/chrome/browser/android/autofill_assistant/starter_android.cc +++ b/chrome/browser/android/autofill_assistant/starter_android.cc
@@ -73,7 +73,7 @@ jlong jtest_service_request_sender_to_inject = Java_AutofillAssistantServiceInjector_getServiceRequestSenderToInject( base::android::AttachCurrentThread()); - std::unique_ptr<ServiceRequestSender> test_service_request_sender = nullptr; + std::unique_ptr<ServiceRequestSender> test_service_request_sender; if (jtest_service_request_sender_to_inject) { test_service_request_sender.reset(static_cast<ServiceRequestSender*>( reinterpret_cast<void*>(jtest_service_request_sender_to_inject))); @@ -117,13 +117,11 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller, jboolean is_interactable) { - if (!is_interactable || !starter_) { + if (!starter_) { return; } - // The tab has become interactable again. Users may have adjusted their - // settings, so we need to check them again. - starter_->CheckSettings(); + starter_->OnTabInteractabilityChanged(is_interactable); } void StarterAndroid::OnActivityAttachmentChanged( @@ -248,20 +246,7 @@ /* onboarding_shown = */ false, /* is_direct_action = */ false, jinitial_url); - starter_->Start(std::move(trigger_context), - base::BindOnce(&StarterAndroid::OnStarterDone, - weak_ptr_factory_.GetWeakPtr())); -} - -void StarterAndroid::OnStarterDone( - bool start_regular_script, - GURL url, - std::unique_ptr<TriggerContext> trigger_context, - const base::Optional<TriggerScriptProto>& trigger_script) { - if (!start_regular_script) { - return; - } - StartRegularScript(url, std::move(trigger_context), trigger_script); + starter_->Start(std::move(trigger_context)); } void StarterAndroid::StartRegularScript(
diff --git a/chrome/browser/android/autofill_assistant/starter_android.h b/chrome/browser/android/autofill_assistant/starter_android.h index 5fa0375..47f3c6a 100644 --- a/chrome/browser/android/autofill_assistant/starter_android.h +++ b/chrome/browser/android/autofill_assistant/starter_android.h
@@ -48,6 +48,10 @@ CreateTriggerScriptUiDelegate() override; std::unique_ptr<ServiceRequestSender> GetTriggerScriptRequestSenderToInject() override; + void StartRegularScript( + GURL url, + std::unique_ptr<TriggerContext> trigger_context, + const base::Optional<TriggerScriptProto>& trigger_script) override; WebsiteLoginManager* GetWebsiteLoginManager() const override; version_info::Channel GetChannel() const override; bool GetFeatureModuleInstalled() const override; @@ -117,19 +121,6 @@ void CreateJavaDependenciesIfNecessary(); - void OnStarterDone(bool start_regular_script, - GURL url, - std::unique_ptr<TriggerContext> trigger_context, - const base::Optional<TriggerScriptProto>& trigger_script); - - // Start autofill-assistant on |url| using |trigger_context|. This will - // create/reuse a ClientAndroid instance which is tied to the WebContents and - // thus independent of this starter. - void StartRegularScript( - GURL url, - std::unique_ptr<TriggerContext> trigger_context, - const base::Optional<TriggerScriptProto>& trigger_script); - WEB_CONTENTS_USER_DATA_KEY_DECL(); content::WebContents* web_contents_; std::unique_ptr<Starter> starter_;
diff --git a/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.cc b/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.cc index 6df93c7e..97b506d 100644 --- a/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.cc +++ b/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.cc
@@ -74,16 +74,6 @@ return trigger_script_coordinator_->OnBackButtonPressed(); } -void TriggerScriptBridgeAndroid::OnTabInteractabilityChanged( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& jcaller, - jboolean jinteractable) { - if (!trigger_script_coordinator_) { - return; - } - trigger_script_coordinator_->OnTabInteractabilityChanged(jinteractable); -} - void TriggerScriptBridgeAndroid::OnKeyboardVisibilityChanged( JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller,
diff --git a/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.h b/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.h index 2105530..e04dd05 100644 --- a/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.h +++ b/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.h
@@ -47,12 +47,6 @@ bool OnBackButtonPressed(JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller); - // Called by the UI when the tab's interactability has changed. - void OnTabInteractabilityChanged( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& jcaller, - jboolean jinteractable); - // Called by the UI when the keyboard was shown or hidden. void OnKeyboardVisibilityChanged( JNIEnv* env,
diff --git a/chrome/browser/android/send_tab_to_self/metrics_recorder.cc b/chrome/browser/android/send_tab_to_self/metrics_recorder.cc new file mode 100644 index 0000000..1cd10fc --- /dev/null +++ b/chrome/browser/android/send_tab_to_self/metrics_recorder.cc
@@ -0,0 +1,17 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/android/jni_string.h" +#include "base/android/scoped_java_ref.h" +#include "chrome/browser/share/android/jni_headers/MetricsRecorder_jni.h" +#include "components/send_tab_to_self/metrics_util.h" + +namespace send_tab_to_self { + +// Static free function declared and called directly from java. +static void JNI_MetricsRecorder_RecordDeviceClickedInShareSheet(JNIEnv* env) { + RecordDeviceClicked(ShareEntryPoint::kShareSheet); +} + +} // namespace send_tab_to_self
diff --git a/chrome/browser/apps/app_service/publishers/borealis_apps.cc b/chrome/browser/apps/app_service/publishers/borealis_apps.cc index e3708ea..254d28ac 100644 --- a/chrome/browser/apps/app_service/publishers/borealis_apps.cc +++ b/chrome/browser/apps/app_service/publishers/borealis_apps.cc
@@ -190,9 +190,7 @@ GetMenuModelCallback callback) { apps::mojom::MenuItemsPtr menu_items = apps::mojom::MenuItems::New(); - // TODO(b/171353248): Uninstall for individual apps (not just the parent one). - if (app_id == borealis::kBorealisAppId && - borealis::BorealisService::GetForProfile(profile_) + if (borealis::BorealisService::GetForProfile(profile_) ->Features() .IsEnabled()) { AddCommandItem(ash::UNINSTALL, IDS_APP_LIST_UNINSTALL_ITEM, &menu_items);
diff --git a/chrome/browser/apps/platform_apps/api/sync_file_system/sync_file_system_api.cc b/chrome/browser/apps/platform_apps/api/sync_file_system/sync_file_system_api.cc index 62dc426..82e7346 100644 --- a/chrome/browser/apps/platform_apps/api/sync_file_system/sync_file_system_api.cc +++ b/chrome/browser/apps/platform_apps/api/sync_file_system/sync_file_system_api.cc
@@ -108,8 +108,8 @@ BindOnce( &storage::FileSystemContext::DeleteFileSystem, file_system_context, url::Origin::Create(source_url().GetOrigin()), file_system_url.type(), - Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem, - this))); + BindOnce(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem, + this))); return RespondLater(); } @@ -212,7 +212,7 @@ sync_file_system_service->GetFileSyncStatus( file_system_url, - Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus, this)); + BindOnce(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus, this)); return RespondLater(); } @@ -264,8 +264,8 @@ sync_file_system_service->GetFileSyncStatus( file_system_url, - Bind(&SyncFileSystemGetFileStatusesFunction::DidGetFileStatus, this, - file_system_url)); + BindOnce(&SyncFileSystemGetFileStatusesFunction::DidGetFileStatus, this, + file_system_url)); } return RespondLater(); @@ -339,8 +339,8 @@ &storage::QuotaManager::GetUsageAndQuotaForWebApps, quota_manager, url::Origin::Create(source_url()), storage::FileSystemTypeToQuotaStorageType(file_system_url.type()), - Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota, - this))); + BindOnce(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota, + this))); return RespondLater(); }
diff --git a/chrome/browser/ash/borealis/borealis_app_uninstaller.cc b/chrome/browser/ash/borealis/borealis_app_uninstaller.cc index 35aec43..e1e3370 100644 --- a/chrome/browser/ash/borealis/borealis_app_uninstaller.cc +++ b/chrome/browser/ash/borealis/borealis_app_uninstaller.cc
@@ -4,23 +4,85 @@ #include "chrome/browser/ash/borealis/borealis_app_uninstaller.h" +#include "base/base64.h" #include "base/logging.h" +#include "chrome/browser/ash/borealis/borealis_app_launcher.h" #include "chrome/browser/ash/borealis/borealis_installer.h" #include "chrome/browser/ash/borealis/borealis_service.h" #include "chrome/browser/ash/borealis/borealis_util.h" +#include "chrome/browser/ash/guest_os/guest_os_registry_service.h" +#include "chrome/browser/ash/guest_os/guest_os_registry_service_factory.h" namespace borealis { +const char kBorealisUninstallPrefix[] = "Oi8vdW5pbnN0YWxsLw=="; + BorealisAppUninstaller::BorealisAppUninstaller(Profile* profile) : profile_(profile) {} void BorealisAppUninstaller::Uninstall(std::string app_id, OnUninstalledCallback callback) { - // TODO(b/171353248): Allow uninstalling other apps - DCHECK(app_id == kBorealisAppId); + if (app_id == kBorealisAppId || app_id == kBorealisMainAppId) { + BorealisService::GetForProfile(profile_)->Installer().Uninstall( + base::BindOnce( + [](OnUninstalledCallback callback, BorealisUninstallResult result) { + if (result != BorealisUninstallResult::kSuccess) { + LOG(ERROR) << "Failed to uninstall borealis"; + std::move(callback).Run(UninstallResult::kError); + return; + } + std::move(callback).Run(UninstallResult::kSuccess); + }, + std::move(callback))); + return; + } - BorealisService::GetForProfile(profile_)->Installer().Uninstall( - base::DoNothing()); + base::Optional<guest_os::GuestOsRegistryService::Registration> registration = + guest_os::GuestOsRegistryServiceFactory::GetForProfile(profile_) + ->GetRegistration(app_id); + if (!registration.has_value()) { + LOG(ERROR) << "Tried to uninstall an application that does not exist in " + "the registry"; + std::move(callback).Run(UninstallResult::kError); + return; + } + base::Optional<int> uninstall_app_id = GetBorealisAppId(registration->Exec()); + if (!uninstall_app_id.has_value()) { + LOG(ERROR) << "Couldn't retrieve the borealis app id from the exec " + "information provided"; + std::move(callback).Run(UninstallResult::kError); + return; + } + // TODO(174282035): Changeup string usage and finish tests. + base::Optional<guest_os::GuestOsRegistryService::Registration> main_app = + guest_os::GuestOsRegistryServiceFactory::GetForProfile(profile_) + ->GetRegistration(kBorealisMainAppId); + if (!main_app.has_value()) { + LOG(ERROR) << "Failed to retrieve a registration for the Borealis main app"; + std::move(callback).Run(UninstallResult::kError); + return; + } + std::string prefix; + if (!base::Base64Decode(kBorealisUninstallPrefix, &prefix)) { + LOG(ERROR) << "Couldn't decode the Borealis uninstall prefix"; + std::move(callback).Run(UninstallResult::kError); + return; + } + std::string uninstall_string = main_app->DesktopFileId() + prefix + + base::NumberToString(*uninstall_app_id); + borealis::BorealisService::GetForProfile(profile_)->AppLauncher().Launch( + kBorealisMainAppId, {uninstall_string}, + base::BindOnce( + [](OnUninstalledCallback callback, + BorealisAppLauncher::LaunchResult result) { + if (result != BorealisAppLauncher::LaunchResult::kSuccess) { + LOG(ERROR) << "Failed to uninstall a borealis application"; + std::move(callback).Run(UninstallResult::kError); + return; + } + std::move(callback).Run(UninstallResult::kSuccess); + }, + std::move(callback))); } } // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_app_uninstaller_unittest.cc b/chrome/browser/ash/borealis/borealis_app_uninstaller_unittest.cc new file mode 100644 index 0000000..ea156231 --- /dev/null +++ b/chrome/browser/ash/borealis/borealis_app_uninstaller_unittest.cc
@@ -0,0 +1,151 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ash/borealis/borealis_app_uninstaller.h" + +#include <memory> + +#include "base/bind.h" +#include "base/test/bind.h" +#include "chrome/browser/ash/borealis/borealis_installer.h" +#include "chrome/browser/ash/borealis/borealis_service_fake.h" +#include "chrome/browser/ash/borealis/borealis_util.h" +#include "chrome/browser/ash/guest_os/guest_os_registry_service.h" +#include "chrome/browser/ash/guest_os/guest_os_registry_service_factory.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace borealis { +namespace { + +class CallbackFactory : public testing::StrictMock<testing::MockFunction<void( + BorealisAppUninstaller::UninstallResult)>> { + public: + base::OnceCallback<void(BorealisAppUninstaller::UninstallResult)> BindOnce() { + return base::BindOnce(&CallbackFactory::Call, base::Unretained(this)); + } +}; + +class BorealisInstallerMock : public BorealisInstaller { + public: + BorealisInstallerMock() = default; + ~BorealisInstallerMock() = default; + MOCK_METHOD(bool, IsProcessing, (), ()); + MOCK_METHOD(void, Start, (), ()); + MOCK_METHOD(void, Cancel, (), ()); + MOCK_METHOD(void, + Uninstall, + (base::OnceCallback<void(BorealisUninstallResult)>), + ()); + MOCK_METHOD(void, AddObserver, (Observer * observer), ()); + MOCK_METHOD(void, RemoveObserver, (Observer * observer), ()); +}; + +class BorealisAppUninstallerTest : public testing::Test { + public: + BorealisAppUninstallerTest() = default; + + protected: + void SetUp() override { + CreateProfile(); + mock_installer_ = + std::make_unique<testing::StrictMock<BorealisInstallerMock>>(); + BorealisServiceFake* fake_service = + BorealisServiceFake::UseFakeForTesting(profile_.get()); + fake_service->SetInstallerForTesting(mock_installer_.get()); + } + + void TearDown() override { + profile_.reset(); + mock_installer_.reset(); + } + + // Sets up the registry with a single app. Returns its app id. + std::string SetDummyApp(const std::string& desktop_file_id, + std::string exec) { + vm_tools::apps::ApplicationList list; + list.set_vm_name("test_vm_name"); + list.set_container_name("test_container_name"); + vm_tools::apps::App* app = list.add_apps(); + app->set_desktop_file_id(desktop_file_id); + vm_tools::apps::App::LocaleString::Entry* entry = + app->mutable_name()->add_values(); + entry->set_locale(std::string()); + entry->set_value(desktop_file_id); + app->set_no_display(false); + guest_os::GuestOsRegistryServiceFactory::GetForProfile(profile_.get()) + ->UpdateApplicationList(list); + return guest_os::GuestOsRegistryService::GenerateAppId( + desktop_file_id, list.vm_name(), list.container_name()); + } + + std::unique_ptr<TestingProfile> profile_; + std::unique_ptr<testing::StrictMock<BorealisInstallerMock>> mock_installer_; + content::BrowserTaskEnvironment task_environment_; + + private: + void CreateProfile() { + TestingProfile::Builder profile_builder; + profile_builder.SetProfileName("defaultprofile"); + profile_ = profile_builder.Build(); + } +}; + +TEST_F(BorealisAppUninstallerTest, BorealisAppUninstallsBorealis) { + CallbackFactory callback_check; + EXPECT_CALL(callback_check, + Call(BorealisAppUninstaller::UninstallResult::kSuccess)); + BorealisAppUninstaller uninstaller = BorealisAppUninstaller(profile_.get()); + EXPECT_CALL(*mock_installer_, Uninstall(testing::_)) + .WillOnce(testing::Invoke( + [](base::OnceCallback<void(BorealisUninstallResult)> callback) { + std::move(callback).Run(BorealisUninstallResult::kSuccess); + })); + uninstaller.Uninstall(kBorealisAppId, callback_check.BindOnce()); +} + +TEST_F(BorealisAppUninstallerTest, BorealisMainAppUninstallsBorealis) { + CallbackFactory callback_check; + EXPECT_CALL(callback_check, + Call(BorealisAppUninstaller::UninstallResult::kSuccess)); + BorealisAppUninstaller uninstaller = BorealisAppUninstaller(profile_.get()); + EXPECT_CALL(*mock_installer_, Uninstall(testing::_)) + .WillOnce(testing::Invoke( + [](base::OnceCallback<void(BorealisUninstallResult)> callback) { + std::move(callback).Run(BorealisUninstallResult::kSuccess); + })); + uninstaller.Uninstall(kBorealisMainAppId, callback_check.BindOnce()); +} + +TEST_F(BorealisAppUninstallerTest, NonExistentAppFails) { + CallbackFactory callback_check; + EXPECT_CALL(callback_check, + Call(BorealisAppUninstaller::UninstallResult::kError)); + BorealisAppUninstaller uninstaller = BorealisAppUninstaller(profile_.get()); + uninstaller.Uninstall("IdontExist", callback_check.BindOnce()); +} + +TEST_F(BorealisAppUninstallerTest, AppWithEmptyExecFails) { + std::string baz_id = SetDummyApp("baz.desktop", ""); + CallbackFactory callback_check; + EXPECT_CALL(callback_check, + Call(BorealisAppUninstaller::UninstallResult::kError)); + BorealisAppUninstaller uninstaller = BorealisAppUninstaller(profile_.get()); + uninstaller.Uninstall(baz_id, callback_check.BindOnce()); +} + +TEST_F(BorealisAppUninstallerTest, AppWithInvalidExecFails) { + std::string baz_id = SetDummyApp("test.desktop", "desktopname with no id"); + CallbackFactory callback_check; + EXPECT_CALL(callback_check, + Call(BorealisAppUninstaller::UninstallResult::kError)); + BorealisAppUninstaller uninstaller = BorealisAppUninstaller(profile_.get()); + uninstaller.Uninstall(baz_id, callback_check.BindOnce()); +} +// TODO(174282035): Add additional tests when strings are changed. + +} // namespace +} // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_util.cc b/chrome/browser/ash/borealis/borealis_util.cc index 968b9ca5..8375c447 100644 --- a/chrome/browser/ash/borealis/borealis_util.cc +++ b/chrome/browser/ash/borealis/borealis_util.cc
@@ -15,8 +15,13 @@ // are updated. const char kBorealisAppIdRegex[] = "([^/]+\\d+)"; -bool GetBorealisAppId(std::string exec, int& app_id) { - return RE2::PartialMatch(exec, kBorealisAppIdRegex, &app_id); +base::Optional<int> GetBorealisAppId(std::string exec) { + int app_id; + if (RE2::PartialMatch(exec, kBorealisAppIdRegex, &app_id)) { + return app_id; + } else { + return base::nullopt_t(0); + } } } // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_util.h b/chrome/browser/ash/borealis/borealis_util.h index 361be39..5dddd2fc 100644 --- a/chrome/browser/ash/borealis/borealis_util.h +++ b/chrome/browser/ash/borealis/borealis_util.h
@@ -30,7 +30,7 @@ // returns true if successful. // TODO(b/173547790): This should probably be moved when we've decided // the details of how/where it will be used. -bool GetBorealisAppId(std::string exec, int& app_id); +base::Optional<int> GetBorealisAppId(std::string exec); // Shows the splash screen (borealis_splash_screen_view). void ShowBorealisSplashScreenView(Profile* profile);
diff --git a/chrome/browser/ash/login/app_mode/auto_launched_kiosk_browsertest.cc b/chrome/browser/ash/login/app_mode/auto_launched_kiosk_browsertest.cc index 59dbd61..5340028e 100644 --- a/chrome/browser/ash/login/app_mode/auto_launched_kiosk_browsertest.cc +++ b/chrome/browser/ash/login/app_mode/auto_launched_kiosk_browsertest.cc
@@ -252,6 +252,9 @@ std::unique_ptr<ExtensionTestMessageListener> app_window_loaded_listener_; std::unique_ptr<TerminationObserver> termination_observer_; + DeviceStateMixin device_state_{ + &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED}; + private: FakeCWS fake_cws_; extensions::SandboxedUnpacker::ScopedVerifierFormatOverrideForTest @@ -262,9 +265,6 @@ &mixin_host_, embedded_test_server()}; LoginManagerMixin login_manager_{&mixin_host_, {}}; - DeviceStateMixin device_state_{ - &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED}; - DISALLOW_COPY_AND_ASSIGN(AutoLaunchedKioskTest); }; @@ -305,6 +305,38 @@ ASSERT_TRUE(CloseAppWindow(KioskAppsMixin::kKioskAppId)); } +class AutoLaunchedKioskEphemeralUsersTest : public AutoLaunchedKioskTest { + public: + AutoLaunchedKioskEphemeralUsersTest() = default; + ~AutoLaunchedKioskEphemeralUsersTest() override = default; + + // AutoLaunchedKioskTest: + void SetUpInProcessBrowserTestFixture() override { + AutoLaunchedKioskTest::SetUpInProcessBrowserTestFixture(); + std::unique_ptr<chromeos::ScopedDevicePolicyUpdate> device_policy_update = + device_state_.RequestDevicePolicyUpdate(); + device_policy_update->policy_payload() + ->mutable_ephemeral_users_enabled() + ->set_ephemeral_users_enabled(true); + } +}; + +IN_PROC_BROWSER_TEST_F(AutoLaunchedKioskEphemeralUsersTest, Launches) { + // Set up default network connections, so tests think the device is online. + DBusThreadManager::Get() + ->GetShillManagerClient() + ->GetTestInterface() + ->SetupDefaultEnvironment(); + + // Check that policy flags have not been lost. + ExpectCommandLineHasDefaultPolicySwitches( + *base::CommandLine::ForCurrentProcess()); + + EXPECT_TRUE(app_window_loaded_listener_->WaitUntilSatisfied()); + + EXPECT_TRUE(IsKioskAppAutoLaunched(KioskAppsMixin::kKioskAppId)); +} + // Used to test app auto-launch flow when the launched app is not kiosk enabled. class AutoLaunchedNonKioskEnabledAppTest : public AutoLaunchedKioskTest { public:
diff --git a/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc b/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc index 7f47f0a1..0bba6ff 100644 --- a/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc +++ b/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc
@@ -43,8 +43,11 @@ bool HasPolicyValue(const PrefService* pref_service, const char* value) { const base::ListValue* quick_unlock_allowlist = pref_service->GetList(prefs::kQuickUnlockModeAllowlist); - return quick_unlock_allowlist->Find(base::Value(value)) != - quick_unlock_allowlist->end(); + // TODO(crbug.com/1187106): Use base::Contains once |quick_unlock_allowlist| + // is not a ListValue. + return std::find(quick_unlock_allowlist->begin(), + quick_unlock_allowlist->end(), + base::Value(value)) != quick_unlock_allowlist->end(); } } // namespace
diff --git a/chrome/browser/ash/login/session/user_session_manager.cc b/chrome/browser/ash/login/session/user_session_manager.cc index d711164..e13a16f 100644 --- a/chrome/browser/ash/login/session/user_session_manager.cc +++ b/chrome/browser/ash/login/session/user_session_manager.cc
@@ -1228,8 +1228,10 @@ SetFirstLoginPrefs(profile, user_context.GetPublicSessionLocale(), user_context.GetPublicSessionInputMethod()); + // Kiosks do not have onboarding. if (user_manager->GetPrimaryUser() == user && - !user_manager->IsUserNonCryptohomeDataEphemeral(user->GetAccountId())) { + !user_manager->IsUserNonCryptohomeDataEphemeral(user->GetAccountId()) && + !user->IsKioskType()) { LoginDisplayHost::default_host() ->GetSigninUI() ->SetAuthSessionForOnboarding(user_context);
diff --git a/chrome/browser/ash/login/ui/login_display_host_common.cc b/chrome/browser/ash/login/ui/login_display_host_common.cc index ffcceb8..a0e7298 100644 --- a/chrome/browser/ash/login/ui/login_display_host_common.cc +++ b/chrome/browser/ash/login/ui/login_display_host_common.cc
@@ -418,7 +418,9 @@ const UserContext& user_context) { if (PinSetupScreen::ShouldSkipBecauseOfPolicy()) return; - GetWizardController()->SetAuthSessionForOnboarding(user_context); + // WizardController may not be initialized in the WebUI login display host. + if (GetWizardController()) + GetWizardController()->SetAuthSessionForOnboarding(user_context); } void LoginDisplayHostCommon::StartEncryptionMigration(
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc index de70cf4..d60c076 100644 --- a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc +++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
@@ -1267,7 +1267,10 @@ const base::ListValue& reporting_users = *(GetLocalState()->GetList(::prefs::kReportingUsers)); base::Value user_id_value(FullyCanonicalize(user_id)); - return !(reporting_users.Find(user_id_value) == reporting_users.end()); + // TODO(crbug.com/1187106): Use base::Contains once |reporting_users| is not a + // ListValue. + return !(std::find(reporting_users.begin(), reporting_users.end(), + user_id_value) == reporting_users.end()); } bool ChromeUserManagerImpl::IsManagedSessionEnabledForUser(
diff --git a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc index 1066d81..f9344e1 100644 --- a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc +++ b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
@@ -219,7 +219,7 @@ // test doesn't provide coverage for that. // Note: If "object-src" is not set in the CSP, the `<embed>` element fails to // load and times out. - constexpr char loadPdf[] = R"( + constexpr char kLoadPdf[] = R"( (() => { const embedBlob = document.createElement('embed'); embedBlob.type ='application/pdf'; @@ -235,7 +235,7 @@ })(); )"; - EXPECT_EQ(true, MediaAppUiBrowserTest::EvalJsInAppFrame(app, loadPdf)); + EXPECT_EQ(true, MediaAppUiBrowserTest::EvalJsInAppFrame(app, kLoadPdf)); } // These tests try to load files bundled in our CIPD package. The CIPD package @@ -257,7 +257,7 @@ // button and is calculated from a hash of the label ("Annotate"). This id is // used since cl/366443893 because the UI toolkit has loose guarantees about // where the actual label appears in the shadow DOM. - constexpr char clickAnnotate[] = R"( + constexpr char kClickAnnotate[] = R"( (async () => { const annotateButton = await waitForNode( '#icon-button-3709949292', ['backlight-app-bar', 'backlight-app']); @@ -265,13 +265,13 @@ return true; })(); )"; - EXPECT_EQ(true, MediaAppUiBrowserTest::EvalJsInAppFrame(app, clickAnnotate)); + EXPECT_EQ(true, MediaAppUiBrowserTest::EvalJsInAppFrame(app, kClickAnnotate)); // Checks ink is loaded for images by ensuring the ink engine canvas has a non // zero width and height attributes (checking <canvas.width/height is // insufficient since it has a default width of 300 and height of 150). // Note: The loading of ink engine elements can be async. - constexpr char checkInkLoaded[] = R"( + constexpr char kCheckInkLoaded[] = R"( (async () => { const inkEngineCanvas = await waitForNode( 'canvas#ink-engine[width]', ['backlight-image-handler']); @@ -284,7 +284,8 @@ )"; // TODO(b/175840855): Consider checking `inkEngineCanvas` size, it is // currently different to image size. - EXPECT_EQ(true, MediaAppUiBrowserTest::EvalJsInAppFrame(app, checkInkLoaded)); + EXPECT_EQ(true, + MediaAppUiBrowserTest::EvalJsInAppFrame(app, kCheckInkLoaded)); } // Tests that clicking on the 'Info' button in the app bar opens the information @@ -300,7 +301,7 @@ EXPECT_EQ("640x480", WaitForImageAlt(app, kFileJpeg640x480)); // Expect info panel to not be open on first load. - constexpr char hasInfoPanelOpen[] = R"( + constexpr char kHasInfoPanelOpen[] = R"( (async () => { const metadataPanel = await getNode( 'backlight-metadata-panel', ['backlight-image-handler']); @@ -308,14 +309,14 @@ })(); )"; EXPECT_EQ(false, - MediaAppUiBrowserTest::EvalJsInAppFrame(app, hasInfoPanelOpen)); + MediaAppUiBrowserTest::EvalJsInAppFrame(app, kHasInfoPanelOpen)); // Click info button. // Note the button id (icon-button-2283726) corresponds to the info panel // button and is calculated from a hash of the label ("Info"). This id is // used because the UI toolkit has loose guarantees about where the actual // label appears in the shadow DOM. - constexpr char clickInfo[] = R"( + constexpr char kClickInfo[] = R"( (async () => { const infoButton = await getNode( '#icon-button-2283726', ['backlight-app-bar', 'backlight-app']); @@ -323,11 +324,11 @@ return true; })(); )"; - EXPECT_EQ(true, MediaAppUiBrowserTest::EvalJsInAppFrame(app, clickInfo)); + EXPECT_EQ(true, MediaAppUiBrowserTest::EvalJsInAppFrame(app, kClickInfo)); // Expect info panel to be open after clicking info button. EXPECT_EQ(true, - MediaAppUiBrowserTest::EvalJsInAppFrame(app, hasInfoPanelOpen)); + MediaAppUiBrowserTest::EvalJsInAppFrame(app, kHasInfoPanelOpen)); } #endif // BUILDFLAG(ENABLE_CROS_MEDIA_APP)
diff --git a/chrome/browser/autofill/autofill_provider_browsertest.cc b/chrome/browser/autofill/autofill_provider_browsertest.cc index 1760ea43..a227f45 100644 --- a/chrome/browser/autofill/autofill_provider_browsertest.cc +++ b/chrome/browser/autofill/autofill_provider_browsertest.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include "base/base_switches.h" -#include "base/bind.h" #include "base/macros.h" #include "build/build_config.h" #include "chrome/browser/ui/browser.h" @@ -13,7 +12,6 @@ #include "chrome/test/base/ui_test_utils.h" #include "components/autofill/content/browser/content_autofill_driver.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" -#include "components/autofill/core/browser/android_autofill_manager.h" #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_provider.h" #include "components/autofill/core/common/autofill_features.h" @@ -121,8 +119,18 @@ ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( web_contents, autofill_client_.get(), "en-US", BrowserAutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER, - base::BindRepeating(&AndroidAutofillManager::Create, - autofill_provider_.get())); + autofill_provider_.get()); + } + + void ReplaceAutofillDriver() { + content::WebContents* web_contents = WebContents(); + // Set AutofillProvider for current WebContents. + ContentAutofillDriverFactory* factory = + ContentAutofillDriverFactory::FromWebContents(web_contents); + ContentAutofillDriver* driver = + factory->DriverForFrame(web_contents->GetMainFrame()); + driver->SetAutofillProviderForTesting(autofill_provider_.get(), + autofill_client_.get()); } void TearDownOnMainThread() override { @@ -158,6 +166,7 @@ } void SetLabelChangeExpectationAndTriggerQuery() { + ReplaceAutofillDriver(); // One query for the single click, and a second query when the typing is // simulated. base::RunLoop run_loop;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index b5e1015..75335bcc 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -224,6 +224,7 @@ "//chromeos/disks", "//chromeos/geolocation", "//chromeos/ime:gencode", + "//chromeos/language/language_packs", "//chromeos/login/auth", "//chromeos/login/login_state", "//chromeos/login/session", @@ -3682,6 +3683,7 @@ "../ash/base/file_flusher_unittest.cc", "../ash/bluetooth/debug_logs_manager_unittest.cc", "../ash/borealis/borealis_app_launcher_unittest.cc", + "../ash/borealis/borealis_app_uninstaller_unittest.cc", "../ash/borealis/borealis_context_manager_unittest.cc", "../ash/borealis/borealis_context_unittest.cc", "../ash/borealis/borealis_features_unittest.cc",
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc index a95ee00..14f3e2b 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -8,7 +8,6 @@ #include <memory> #include "ash/constants/ash_features.h" -#include "ash/public/cpp/ash_features.h" #include "base/base64.h" #include "base/bind.h" #include "base/path_service.h" @@ -355,25 +354,6 @@ file_manager::EventRouter* event_router_ = nullptr; }; -// Parameterize by whether holding space feature is enabled. -class FileManagerPrivateHoldingSpaceApiTest - : public FileManagerPrivateApiTest, - public testing::WithParamInterface<bool> { - public: - FileManagerPrivateHoldingSpaceApiTest() { - scoped_feature_list_.InitWithFeatureState( - ash::features::kTemporaryHoldingSpace, GetParam()); - } - ~FileManagerPrivateHoldingSpaceApiTest() override = default; - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -INSTANTIATE_TEST_SUITE_P(HoldingSpaceEnabled, - FileManagerPrivateHoldingSpaceApiTest, - testing::Bool()); - IN_PROC_BROWSER_TEST_F(FileManagerPrivateApiTest, Mount) { using chromeos::file_system_provider::IconSet; profile()->GetPrefs()->SetBoolean(drive::prefs::kDisableDrive, true); @@ -618,7 +598,7 @@ EXPECT_TRUE(response_helper.GetResponse()); } -IN_PROC_BROWSER_TEST_P(FileManagerPrivateHoldingSpaceApiTest, HoldingSpace) { +IN_PROC_BROWSER_TEST_F(FileManagerPrivateApiTest, HoldingSpace) { const base::FilePath test_dir = temp_dir_.GetPath(); AddLocalFileSystem(browser()->profile(), test_dir); @@ -635,14 +615,8 @@ ASSERT_TRUE(video_file.IsValid()); } - if (GetParam()) { - EXPECT_TRUE(RunExtensionTest({.name = "file_browser/holding_space"}, - {.load_as_component = true})); - } else { - EXPECT_TRUE( - RunExtensionTest({.name = "file_browser/holding_space_disabled"}, - {.load_as_component = true})); - } + EXPECT_TRUE(RunExtensionTest({.name = "file_browser/holding_space"}, + {.load_as_component = true})); } IN_PROC_BROWSER_TEST_F(FileManagerPrivateApiTest, GetVolumeRoot) {
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc index 71ef7ce..406414b 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -143,11 +143,6 @@ return *this; } - TestCase& EnableHoldingSpace(bool enable) { - options.enable_holding_space = enable; - return *this; - } - TestCase& DisableJsModules() { options.enable_js_modules = false; return *this; @@ -705,21 +700,13 @@ HoldingSpace, /* holding_space.js */ FilesAppBrowserTest, ::testing::Values( - TestCase("holdingSpaceWelcomeBannerWithFeatureDisabled") - .EnableHoldingSpace(false), - TestCase("holdingSpaceWelcomeBannerWithFeatureEnabled") - .EnableHoldingSpace(true), - TestCase("holdingSpaceWelcomeBannerWontShowAfterBeingDismissed") - .EnableHoldingSpace(true), - TestCase("holdingSpaceWelcomeBannerWontShowAfterReachingLimit") - .EnableHoldingSpace(true), + TestCase("holdingSpaceWelcomeBanner"), + TestCase("holdingSpaceWelcomeBannerWontShowAfterBeingDismissed"), + TestCase("holdingSpaceWelcomeBannerWontShowAfterReachingLimit"), TestCase("holdingSpaceWelcomeBannerWontShowForModalDialogs") - .EnableHoldingSpace(true) .WithBrowser(), - TestCase("holdingSpaceWelcomeBannerWontShowOnDrive") - .EnableHoldingSpace(true), - TestCase("holdingSpaceWelcomeBannerOnTabletModeChanged") - .EnableHoldingSpace(true))); + TestCase("holdingSpaceWelcomeBannerWontShowOnDrive"), + TestCase("holdingSpaceWelcomeBannerOnTabletModeChanged"))); WRAPPED_INSTANTIATE_TEST_SUITE_P( Transfer, /* transfer.js */
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc index 8dbb430..223802a0 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -1717,12 +1717,6 @@ disabled_features.push_back(chromeos::features::kFilesTrash); } - if (options.enable_holding_space) { - enabled_features.push_back(ash::features::kTemporaryHoldingSpace); - } else { - disabled_features.push_back(ash::features::kTemporaryHoldingSpace); - } - if (options.enable_js_modules) { enabled_features.push_back(chromeos::features::kFilesJsModules); } else {
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h index b817dff..a6b984e 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
@@ -109,9 +109,6 @@ // Whether test should enable trash. bool enable_trash = false; - // Whether test should enable holding space. - bool enable_holding_space = false; - // Whether test should run Files app UI as JS modules. bool enable_js_modules = true; };
diff --git a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc index 3abc2eb8..7a1e68e 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
@@ -5,7 +5,6 @@ #include "chrome/browser/chromeos/file_manager/file_manager_string_util.h" #include "ash/constants/ash_features.h" -#include "ash/public/cpp/ash_features.h" #include "base/feature_list.h" #include "base/logging.h" #include "base/strings/stringprintf.h" @@ -1078,8 +1077,6 @@ dict->SetBoolean( "FILTERS_IN_RECENTS_ENABLED", base::FeatureList::IsEnabled(chromeos::features::kFiltersInRecents)); - dict->SetBoolean("HOLDING_SPACE_ENABLED", - ash::features::IsTemporaryHoldingSpaceEnabled()); dict->SetBoolean("FILES_SINGLE_PARTITION_FORMAT_ENABLED", base::FeatureList::IsEnabled( chromeos::features::kFilesSinglePartitionFormat));
diff --git a/chrome/browser/chromeos/fileapi/recent_model.cc b/chrome/browser/chromeos/fileapi/recent_model.cc index 87dd00fb..32c7e27 100644 --- a/chrome/browser/chromeos/fileapi/recent_model.cc +++ b/chrome/browser/chromeos/fileapi/recent_model.cc
@@ -49,7 +49,7 @@ // Downloads / MyFiles. sources.emplace_back(std::make_unique<RecentDiskSource>( file_manager::util::GetDownloadsMountPointName(profile), - false /* ignore_dotfiles */, 0 /* max_depth unlimited */, + true /* ignore_dotfiles */, 0 /* max_depth unlimited */, "FileBrowser.Recent.LoadDownloads")); sources.emplace_back(std::make_unique<RecentDriveSource>(profile)); return sources;
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc b/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc index 55a75e3..a948c752 100644 --- a/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc +++ b/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
@@ -357,7 +357,8 @@ signin::IdentityManager* identity_manager = IdentityManagerFactory::GetForProfileIfExists(profile_); - signin::SetPrimaryAccount(identity_manager, "johnwayne@me.xyz"); + signin::SetPrimaryAccount(identity_manager, "johnwayne@me.xyz", + signin::ConsentLevel::kSync); engine_->Enable(kEngineIdUs); @@ -399,7 +400,8 @@ signin::IdentityManager* identity_manager = IdentityManagerFactory::GetForProfileIfExists(profile_); - signin::SetPrimaryAccount(identity_manager, "johnwayne@me.xyz"); + signin::SetPrimaryAccount(identity_manager, "johnwayne@me.xyz", + signin::ConsentLevel::kSync); engine_->Enable(kEngineIdUs);
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc index 3483eeeb..f060f2a 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc +++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
@@ -285,4 +285,10 @@ } } +void DeviceCloudPolicyStoreChromeOS::UpdateFirstPoliciesLoaded() { + CloudPolicyStore::UpdateFirstPoliciesLoaded(); + // Mark policies as loaded if we don't expect any policies to be loaded. + first_policies_loaded_ |= !install_attributes_->IsEnterpriseManaged(); +} + } // namespace policy
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h index 9bcf4164..64bd4aea 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h +++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h
@@ -60,6 +60,9 @@ void DeviceSettingsUpdated() override; void OnDeviceSettingsServiceShutdown() override; + // CloudPolicyStore: + void UpdateFirstPoliciesLoaded() override; + private: // Create a validator for |policy| with basic device policy configuration and // OnPolicyStored() as the completion callback.
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc index c10452b0..c341995 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc +++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc
@@ -85,6 +85,8 @@ void ExpectFailure(CloudPolicyStore::Status expected_status) { EXPECT_EQ(expected_status, store_->status()); EXPECT_TRUE(store_->is_initialized()); + EXPECT_EQ(!install_attributes_->IsEnterpriseManaged(), + store_->first_policies_loaded()); EXPECT_FALSE(store_->has_policy()); EXPECT_FALSE(store_->is_managed()); EXPECT_EQ(std::string(), store_->policy_signature_public_key()); @@ -93,6 +95,7 @@ void ExpectSuccess() { EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); EXPECT_TRUE(store_->is_initialized()); + EXPECT_TRUE(store_->first_policies_loaded()); EXPECT_TRUE(store_->has_policy()); EXPECT_TRUE(store_->is_managed()); EXPECT_TRUE(store_->policy());
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc index c5f813af..838a512 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.cc +++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -1140,30 +1140,35 @@ void DevToolsUIBindings::DevicesDiscoveryConfigUpdated() { base::DictionaryValue config; config.Set(kConfigDiscoverUsbDevices, - profile_->GetPrefs() - ->FindPreference(prefs::kDevToolsDiscoverUsbDevicesEnabled) - ->GetValue() - ->CreateDeepCopy()); + base::Value::ToUniquePtrValue( + profile_->GetPrefs() + ->FindPreference(prefs::kDevToolsDiscoverUsbDevicesEnabled) + ->GetValue() + ->Clone())); config.Set(kConfigPortForwardingEnabled, - profile_->GetPrefs() - ->FindPreference(prefs::kDevToolsPortForwardingEnabled) - ->GetValue() - ->CreateDeepCopy()); + base::Value::ToUniquePtrValue( + profile_->GetPrefs() + ->FindPreference(prefs::kDevToolsPortForwardingEnabled) + ->GetValue() + ->Clone())); config.Set(kConfigPortForwardingConfig, - profile_->GetPrefs() - ->FindPreference(prefs::kDevToolsPortForwardingConfig) - ->GetValue() - ->CreateDeepCopy()); + base::Value::ToUniquePtrValue( + profile_->GetPrefs() + ->FindPreference(prefs::kDevToolsPortForwardingConfig) + ->GetValue() + ->Clone())); config.Set(kConfigNetworkDiscoveryEnabled, - profile_->GetPrefs() - ->FindPreference(prefs::kDevToolsDiscoverTCPTargetsEnabled) - ->GetValue() - ->CreateDeepCopy()); + base::Value::ToUniquePtrValue( + profile_->GetPrefs() + ->FindPreference(prefs::kDevToolsDiscoverTCPTargetsEnabled) + ->GetValue() + ->Clone())); config.Set(kConfigNetworkDiscoveryConfig, - profile_->GetPrefs() - ->FindPreference(prefs::kDevToolsTCPDiscoveryConfig) - ->GetValue() - ->CreateDeepCopy()); + base::Value::ToUniquePtrValue( + profile_->GetPrefs() + ->FindPreference(prefs::kDevToolsTCPDiscoveryConfig) + ->GetValue() + ->Clone())); CallClientMethod("DevToolsAPI", "devicesDiscoveryConfigChanged", std::move(config)); }
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc index 7f76a77..b8921a4 100644 --- a/chrome/browser/extensions/api/identity/identity_apitest.cc +++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -463,7 +463,8 @@ ASSERT_FALSE( identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)); signin::MakeAccountAvailable(identity_manager, "primary@example.com"); - signin::SetPrimaryAccount(identity_manager, "primary@example.com"); + signin::SetPrimaryAccount(identity_manager, "primary@example.com", + signin::ConsentLevel::kSync); } else { FixOrAddSecondaryAccount(); }
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc index 5b932100..ca7e90b 100644 --- a/chrome/browser/extensions/external_provider_impl.cc +++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -370,8 +370,8 @@ extension->FindStringPath(kWebAppMigrationFlag); bool is_migrating_to_web_app = web_app_migration_flag && - web_app::IsPreinstalledAppInstallFeatureEnabled( - *web_app_migration_flag); + web_app::IsPreinstalledAppInstallFeatureEnabled(*web_app_migration_flag, + *profile_); bool keep_if_present = extension->FindBoolPath(kKeepIfPresent).value_or(false); if (keep_if_present || is_migrating_to_web_app) {
diff --git a/chrome/browser/extensions/preinstalled_apps.cc b/chrome/browser/extensions/preinstalled_apps.cc index 4e03dc8f..3294fe5 100644 --- a/chrome/browser/extensions/preinstalled_apps.cc +++ b/chrome/browser/extensions/preinstalled_apps.cc
@@ -188,7 +188,8 @@ pref.FindStringPath(kWebAppMigrationFlag); if (!web_app_flag) return false; // Isn't migrating. - if (web_app::IsPreinstalledAppInstallFeatureEnabled(*web_app_flag)) { + if (web_app::IsPreinstalledAppInstallFeatureEnabled(*web_app_flag, + *profile)) { // The feature is still enabled; it's responsible for the behavior. return false; }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 9d9e672..154c0a6 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1919,16 +1919,6 @@ "expiry_milestone": 76 }, { - "name": "enable-holding-space", - "owners": [ "//ash/public/cpp/holding_space/OWNERS" ], - "expiry_milestone": 90 - }, - { - "name": "enable-holding-space-previews", - "owners": [ "//ash/public/cpp/holding_space/OWNERS" ], - "expiry_milestone": 90 - }, - { "name": "enable-hosted-app-quit-notification", "owners": [ "ccameron" ], "expiry_milestone": 77 @@ -2098,12 +2088,12 @@ { "name": "enable-migrate-default-chrome-app-to-web-apps-gsuite", "owners": [ "alancutter", "desktop-pwas-team@google.com" ], - "expiry_milestone": 91 + "expiry_milestone": 94 }, { "name": "enable-migrate-default-chrome-app-to-web-apps-non-gsuite", "owners": [ "alancutter", "desktop-pwas-team@google.com" ], - "expiry_milestone": 91 + "expiry_milestone": 94 }, { "name": "enable-nacl",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index e6c98a1..94ac969b7 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -4535,14 +4535,6 @@ "Hides media notifications for ARC apps. Requires " "#enable-media-session-notifications to be enabled."; -const char kHoldingSpaceName[] = - "Quick access to screenshots, downloads, and files"; -const char kHoldingSpaceDescription[] = - "Enables quick access to screenshots, downloads, and important files which " - "aims to increase productivity by saving time. When enabled, access recent " - "screenshots and downloads from the shelf. Pin important files with the " - "Files App context menu to keep them one click away."; - const char kImeAssistAutocorrectName[] = "Enable assistive autocorrect"; const char kImeAssistAutocorrectDescription[] = "Enable assistive auto-correct features for native IME";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index f4cee371..c49f135 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -2639,12 +2639,6 @@ extern const char kHideArcMediaNotificationsName[]; extern const char kHideArcMediaNotificationsDescription[]; -extern const char kHoldingSpaceName[]; -extern const char kHoldingSpaceDescription[]; - -extern const char kHoldingSpacePreviewsName[]; -extern const char kHoldingSpacePreviewsDescription[]; - extern const char kImeAssistAutocorrectName[]; extern const char kImeAssistAutocorrectDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index bc9d3aa..7e79456f 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -258,6 +258,7 @@ &kTrustedWebActivityQualityEnforcementWarning, &kStartSurfaceAndroid, &kUmaBackgroundSessions, + &kUpdateHistoryEntryPointsInIncognito, &kUpdateNotificationSchedulingIntegration, &kUpdateNotificationScheduleServiceImmediateShowOption, &kVoiceSearchAudioCapturePolicy, @@ -309,6 +310,7 @@ &signin::kMobileIdentityConsistencyFRE, &switches::kDeprecateMenagerieAPI, &switches::kDecoupleSyncFromAndroidMasterSync, + &switches::kMinorModeSupport, &switches::kSyncUseSessionsUnregisterDelay, &subresource_filter::kSafeBrowsingSubresourceFilter, &video_tutorials::features::kVideoTutorials, @@ -722,6 +724,9 @@ const base::Feature kUmaBackgroundSessions{"UMABackgroundSessions", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kUpdateHistoryEntryPointsInIncognito{ + "UpdateHistoryEntryPointsInIncognito", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kUpdateNotificationSchedulingIntegration{ "UpdateNotificationSchedulingIntegration", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index ec7a8f76..7fbce753 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -149,6 +149,7 @@ extern const base::Feature kTrustedWebActivityQualityEnforcementWarning; extern const base::Feature kStartSurfaceAndroid; extern const base::Feature kUmaBackgroundSessions; +extern const base::Feature kUpdateHistoryEntryPointsInIncognito; extern const base::Feature kUpdateNotificationSchedulingIntegration; extern const base::Feature kUpdateNotificationScheduleServiceImmediateShowOption;
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 5a977e6..c5b52ab 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
@@ -376,6 +376,7 @@ public static final String MOBILE_IDENTITY_CONSISTENCY_M2 = "MobileIdentityConsistencyFRE"; public static final String MODAL_PERMISSION_DIALOG_VIEW = "ModalPermissionDialogView"; public static final String METRICS_SETTINGS_ANDROID = "MetricsSettingsAndroid"; + public static final String MINOR_MODE_SUPPORT = "MinorModeSupport"; public static final String NOTIFICATION_SUSPENDER = "NotificationSuspender"; public static final String OFFLINE_INDICATOR = "OfflineIndicator"; public static final String OFFLINE_INDICATOR_V2 = "OfflineIndicatorV2"; @@ -490,6 +491,8 @@ "UpdateNotificationSchedulingIntegration"; public static final String UPDATE_NOTIFICATION_IMMEDIATE_SHOW_OPTION = "UpdateNotificationScheduleServiceImmediateShowOption"; + public static final String UPDATE_HISTORY_ENTRY_POINTS_IN_INCOGNITO = + "UpdateHistoryEntryPointsInIncognito"; public static final String USE_CHIME_ANDROID_SDK = "UseChimeAndroidSdk"; public static final String USE_NOTIFICATION_COMPAT_BUILDER = "UseNotificationCompatBuilder"; public static final String VOICE_SEARCH_AUDIO_CAPTURE_POLICY = "VoiceSearchAudioCapturePolicy";
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager.cc b/chrome/browser/nearby_sharing/nearby_notification_manager.cc index 57e6bbdf..2a2d4a0f 100644 --- a/chrome/browser/nearby_sharing/nearby_notification_manager.cc +++ b/chrome/browser/nearby_sharing/nearby_notification_manager.cc
@@ -6,7 +6,6 @@ #include <string> -#include "ash/public/cpp/ash_features.h" #include "base/callback_helpers.h" #include "base/files/file_util.h" #include "base/notreached.h" @@ -883,15 +882,12 @@ NotificationHandler::Type::NEARBY_SHARE, notification, /*metadata=*/nullptr); - if (ash::features::IsTemporaryHoldingSpaceEnabled()) { - ash::HoldingSpaceKeyedService* holding_space_keyed_service = - ash::HoldingSpaceKeyedServiceFactory::GetInstance()->GetService( - profile_); - if (holding_space_keyed_service) { - for (const auto& file : share_target.file_attachments) { - if (file.file_path().has_value()) - holding_space_keyed_service->AddNearbyShare(file.file_path().value()); - } + ash::HoldingSpaceKeyedService* holding_space_keyed_service = + ash::HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(profile_); + if (holding_space_keyed_service) { + for (const auto& file : share_target.file_attachments) { + if (file.file_path().has_value()) + holding_space_keyed_service->AddNearbyShare(file.file_path().value()); } } }
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc index 571a9494..1f7dbd0 100644 --- a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
@@ -7,7 +7,6 @@ #include <memory> #include <vector> -#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/holding_space/holding_space_controller.h" #include "ash/public/cpp/holding_space/holding_space_item.h" #include "ash/public/cpp/holding_space/holding_space_model.h" @@ -1324,8 +1323,7 @@ NearbyFilesHoldingSpaceTest() : session_controller_(std::make_unique<TestSessionController>()), user_manager_(new ash::FakeChromeUserManager) { - scoped_feature_list_.InitWithFeatures( - {features::kNearbySharing, ash::features::kTemporaryHoldingSpace}, {}); + scoped_feature_list_.InitAndEnableFeature(features::kNearbySharing); holding_space_controller_ = std::make_unique<ash::HoldingSpaceController>(); profile_manager_ = CreateTestingProfileManager();
diff --git a/chrome/browser/notifications/alert_dispatcher_mojo.mm b/chrome/browser/notifications/alert_dispatcher_mojo.mm index feb1ee40b..b32798d 100644 --- a/chrome/browser/notifications/alert_dispatcher_mojo.mm +++ b/chrome/browser/notifications/alert_dispatcher_mojo.mm
@@ -64,7 +64,8 @@ } - (void)closeAllNotifications { - [[self serviceProxy] closeAllNotifications]; + if (_mojoService) + [[self serviceProxy] closeAllNotifications]; // We know that there are no more notifications after this. [self onServiceDisconnectedGracefully:YES]; }
diff --git a/chrome/browser/notifications/alert_dispatcher_mojo_unittest.mm b/chrome/browser/notifications/alert_dispatcher_mojo_unittest.mm index b4cdb74c..cf7dab0 100644 --- a/chrome/browser/notifications/alert_dispatcher_mojo_unittest.mm +++ b/chrome/browser/notifications/alert_dispatcher_mojo_unittest.mm
@@ -178,15 +178,6 @@ FakeMacNotificationProviderFactory* provider_factory_ = nullptr; }; -TEST_F(AlertDispatcherMojoTest, CloseAllNotifications) { - base::RunLoop run_loop; - // Expect that we disconnect after closing all notifications. - ExpectDisconnect(run_loop.QuitClosure()); - EXPECT_CALL(service(), CloseAllNotifications); - [alert_dispatcher_ closeAllNotifications]; - run_loop.Run(); -} - TEST_F(AlertDispatcherMojoTest, CloseNotificationAndDisconnect) { base::RunLoop run_loop; // Expect that we disconnect after closing the last notification. @@ -233,6 +224,13 @@ run_loop.Run(); ExpectKeepConnected(); + + base::RunLoop run_loop2; + // Expect that we disconnect after closing all notifications. + ExpectDisconnect(run_loop2.QuitClosure()); + EXPECT_CALL(service(), CloseAllNotifications); + [alert_dispatcher_ closeAllNotifications]; + run_loop2.Run(); } TEST_F(AlertDispatcherMojoTest, CloseProfileNotificationsAndDisconnect) {
diff --git a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc index 9f093b7..7bcb119 100644 --- a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc +++ b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
@@ -226,7 +226,8 @@ auto* identity_manager = IdentityManagerFactory::GetForProfile(browser()->profile()); ASSERT_TRUE(identity_manager); - signin::SetPrimaryAccount(identity_manager, GetTestUser()); + signin::SetPrimaryAccount(identity_manager, GetTestUser(), + signin::ConsentLevel::kSync); UserCloudPolicyManager* policy_manager = browser()->profile()->GetUserCloudPolicyManager();
diff --git a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc index cf0069d..cfa59cf5 100644 --- a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc +++ b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
@@ -177,7 +177,8 @@ // the username to the UserCloudPolicyValidator. auto* identity_manager = IdentityManagerFactory::GetForProfile(browser()->profile()); - signin::SetPrimaryAccount(identity_manager, "user@example.com"); + signin::SetPrimaryAccount(identity_manager, "user@example.com", + signin::ConsentLevel::kSync); ASSERT_TRUE(policy_manager()); policy_manager()->Connect(
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc index 3d0e85e..74f0229 100644 --- a/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc +++ b/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc
@@ -186,7 +186,7 @@ // the account id to the UserCloudPolicyValidator. signin::SetPrimaryAccount( IdentityManagerFactory::GetForProfile(browser()->profile()), - PolicyBuilder::kFakeUsername); + PolicyBuilder::kFakeUsername, signin::ConsentLevel::kSync); UserCloudPolicyManager* policy_manager = browser()->profile()->GetUserCloudPolicyManager();
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index 8e5fd2a..72b02e0 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -117,6 +117,7 @@ #include "components/search_engines/search_engines_pref_names.h" #include "components/search_engines/template_url.h" #include "components/search_engines/template_url_service.h" +#include "components/send_tab_to_self/metrics_util.h" #include "components/spellcheck/browser/pref_names.h" #include "components/spellcheck/browser/spellcheck_host_metrics.h" #include "components/spellcheck/common/spellcheck_common.h" @@ -2392,16 +2393,16 @@ case IDC_SEND_TAB_TO_SELF_SINGLE_TARGET: send_tab_to_self::ShareToSingleTarget( GetBrowser()->tab_strip_model()->GetActiveWebContents()); - send_tab_to_self::RecordSendTabToSelfClickResult( - send_tab_to_self::kContentMenu, SendTabToSelfClickResult::kClickItem); + send_tab_to_self::RecordDeviceClicked( + send_tab_to_self::ShareEntryPoint::kContentMenu); break; case IDC_CONTENT_LINK_SEND_TAB_TO_SELF_SINGLE_TARGET: send_tab_to_self::ShareToSingleTarget( GetBrowser()->tab_strip_model()->GetActiveWebContents(), params_.link_url); - send_tab_to_self::RecordSendTabToSelfClickResult( - send_tab_to_self::kLinkMenu, SendTabToSelfClickResult::kClickItem); + send_tab_to_self::RecordDeviceClicked( + send_tab_to_self::ShareEntryPoint::kLinkMenu); break; case IDC_CONTENT_CONTEXT_GENERATE_QR_CODE: {
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_button.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_button.html index a2eb61d..09bc60a 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_button.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_button.html
@@ -87,8 +87,8 @@ aria-label="[[_label(emoji, variants)]]"> [[emoji]] </button> -<paper-tooltip id="tooltip" for="button" fit-to-visible-bounds part="tooltip" - offset="8"> +<paper-tooltip id="tooltip" for="emoji-button" fit-to-visible-bounds + part="tooltip" offset="8"> [[tooltip]] </paper-tooltip> <template is="dom-if" if="[[variantsVisible]]">
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html index 670a25d..65f5667e 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
@@ -63,6 +63,10 @@ border: 2px solid var(--cr-toggle-color); } + #fake-focus-target { + position: absolute; + } + </style> <div id="heading" role="heading" aria-level="2" tabindex="0"> @@ -79,6 +83,7 @@ </button> </template> <div id="emoji"> + <div id="fake-focus-target" tabindex="-1"></div> <template is="dom-repeat" items="[[data.emoji]]"> <emoji-button emoji="[[getDisplayEmojiForEmoji(item.base.string)]]" variants="[[item.alternates]]" tooltip="[[getTooltipForEmoji(item.base)]]"
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html index a2e9ef48..9e67d04 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
@@ -86,6 +86,7 @@ .chevron { background-color: var(--cr-card-background-color); + border-radius: 0; height: var(--emoji-group-button-size); margin: 0; padding: 0; @@ -98,6 +99,10 @@ left: calc((var(--emoji-picker-width) - 2 * var(--emoji-picker-side-padding)) / 9 * 8 + var(--emoji-picker-side-padding)); + /* Icons may become visible to the right of this during scrolling without + * the additional padding. + */ + padding-inline-end: 5px; } #left-chevron {
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js index 88f89ce..816c085d 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
@@ -259,8 +259,8 @@ const group = this.shadowRoot.querySelector(`div[data-group="${newGroup}"]`); group.querySelector('emoji-group') - .shadowRoot.querySelector('emoji-button') - .focusButton(); + .shadowRoot.querySelector('#fake-focus-target') + .focus(); group.scrollIntoView(); }
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.html b/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.html index 1d7e40eb..84793a4 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.html
@@ -25,7 +25,6 @@ <dom-module id="cellular-networks-list"> <template> <style include="cr-shared-style os-settings-icons settings-shared iron-flex"> - :host > div { /* network-list is padded to the right to allow space for a ripple */ padding-inline-end: calc(var(--cr-section-padding) - @@ -39,14 +38,13 @@ } .cellular-network-list-header { - padding-bottom: 8px; + align-items: center; + display: flex; + height: 72px; + padding-bottom: 16px; padding-top: 16px; } - .esim-list-header { - padding-top: 6px; - } - .esim-list-title { align-self: center; } @@ -70,46 +68,78 @@ flex-direction: column; } - .add-button { - margin-inline-end: 2px; + #eidPopupButton { + --cr-icon-button-size: 18px; + cursor: pointer; + margin-inline-start: 4px; + } + + #alignEnd { + align-items: center; + display: flex; + margin-inline-end: 12px; margin-inline-start: auto; } - #eidPopupButton { - cursor: pointer; - margin-inline-start: 0; + #inhibitedSubtext { + color: var(--cr-secondary-text-color); + } + + paper-spinner-lite { + height: 20px; + width: 20px; } </style> <template is="dom-if" if="[[shouldShowEsimSection_(euicc_, cellularDeviceState, cellularDeviceState.*)]]" restamp> <div class="cellular-network-list-separator"></div> - <div class="cellular-network-list-header esim-list-header flex"> - <div class="esim-list-title">$i18n{cellularNetworkEsimLabel}</div> - <div class="flex-column"> - <cr-icon-button - id="eidPopupButton" - iron-icon="cr:info-outline" - title="$i18n{showEidPopupButtonLabel}" - aria-label="$i18n{showEidPopupButtonLabel}" - on-click="toggleEidPopup_"> - </cr-icon-button> - <template is="dom-if" if="[[shouldShowEidPopup_]]" restamp> - <cellular-eid-popup class="eid-popup" euicc="[[euicc_]]"> - </cellular-eid-popup> - </template> + <div class="cellular-network-list-header esim-list-header + flex settings-box-text"> + <div class="flex-column"> + <div class="flex header-row"> + <div class="esim-list-title"> + $i18n{cellularNetworkEsimLabel} + </div> + <div class="flex-column"> + <cr-icon-button + id="eidPopupButton" + iron-icon="cr:info-outline" + title="$i18n{showEidPopupButtonLabel}" + aria-label="$i18n{showEidPopupButtonLabel}" + on-click="toggleEidPopup_"> + </cr-icon-button> + <template is="dom-if" if="[[shouldShowEidPopup_]]" restamp> + <cellular-eid-popup class="eid-popup" euicc="[[euicc_]]"> + </cellular-eid-popup> + </template> + </div> + </div> + <div id="inhibitedSubtext" class="header-row secondary-box-text" + hidden="[[!isDeviceInhibited_(cellularDeviceState, + cellularDeviceState.inhibitReason)]]"> + [[getInhibitedSubtextMessage_(cellularDeviceState, + cellularDeviceState.inhibitReason)]] + </div> + </div> + <div id="alignEnd"> + <paper-spinner-lite id="inhibitedSpinner" + active="[[isDeviceInhibited_(cellularDeviceState, + cellularDeviceState.inhibitReason)]]"> + </paper-spinner-lite> + <template is="dom-if" if="[[showAddESimButton_(cellularDeviceState, + globalPolicy)]]" restamp> + <cr-icon-button class="icon-add-cellular add-button" + aria-label="$i18n{internetAddCellular}" id="addESimButton" + disabled="[[isDeviceInhibited_(cellularDeviceState, + cellularDeviceState.inhibitReason)]]" + on-click="onAddEsimButtonTap_"> + </cr-icon-button> + </template> + </div> </div> - <template is="dom-if" - if="[[showAddESimButton_(cellularDeviceState, globalPolicy)]]" restamp> - <cr-icon-button class="icon-add-cellular add-button" - aria-label="$i18n{internetAddCellular}" id="addESimButton" - disabled="[[isDeviceInhibited_(cellularDeviceState, - cellularDeviceState.inhibitReason)]]" - on-click="onAddEsimButtonTap_"> - </cr-icon-button> - </template> </div> - <template is="dom-if" - if="[[shouldShowNetworkSublist_(eSimNetworks_, eSimPendingProfileItems_)]]" restamp> + <template is="dom-if" if="[[shouldShowNetworkSublist_(eSimNetworks_, + eSimPendingProfileItems_)]]" restamp> <div class="cellular-network-content"> <network-list id="esimNetworkList" show-buttons show-technology-badge="[[showTechnologyBadge]]" @@ -119,9 +149,8 @@ </network-list> </div> </template> - <template - is="dom-if" - if="[[!shouldShowNetworkSublist_(eSimNetworks_, eSimPendingProfileItems_)]]" restamp> + <template is="dom-if" if="[[!shouldShowNetworkSublist_(eSimNetworks_, + eSimPendingProfileItems_)]]" restamp> <div id="eSimNoNetworkFound" class="cellular-network-content cellular-not-setup"> <settings-localized-link @@ -137,7 +166,7 @@ if="[[shouldShowPSimSection_(cellularDeviceState, cellularDeviceState.*)]]" restamp> <div class="cellular-network-list-separator"></div> - <div class="cellular-network-list-header"> + <div class="cellular-network-list-header settings-box-text"> $i18n{cellularNetworkPsimLabel} </div> <template
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.js b/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.js index 394719b..bb19d2290 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.js +++ b/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.js
@@ -488,4 +488,32 @@ getAddEsimButton() { return /** @type {?CrIconButtonElement} */ (this.$$('#addESimButton')); }, + + /** + * @return {string} Inhibited subtext message. + * @private + */ + getInhibitedSubtextMessage_() { + if (!this.cellularDeviceState) { + return ''; + } + + const mojom = chromeos.networkConfig.mojom.InhibitReason; + const inhibitReason = this.cellularDeviceState.inhibitReason; + + switch (inhibitReason) { + case mojom.kInstallingProfile: + return this.i18n('cellularNetworkInstallingProfile'); + case mojom.kRenamingProfile: + return this.i18n('cellularNetworkRenamingProfile'); + case mojom.kRemovingProfile: + return this.i18n('cellularNetworkRemovingProfile'); + case mojom.kConnectingToProfile: + return this.i18n('cellularNetworkConnectingToProfile'); + case mojom.kRefreshingProfileList: + return this.i18n('cellularNetworRefreshingProfileListProfile'); + } + + return ''; + }, });
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html index a328a20..f5051c5 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html
@@ -82,9 +82,6 @@ border-top: none; } </style> - <template is="dom-if" if="[[disabled_]]" restamp> - <cellular-banner device-state="[[deviceState_]]"></cellular-banner> - </template> <!-- Title section: Icon + name + connection state. --> <div id="titleDiv" class="settings-box first"> <div class="start layout horizontal center">
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.html b/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.html index f0225532..9ab9db0 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.html
@@ -35,6 +35,11 @@ min-height: var(--settings-row-min-height); } + #cellularNetworkList { + /* No extra margin-top when displaying the cellular network list. */ + margin-top: calc(-1*var(--cr-section-vertical-margin)); + } + /* Set padding on children instead of the container itself to ensure that separator lines can fill the entire width of the page. */ #networkListDiv > * { @@ -97,10 +102,6 @@ padding-inline-start: 0; } </style> - <template is="dom-if" restamp - if="[[isDeviceInhibited_(deviceState, deviceState.inhibitReason)]]"> - <cellular-banner device-state="[[deviceState]]"></cellular-banner> - </template> <template is="dom-if" if="[[enableToggleIsVisible_(deviceState)]]"> <div class="settings-box first"> <div id="onOff" class="start" on$="[[deviceIsEnabled_(deviceState)]]"
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js b/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js index 9570e7c2..b614cdd 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js +++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js
@@ -311,7 +311,14 @@ this.hasCompletedScanSinceLastEnabled_ = this.showSpinner && !this.deviceState.scanning && this.deviceState.deviceState === mojom.DeviceStateType.kEnabled; - this.showSpinner = !!this.deviceState.scanning; + + // If the cellular network list is showing and currently inhibited, there + // is a separate spinner that shows in the CellularNetworkList. + if (this.shouldShowCellularNetworkList_() && this.isDeviceInhibited_()) { + this.showSpinner = false; + } else { + this.showSpinner = !!this.deviceState.scanning; + } } // Scans should only be triggered by the "networks" subpage.
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html index 9cb24589..27dcb4fb 100644 --- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html +++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
@@ -100,6 +100,22 @@ clip: rect(0, 0, 0, 0); position: fixed; } + + #searchHistoryTextBox { + background-color: var(--google-grey-50); + border: 1px solid var(--google-grey-200); + border-radius: 4px; + margin-top: 12px; + padding: 12px; + } + + /* dark mode */ + @media (prefers-color-scheme: dark) { + #searchHistoryTextBox { + background-color: rgba(0, 0, 0, .3); + border-color: transparent; + } + } </style> <cr-dialog id="clearBrowsingDataDialog" @@ -164,7 +180,7 @@ </settings-checkbox> <div id="searchHistoryTextBox" hidden="[[!shouldShowSearchHistoryLabel_]]"> - $i18nRaw{clearSearchHistorySummarySignedIn} + $i18nRaw{clearSearchHistorySummarySignedIn} </div> </div> <div id="advanced-tab">
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc index 7fe293c1..aea823fb 100644 --- a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc +++ b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc
@@ -76,12 +76,6 @@ link_url); } -void RecordSendTabToSelfClickResult(const std::string& entry_point, - SendTabToSelfClickResult state) { - base::UmaHistogramEnumeration("SendTabToSelf." + entry_point + ".ClickResult", - state); -} - size_t GetValidDeviceCount(Profile* profile) { SendTabToSelfSyncService* service = SendTabToSelfSyncServiceFactory::GetForProfile(profile);
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h index faf553b0..b9bd40d 100644 --- a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h +++ b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h
@@ -16,24 +16,8 @@ class WebContents; } -// State of the send tab to self option in the context menu. -// These values are persisted to logs. Entries should not be renumbered and -// numeric values should never be reused. -enum class SendTabToSelfClickResult { - kShowItem = 0, - kClickItem = 1, - kShowDeviceList = 2, - kMaxValue = kShowDeviceList, -}; - namespace send_tab_to_self { -const char kOmniboxIcon[] = "OmniboxIcon"; -const char kContentMenu[] = "ContentMenu"; -const char kLinkMenu[] = "LinkMenu"; -const char kOmniboxMenu[] = "OmniboxMenu"; -const char kTabMenu[] = "TabMenu"; - enum SendTabToSelfMenuType { kTab, kOmnibox, kContent, kLink }; // Adds a new entry to SendTabToSelfModel when user clicks a target device. Will @@ -48,11 +32,6 @@ void ShareToSingleTarget(content::WebContents* tab, const GURL& link_url = GURL()); -// Records whether the user click to send a tab or link when send tab to self -// entry point is shown. -void RecordSendTabToSelfClickResult(const std::string& entry_point, - SendTabToSelfClickResult state); - // Gets the count of valid device number. size_t GetValidDeviceCount(Profile* profile);
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc index 0f6b3fb..19c20eb 100644 --- a/chrome/browser/sessions/better_session_restore_browsertest.cc +++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -527,10 +527,13 @@ // ... but not if the content setting is set to clear on exit. CookieSettingsFactory::GetForProfile(new_browser->profile()) ->SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY); - // ... unless background mode is active. + EnableBackgroundMode(); new_browser = QuitBrowserAndRestore(new_browser, false); - CheckReloadedPageRestored(new_browser); + if (browser_defaults::kBrowserAliveWithNoWindows) + CheckReloadedPageRestored(new_browser); + else + CheckReloadedPageNotRestored(new_browser); DisableBackgroundMode(); new_browser = QuitBrowserAndRestore(new_browser, false); @@ -798,10 +801,13 @@ // ... but not if the content setting is set to clear on exit. CookieSettingsFactory::GetForProfile(new_browser->profile()) ->SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY); - // ... unless background mode is active. + EnableBackgroundMode(); new_browser = QuitBrowserAndRestore(new_browser, false); - NavigateAndCheckStoredData(new_browser, "cookies.html"); + if (browser_defaults::kBrowserAliveWithNoWindows) + NavigateAndCheckStoredData(new_browser, "cookies.html"); + else + StoreDataWithPage(new_browser, "cookies.html"); DisableBackgroundMode(); new_browser = QuitBrowserAndRestore(new_browser, false); if (browser_defaults::kBrowserAliveWithNoWindows) @@ -846,7 +852,10 @@ StoreDataWithPage("session_cookies.html"); EnableBackgroundMode(); Browser* new_browser = QuitBrowserAndRestore(browser(), false); - NavigateAndCheckStoredData(new_browser, "session_cookies.html"); + if (browser_defaults::kBrowserAliveWithNoWindows) + NavigateAndCheckStoredData(new_browser, "session_cookies.html"); + else + StoreDataWithPage(new_browser, "session_cookies.html"); DisableBackgroundMode(); new_browser = QuitBrowserAndRestore(new_browser, false); if (browser_defaults::kBrowserAliveWithNoWindows)
diff --git a/chrome/browser/sessions/session_data_service.cc b/chrome/browser/sessions/session_data_service.cc index 6d3d4b12..010da88 100644 --- a/chrome/browser/sessions/session_data_service.cc +++ b/chrome/browser/sessions/session_data_service.cc
@@ -5,8 +5,6 @@ #include "chrome/browser/sessions/session_data_service.h" #include "base/bind.h" -#include "chrome/browser/background/background_mode_manager.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/defaults.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_data_deleter.h" @@ -45,12 +43,9 @@ return; // Clear session data if the last window for a profile has been closed and - // closing the last window would normally close Chrome, unless background mode - // is active. Tests don't have a background_mode_manager. - if (browser_defaults::kBrowserAliveWithNoWindows || - g_browser_process->background_mode_manager()->IsBackgroundModeActive()) { + // closing the last window would normally close Chrome. + if (browser_defaults::kBrowserAliveWithNoWindows) return; - } // Check for any open windows for the current profile that we aren't tracking. for (auto* browser : *BrowserList::GetInstance()) {
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc index ad43a3d3f2..0cb1e123 100644 --- a/chrome/browser/sessions/session_service.cc +++ b/chrome/browser/sessions/session_service.cc
@@ -16,12 +16,13 @@ #include "base/metrics/histogram_functions.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/launch_utils.h" -#include "chrome/browser/background/background_mode_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/buildflags.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_attributes_entry.h" +#include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/sessions/session_common_utils.h" #include "chrome/browser/sessions/session_data_deleter.h"
diff --git a/chrome/browser/share/android/BUILD.gn b/chrome/browser/share/android/BUILD.gn index 38ee4ff..70dafd8 100644 --- a/chrome/browser/share/android/BUILD.gn +++ b/chrome/browser/share/android/BUILD.gn
@@ -41,6 +41,7 @@ "java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsTabServiceFactory.java", "java/src/org/chromium/chrome/browser/share/qrcode/QRCodeGenerationRequest.java", "java/src/org/chromium/chrome/browser/share/screenshot/EditorScreenshotTask.java", + "java/src/org/chromium/chrome/browser/share/send_tab_to_self/MetricsRecorder.java", "java/src/org/chromium/chrome/browser/share/send_tab_to_self/NotificationManager.java", "java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfAndroidBridge.java", "java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfEntry.java",
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DevicePickerBottomSheetContent.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DevicePickerBottomSheetContent.java index 3b49c22..1b3de8e 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DevicePickerBottomSheetContent.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DevicePickerBottomSheetContent.java
@@ -18,7 +18,6 @@ import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfMetrics.SendTabToSelfShareClickResult; import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.settings.SettingsLauncher; @@ -175,8 +174,7 @@ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - SendTabToSelfShareClickResult.recordClickResult( - SendTabToSelfShareClickResult.ClickType.CLICK_ITEM); + MetricsRecorder.recordDeviceClickedInShareSheet(); TargetDeviceInfo targetDeviceInfo = mAdapter.getItem(position); SendTabToSelfAndroidBridge.addEntry(
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/MetricsRecorder.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/MetricsRecorder.java new file mode 100644 index 0000000..5d5dbb6 --- /dev/null +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/MetricsRecorder.java
@@ -0,0 +1,23 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.share.send_tab_to_self; + +import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; + +/** + * Class that captures all the metrics needed for Send Tab To Self on Android. + */ +@JNINamespace("send_tab_to_self") +class MetricsRecorder { + public static void recordDeviceClickedInShareSheet() { + MetricsRecorderJni.get().recordDeviceClickedInShareSheet(); + } + + @NativeMethods + interface Natives { + void recordDeviceClickedInShareSheet(); + } +}
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfMetrics.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfMetrics.java deleted file mode 100644 index e528b069..0000000 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfMetrics.java +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.share.send_tab_to_self; - -import androidx.annotation.IntDef; - -import org.chromium.base.metrics.RecordHistogram; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Class that captures all the metrics needed for Send Tab To Self on Android. - */ -class SendTabToSelfMetrics { - /** - * Metrics captured when a user initiates and completes the sending flow. - */ - static class SendTabToSelfShareClickResult { - @Retention(RetentionPolicy.SOURCE) - @IntDef({ClickType.SHOW_ITEM, ClickType.CLICK_ITEM, ClickType.SHOW_DEVICE_LIST}) - @interface ClickType { - // These values are used for UMA. Don't reuse or reorder values. - // If you add something, update NUM_ENTRIES.This must be kept in sync with - // send_tab_to_self_desktop_util.h - int SHOW_ITEM = 0; - int CLICK_ITEM = 1; - int SHOW_DEVICE_LIST = 2; - int NUM_ENTRIES = 3; - } - - static void recordClickResult(@ClickType int result) { - RecordHistogram.recordEnumeratedHistogram( - "SendTabToSelf.AndroidShareSheet.ClickResult", result, ClickType.NUM_ENTRIES); - } - } -}
diff --git a/chrome/browser/share/android/java_sources.gni b/chrome/browser/share/android/java_sources.gni index f32f301..78fd3513 100644 --- a/chrome/browser/share/android/java_sources.gni +++ b/chrome/browser/share/android/java_sources.gni
@@ -53,6 +53,7 @@ "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewProperties.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DevicePickerBottomSheetAdapter.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DevicePickerBottomSheetContent.java", + "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/MetricsRecorder.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/NotificationManager.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/NotificationSharedPrefManager.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfAndroidBridge.java", @@ -60,7 +61,6 @@ "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfEntry.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfInfoBar.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfInfoBarController.java", - "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfMetrics.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfModelObserverBridge.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/TargetDeviceInfo.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java",
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SigninCheckerTest.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SigninCheckerTest.java index 9985f5a8..2a51a9a 100644 --- a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SigninCheckerTest.java +++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SigninCheckerTest.java
@@ -74,7 +74,7 @@ final CoreAccountInfo expectedPrimaryAccount = mAccountManagerTestRule.addAccount(newAccountEmail); - mAccountManagerTestRule.removeAccountAndWaitForSeeding(oldAccount.getEmail()); + mAccountManagerTestRule.removeAccount(oldAccount.getEmail()); CriteriaHelper.pollUiThread(() -> { return expectedPrimaryAccount.equals( @@ -92,7 +92,7 @@ when(mAccountRenameCheckerDelegateMock.getNewNameOfRenamedAccount(oldAccount.getEmail())) .thenReturn(newAccountEmail); - mAccountManagerTestRule.removeAccountAndWaitForSeeding(oldAccount.getEmail()); + mAccountManagerTestRule.removeAccount(oldAccount.getEmail()); CriteriaHelper.pollUiThread(() -> { return !IdentityServicesProvider.get() @@ -109,7 +109,7 @@ final CoreAccountInfo oldAccount = mAccountManagerTestRule.addTestAccountThenSigninAndEnableSync(); - mAccountManagerTestRule.removeAccountAndWaitForSeeding(oldAccount.getEmail()); + mAccountManagerTestRule.removeAccount(oldAccount.getEmail()); CriteriaHelper.pollUiThread(() -> { return !IdentityServicesProvider.get()
diff --git a/chrome/browser/speech/chrome_speech_recognition_service.cc b/chrome/browser/speech/chrome_speech_recognition_service.cc index 5476a4d..d513ec6 100644 --- a/chrome/browser/speech/chrome_speech_recognition_service.cc +++ b/chrome/browser/speech/chrome_speech_recognition_service.cc
@@ -24,9 +24,8 @@ ChromeSpeechRecognitionService::ChromeSpeechRecognitionService( content::BrowserContext* context) - : context_(context), - enable_soda_( - base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) {} + : enable_soda_(base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)), + context_(context) {} ChromeSpeechRecognitionService::~ChromeSpeechRecognitionService() = default; @@ -69,12 +68,15 @@ DCHECK(profile_prefs); DCHECK(global_prefs); - auto binary_path = global_prefs->GetFilePath(prefs::kSodaBinaryPath); - auto config_path = - ChromeSpeechRecognitionService::GetSodaConfigPath(profile_prefs); - if (enable_soda_ && (binary_path.empty() || config_path.empty())) { - LOG(ERROR) << "Unable to find SODA files on the device."; - return; + base::FilePath binary_path, config_path; + if (enable_soda_) { + binary_path = global_prefs->GetFilePath(prefs::kSodaBinaryPath); + config_path = + ChromeSpeechRecognitionService::GetSodaConfigPath(profile_prefs); + if (binary_path.empty() || config_path.empty()) { + LOG(ERROR) << "Unable to find SODA files on the device."; + return; + } } content::ServiceProcessHost::Launch(
diff --git a/chrome/browser/speech/chrome_speech_recognition_service.h b/chrome/browser/speech/chrome_speech_recognition_service.h index d90f23b..b7bb770 100644 --- a/chrome/browser/speech/chrome_speech_recognition_service.h +++ b/chrome/browser/speech/chrome_speech_recognition_service.h
@@ -39,6 +39,11 @@ // media::mojom::SpeechRecognitionServiceClient void OnNetworkServiceDisconnect() override; + protected: + // A flag indicating whether to use the Speech On-Device API (SODA) for speech + // recognition. + const bool enable_soda_; + private: // Launches the speech recognition service in a sandboxed utility process. void LaunchIfNotRunning(); @@ -49,10 +54,6 @@ // The browser context associated with the keyed service. content::BrowserContext* const context_; - // A flag indicating whether to use the Speech On-Device API (SODA) for speech - // recognition. - const bool enable_soda_; - // The remote to the speech recognition service. The browser will not launch a // new speech recognition service process if this remote is already bound. mojo::Remote<media::mojom::SpeechRecognitionService>
diff --git a/chrome/browser/speech/cros_speech_recognition_service.cc b/chrome/browser/speech/cros_speech_recognition_service.cc index c783fd26..19d2f972 100644 --- a/chrome/browser/speech/cros_speech_recognition_service.cc +++ b/chrome/browser/speech/cros_speech_recognition_service.cc
@@ -16,9 +16,7 @@ CrosSpeechRecognitionService::CrosSpeechRecognitionService( content::BrowserContext* context) - : ChromeSpeechRecognitionService(context), - enable_soda_( - base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) {} + : ChromeSpeechRecognitionService(context) {} CrosSpeechRecognitionService::~CrosSpeechRecognitionService() {}
diff --git a/chrome/browser/speech/cros_speech_recognition_service.h b/chrome/browser/speech/cros_speech_recognition_service.h index 97dfee5..948061df 100644 --- a/chrome/browser/speech/cros_speech_recognition_service.h +++ b/chrome/browser/speech/cros_speech_recognition_service.h
@@ -50,7 +50,6 @@ base::FilePath& languagepack_path); mojo::ReceiverSet<media::mojom::SpeechRecognitionContext> speech_recognition_contexts_; - const bool enable_soda_; }; } // namespace speech
diff --git a/chrome/browser/subresource_filter/chrome_content_subresource_filter_throttle_manager_factory.cc b/chrome/browser/subresource_filter/chrome_content_subresource_filter_throttle_manager_factory.cc index e7e33ee..0d5541d 100644 --- a/chrome/browser/subresource_filter/chrome_content_subresource_filter_throttle_manager_factory.cc +++ b/chrome/browser/subresource_filter/chrome_content_subresource_filter_throttle_manager_factory.cc
@@ -8,7 +8,6 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h" -#include "components/infobars/content/content_infobar_manager.h" #include "components/safe_browsing/core/db/database_manager.h" #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h" #include "components/subresource_filter/content/browser/ruleset_service.h" @@ -38,6 +37,5 @@ web_contents, SubresourceFilterProfileContextFactory::GetForProfile( Profile::FromBrowserContext(web_contents->GetBrowserContext())), - infobars::ContentInfoBarManager::FromWebContents(web_contents), GetDatabaseManagerFromSafeBrowsingService(), dealer); }
diff --git a/chrome/browser/sync/test/integration/preferences_helper.cc b/chrome/browser/sync/test/integration/preferences_helper.cc index 4c748a3..c7b48b7 100644 --- a/chrome/browser/sync/test/integration/preferences_helper.cc +++ b/chrome/browser/sync/test/integration/preferences_helper.cc
@@ -61,7 +61,7 @@ ListPrefUpdate update(GetPrefs(index), pref_name); base::ListValue* list = update.Get(); for (const auto& it : new_value) { - list->Append(it.CreateDeepCopy()); + list->Append(it.Clone()); } }
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc index f6c9fdef..ff0adad 100644 --- a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc +++ b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
@@ -10,7 +10,6 @@ #include <utility> #include <vector> -#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/notification_utils.h" #include "ash/shell.h" #include "base/base64.h" @@ -545,7 +544,7 @@ ->Display(NotificationHandler::Type::TRANSIENT, *notification, /*metadata=*/nullptr); - if (success && ash::features::IsTemporaryHoldingSpaceEnabled()) { + if (success) { ash::HoldingSpaceKeyedServiceFactory::GetInstance() ->GetService(GetProfile()) ->AddScreenshot(screenshot_path);
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber_browsertest.cc b/chrome/browser/ui/ash/chrome_screenshot_grabber_browsertest.cc index 19d98a7e..cb4c181 100644 --- a/chrome/browser/ui/ash/chrome_screenshot_grabber_browsertest.cc +++ b/chrome/browser/ui/ash/chrome_screenshot_grabber_browsertest.cc
@@ -32,17 +32,12 @@ using testing::_; using testing::Return; -// Parameterized by TemporaryHoldingSpace feature state. class ChromeScreenshotGrabberBrowserTest : public InProcessBrowserTest, - public testing::WithParamInterface<bool>, public ChromeScreenshotGrabberTestObserver, public ui::ClipboardObserver { public: - ChromeScreenshotGrabberBrowserTest() { - scoped_feature_list_.InitWithFeatureState( - ash::features::kTemporaryHoldingSpace, GetParam()); - } + ChromeScreenshotGrabberBrowserTest() = default; ~ChromeScreenshotGrabberBrowserTest() override = default; void SetUpOnMainThread() override { @@ -90,8 +85,6 @@ ui::ClipboardBuffer::kCopyPaste, /* data_dst = */ nullptr); } - bool TemporaryHoldingSpaceEnabled() const { return GetParam(); } - ash::HoldingSpaceModel* GetHoldingSpaceModel() const { ash::HoldingSpaceController* const controller = ash::HoldingSpaceController::Get(); @@ -108,16 +101,10 @@ policy::MockDlpContentManager mock_dlp_content_manager_; private: - base::test::ScopedFeatureList scoped_feature_list_; - DISALLOW_COPY_AND_ASSIGN(ChromeScreenshotGrabberBrowserTest); }; -INSTANTIATE_TEST_SUITE_P(All, - ChromeScreenshotGrabberBrowserTest, - testing::Bool()); - -IN_PROC_BROWSER_TEST_P(ChromeScreenshotGrabberBrowserTest, TakeScreenshot) { +IN_PROC_BROWSER_TEST_F(ChromeScreenshotGrabberBrowserTest, TakeScreenshot) { ChromeScreenshotGrabber* chrome_screenshot_grabber = ChromeScreenshotGrabber::Get(); SetTestObserver(chrome_screenshot_grabber, this); @@ -149,19 +136,15 @@ EXPECT_TRUE(base::PathExists(screenshot_path_)); } - if (TemporaryHoldingSpaceEnabled()) { - ash::HoldingSpaceModel* holding_space_model = GetHoldingSpaceModel(); - ASSERT_TRUE(holding_space_model); - ASSERT_EQ(1u, holding_space_model->items().size()); + ash::HoldingSpaceModel* holding_space_model = GetHoldingSpaceModel(); + ASSERT_TRUE(holding_space_model); + ASSERT_EQ(1u, holding_space_model->items().size()); - ash::HoldingSpaceItem* holding_space_item = - holding_space_model->items()[0].get(); - EXPECT_EQ(ash::HoldingSpaceItem::Type::kScreenshot, - holding_space_item->type()); - EXPECT_EQ(screenshot_path_, holding_space_item->file_path()); - } else { - EXPECT_FALSE(GetHoldingSpaceModel()); - } + ash::HoldingSpaceItem* holding_space_item = + holding_space_model->items()[0].get(); + EXPECT_EQ(ash::HoldingSpaceItem::Type::kScreenshot, + holding_space_item->type()); + EXPECT_EQ(screenshot_path_, holding_space_item->file_path()); EXPECT_FALSE(IsImageClipboardAvailable()); ui::ClipboardMonitor::GetInstance()->AddObserver(this); @@ -177,7 +160,7 @@ EXPECT_TRUE(IsImageClipboardAvailable()); } -IN_PROC_BROWSER_TEST_P(ChromeScreenshotGrabberBrowserTest, +IN_PROC_BROWSER_TEST_F(ChromeScreenshotGrabberBrowserTest, ScreenshotsDisallowed) { ChromeScreenshotGrabber* chrome_screenshot_grabber = ChromeScreenshotGrabber::Get(); @@ -196,16 +179,12 @@ notification->system_notification_warning_level()); EXPECT_EQ(ui::ScreenshotResult::DISABLED, screenshot_result_); - if (TemporaryHoldingSpaceEnabled()) { - ash::HoldingSpaceModel* holding_space_model = GetHoldingSpaceModel(); - ASSERT_TRUE(holding_space_model); - EXPECT_TRUE(holding_space_model->items().empty()); - } else { - EXPECT_FALSE(GetHoldingSpaceModel()); - } + ash::HoldingSpaceModel* holding_space_model = GetHoldingSpaceModel(); + ASSERT_TRUE(holding_space_model); + EXPECT_TRUE(holding_space_model->items().empty()); } -IN_PROC_BROWSER_TEST_P(ChromeScreenshotGrabberBrowserTest, +IN_PROC_BROWSER_TEST_F(ChromeScreenshotGrabberBrowserTest, ScreenshotsRestricted) { ChromeScreenshotGrabber* chrome_screenshot_grabber = ChromeScreenshotGrabber::Get(); @@ -228,11 +207,7 @@ notification->system_notification_warning_level()); EXPECT_EQ(ui::ScreenshotResult::DISABLED_BY_DLP, screenshot_result_); - if (TemporaryHoldingSpaceEnabled()) { - ash::HoldingSpaceModel* holding_space_model = GetHoldingSpaceModel(); - ASSERT_TRUE(holding_space_model); - EXPECT_TRUE(holding_space_model->items().empty()); - } else { - EXPECT_FALSE(GetHoldingSpaceModel()); - } + ash::HoldingSpaceModel* holding_space_model = GetHoldingSpaceModel(); + ASSERT_TRUE(holding_space_model); + EXPECT_TRUE(holding_space_model->items().empty()); }
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc b/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc index f993d5b9..26acd607 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc
@@ -6,7 +6,6 @@ #include <string> -#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/holding_space/holding_space_controller.h" #include "ash/public/cpp/holding_space/holding_space_image.h" #include "ash/public/cpp/holding_space/holding_space_item.h" @@ -126,9 +125,7 @@ // HoldingSpaceBrowserTestBase ------------------------------------------------- HoldingSpaceBrowserTestBase::HoldingSpaceBrowserTestBase() - : web_app::SystemWebAppBrowserTestBase(false) { - scoped_feature_list_.InitAndEnableFeature(features::kTemporaryHoldingSpace); -} + : web_app::SystemWebAppBrowserTestBase(false) {} HoldingSpaceBrowserTestBase::~HoldingSpaceBrowserTestBase() = default;
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.cc b/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.cc index 3fa2987..55b68cd5 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.cc
@@ -38,7 +38,7 @@ void HoldingSpaceDownloadsDelegate::Init() { // ARC downloads. - if (features::IsTemporaryHoldingSpaceArcIntegrationEnabled()) { + if (features::IsHoldingSpaceArcIntegrationEnabled()) { // NOTE: The `arc_intent_helper_bridge` may be `nullptr` if the `profile()` // is not allowed to use ARC, e.g. if the `profile()` is OTR. auto* const arc_intent_helper_bridge = @@ -67,7 +67,7 @@ void HoldingSpaceDownloadsDelegate::OnArcDownloadAdded( const base::FilePath& relative_path, const std::string& owner_package_name) { - DCHECK(features::IsTemporaryHoldingSpaceArcIntegrationEnabled()); + DCHECK(features::IsHoldingSpaceArcIntegrationEnabled()); if (is_restoring_persistence()) return;
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc index 80c71b38..a56185c 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc
@@ -6,7 +6,6 @@ #include <vector> -#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/holding_space/holding_space_controller.h" #include "ash/public/cpp/holding_space/holding_space_image.h" #include "ash/public/cpp/holding_space/holding_space_item.h" @@ -21,7 +20,6 @@ #include "base/scoped_observation.h" #include "base/strings/stringprintf.h" #include "base/test/bind.h" -#include "base/test/scoped_feature_list.h" #include "base/test/scoped_path_override.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/unguessable_token.h" @@ -287,10 +285,7 @@ : public InProcessBrowserTest, public ::testing::WithParamInterface<FileSystemType> { public: - HoldingSpaceKeyedServiceBrowserTest() { - scoped_feature_list_.InitAndEnableFeature( - ash::features::kTemporaryHoldingSpace); - } + HoldingSpaceKeyedServiceBrowserTest() = default; // InProcessBrowserTest: bool SetUpUserDataDirectory() override { @@ -377,8 +372,6 @@ } private: - base::test::ScopedFeatureList scoped_feature_list_; - // List of files paths that are created by default by the test suite. std::vector<base::FilePath> predefined_test_files_;
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc index 49e0240..59b94eb 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc
@@ -29,7 +29,7 @@ : BrowserContextKeyedServiceFactory( "HoldingSpaceService", BrowserContextDependencyManager::GetInstance()) { - if (features::IsTemporaryHoldingSpaceArcIntegrationEnabled()) + if (features::IsHoldingSpaceArcIntegrationEnabled()) DependsOn(arc::ArcIntentHelperBridge::GetFactory()); DependsOn(chromeos::FileChangeServiceFactory::GetInstance()); DependsOn(drive::DriveIntegrationServiceFactory::GetInstance()); @@ -57,9 +57,6 @@ KeyedService* HoldingSpaceKeyedServiceFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - if (!features::IsTemporaryHoldingSpaceEnabled()) - return nullptr; - Profile* const profile = Profile::FromBrowserContext(context); DCHECK_EQ(profile->IsGuestSession(), profile->IsOffTheRecord());
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc index 345e82a..051419f 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
@@ -285,7 +285,6 @@ HoldingSpaceKeyedServiceTest() : fake_user_manager_(new FakeChromeUserManager), user_manager_enabler_(base::WrapUnique(fake_user_manager_)) { - scoped_feature_list_.InitAndEnableFeature(features::kTemporaryHoldingSpace); HoldingSpaceImage::SetUseZeroInvalidationDelayForTesting(true); } @@ -461,8 +460,6 @@ user_manager::ScopedUserManager user_manager_enabler_; testing::NiceMock<MockDownloadManager> download_manager_; arc::ArcServiceManager arc_service_manager_; - - base::test::ScopedFeatureList scoped_feature_list_; }; TEST_F(HoldingSpaceKeyedServiceTest, GuestUserProfile) { @@ -1692,7 +1689,7 @@ public: HoldingSpaceKeyedServiceArcIntegrationTest() { scoped_feature_list_.InitAndEnableFeature( - features::kTemporaryHoldingSpaceArcIntegration); + features::kHoldingSpaceArcIntegration); } private:
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc index cd7576a..c984ed1 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -21,7 +21,6 @@ #include "components/autofill/content/browser/content_autofill_driver.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/autofill_external_delegate.h" -#include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/browser_autofill_manager.h" #include "components/autofill/core/browser/test_autofill_client.h" @@ -78,12 +77,11 @@ class MockAutofillDriver : public ContentAutofillDriver { public: MockAutofillDriver(content::RenderFrameHost* rfh, MockAutofillClient* client) - : ContentAutofillDriver( - rfh, - client, - kAppLocale, - kDownloadState, - AutofillManager::AutofillManagerFactoryCallback()) {} + : ContentAutofillDriver(rfh, + client, + kAppLocale, + kDownloadState, + nullptr) {} ~MockAutofillDriver() override = default; MOCK_CONST_METHOD0(GetAxTreeId, ui::AXTreeID());
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc index fbeffe5..be40799 100644 --- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc +++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -76,7 +76,7 @@ #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/keycode_converter.h" -#if defined(OS_CHROMEOS) || defined(OS_LINUX) +#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MAC) #include "third_party/blink/public/common/switches.h" #endif @@ -114,9 +114,9 @@ ASSERT_TRUE(embedded_test_server()->Start()); } -#if defined(OS_CHROMEOS) || defined(OS_LINUX) - // ChromeOS testing via linux, chromeos and maybe others, is flaky - // due to slower loading interacting with deferred commits. +#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MAC) + // Testing on some platforms is flaky due to slower loading interacting with + // deferred commits. void SetUpCommandLine(base::CommandLine* command_line) override { InProcessBrowserTest::SetUpCommandLine(command_line); command_line->AppendSwitch(blink::switches::kAllowPreCommitInput); @@ -735,13 +735,7 @@ // Tests that the tapping gesture with cntl/cmd key on a link open the // backgournd tab. -// crbug.com/1192343: flaky on Mac -#if defined(OS_MAC) -#define MAYBE_TapGestureWithCtrlKey DISABLED_TapGestureWithCtrlKey -#else -#define MAYBE_TapGestureWithCtrlKey TapGestureWithCtrlKey -#endif -IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, MAYBE_TapGestureWithCtrlKey) { +IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, TapGestureWithCtrlKey) { WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); GURL url(embedded_test_server()->GetURL(
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.cc b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.cc index a786f2906..41a0089b3 100644 --- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.cc +++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_view.h" #include "chrome/grit/generated_resources.h" #include "components/pref_registry/pref_registry_syncable.h" +#include "components/send_tab_to_self/metrics_util.h" #include "components/send_tab_to_self/pref_names.h" #include "components/send_tab_to_self/send_tab_to_self_model.h" #include "components/send_tab_to_self/send_tab_to_self_sync_service.h" @@ -78,8 +79,7 @@ void SendTabToSelfBubbleController::OnDeviceSelected( const std::string& target_device_name, const std::string& target_device_guid) { - RecordSendTabToSelfClickResult(kOmniboxIcon, - SendTabToSelfClickResult::kClickItem); + send_tab_to_self::RecordDeviceClicked(ShareEntryPoint::kOmniboxIcon); CreateNewEntry(web_contents_, target_device_name, target_device_guid, GURL()); }
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_sub_menu_model.cc b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_sub_menu_model.cc index d886ed7b..e464bef 100644 --- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_sub_menu_model.cc +++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_sub_menu_model.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h" #include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h" #include "chrome/grit/generated_resources.h" +#include "components/send_tab_to_self/metrics_util.h" #include "components/send_tab_to_self/send_tab_to_self_model.h" #include "components/send_tab_to_self/send_tab_to_self_sync_service.h" #include "components/send_tab_to_self/target_device_info.h" @@ -61,18 +62,16 @@ } // Converts menu type to string. -const std::string MenuTypeToString(SendTabToSelfMenuType menu_type) { +ShareEntryPoint MenuTypeToEntryPoint(SendTabToSelfMenuType menu_type) { switch (menu_type) { case SendTabToSelfMenuType::kTab: - return kTabMenu; + return ShareEntryPoint::kTabMenu; case SendTabToSelfMenuType::kContent: - return kContentMenu; + return ShareEntryPoint::kContentMenu; case SendTabToSelfMenuType::kOmnibox: - return kOmniboxMenu; + return ShareEntryPoint::kOmniboxMenu; case SendTabToSelfMenuType::kLink: - return kLinkMenu; - default: - NOTREACHED(); + return ShareEntryPoint::kLinkMenu; } } @@ -125,8 +124,7 @@ CreateNewEntry(tab_, item.device_name, item.cache_guid); } - RecordSendTabToSelfClickResult(MenuTypeToString(menu_type_), - SendTabToSelfClickResult::kClickItem); + send_tab_to_self::RecordDeviceClicked(MenuTypeToEntryPoint(menu_type_)); return; }
diff --git a/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc b/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc index 92c5b99..3e665fe 100644 --- a/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc +++ b/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc
@@ -173,9 +173,10 @@ https_server(), kChallengePath); https_server()->StartAcceptingConnections(); - account_id_ = signin::SetUnconsentedPrimaryAccount(identity_manager(), - "alice@gmail.com") - .account_id; + account_id_ = + signin::SetPrimaryAccount(identity_manager(), "alice@gmail.com", + signin::ConsentLevel::kSignin) + .account_id; reauth_result_loop_ = std::make_unique<base::RunLoop>(); InProcessBrowserTest::SetUpOnMainThread();
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc index 673aa1a9..e5d570e9 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.cc +++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -47,6 +47,7 @@ #include "chrome/grit/generated_resources.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/reading_list/core/reading_list_model.h" +#include "components/send_tab_to_self/metrics_util.h" #include "components/tab_groups/tab_group_id.h" #include "components/tab_groups/tab_group_visual_data.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" @@ -1405,8 +1406,8 @@ case CommandSendTabToSelfSingleTarget: { send_tab_to_self::ShareToSingleTarget(GetWebContentsAt(context_index)); - send_tab_to_self::RecordSendTabToSelfClickResult( - send_tab_to_self::kTabMenu, SendTabToSelfClickResult::kClickItem); + send_tab_to_self::RecordDeviceClicked( + send_tab_to_self::ShareEntryPoint::kTabMenu); break; }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index af6ab3eb..521e0c5 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -52,6 +52,7 @@ #include "components/omnibox/browser/omnibox_prefs.h" #include "components/prefs/pref_service.h" #include "components/security_state/core/security_state.h" +#include "components/send_tab_to_self/metrics_util.h" #include "components/strings/grit/components_strings.h" #include "components/url_formatter/elide_url.h" #include "components/url_formatter/url_fixer.h" @@ -805,8 +806,8 @@ case IDC_SEND_TAB_TO_SELF_SINGLE_TARGET: send_tab_to_self::ShareToSingleTarget( location_bar_view_->GetWebContents()); - send_tab_to_self::RecordSendTabToSelfClickResult( - send_tab_to_self::kOmniboxMenu, SendTabToSelfClickResult::kClickItem); + send_tab_to_self::RecordDeviceClicked( + send_tab_to_self::ShareEntryPoint::kOmniboxMenu); return; // These commands do invoke the popup.
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc index a737261..55d4261b 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
@@ -522,47 +522,6 @@ } IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest, - CreateSignedInProfileWithSyncDisabled) { - ASSERT_EQ(1u, BrowserList::GetInstance()->size()); - Profile* profile_being_created = StartSigninFlow(); - - // Disable sync by setting the device as managed in prefs. - syncer::SyncPrefs prefs(profile_being_created->GetPrefs()); - prefs.SetManagedForTest(true); - syncer::SyncService* sync_service = - ProfileSyncServiceFactory::GetForProfile(profile_being_created); - - // Simulate a successful Gaia sign-in. - SignIn(profile_being_created, "joe.consumer@gmail.com", "Joe"); - - // Wait for the sign-in to propagate to the flow, resulting in new browser - // getting opened. - Browser* new_browser = BrowserAddedWaiter(2u).Wait(); - WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(), - GURL("chrome://newtab/")); - - WaitForPickerClosed(); - - // Now the sync consent screen is shown, simulate closing the UI with "Stay - // signed in" - LoginUIServiceFactory::GetForProfile(profile_being_created) - ->SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); - - // Check expectations when the profile creation flow is done. - ProfileAttributesEntry* entry = - g_browser_process->profile_manager() - ->GetProfileAttributesStorage() - .GetProfileAttributesWithPath(profile_being_created->GetPath()); - ASSERT_NE(entry, nullptr); - EXPECT_FALSE(entry->IsEphemeral()); - EXPECT_EQ(entry->GetLocalProfileName(), u"Joe"); - EXPECT_EQ(ThemeServiceFactory::GetForProfile(profile_being_created) - ->GetAutogeneratedThemeColor(), - kProfileColor); - EXPECT_FALSE(sync_service->GetUserSettings()->IsSyncRequested()); -} - -IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest, CreateSignedInProfileSettings) { ASSERT_EQ(1u, BrowserList::GetInstance()->size()); Profile* profile_being_created = StartSigninFlow(); @@ -903,7 +862,10 @@ class ProfilePickerEnterpriseCreationFlowBrowserTest : public ProfilePickerCreationFlowBrowserTest { public: - ProfilePickerEnterpriseCreationFlowBrowserTest() = default; + explicit ProfilePickerEnterpriseCreationFlowBrowserTest(bool enable_feature) { + feature_list_.InitWithFeatureState( + features::kSignInProfileCreationEnterprise, enable_feature); + } void OnWillCreateBrowserContextServices( content::BrowserContext* context) override { @@ -911,9 +873,20 @@ context, base::BindRepeating(&FakeUserPolicySigninService::BuildForEnterprise)); } + + private: + base::test::ScopedFeatureList feature_list_; }; -IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest, +class ProfilePickerSeparateEnterpriseCreationFlowBrowserTest + : public ProfilePickerEnterpriseCreationFlowBrowserTest { + public: + ProfilePickerSeparateEnterpriseCreationFlowBrowserTest() + : ProfilePickerEnterpriseCreationFlowBrowserTest( + /*enable_feature=*/false) {} +}; + +IN_PROC_BROWSER_TEST_F(ProfilePickerSeparateEnterpriseCreationFlowBrowserTest, CreateSignedInProfile) { ASSERT_EQ(1u, BrowserList::GetInstance()->size()); Profile* profile_being_created = StartSigninFlow(); @@ -961,9 +934,55 @@ ->UsingAutogeneratedTheme()); } +IN_PROC_BROWSER_TEST_F(ProfilePickerSeparateEnterpriseCreationFlowBrowserTest, + CreateSignedInProfileWithSyncDisabledBefore) { + ASSERT_EQ(1u, BrowserList::GetInstance()->size()); + Profile* profile_being_created = StartSigninFlow(); + + // Disable sync by setting the device as managed in prefs. + syncer::SyncPrefs prefs(profile_being_created->GetPrefs()); + prefs.SetManagedForTest(true); + syncer::SyncService* sync_service = + ProfileSyncServiceFactory::GetForProfile(profile_being_created); + + // Consumer-looking gmail address avoids code that forces the sync service to + // actually start which would add overhead in mocking further stuff. + // Enterprise domain needed for this profile being detected as Work. + SignIn(profile_being_created, "joe.enterprise@gmail.com", "Joe", + "enterprise.com"); + + // Wait for the sign-in to propagate to the flow, resulting in new browser + // getting opened. + Browser* new_browser = BrowserAddedWaiter(2u).Wait(); + WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(), + GURL("chrome://newtab/")); + + WaitForPickerClosed(); + + // Now the sync disabled screen is shown, simulate closing the UI with "Stay + // signed in" + LoginUIServiceFactory::GetForProfile(profile_being_created) + ->SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); + + // Check expectations when the profile creation flow is done. + ProfileAttributesEntry* entry = + g_browser_process->profile_manager() + ->GetProfileAttributesStorage() + .GetProfileAttributesWithPath(profile_being_created->GetPath()); + ASSERT_NE(entry, nullptr); + EXPECT_FALSE(entry->IsEphemeral()); + EXPECT_EQ(entry->GetLocalProfileName(), u"enterprise.com"); + + // The color is not applied for enterprise users. + EXPECT_FALSE(ThemeServiceFactory::GetForProfile(profile_being_created) + ->UsingAutogeneratedTheme()); + // Sync is disabled. + EXPECT_FALSE(sync_service->GetUserSettings()->IsSyncRequested()); +} + // Regression test for https://crbug.com/1184746. -IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest, - CreateSignedInProfileWithSyncDisabled) { +IN_PROC_BROWSER_TEST_F(ProfilePickerSeparateEnterpriseCreationFlowBrowserTest, + CreateSignedInProfileWithSyncDisabledAfter) { ASSERT_EQ(1u, BrowserList::GetInstance()->size()); Profile* profile_being_created = StartSigninFlow(); @@ -1000,7 +1019,7 @@ GURL("chrome://newtab/")); WaitForPickerClosed(); - // Now the sync consent screen is shown, simulate closing the UI with "Stay + // Now the sync disabled screen is shown, simulate closing the UI with "Stay // signed in" LoginUIServiceFactory::GetForProfile(profile_being_created) ->SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); @@ -1021,7 +1040,7 @@ EXPECT_FALSE(sync_service->GetUserSettings()->IsSyncRequested()); } -IN_PROC_BROWSER_TEST_F(ProfilePickerEnterpriseCreationFlowBrowserTest, +IN_PROC_BROWSER_TEST_F(ProfilePickerSeparateEnterpriseCreationFlowBrowserTest, CreateSignedInProfileSettings) { ASSERT_EQ(1u, BrowserList::GetInstance()->size()); Profile* profile_being_created = StartSigninFlow(); @@ -1068,10 +1087,9 @@ class ProfilePickerIntegratedEnterpriseCreationFlowBrowserTest : public ProfilePickerEnterpriseCreationFlowBrowserTest { public: - ProfilePickerIntegratedEnterpriseCreationFlowBrowserTest() { - feature_list_.InitAndEnableFeature( - features::kSignInProfileCreationEnterprise); - } + ProfilePickerIntegratedEnterpriseCreationFlowBrowserTest() + : ProfilePickerEnterpriseCreationFlowBrowserTest( + /*enable_feature=*/true) {} void ExpectEnterpriseScreenTypeAndProceed( EnterpriseProfileWelcomeUI::ScreenType expected_type, @@ -1087,9 +1105,6 @@ // Simulate clicking on the next button. handler->CallProceedCallbackForTesting(proceed); } - - private: - base::test::ScopedFeatureList feature_list_; }; IN_PROC_BROWSER_TEST_F(ProfilePickerIntegratedEnterpriseCreationFlowBrowserTest,
diff --git a/chrome/browser/ui/web_applications/web_share_target_browsertest.cc b/chrome/browser/ui/web_applications/web_share_target_browsertest.cc index e3a72a5e..10f943fe 100644 --- a/chrome/browser/ui/web_applications/web_share_target_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_share_target_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 <limits> #include <string> #include <vector> @@ -10,13 +11,17 @@ #include "base/files/file_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/bind.h" #include "base/threading/thread_restrictions.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/browser_app_launcher.h" #include "chrome/browser/apps/app_service/intent_util.h" #include "chrome/browser/apps/app_service/launch_utils.h" +#include "chrome/browser/chromeos/file_manager/fileapi_util.h" #include "chrome/browser/chromeos/file_manager/path_util.h" +#include "chrome/browser/chromeos/fileapi/recent_file.h" +#include "chrome/browser/chromeos/fileapi/recent_model.h" #include "chrome/browser/sharesheet/sharesheet_service.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -26,10 +31,12 @@ #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/test/base/ui_test_utils.h" #include "components/services/app_service/public/cpp/share_target.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "services/network/public/cpp/resource_request_body.h" +#include "storage/browser/file_system/file_system_context.h" #include "ui/display/types/display_constants.h" #include "url/gurl.h" @@ -126,6 +133,28 @@ EXPECT_TRUE(content::WaitForLoadStop(contents)); return contents; } + + unsigned NumRecentFiles(content::WebContents* contents) { + unsigned result = std::numeric_limits<unsigned>::max(); + base::RunLoop run_loop; + + const scoped_refptr<storage::FileSystemContext> file_system_context = + file_manager::util::GetFileSystemContextForRenderFrameHost( + profile(), contents->GetMainFrame()); + chromeos::RecentModel::GetForProfile(profile())->GetRecentFiles( + file_system_context.get(), + /*origin=*/GURL(), + /*file_type=*/chromeos::RecentModel::FileType::kAll, + base::BindLambdaForTesting( + [&result, + &run_loop](const std::vector<chromeos::RecentFile>& files) { + result = files.size(); + run_loop.Quit(); + })); + + run_loop.Run(); + return result; + } }; IN_PROC_BROWSER_TEST_F(WebShareTargetBrowserTest, ShareTextFiles) { @@ -151,6 +180,7 @@ content::WebContents* const web_contents = LaunchAppWithIntent(app_id, std::move(intent), share_target_url()); EXPECT_EQ("1,2,3,4,5 6,7,8,9,0", ReadTextContent(web_contents, "records")); + EXPECT_EQ(NumRecentFiles(web_contents), 0U); RemoveWebShareDirectory(directory); } @@ -182,6 +212,7 @@ EXPECT_EQ("Elements", ReadTextContent(web_contents, "headline")); EXPECT_EQ("Euclid", ReadTextContent(web_contents, "author")); EXPECT_EQ("https://example.org/", ReadTextContent(web_contents, "link")); + EXPECT_EQ(NumRecentFiles(web_contents), 0U); RemoveWebShareDirectory(directory); } @@ -214,6 +245,7 @@ content::WebContents* const web_contents = LaunchAppWithIntent(app_id, std::move(intent), share_target_url()); EXPECT_EQ("a b c", ReadTextContent(web_contents, "notes")); + EXPECT_EQ(NumRecentFiles(web_contents), 0U); RemoveWebShareDirectory(directory); } @@ -230,7 +262,6 @@ content::WebContents* const web_contents = LaunchAppWithIntent(app_id, std::move(intent), share_target_url()); - // Poster web app's service worker detects omitted values. EXPECT_EQ("N/A", ReadTextContent(web_contents, "headline")); EXPECT_EQ("N/A", ReadTextContent(web_contents, "author")); @@ -336,6 +367,7 @@ web_contents = ShareToTarget("share_url()"); EXPECT_EQ("https://example.com/", ReadTextContent(web_contents, "link")); + EXPECT_EQ(NumRecentFiles(web_contents), 0U); } IN_PROC_BROWSER_TEST_F(WebShareTargetBrowserTest, ShareToPartialWild) { @@ -352,6 +384,7 @@ content::WebContents* web_contents = ShareToTarget("share_single_file()"); EXPECT_EQ("************", ReadTextContent(web_contents, "graphs")); + EXPECT_EQ(NumRecentFiles(web_contents), 0U); } } // namespace web_app
diff --git a/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos_onboarding.cc b/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos_onboarding.cc index 3eef888c1..868fd64 100644 --- a/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos_onboarding.cc +++ b/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos_onboarding.cc
@@ -84,6 +84,12 @@ return dialog; } +ui::ModalType InlineLoginDialogChromeOSOnboarding::GetDialogModalType() const { + // Override the default system-modal behavior of the dialog so that the + // shelf can be accessed during onboarding. + return ui::ModalType::MODAL_TYPE_WINDOW; +} + InlineLoginDialogChromeOSOnboarding::InlineLoginDialogChromeOSOnboarding( const gfx::Size& size, base::OnceCallback<void(void)> dialog_closed_callback)
diff --git a/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos_onboarding.h b/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos_onboarding.h index 1a69897..c559229 100644 --- a/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos_onboarding.h +++ b/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos_onboarding.h
@@ -8,6 +8,7 @@ #include "chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h" #include "base/callback.h" +#include "ui/base/ui_base_types.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/native_widget_types.h" #include "ui/views/widget/widget_observer.h" @@ -55,6 +56,10 @@ gfx::NativeWindow window, base::OnceCallback<void(void)> dialog_closed_callback); + protected: + // ui::WebDialogDelegate overrides + ui::ModalType GetDialogModalType() const override; + private: InlineLoginDialogChromeOSOnboarding( const gfx::Size& bounds,
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn index fa475a9..d701097 100644 --- a/chrome/browser/web_applications/components/BUILD.gn +++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -224,6 +224,7 @@ "file_handler_manager_unittest.cc", "install_finalizer_unittest.cc", "os_integration_manager_unittest.cc", + "preinstalled_app_install_features_unittest.cc", "protocol_handler_manager_unittest.cc", "web_app_constants_unittest.cc", "web_app_data_retriever_unittest.cc",
diff --git a/chrome/browser/web_applications/components/preinstalled_app_install_features.cc b/chrome/browser/web_applications/components/preinstalled_app_install_features.cc index ec7a27f..072e4a47 100644 --- a/chrome/browser/web_applications/components/preinstalled_app_install_features.cc +++ b/chrome/browser/web_applications/components/preinstalled_app_install_features.cc
@@ -5,6 +5,8 @@ #include "chrome/browser/web_applications/components/preinstalled_app_install_features.h" #include "base/feature_list.h" +#include "chrome/browser/policy/profile_policy_connector.h" +#include "chrome/browser/profiles/profile.h" namespace web_app { @@ -24,6 +26,13 @@ bool g_always_enabled_for_testing = false; +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) +bool IsMigrationFeature(const base::Feature& feature) { + return &feature == &kMigrateDefaultChromeAppToWebAppsGSuite || + &feature == &kMigrateDefaultChromeAppToWebAppsNonGSuite; +} +#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + } // namespace // Enables migration of default installed GSuite apps over to their replacement @@ -41,6 +50,20 @@ }; #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) +// Whether to allow the MigrateDefaultChromeAppToWebAppsGSuite and +// MigrateDefaultChromeAppToWebAppsNonGSuite flags for managed users. +// Without this flag enabled managed users will not undergo the default web app +// migration. +// +// Why have a separate flag? +// Field trials are not able to accurately distinguish managed Chrome OS users. +// Because admin installed Chrome apps conflict with the default web app +// migration we need to maintain separate control over the rollout for mananged +// users. +const base::Feature kAllowDefaultWebAppMigrationForChromeOsManagedUsers{ + "AllowDefaultWebAppMigrationForChromeOsManagedUsers", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables default installing the Chat web app. const base::Feature kDefaultChatWebApp{"DefaultChatWebApp", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -50,11 +73,22 @@ base::FEATURE_DISABLED_BY_DEFAULT}; #endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) -bool IsPreinstalledAppInstallFeatureEnabled(base::StringPiece feature_name) { +bool IsPreinstalledAppInstallFeatureEnabled(base::StringPiece feature_name, + const Profile& profile) { if (g_always_enabled_for_testing) return true; for (const base::Feature* feature : kPreinstalledAppInstallFeatures) { +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + // See |kAllowDefaultWebAppMigrationForChromeOsManagedUsers| comment above. + if (base::FeatureList::IsEnabled(*feature) && + feature->name == feature_name && IsMigrationFeature(*feature) && + profile.GetProfilePolicyConnector()->IsManaged()) { + return base::FeatureList::IsEnabled( + kAllowDefaultWebAppMigrationForChromeOsManagedUsers); + } +#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + if (feature->name == feature_name) return base::FeatureList::IsEnabled(*feature); }
diff --git a/chrome/browser/web_applications/components/preinstalled_app_install_features.h b/chrome/browser/web_applications/components/preinstalled_app_install_features.h index 4365272..77de463a 100644 --- a/chrome/browser/web_applications/components/preinstalled_app_install_features.h +++ b/chrome/browser/web_applications/components/preinstalled_app_install_features.h
@@ -9,6 +9,8 @@ #include "base/feature_list.h" #include "base/strings/string_piece_forward.h" +class Profile; + namespace web_app { extern const base::Feature kMigrateDefaultChromeAppToWebAppsGSuite; @@ -16,6 +18,8 @@ extern const base::Feature kMigrateDefaultChromeAppToWebAppsNonGSuite; #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) +extern const base::Feature kAllowDefaultWebAppMigrationForChromeOsManagedUsers; + extern const base::Feature kDefaultChatWebApp; extern const base::Feature kDefaultMeetWebApp; @@ -24,7 +28,8 @@ // Returns the base::Feature in |kPreinstalledAppInstallFeatures| that // corresponds to |feature_name|. Used by external app install configs to gate // installation on features listed in |kPreinstalledAppInstallFeatures|. -bool IsPreinstalledAppInstallFeatureEnabled(base::StringPiece feature_name); +bool IsPreinstalledAppInstallFeatureEnabled(base::StringPiece feature_name, + const Profile& profile); base::AutoReset<bool> SetPreinstalledAppInstallFeatureAlwaysEnabledForTesting();
diff --git a/chrome/browser/web_applications/components/preinstalled_app_install_features_unittest.cc b/chrome/browser/web_applications/components/preinstalled_app_install_features_unittest.cc new file mode 100644 index 0000000..bd41f6f --- /dev/null +++ b/chrome/browser/web_applications/components/preinstalled_app_install_features_unittest.cc
@@ -0,0 +1,123 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/components/preinstalled_app_install_features.h" + +#include "base/strings/strcat.h" +#include "base/system/sys_info.h" +#include "build/build_config.h" +#include "build/chromeos_buildflags.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace web_app { + +struct Migrate { + bool base; + bool managed; +}; + +class PreinstalledWebAppInstallFeaturesTest + : public testing::Test, + public ::testing::WithParamInterface<Migrate> { + public: + static std::string ParamToString( + const ::testing::TestParamInfo<Migrate> param_info) { + std::string result = "Migrate"; + if (param_info.param.base) + result += "Base"; + if (param_info.param.managed) + result += "Managed"; + if (result == "Migrate") + result += "None"; + return result; + } + + PreinstalledWebAppInstallFeaturesTest() { + if (MigrateBase()) { + base_migration_.InitWithFeatures( + {kMigrateDefaultChromeAppToWebAppsGSuite, + kMigrateDefaultChromeAppToWebAppsNonGSuite}, + {}); + } else { + base_migration_.InitWithFeatures( + {}, {kMigrateDefaultChromeAppToWebAppsGSuite, + kMigrateDefaultChromeAppToWebAppsNonGSuite}); + } +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + if (MigrateManaged()) { + managed_migration_.InitAndEnableFeature( + kAllowDefaultWebAppMigrationForChromeOsManagedUsers); + } else { + managed_migration_.InitAndDisableFeature( + kAllowDefaultWebAppMigrationForChromeOsManagedUsers); + } +#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + } + + ~PreinstalledWebAppInstallFeaturesTest() override = default; + + bool MigrateBase() const { return GetParam().base; } + bool MigrateManaged() const { return GetParam().managed; } + + void ExpectMigrationEnabled(bool unmanaged_expectation, + bool managed_expectation) { + { + TestingProfile::Builder builder; + builder.OverridePolicyConnectorIsManagedForTesting(false); + std::unique_ptr<TestingProfile> unmanaged_profile = builder.Build(); + EXPECT_EQ( + IsPreinstalledAppInstallFeatureEnabled( + kMigrateDefaultChromeAppToWebAppsGSuite.name, *unmanaged_profile), + unmanaged_expectation); + EXPECT_EQ(IsPreinstalledAppInstallFeatureEnabled( + kMigrateDefaultChromeAppToWebAppsNonGSuite.name, + *unmanaged_profile), + unmanaged_expectation); + } + + { + TestingProfile::Builder builder; + builder.OverridePolicyConnectorIsManagedForTesting(true); + std::unique_ptr<TestingProfile> managed_profile = builder.Build(); + EXPECT_EQ( + IsPreinstalledAppInstallFeatureEnabled( + kMigrateDefaultChromeAppToWebAppsGSuite.name, *managed_profile), + managed_expectation); + EXPECT_EQ(IsPreinstalledAppInstallFeatureEnabled( + kMigrateDefaultChromeAppToWebAppsNonGSuite.name, + *managed_profile), + managed_expectation); + } + } + + protected: + base::test::ScopedFeatureList base_migration_; + base::test::ScopedFeatureList managed_migration_; + + content::BrowserTaskEnvironment task_environment_; +}; + +TEST_P(PreinstalledWebAppInstallFeaturesTest, MigrationEnabled) { + ExpectMigrationEnabled( + /*unmanaged_expectation=*/MigrateBase(), +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + /*managed_expectation=*/MigrateBase() && MigrateManaged() +#else + /*managed_expectation=*/MigrateBase() +#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + ); +} + +INSTANTIATE_TEST_SUITE_P( + All, + PreinstalledWebAppInstallFeaturesTest, + testing::Values(Migrate{.base = false, .managed = false}, + Migrate{.base = false, .managed = true}, + Migrate{.base = true, .managed = false}, + Migrate{.base = true, .managed = true}), + &PreinstalledWebAppInstallFeaturesTest::ParamToString); + +} // namespace web_app
diff --git a/chrome/browser/web_applications/preinstalled_web_app_manager.cc b/chrome/browser/web_applications/preinstalled_web_app_manager.cc index 62739da9..69f6397 100644 --- a/chrome/browser/web_applications/preinstalled_web_app_manager.cc +++ b/chrome/browser/web_applications/preinstalled_web_app_manager.cc
@@ -164,8 +164,8 @@ } // Remove if gated on a disabled feature. - if (options.gate_on_feature && - !IsPreinstalledAppInstallFeatureEnabled(*options.gate_on_feature)) { + if (options.gate_on_feature && !IsPreinstalledAppInstallFeatureEnabled( + *options.gate_on_feature, *profile)) { return options.install_url.spec() + " disabled because feature is disabled: " + *options.gate_on_feature; } @@ -541,10 +541,11 @@ SetMigrationRun(profile_, kMigrateDefaultChromeAppToWebAppsGSuite.name, IsPreinstalledAppInstallFeatureEnabled( - kMigrateDefaultChromeAppToWebAppsGSuite.name)); - SetMigrationRun(profile_, kMigrateDefaultChromeAppToWebAppsNonGSuite.name, - IsPreinstalledAppInstallFeatureEnabled( - kMigrateDefaultChromeAppToWebAppsNonGSuite.name)); + kMigrateDefaultChromeAppToWebAppsGSuite.name, *profile_)); + SetMigrationRun( + profile_, kMigrateDefaultChromeAppToWebAppsNonGSuite.name, + IsPreinstalledAppInstallFeatureEnabled( + kMigrateDefaultChromeAppToWebAppsNonGSuite.name, *profile_)); if (callback) { std::move(callback).Run(std::move(install_results),
diff --git a/chrome/browser/web_applications/preinstalled_web_app_migration_browsertest.cc b/chrome/browser/web_applications/preinstalled_web_app_migration_browsertest.cc index 95b8076..66e359f 100644 --- a/chrome/browser/web_applications/preinstalled_web_app_migration_browsertest.cc +++ b/chrome/browser/web_applications/preinstalled_web_app_migration_browsertest.cc
@@ -249,7 +249,8 @@ // Set up pre-migration state. { - ASSERT_FALSE(IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag)); + ASSERT_FALSE( + IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag, *profile())); SyncExternalExtensions(); SyncExternalWebApps(/*expect_install=*/false, /*expect_uninstall=*/false); @@ -274,7 +275,8 @@ { base::AutoReset<bool> testing_scope = SetPreinstalledAppInstallFeatureAlwaysEnabledForTesting(); - ASSERT_TRUE(IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag)); + ASSERT_TRUE( + IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag, *profile())); SyncExternalExtensions(); // Extension sticks around to be uninstalled by the replacement web app. @@ -317,7 +319,8 @@ // Revert migration. { - ASSERT_FALSE(IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag)); + ASSERT_FALSE( + IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag, *profile())); SyncExternalExtensions(); SyncExternalWebApps(/*expect_install=*/false, /*expect_uninstall=*/true); @@ -340,7 +343,8 @@ base::HistogramTester histograms; base::AutoReset<bool> testing_scope = SetPreinstalledAppInstallFeatureAlwaysEnabledForTesting(); - ASSERT_TRUE(IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag)); + ASSERT_TRUE( + IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag, *profile())); extensions::TestExtensionRegistryObserver uninstall_observer( extensions::ExtensionRegistry::Get(profile())); @@ -388,7 +392,8 @@ // Set up pre-migration state. { - ASSERT_FALSE(IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag)); + ASSERT_FALSE( + IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag, *profile())); SyncExternalExtensions(); SyncExternalWebApps(/*expect_install=*/false, /*expect_uninstall=*/false); @@ -422,7 +427,8 @@ { base::AutoReset<bool> testing_scope = SetPreinstalledAppInstallFeatureAlwaysEnabledForTesting(); - ASSERT_TRUE(IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag)); + ASSERT_TRUE( + IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag, *profile())); SyncExternalExtensions(); // Extension sticks around to be uninstalled by the replacement web app. @@ -482,7 +488,8 @@ UserUninstalledExtensionApp) { // Set up pre-migration state. { - ASSERT_FALSE(IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag)); + ASSERT_FALSE( + IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag, *profile())); SyncExternalExtensions(); SyncExternalWebApps(/*expect_install=*/false, /*expect_uninstall=*/false); @@ -507,7 +514,8 @@ { base::AutoReset<bool> testing_scope = SetPreinstalledAppInstallFeatureAlwaysEnabledForTesting(); - ASSERT_TRUE(IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag)); + ASSERT_TRUE( + IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag, *profile())); SyncExternalExtensions(); EXPECT_FALSE(IsExtensionAppInstalled()); @@ -540,7 +548,8 @@ { base::HistogramTester histograms; - ASSERT_FALSE(IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag)); + ASSERT_FALSE( + IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag, *profile())); SyncExternalExtensions(); SyncExternalWebApps(/*expect_install=*/false, /*expect_uninstall=*/false, @@ -561,7 +570,8 @@ { base::AutoReset<bool> testing_scope = SetPreinstalledAppInstallFeatureAlwaysEnabledForTesting(); - ASSERT_TRUE(IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag)); + ASSERT_TRUE( + IsPreinstalledAppInstallFeatureEnabled(kMigrationFlag, *profile())); SyncExternalExtensions(); // Extension sticks around to be uninstalled by the replacement web app.
diff --git a/chrome/browser/web_applications/preinstalled_web_apps/BUILD.gn b/chrome/browser/web_applications/preinstalled_web_apps/BUILD.gn index 77d24831..053e3cf 100644 --- a/chrome/browser/web_applications/preinstalled_web_apps/BUILD.gn +++ b/chrome/browser/web_applications/preinstalled_web_apps/BUILD.gn
@@ -44,6 +44,8 @@ sources += [ "google_calendar.cc", "google_calendar.h", + "google_chat.cc", + "google_chat.h", ] }
diff --git a/chrome/browser/web_applications/preinstalled_web_apps/google_chat.cc b/chrome/browser/web_applications/preinstalled_web_apps/google_chat.cc new file mode 100644 index 0000000..78ec1b67 --- /dev/null +++ b/chrome/browser/web_applications/preinstalled_web_apps/google_chat.cc
@@ -0,0 +1,27 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/preinstalled_web_apps/google_chat.h" + +#include "chrome/browser/web_applications/components/preinstalled_app_install_features.h" + +namespace web_app { + +ExternalInstallOptions GetConfigForGoogleChat() { + ExternalInstallOptions options( + /*install_url=*/GURL( + "https://mail.google.com/chat/download?usp=chrome_default"), + /*user_display_mode=*/DisplayMode::kStandalone, + /*install_source=*/ExternalInstallSource::kExternalDefault); + + options.user_type_allowlist = {"unmanaged", "managed", "child"}; + options.gate_on_feature = kDefaultChatWebApp.name; + options.add_to_quick_launch_bar = false; + options.add_to_desktop = false; + options.only_for_new_users = true; + + return options; +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/preinstalled_web_apps/google_chat.h b/chrome/browser/web_applications/preinstalled_web_apps/google_chat.h new file mode 100644 index 0000000..d2d0dc2 --- /dev/null +++ b/chrome/browser/web_applications/preinstalled_web_apps/google_chat.h
@@ -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. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_PREINSTALLED_WEB_APPS_GOOGLE_CHAT_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_PREINSTALLED_WEB_APPS_GOOGLE_CHAT_H_ + +#include "chrome/browser/web_applications/components/external_install_options.h" + +namespace web_app { + +ExternalInstallOptions GetConfigForGoogleChat(); + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_PREINSTALLED_WEB_APPS_GOOGLE_CHAT_H_
diff --git a/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc b/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc index fcae4089..d8c5e6e 100644 --- a/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc +++ b/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc
@@ -23,6 +23,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/web_applications/preinstalled_web_apps/google_calendar.h" +#include "chrome/browser/web_applications/preinstalled_web_apps/google_chat.h" #endif // BUILDFLAG(IS_CHROMEOS_ASH) #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) @@ -67,6 +68,7 @@ GetConfigForYouTube(), #if BUILDFLAG(IS_CHROMEOS_ASH) GetConfigForGoogleCalendar(), + GetConfigForGoogleChat(), #endif // BUILDFLAG(IS_CHROMEOS_ASH) // clang-format on };
diff --git a/chrome/browser/web_applications/preinstalled_web_apps_browsertest.cc b/chrome/browser/web_applications/preinstalled_web_apps_browsertest.cc index bfb4a23..fd0dd3b 100644 --- a/chrome/browser/web_applications/preinstalled_web_apps_browsertest.cc +++ b/chrome/browser/web_applications/preinstalled_web_apps_browsertest.cc
@@ -41,11 +41,11 @@ auto& provider = *WebAppProvider::Get(browser()->profile()); - struct Expectation { + struct OfflineOnlyExpectation { const char* app_id; const char* install_url; const char* launch_url; - } kExpectations[] = { + } kOfflineOnlyExpectations[] = { #if BUILDFLAG(GOOGLE_CHROME_BRANDING) #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) { @@ -86,7 +86,22 @@ }, #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) }; - size_t kExpectedCount = sizeof(kExpectations) / sizeof(kExpectations[0]); + size_t kOfflineOnlyExpectedCount = + sizeof(kOfflineOnlyExpectations) / sizeof(kOfflineOnlyExpectations[0]); + + struct OnlineOnlyExpectation { + const char* install_url; + } kOnlineOnlyExpectations[] = { +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + { + "https://mail.google.com/chat/download?usp=chrome_default", + }, +#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) + }; + size_t kOnlineOnlyExpectedCount = + sizeof(kOnlineOnlyExpectations) / sizeof(kOnlineOnlyExpectations[0]); base::RunLoop run_loop; provider.preinstalled_web_app_manager().LoadAndSynchronizeForTesting( @@ -94,20 +109,26 @@ [&](std::map<GURL, ExternallyManagedAppManager::InstallResult> install_results, std::map<GURL, bool> uninstall_results) { - EXPECT_EQ(install_results.size(), kExpectedCount); + EXPECT_EQ(install_results.size(), + kOfflineOnlyExpectedCount + kOnlineOnlyExpectedCount); - for (const Expectation& expectation : kExpectations) { + for (const auto& expectation : kOfflineOnlyExpectations) { EXPECT_EQ(install_results[GURL(expectation.install_url)].code, InstallResultCode::kSuccessOfflineOnlyInstall); } + for (const auto& expectation : kOnlineOnlyExpectations) { + EXPECT_EQ(install_results[GURL(expectation.install_url)].code, + InstallResultCode::kInstallURLLoadFailed); + } + EXPECT_EQ(uninstall_results.size(), 0u); run_loop.Quit(); })); run_loop.Run(); - for (const Expectation& expectation : kExpectations) { + for (const auto& expectation : kOfflineOnlyExpectations) { EXPECT_EQ(provider.registrar().GetAppLaunchUrl(expectation.app_id), GURL(expectation.launch_url)); }
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 687fad9c..591975d 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-master-1620172529-2e7042d3e0d503f2fbf4b5265e801bd87c4ffdbc.profdata +chrome-win32-master-1620193489-ecb74f092b3d0ff9732042da0ab458ae29c4bd49.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index a6fea34..6ea73e6 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1620172529-8f86fc13ad1836b1082b9990ba65808c278ad45e.profdata +chrome-win64-master-1620205001-59a405d5d3cc1e81f6386200200564e6437ec397.profdata
diff --git a/chrome/renderer/cart/commerce_hint_agent_browsertest.cc b/chrome/renderer/cart/commerce_hint_agent_browsertest.cc index df1b3e1..feba8c4 100644 --- a/chrome/renderer/cart/commerce_hint_agent_browsertest.cc +++ b/chrome/renderer/cart/commerce_hint_agent_browsertest.cc
@@ -162,7 +162,8 @@ service_ = CartServiceFactory::GetForProfile(profile); auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); ASSERT_TRUE(identity_manager); - signin::SetPrimaryAccount(identity_manager, "user@gmail.com"); + signin::SetPrimaryAccount(identity_manager, "user@gmail.com", + signin::ConsentLevel::kSync); // This is necessary to test non-localhost domains. See |NavigateToURL|. host_resolver()->AddRule("*", "127.0.0.1"); @@ -451,7 +452,8 @@ SendXHR("/add-to-cart", "product: 123"); WaitForCartCount(kEmptyExpected); - signin::SetPrimaryAccount(identity_manager, "user@gmail.com"); + signin::SetPrimaryAccount(identity_manager, "user@gmail.com", + signin::ConsentLevel::kSync); NavigateToURL("https://www.guitarcenter.com/"); SendXHR("/add-to-cart", "product: 123"); WaitForCartCount(kExpectedExampleFallbackCart);
diff --git a/chrome/test/data/extensions/api_test/file_browser/holding_space_disabled/manifest.json b/chrome/test/data/extensions/api_test/file_browser/holding_space_disabled/manifest.json deleted file mode 100644 index 31bb8d1..0000000 --- a/chrome/test/data/extensions/api_test/file_browser/holding_space_disabled/manifest.json +++ /dev/null
@@ -1,19 +0,0 @@ -{ - // chrome-extension://pkplfbidichfdicaijlchgnapepdginl - "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtDfX9dHNh948bt00YhZBm3P6E5QLaOt+v8kXVtibQfiPtOD2FTScB/f0wX/EQWVO7BkaSOsRkTPcPIgocyMPYr2FLgqGLFlYT9nQpKJZUFNF5oJ5rG6Nv7ppf4zEB3j6da1IBRTz2yOZ+6O1TMZxol/V62/QcqrJeggsHTEPGLdr9Ua4b1Ka0xKJnJngZljsbw93FI1o+P9dAh5BS6wTPiZI/vmJVjvMTkSTnaZ3n9Go2t7A0XLcSxLcVyuLAd2mAvSN0mIviOukdM66wr7llif71nKuUt+4qvlr/r9HfwzN6pA4jkwhtS1UD+3CmB+wsHwsnohNcuu4FIQ6rgq/7QIDAQAB", - "name": "chrome.fileManagerPrivate tests", - "version": "0.1", - "manifest_version": 2, - "description": "Tests of chrome.fileManagerPrivate holding space methods", - "app": { - "background": { - "scripts": ["test.js"] - } - }, - "permissions": [ - "fileManagerPrivate", - { - "fileSystem": ["requestFileSystem"] - } - ] -}
diff --git a/chrome/test/data/extensions/api_test/file_browser/holding_space_disabled/test.js b/chrome/test/data/extensions/api_test/file_browser/holding_space_disabled/test.js deleted file mode 100644 index 456461a..0000000 --- a/chrome/test/data/extensions/api_test/file_browser/holding_space_disabled/test.js +++ /dev/null
@@ -1,41 +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. - -/** - * Gets an external file entry from a path. - * @param {string} volumeType volume type for entry. - * @param {string} path path of entry. - * @return {!Promise<Entry>} specified entry. - */ -function getFileEntry(volumeType, path) { - return new Promise(resolve => { - chrome.fileManagerPrivate.getVolumeMetadataList(list => { - const volume = list.find(v => v.volumeType === volumeType); - chrome.fileSystem.requestFileSystem({volumeId: volume.volumeId}, fs => { - fs.root.getFile(path, {}, entry => { - chrome.fileManagerPrivate.resolveIsolatedEntries( - [entry], externalEntries => { - resolve(externalEntries[0]); - }); - }); - }); - }); - }); -} - -// Run the tests. -chrome.test.runTests([ - function testGetHoldingSpaceFails() { - chrome.fileManagerPrivate.getHoldingSpaceState( - chrome.test.callbackFail('Not enabled')); - }, - - function testAddSingleEntry() { - getFileEntry('testing', 'test_dir/test_file.txt') - .then(chrome.test.callbackPass(entry => { - chrome.fileManagerPrivate.toggleAddedToHoldingSpace( - [entry], true, chrome.test.callbackFail('Not enabled')); - })); - }, -]);
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js index a2c76525..d121845 100644 --- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js +++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js
@@ -147,7 +147,7 @@ const emojiButton = (await waitForCondition( () => findInEmojiPicker( '[data-group="0"] > emoji-group', - 'emoji-button:nth-child(2)'))) + 'emoji-button:nth-child(3)'))) .shadowRoot.querySelector('button'); emojiButton.click(); @@ -171,7 +171,7 @@ const emojiButton = (await waitForCondition( () => findInEmojiPicker( '[data-group="0"] > emoji-group', - 'emoji-button:nth-child(1)'))) + 'emoji-button:nth-child(2)'))) .shadowRoot.querySelector('button'); emojiButton.click(); @@ -221,7 +221,7 @@ firstEmojiButton = (await waitForCondition( () => findInEmojiPicker( '[data-group="0"] > emoji-group', - 'emoji-button:nth-child(2)'))) + 'emoji-button:nth-child(3)'))) .shadowRoot; @@ -257,7 +257,7 @@ const emojiButton2 = await waitForCondition( () => findInEmojiPicker( - '[data-group="0"] > emoji-group', 'emoji-button:nth-child(3)') + '[data-group="0"] > emoji-group', 'emoji-button:nth-child(4)') .shadowRoot); // right click on second emoji button
diff --git a/chrome/test/data/webui/ntp4_browsertest.cc b/chrome/test/data/webui/ntp4_browsertest.cc index d244ccc..7837107e 100644 --- a/chrome/test/data/webui/ntp4_browsertest.cc +++ b/chrome/test/data/webui/ntp4_browsertest.cc
@@ -16,5 +16,6 @@ void NTP4LoggedInWebUITest::SetLoginName(const std::string& name) { auto* identity_manager = IdentityManagerFactory::GetForProfile(browser()->profile()); - signin::SetPrimaryAccount(identity_manager, name); + signin::SetPrimaryAccount(identity_manager, name, + signin::ConsentLevel::kSync); }
diff --git a/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js b/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js index 1ef37ad..c649067 100644 --- a/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js +++ b/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js
@@ -407,4 +407,32 @@ await flushAsync(); assertTrue(esimLocalizedLink.linkDisabled); }); + + test('Show inhibited subtext and spinner when inhibited', async () => { + eSimManagerRemote.addEuiccForTest(0); + init(); + cellularNetworkList.deviceState = { + type: mojom.NetworkType.kCellular, + deviceState: mojom.DeviceStateType.kEnabled, + inhibitReason: mojom.InhibitReason.kNotInhibited + }; + addESimSlot(); + + await flushAsync(); + + const inhibitedSubtext = cellularNetworkList.$$('#inhibitedSubtext'); + const inhibitedSpinner = cellularNetworkList.$$('#inhibitedSpinner'); + assertTrue(inhibitedSubtext.hidden); + assertFalse(inhibitedSpinner.active); + + cellularNetworkList.cellularDeviceState = { + type: mojom.NetworkType.kCellular, + deviceState: mojom.DeviceStateType.kEnabled, + inhibitReason: mojom.InhibitReason.kInstallingProfile + }; + addESimSlot(); + await flushAsync(); + assertFalse(inhibitedSubtext.hidden); + assertTrue(inhibitedSpinner.active); + }); });
diff --git a/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js b/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js index df87ebe2..11dc259 100644 --- a/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js
@@ -832,7 +832,6 @@ assertFalse(networkIpConfig.disabled); assertFalse(networkNameservers.disabled); assertFalse(networkProxySection.disabled); - assertFalse(!!internetDetailPage.$$('cellular-banner')); // Mock device being inhibited. mojoApi_.setDeviceStateForTest({ @@ -857,7 +856,6 @@ assertTrue(networkIpConfig.disabled); assertTrue(networkNameservers.disabled); assertTrue(networkProxySection.disabled); - assertTrue(!!internetDetailPage.$$('cellular-banner')); // Uninhibit. mojoApi_.setDeviceStateForTest({ @@ -882,7 +880,6 @@ assertFalse(networkIpConfig.disabled); assertFalse(networkNameservers.disabled); assertFalse(networkProxySection.disabled); - assertFalse(!!internetDetailPage.$$('cellular-banner')); }); });
diff --git a/chrome/test/data/webui/settings/chromeos/internet_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/internet_subpage_tests.js index 1342d6c3..9c4556e 100644 --- a/chrome/test/data/webui/settings/chromeos/internet_subpage_tests.js +++ b/chrome/test/data/webui/settings/chromeos/internet_subpage_tests.js
@@ -231,34 +231,6 @@ deepLinkElement, getDeepActiveElement(), 'Add cellular button should be focused for settingId=26.'); }); - test( - 'Device inhibited disables toggle and shows banner', async () => { - initSubpage(true); - const mojom = chromeos.networkConfig.mojom; - mojoApi_.setNetworkTypeEnabledState(mojom.NetworkType.kCellular); - setNetworksForTest(mojom.NetworkType.kCellular, [ - OncMojo.getDefaultNetworkState( - mojom.NetworkType.kCellular, 'cellular1'), - ]); - internetSubpage.deviceState = { - type: mojom.NetworkType.kCellular, - deviceState: mojom.DeviceStateType.kEnabled, - inhibitReason: mojom.InhibitReason.kInstallingProfile - }; - internetSubpage.globalPolicy = { - allowOnlyPolicyNetworksToConnect: false, - }; - - await flushAsync(); - - const deviceEnabledButton = - internetSubpage.$$('#deviceEnabledButton'); - assertTrue(!!deviceEnabledButton); - assertTrue(deviceEnabledButton.disabled); - - const cellularBanner = internetSubpage.$$('cellular-banner'); - assertTrue(!!cellularBanner); - }); test( 'Tether plus Cellular with updatedCellularActivationUi false',
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn index a5ac324..d986730 100644 --- a/chromeos/BUILD.gn +++ b/chromeos/BUILD.gn
@@ -185,6 +185,7 @@ "//chromeos/dbus/services:unit_tests", "//chromeos/disks:unit_tests", "//chromeos/geolocation:unit_tests", + "//chromeos/language/language_packs:unit_tests", "//chromeos/login/auth:unit_tests", "//chromeos/login/login_state:unit_tests", "//chromeos/login/session:unit_tests",
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 7983f80..18cc3ef3 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -13929.0.0 \ No newline at end of file +13951.0.0 \ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources/css/ptz_panel.css b/chromeos/components/camera_app_ui/resources/css/ptz_panel.css index b898ed6..ec63c1a5 100644 --- a/chromeos/components/camera_app_ui/resources/css/ptz_panel.css +++ b/chromeos/components/camera_app_ui/resources/css/ptz_panel.css
@@ -3,6 +3,9 @@ * found in the LICENSE file. */ #panel-container { + --divider-color: rgba(95, 99, 104, 0.38); + --divider-width: 1px; + backdrop-filter: blur(10px); background: rgba(32, 33, 36, 0.9); border-radius: 4px; @@ -37,33 +40,33 @@ } #pan-left { - --svg-width: 8px; - --svg-height: 10px; + --svg-width: 20px; + --svg-height: 20px; } #pan-right { - --svg-width: 8px; - --svg-height: 10px; + --svg-width: 20px; + --svg-height: 20px; } #tilt-up { - --svg-width: 12px; - --svg-height: 8px; + --svg-width: 20px; + --svg-height: 20px; } #tilt-down { - --svg-width: 12px; - --svg-height: 8px; + --svg-width: 20px; + --svg-height: 20px; } #zoom-in { - --svg-width: 16px; - --svg-height: 16px; + --svg-width: 20px; + --svg-height: 20px; } #zoom-out { - --svg-width: 16px; - --svg-height: 16px; + --svg-width: 20px; + --svg-height: 20px; } /* Icons. */ @@ -310,9 +313,9 @@ } .ptz-divider { - background: rgba(95, 99, 104, 0.38); + background: var(--divider-color); position: absolute; - width: 1px; + width: var(--divider-width); } #ptz-divider1 { @@ -353,3 +356,15 @@ body.has-pan-support.has-tilt-support.has-zoom-support .ptz-divider { height: 98px; } + +body.has-pan-support.has-tilt-support.has-zoom-support :is(#zoom-in, #zoom-out) { + border: var(--divider-width) solid var(--divider-color); +} + +body.has-pan-support.has-tilt-support.has-zoom-support #zoom-in { + border-left-width: 0; /* csschecker-disable-line left-right */ +} + +body.has-pan-support.has-tilt-support.has-zoom-support #zoom-out { + border-right-width: 0; /* csschecker-disable-line left-right */ +}
diff --git a/chromeos/components/camera_app_ui/resources/images/ptz_pan_left.svg b/chromeos/components/camera_app_ui/resources/images/ptz_pan_left.svg index 0764f78..884ea3b 100644 --- a/chromeos/components/camera_app_ui/resources/images/ptz_pan_left.svg +++ b/chromeos/components/camera_app_ui/resources/images/ptz_pan_left.svg
@@ -1,3 +1,3 @@ -<svg width="8" height="10" viewBox="0 0 8 10" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path fill-rule="evenodd" clip-rule="evenodd" d="M7.33667 8.825L3.21611 5L7.33667 1.175L6.06811 0L0.670003 5L6.06811 10L7.33667 8.825Z" fill="#E8EAED"/> +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M14 14.59L9.05533 10L14 5.41L12.4777 4L6 10L12.4777 16L14 14.59Z" fill="#EEEEEE"/> </svg>
diff --git a/chromeos/components/camera_app_ui/resources/images/ptz_pan_right.svg b/chromeos/components/camera_app_ui/resources/images/ptz_pan_right.svg index a7d8343f..0f3c59ad 100644 --- a/chromeos/components/camera_app_ui/resources/images/ptz_pan_right.svg +++ b/chromeos/components/camera_app_ui/resources/images/ptz_pan_right.svg
@@ -1,3 +1,3 @@ -<svg width="8" height="10" viewBox="0 0 8 10" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path fill-rule="evenodd" clip-rule="evenodd" d="M0.666687 8.825L4.78724 5L0.666687 1.175L1.93524 0L7.33335 5L1.93524 10L0.666687 8.825Z" fill="#E8EAED"/> +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M6 5.41L10.9447 10L6 14.59L7.52227 16L14 10L7.52227 4L6 5.41Z" fill="#EEEEEE"/> </svg>
diff --git a/chromeos/components/camera_app_ui/resources/images/ptz_tilt_down.svg b/chromeos/components/camera_app_ui/resources/images/ptz_tilt_down.svg index c24aeff..0a80017 100644 --- a/chromeos/components/camera_app_ui/resources/images/ptz_tilt_down.svg +++ b/chromeos/components/camera_app_ui/resources/images/ptz_tilt_down.svg
@@ -1,3 +1,3 @@ -<svg width="12" height="8" viewBox="0 0 12 8" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path fill-rule="evenodd" clip-rule="evenodd" d="M1.41 0L6 4.94467L10.59 0L12 1.52227L6 8L0 1.52227L1.41 0Z" fill="#E8EAED"/> +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M5.41 6L10 10.9447L14.59 6L16 7.52227L10 14L4 7.52227L5.41 6Z" fill="#EEEEEE"/> </svg>
diff --git a/chromeos/components/camera_app_ui/resources/images/ptz_tilt_up.svg b/chromeos/components/camera_app_ui/resources/images/ptz_tilt_up.svg index 58ae20a..7856c56 100644 --- a/chromeos/components/camera_app_ui/resources/images/ptz_tilt_up.svg +++ b/chromeos/components/camera_app_ui/resources/images/ptz_tilt_up.svg
@@ -1,3 +1,3 @@ -<svg width="12" height="8" viewBox="0 0 12 8" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path fill-rule="evenodd" clip-rule="evenodd" d="M1.41 8L6 3.05533L10.59 8L12 6.47773L6 0L0 6.47773L1.41 8Z" fill="#E8EAED"/> +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M5.41 14L10 9.05533L14.59 14L16 12.4777L10 6L4 12.4777L5.41 14Z" fill="#EEEEEE"/> </svg>
diff --git a/chromeos/components/camera_app_ui/resources/images/ptz_zoom_in.svg b/chromeos/components/camera_app_ui/resources/images/ptz_zoom_in.svg index 9386682..3f4dc71 100644 --- a/chromeos/components/camera_app_ui/resources/images/ptz_zoom_in.svg +++ b/chromeos/components/camera_app_ui/resources/images/ptz_zoom_in.svg
@@ -1,3 +1,5 @@ -<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path fill-rule="evenodd" clip-rule="evenodd" d="M15.49 14L11.76 10.27C12.53 9.2 13 7.91 13 6.5C13 2.91 10.09 0 6.5 0C2.91 0 0 2.91 0 6.5C0 10.09 2.91 13 6.5 13C7.91 13 9.2 12.53 10.27 11.76L14 15.49L15.49 14ZM6.5 11C4.01 11 2 8.99 2 6.5C2 4.01 4.01 2 6.5 2C8.99 2 11 4.01 11 6.5C11 8.99 8.99 11 6.5 11ZM7.5 5.5H9.5V7.5H7.5V9.5H5.5V7.5H3.5V5.5H5.5V3.5H7.5V5.5Z" fill="#E8EAED"/> +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g id="zoom-in"> +<path id="Shape 1" fill-rule="evenodd" clip-rule="evenodd" d="M17.49 16L13.76 12.27C14.53 11.2 15 9.91 15 8.5C15 4.91 12.09 2 8.5 2C4.91 2 2 4.91 2 8.5C2 12.09 4.91 15 8.5 15C9.91 15 11.2 14.53 12.27 13.76L16 17.49L17.49 16ZM8.5 13C6.01 13 4 10.99 4 8.5C4 6.01 6.01 4 8.5 4C10.99 4 13 6.01 13 8.5C13 10.99 10.99 13 8.5 13ZM9.5 7.5H11.5V9.5H9.5V11.5H7.5V9.5H5.5V7.5H7.5V5.5H9.5V7.5Z" fill="#EEEEEE"/> +</g> </svg>
diff --git a/chromeos/components/camera_app_ui/resources/images/ptz_zoom_out.svg b/chromeos/components/camera_app_ui/resources/images/ptz_zoom_out.svg index 3bc6b24..a6d5c5e 100644 --- a/chromeos/components/camera_app_ui/resources/images/ptz_zoom_out.svg +++ b/chromeos/components/camera_app_ui/resources/images/ptz_zoom_out.svg
@@ -1,3 +1,5 @@ -<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path fill-rule="evenodd" clip-rule="evenodd" d="M15.49 14L11.76 10.27C12.53 9.2 13 7.91 13 6.5C13 2.91 10.09 0 6.5 0C2.91 0 0 2.91 0 6.5C0 10.09 2.91 13 6.5 13C7.91 13 9.2 12.53 10.27 11.76L14 15.49L15.49 14ZM6.5 11C4.01 11 2 8.99 2 6.5C2 4.01 4.01 2 6.5 2C8.99 2 11 4.01 11 6.5C11 8.99 8.99 11 6.5 11ZM9.5 5.5V7.5H3.5V5.5H9.5Z" fill="#E8EAED"/> +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g id="zoom-out"> +<path id="Shape 1" fill-rule="evenodd" clip-rule="evenodd" d="M17.49 16L13.76 12.27C14.53 11.2 15 9.91 15 8.5C15 4.91 12.09 2 8.5 2C4.91 2 2 4.91 2 8.5C2 12.09 4.91 15 8.5 15C9.91 15 11.2 14.53 12.27 13.76L16 17.49L17.49 16ZM8.5 13C6.01 13 4 10.99 4 8.5C4 6.01 6.01 4 8.5 4C10.99 4 13 6.01 13 8.5C13 10.99 10.99 13 8.5 13ZM11.5 7.5V9.5H5.5V7.5H11.5Z" fill="#EEEEEE"/> +</g> </svg>
diff --git a/chromeos/dbus/dlcservice/fake_dlcservice_client.h b/chromeos/dbus/dlcservice/fake_dlcservice_client.h index f9eb553..2dcba28 100644 --- a/chromeos/dbus/dlcservice/fake_dlcservice_client.h +++ b/chromeos/dbus/dlcservice/fake_dlcservice_client.h
@@ -55,8 +55,7 @@ const dlcservice::DlcsWithContent& dlcs_with_content) { dlcs_with_content_ = dlcs_with_content; } - void set_dlc_state( - const dlcservice::DlcState& dlc_state) { + void set_dlc_state(const dlcservice::DlcState& dlc_state) { dlc_state_ = dlc_state; }
diff --git a/chromeos/language/DIR_METADATA b/chromeos/language/DIR_METADATA new file mode 100644 index 0000000..fd396f22 --- /dev/null +++ b/chromeos/language/DIR_METADATA
@@ -0,0 +1,7 @@ +buganizer { + component_id: 934840 +} +monorail { + component: "OS>Software>MarketExpansion" +} +team_email: "cros-borders-eng@google.com" \ No newline at end of file
diff --git a/chromeos/language/OWNERS b/chromeos/language/OWNERS new file mode 100644 index 0000000..9aaf0f7e --- /dev/null +++ b/chromeos/language/OWNERS
@@ -0,0 +1,3 @@ +claudiomagni@chromium.org +dvallet@chromium.org +mlcui@google.com \ No newline at end of file
diff --git a/chromeos/language/language_packs/BUILD.gn b/chromeos/language/language_packs/BUILD.gn new file mode 100644 index 0000000..ed5b870e --- /dev/null +++ b/chromeos/language/language_packs/BUILD.gn
@@ -0,0 +1,31 @@ +# Copyright 2021 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos") + +static_library("language_packs") { + sources = [ + "language_pack_manager.cc", + "language_pack_manager.h", + ] + deps = [ + "//base", + "//chromeos/dbus/dlcservice:dlcservice", + "//chromeos/dbus/dlcservice:dlcservice_proto", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ "language_pack_manager_unittest.cc" ] + deps = [ + ":language_packs", + "//base", + "//base/test:test_support", + "//chromeos/dbus/dlcservice:dlcservice", + "//chromeos/dbus/dlcservice:test_support", + "//testing/gmock", + "//testing/gtest", + ] +}
diff --git a/chromeos/language/language_packs/language_pack_manager.cc b/chromeos/language/language_packs/language_pack_manager.cc new file mode 100644 index 0000000..55fbe63 --- /dev/null +++ b/chromeos/language/language_packs/language_pack_manager.cc
@@ -0,0 +1,185 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/language/language_packs/language_pack_manager.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "base/callback_helpers.h" +#include "base/containers/contains.h" +#include "base/containers/flat_map.h" +#include "base/logging.h" +#include "chromeos/dbus/dlcservice/dlcservice.pb.h" +#include "chromeos/dbus/dlcservice/dlcservice_client.h" + +namespace chromeos { +namespace language_packs { +namespace { + +const base::flat_map<PackSpecPair, std::string>& GetAllDlcIds() { + // Create the map of all DLCs and corresponding IDs. + // Whenever a new DLC is created, it needs to be added here. + // Clients of Language Packs don't need to know the IDs. + static const base::NoDestructor<base::flat_map<PackSpecPair, std::string>> + all_dlc_ids({{{kHandwritingFeatureId, "en"}, "handwriting-en-dlc"}}); + + return *all_dlc_ids; +} + +void OnInstallDlcComplete( + OnInstallCompleteCallback callback, + const chromeos::DlcserviceClient::InstallResult& dlc_result) { + PackResult result; + result.operation_error = dlc_result.error; + + if (dlc_result.error == dlcservice::kErrorNone) { + result.pack_state = PackResult::INSTALLED; + result.path = dlc_result.root_path; + } else { + result.pack_state = PackResult::UNKNOWN; + } + + std::move(callback).Run(result); +} + +void OnGetDlcState(GetPackStateCallback callback, + const std::string& err, + const dlcservice::DlcState& dlc_state) { + PackResult result; + result.operation_error = err; + + if (err == dlcservice::kErrorNone) { + switch (dlc_state.state()) { + case dlcservice::DlcState_State_INSTALLED: + result.pack_state = PackResult::INSTALLED; + result.path = dlc_state.root_path(); + break; + case dlcservice::DlcState_State_INSTALLING: + result.pack_state = PackResult::IN_PROGRESS; + break; + case dlcservice::DlcState_State_NOT_INSTALLED: + result.pack_state = PackResult::NOT_INSTALLED; + break; + default: + result.pack_state = PackResult::UNKNOWN; + break; + } + + } else { + result.pack_state = PackResult::UNKNOWN; + } + + std::move(callback).Run(result); +} + +void OnUninstallDlcComplete(OnUninstallCompleteCallback callback, + const std::string& err) { + PackResult result; + result.operation_error = err; + + if (err == dlcservice::kErrorNone) { + result.pack_state = PackResult::NOT_INSTALLED; + } else { + result.pack_state = PackResult::UNKNOWN; + } + + std::move(callback).Run(result); +} + +} // namespace + +bool LanguagePackManager::IsPackAvailable(const std::string& pack_id, + const std::string& locale) { + // We search in the static list for the given Pack spec. + const PackSpecPair spec(pack_id, locale); + return base::Contains(GetAllDlcIds(), spec); +} + +bool LanguagePackManager::GetDlcId(const std::string& pack_id, + const std::string& locale, + std::string* const dlc_id) { + // We search in the static list for the given Pack spec. + const PackSpecPair spec(pack_id, locale); + const auto it = GetAllDlcIds().find(spec); + + if (it == GetAllDlcIds().end()) { + return false; + } + + *dlc_id = it->second; + return true; +} + +void LanguagePackManager::InstallPack(const std::string& pack_id, + const std::string& locale, + OnInstallCompleteCallback callback) { + std::string dlc_id; + const bool found = GetDlcId(pack_id, locale, &dlc_id); + + // If the given Language Pack doesn't exist, run callback and don't reach the + // DLC Service. + if (!found) { + PackResult result; + result.operation_error = dlcservice::kErrorInvalidDlc; + result.pack_state = PackResult::WRONG_ID; + std::move(callback).Run(result); + return; + } + + chromeos::DlcserviceClient::Get()->Install( + dlc_id, base::BindOnce(&OnInstallDlcComplete, std::move(callback)), + base::DoNothing()); +} + +void LanguagePackManager::GetPackState(const std::string& pack_id, + const std::string& locale, + GetPackStateCallback callback) { + std::string dlc_id; + const bool found = GetDlcId(pack_id, locale, &dlc_id); + + // If the given Language Pack doesn't exist, run callback and don't reach the + // DLC Service. + if (!found) { + PackResult result; + result.operation_error = dlcservice::kErrorInvalidDlc; + result.pack_state = PackResult::WRONG_ID; + std::move(callback).Run(result); + return; + } + + chromeos::DlcserviceClient::Get()->GetDlcState( + dlc_id, base::BindOnce(&OnGetDlcState, std::move(callback))); +} + +void LanguagePackManager::RemovePack(const std::string& pack_id, + const std::string& locale, + OnUninstallCompleteCallback callback) { + std::string dlc_id; + const bool found = GetDlcId(pack_id, locale, &dlc_id); + + // If the given Language Pack doesn't exist, run callback and don't reach the + // DLC Service. + if (!found) { + PackResult result; + result.operation_error = dlcservice::kErrorInvalidDlc; + result.pack_state = PackResult::WRONG_ID; + std::move(callback).Run(result); + return; + } + + chromeos::DlcserviceClient::Get()->Uninstall( + dlc_id, base::BindOnce(&OnUninstallDlcComplete, std::move(callback))); +} + +LanguagePackManager::LanguagePackManager() = default; +LanguagePackManager::~LanguagePackManager() = default; + +// static +LanguagePackManager* LanguagePackManager::GetInstance() { + static base::NoDestructor<LanguagePackManager> instance; + return instance.get(); +} + +} // namespace language_packs +} // namespace chromeos
diff --git a/chromeos/language/language_packs/language_pack_manager.h b/chromeos/language/language_packs/language_pack_manager.h new file mode 100644 index 0000000..1fd0506 --- /dev/null +++ b/chromeos/language/language_packs/language_pack_manager.h
@@ -0,0 +1,141 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_ +#define CHROMEOS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_ + +#include <string> + +#include "base/callback.h" +#include "base/no_destructor.h" +#include "base/strings/strcat.h" + +namespace chromeos { +namespace language_packs { + +// All Language Pack IDs are listed here. +constexpr char kHandwritingFeatureId[] = "LP_ID_HANDWRITING"; + +// Status contains information about the status of an operation. +struct PackResult { + // This string contains the error returns by DLC Service. + std::string operation_error; + + enum StatusCode { + UNKNOWN = 0, + WRONG_ID, + NOT_INSTALLED, + IN_PROGRESS, + INSTALLED + }; + + // The code that indicates the current state of the Pack. + // INSTALLED means that the Pack is ready to be used. + StatusCode pack_state; + + // The path where the Pack is available for users to use. + std::string path; +}; + +// We define an internal type to identify a Language Pack. +// It's a pair of featured_id and locale that is hashable. +struct PackSpecPair { + std::string feature_id; + std::string locale; + + PackSpecPair(const std::string& feature_id, const std::string& locale) + : feature_id(feature_id), locale(locale) {} + + bool operator==(const PackSpecPair& other) const { + return (feature_id == other.feature_id && locale == other.locale); + } + + bool operator!=(const PackSpecPair& other) const { return !(*this == other); } + + // Allows PackSpecPair to be used as a key in STL containers, like flat_map. + bool operator<(const PackSpecPair& other) const { + if (feature_id == other.feature_id) + return locale < other.locale; + + return feature_id < other.feature_id; + } + + // Simple hash function: XOR the string hash. + struct HashFunction { + size_t operator()(const PackSpecPair& obj) const { + size_t first_hash = std::hash<std::string>()(obj.feature_id); + size_t second_hash = std::hash<std::string>()(obj.locale) << 1; + return first_hash ^ second_hash; + } + }; +}; + +using OnInstallCompleteCallback = + base::OnceCallback<void(const PackResult& pack_result)>; +using GetPackStateCallback = + base::OnceCallback<void(const PackResult& pack_result)>; +using OnUninstallCompleteCallback = + base::OnceCallback<void(const PackResult& pack_result)>; + +// This class manages all Language Packs on the device. +// This is a Singleton and needs to be accessed via Get(). +class LanguagePackManager { + public: + // Returns true if the given Language Pack exists and can be installed on + // this device. + // TODO(claudiomagni): Check per board. + bool IsPackAvailable(const std::string& pack_id, const std::string& locale); + + // Installs the Language Pack. + // It takes a callback that will be triggered once the operation is done. + // A state is passed to the callback. + void InstallPack(const std::string& pack_id, + const std::string& locale, + OnInstallCompleteCallback callback); + + // Checks the state of a Language Pack. + // It takes a callback that will be triggered once the operation is done. + // A state is passed to the callback. + // If the state marks the Language Pack as ready, then there's no need to + // call Install(), otherwise the client should call Install() and not call + // this method a second time. + void GetPackState(const std::string& pack_id, + const std::string& locale, + GetPackStateCallback callback); + + // Features should call this method to indicate that they do not intend to + // use the Pack again, until they will call |InstallPack()|. + // The Language Pack will be removed from disk, but no guarantee is given on + // when that will happen. + // TODO(claudiomagni): Allow callers to force immediate removal. Useful to + // clear space on disk for another language. + void RemovePack(const std::string& pack_id, + const std::string& locale, + OnUninstallCompleteCallback callback); + + // Returns the global instance.. + static LanguagePackManager* GetInstance(); + + private: + friend base::NoDestructor<LanguagePackManager>; + + // This class should be accessed only via GetInstance(); + LanguagePackManager(); + ~LanguagePackManager(); + + // Disallow copy and assign. + LanguagePackManager(const LanguagePackManager&) = delete; + LanguagePackManager& operator=(const LanguagePackManager&) = delete; + + // Finds the ID of the DLC corresponding to the given spec. + // Returns true if the DLC exists or false otherwise. + bool GetDlcId(const std::string& pack_id, + const std::string& locale, + std::string* dlc_id); +}; + +} // namespace language_packs +} // namespace chromeos + +#endif // CHROMEOS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_
diff --git a/chromeos/language/language_packs/language_pack_manager_unittest.cc b/chromeos/language/language_packs/language_pack_manager_unittest.cc new file mode 100644 index 0000000..4dc7fd2 --- /dev/null +++ b/chromeos/language/language_packs/language_pack_manager_unittest.cc
@@ -0,0 +1,267 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/language/language_packs/language_pack_manager.h" + +#include "base/bind.h" +#include "base/run_loop.h" +#include "base/test/task_environment.h" +#include "chromeos/dbus/dlcservice/dlcservice_client.h" +#include "chromeos/dbus/dlcservice/fake_dlcservice_client.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::chromeos::language_packs::LanguagePackManager; +using ::testing::_; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::WithArg; + +namespace chromeos { +namespace language_packs { + +namespace { + +constexpr char kFakeDlcId[] = "FakeDlc"; + +// We need a mock callback so that we can check that it gets called. +class CallbackForTesting { + public: + OnInstallCompleteCallback GetInstallCallback() { + return base::BindOnce(&CallbackForTesting::Callback, + base::Unretained(this)); + } + + GetPackStateCallback GetPackStateCallback() { + return base::BindOnce(&CallbackForTesting::Callback, + base::Unretained(this)); + } + + OnUninstallCompleteCallback GetRemoveCallback() { + return base::BindOnce(&CallbackForTesting::Callback, + base::Unretained(this)); + } + + MOCK_METHOD(void, Callback, (const PackResult&), ()); +}; + +} // namespace + +class LanguagePackManagerTest : public testing::Test { + public: + void SetUp() override { + manager_ = LanguagePackManager::GetInstance(); + + DlcserviceClient::InitializeFake(); + dlcservice_client_ = + static_cast<FakeDlcserviceClient*>(DlcserviceClient::Get()); + + ResetPackResult(); + + base::RunLoop().RunUntilIdle(); + } + + void TearDown() override { DlcserviceClient::Shutdown(); } + + void InstallTestCallback(const PackResult& pack_result) { + pack_result_ = pack_result; + } + + void GetPackStateTestCallback(const PackResult& pack_result) { + pack_result_ = pack_result; + } + + void RemoveTestCallback(const PackResult& pack_result) { + pack_result_ = pack_result; + } + + protected: + LanguagePackManager* manager_; + PackResult pack_result_; + FakeDlcserviceClient* dlcservice_client_; + + private: + base::test::SingleThreadTaskEnvironment task_environment_; + + void ResetPackResult() { + PackResult temp = PackResult(); + pack_result_ = temp; + } +}; + +TEST_F(LanguagePackManagerTest, IsPackAvailableTrueTest) { + const bool available = manager_->IsPackAvailable(kHandwritingFeatureId, "en"); + EXPECT_TRUE(available); +} + +TEST_F(LanguagePackManagerTest, IsPackAvailableFalseTest) { + // Correct ID, wrong language. + bool available = manager_->IsPackAvailable(kHandwritingFeatureId, "fr"); + EXPECT_FALSE(available); + + // ID doesn't exists. + available = manager_->IsPackAvailable("foo", "fr"); + EXPECT_FALSE(available); +} + +TEST_F(LanguagePackManagerTest, InstallSuccessTest) { + dlcservice_client_->set_install_error(dlcservice::kErrorNone); + dlcservice_client_->set_install_root_path("/path"); + + // We need to use an existing Pack ID, so that we do get a result back. + manager_->InstallPack( + kHandwritingFeatureId, "en", + base::BindOnce(&LanguagePackManagerTest::InstallTestCallback, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(pack_result_.operation_error, dlcservice::kErrorNone); + EXPECT_EQ(pack_result_.pack_state, PackResult::INSTALLED); + EXPECT_EQ(pack_result_.path, "/path"); +} + +TEST_F(LanguagePackManagerTest, InstallFailureTest) { + dlcservice_client_->set_install_error(dlcservice::kErrorInternal); + + // We need to use an existing Pack ID, so that we do get a result back. + manager_->InstallPack( + kHandwritingFeatureId, "en", + base::BindOnce(&LanguagePackManagerTest::InstallTestCallback, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(pack_result_.operation_error, dlcservice::kErrorInternal); + EXPECT_NE(pack_result_.pack_state, PackResult::INSTALLED); +} + +TEST_F(LanguagePackManagerTest, InstallWrongIdTest) { + manager_->InstallPack( + kFakeDlcId, "en", + base::BindOnce(&LanguagePackManagerTest::InstallTestCallback, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(pack_result_.operation_error, dlcservice::kErrorInvalidDlc); + EXPECT_EQ(pack_result_.pack_state, PackResult::WRONG_ID); +} + +// Check that the callback is actually called. +TEST_F(LanguagePackManagerTest, InstallCallbackTest) { + dlcservice_client_->set_install_error(dlcservice::kErrorNone); + dlcservice_client_->set_install_root_path("/path"); + + testing::StrictMock<CallbackForTesting> callback; + EXPECT_CALL(callback, Callback(_)); + + manager_->InstallPack(kFakeDlcId, "en", callback.GetInstallCallback()); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(LanguagePackManagerTest, GetPackStateSuccessTest) { + dlcservice_client_->set_get_dlc_state_error(dlcservice::kErrorNone); + dlcservice::DlcState dlc_state; + dlc_state.set_state(dlcservice::DlcState_State_INSTALLED); + dlc_state.set_is_verified(true); + dlc_state.set_root_path("/path"); + dlcservice_client_->set_dlc_state(dlc_state); + + // We need to use an existing Pack ID, so that we do get a result back. + manager_->GetPackState( + kHandwritingFeatureId, "en", + base::BindOnce(&LanguagePackManagerTest::GetPackStateTestCallback, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(pack_result_.operation_error, dlcservice::kErrorNone); + EXPECT_EQ(pack_result_.pack_state, PackResult::INSTALLED); + EXPECT_EQ(pack_result_.path, "/path"); +} + +TEST_F(LanguagePackManagerTest, GetPackStateFailureTest) { + dlcservice_client_->set_get_dlc_state_error(dlcservice::kErrorInternal); + + // We need to use an existing Pack ID, so that we do get a result back. + manager_->GetPackState( + kHandwritingFeatureId, "en", + base::BindOnce(&LanguagePackManagerTest::GetPackStateTestCallback, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(pack_result_.operation_error, dlcservice::kErrorInternal); + EXPECT_NE(pack_result_.pack_state, PackResult::INSTALLED); +} + +TEST_F(LanguagePackManagerTest, GetPackStateWrongIdTest) { + manager_->GetPackState( + kFakeDlcId, "en", + base::BindOnce(&LanguagePackManagerTest::GetPackStateTestCallback, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(pack_result_.operation_error, dlcservice::kErrorInvalidDlc); + EXPECT_EQ(pack_result_.pack_state, PackResult::WRONG_ID); +} + +// Check that the callback is actually called. +TEST_F(LanguagePackManagerTest, GetPackStateCallbackTest) { + dlcservice_client_->set_get_dlc_state_error(dlcservice::kErrorNone); + + testing::StrictMock<CallbackForTesting> callback; + EXPECT_CALL(callback, Callback(_)); + + manager_->GetPackState(kFakeDlcId, "en", callback.GetPackStateCallback()); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(LanguagePackManagerTest, RemovePackSuccessTest) { + dlcservice_client_->set_uninstall_error(dlcservice::kErrorNone); + + // We need to use an existing Pack ID, so that we do get a result back. + manager_->RemovePack( + kHandwritingFeatureId, "en", + base::BindOnce(&LanguagePackManagerTest::RemoveTestCallback, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(pack_result_.operation_error, dlcservice::kErrorNone); + EXPECT_EQ(pack_result_.pack_state, PackResult::NOT_INSTALLED); +} + +TEST_F(LanguagePackManagerTest, RemovePackFailureTest) { + dlcservice_client_->set_uninstall_error(dlcservice::kErrorInternal); + + // We need to use an existing Pack ID, so that we do get a result back. + manager_->RemovePack( + kHandwritingFeatureId, "en", + base::BindOnce(&LanguagePackManagerTest::RemoveTestCallback, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(pack_result_.operation_error, dlcservice::kErrorInternal); +} + +TEST_F(LanguagePackManagerTest, RemovePackWrongIdTest) { + manager_->RemovePack( + kFakeDlcId, "en", + base::BindOnce(&LanguagePackManagerTest::RemoveTestCallback, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(pack_result_.operation_error, dlcservice::kErrorInvalidDlc); + EXPECT_EQ(pack_result_.pack_state, PackResult::WRONG_ID); +} + +// Check that the callback is actually called. +TEST_F(LanguagePackManagerTest, RemovePackCallbackTest) { + dlcservice_client_->set_uninstall_error(dlcservice::kErrorNone); + + testing::StrictMock<CallbackForTesting> callback; + EXPECT_CALL(callback, Callback(_)); + + manager_->RemovePack(kFakeDlcId, "en", callback.GetRemoveCallback()); + base::RunLoop().RunUntilIdle(); +} + +} // namespace language_packs +} // namespace chromeos
diff --git a/chromeos/services/libassistant/chromium_api_delegate.h b/chromeos/services/libassistant/chromium_api_delegate.h index 2990b59..bb70ee3d 100644 --- a/chromeos/services/libassistant/chromium_api_delegate.h +++ b/chromeos/services/libassistant/chromium_api_delegate.h
@@ -23,7 +23,7 @@ class ChromiumHttpConnectionFactory; -class ChromiumApiDelegate : public assistant_client::ChromeOSApiDelegate { +class ChromiumApiDelegate : public assistant_client::FuchsiaApiDelegate { public: explicit ChromiumApiDelegate( std::unique_ptr<network::PendingSharedURLLoaderFactory>
diff --git a/chromeos/services/libassistant/service_controller.cc b/chromeos/services/libassistant/service_controller.cc index e452385..1ca11ba 100644 --- a/chromeos/services/libassistant/service_controller.cc +++ b/chromeos/services/libassistant/service_controller.cc
@@ -327,7 +327,7 @@ assistant_manager_internal() ->GetFuchsiaApiHelperOrDie() - ->SetChromeOSApiDelegate(chromium_api_delegate_.get()); + ->SetFuchsiaApiDelegate(chromium_api_delegate_.get()); } void ServiceController::CreateChromiumApiDelegate(
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc index 7525ba7..48e42cfa 100644 --- a/components/autofill/content/browser/content_autofill_driver.cc +++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -4,7 +4,6 @@ #include "components/autofill/content/browser/content_autofill_driver.h" -#include <memory> #include <tuple> #include <utility> #include <vector> @@ -13,6 +12,7 @@ #include "base/metrics/histogram_macros.h" #include "build/build_config.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" +#include "components/autofill/core/browser/android_autofill_manager.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/browser_autofill_manager.h" #include "components/autofill/core/browser/form_structure.h" @@ -64,21 +64,15 @@ AutofillClient* client, const std::string& app_locale, AutofillManager::AutofillDownloadManagerState enable_download_manager, - AutofillManager::AutofillManagerFactoryCallback - autofill_manager_factory_callback) + AutofillProvider* provider) : render_frame_host_(render_frame_host), browser_autofill_manager_(nullptr), key_press_handler_manager_(this), log_manager_(client->GetLogManager()) { - // AutofillManager isn't used if provider is valid, Autofill provider is - // currently used by Android WebView only. - if (autofill_manager_factory_callback) { - autofill_manager_ = autofill_manager_factory_callback.Run( - this, client, app_locale, enable_download_manager); - GetAutofillAgent()->SetUserGestureRequired(false); - GetAutofillAgent()->SetSecureContextRequired(true); - GetAutofillAgent()->SetFocusRequiresScroll(false); - GetAutofillAgent()->SetQueryPasswordSuggestion(true); + // BrowserAutofillManager isn't used if provider is valid, Autofill provider + // is currently used by Android WebView only. + if (provider) { + SetAutofillProvider(provider, client, enable_download_manager); } else { SetBrowserAutofillManager(std::make_unique<BrowserAutofillManager>( this, client, app_locale, enable_download_manager)); @@ -177,11 +171,11 @@ void ContentAutofillDriver::PropagateAutofillPredictions( const std::vector<FormStructure*>& forms) { - AutofillManager* manager = browser_autofill_manager_ + AutofillManager* handler = browser_autofill_manager_ ? browser_autofill_manager_ : autofill_manager_.get(); - DCHECK(manager); - manager->PropagateAutofillPredictions(render_frame_host_, forms); + DCHECK(handler); + handler->PropagateAutofillPredictions(render_frame_host_, forms); } void ContentAutofillDriver::HandleParsedForms( @@ -377,7 +371,7 @@ ShowOfferNotificationIfApplicable(navigation_handle); // When IsServedFromBackForwardCache, the form data is not parsed - // again. So, we should keep and use the autofill manager's + // again. So, we should keep and use the autofill handler's // form_structures from BFCache for form submit. if (navigation_handle->IsServedFromBackForwardCache()) return; @@ -435,6 +429,18 @@ view->GetRenderWidgetHost()->RemoveKeyPressEventCallback(handler); } +void ContentAutofillDriver::SetAutofillProvider( + AutofillProvider* provider, + AutofillClient* client, + AutofillManager::AutofillDownloadManagerState enable_download_manager) { + autofill_manager_ = std::make_unique<AndroidAutofillManager>( + this, client, provider, enable_download_manager); + GetAutofillAgent()->SetUserGestureRequired(false); + GetAutofillAgent()->SetSecureContextRequired(true); + GetAutofillAgent()->SetFocusRequiresScroll(false); + GetAutofillAgent()->SetQueryPasswordSuggestion(true); +} + bool ContentAutofillDriver::DocumentUsedWebOTP() const { return render_frame_host_->DocumentUsedWebOTP(); } @@ -475,6 +481,16 @@ static_cast<PhoneCollectionMetricState>(phone_collection_metric_state_)); } +void ContentAutofillDriver::SetAutofillProviderForTesting( + AutofillProvider* provider, + AutofillClient* client) { + SetAutofillProvider(provider, client, + AutofillManager::AutofillDownloadManagerState:: + DISABLE_AUTOFILL_DOWNLOAD_MANAGER); + // BrowserAutofillManager isn't used if provider is valid. + browser_autofill_manager_ = nullptr; +} + void ContentAutofillDriver::ShowOfferNotificationIfApplicable( content::NavigationHandle* navigation_handle) { if (!navigation_handle->IsInMainFrame())
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h index ca0f934..7c96eb16 100644 --- a/components/autofill/content/browser/content_autofill_driver.h +++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -29,6 +29,7 @@ namespace autofill { class AutofillClient; +class AutofillProvider; class LogManager; // Use <Phone><WebOTP><OTC> as the bit pattern to identify the metrics state. @@ -62,8 +63,7 @@ AutofillClient* client, const std::string& app_locale, AutofillManager::AutofillDownloadManagerState enable_download_manager, - AutofillManager::AutofillManagerFactoryCallback - autofill_manager_factory_callback); + AutofillProvider* provider); ~ContentAutofillDriver() override; // Gets the driver for |render_frame_host|. @@ -159,6 +159,9 @@ const content::RenderWidgetHost::KeyPressEventCallback& handler); void RemoveKeyPressHandler(); + void SetAutofillProviderForTesting(AutofillProvider* provider, + AutofillClient* client); + // Sets the manager to |manager|. Takes ownership of |manager|. void SetBrowserAutofillManager( std::unique_ptr<BrowserAutofillManager> manager); @@ -185,6 +188,11 @@ void RemoveHandler( const content::RenderWidgetHost::KeyPressEventCallback& handler) override; + void SetAutofillProvider( + AutofillProvider* provider, + AutofillClient* client, + AutofillManager::AutofillDownloadManagerState enable_download_manager); + // Returns whether navigator.credentials.get({otp: {transport:"sms"}}) has // been used. bool DocumentUsedWebOTP() const;
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc index 34d4ea9..780119b 100644 --- a/components/autofill/content/browser/content_autofill_driver_factory.cc +++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -30,11 +30,9 @@ const std::string& app_locale, BrowserAutofillManager::AutofillDownloadManagerState enable_download_manager, - AutofillManager::AutofillManagerFactoryCallback - autofill_manager_factory_callback) { + AutofillProvider* provider) { return std::make_unique<ContentAutofillDriver>( - render_frame_host, client, app_locale, enable_download_manager, - std::move(autofill_manager_factory_callback)); + render_frame_host, client, app_locale, enable_download_manager, provider); } } // namespace @@ -52,9 +50,8 @@ const std::string& app_locale, BrowserAutofillManager::AutofillDownloadManagerState enable_download_manager) { - CreateForWebContentsAndDelegate( - contents, client, app_locale, enable_download_manager, - AutofillManager::AutofillManagerFactoryCallback()); + CreateForWebContentsAndDelegate(contents, client, app_locale, + enable_download_manager, nullptr); } void ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( @@ -63,16 +60,14 @@ const std::string& app_locale, BrowserAutofillManager::AutofillDownloadManagerState enable_download_manager, - AutofillManager::AutofillManagerFactoryCallback - autofill_manager_factory_callback) { + AutofillProvider* provider) { if (FromWebContents(contents)) return; contents->SetUserData( kContentAutofillDriverFactoryWebContentsUserDataKey, std::make_unique<ContentAutofillDriverFactory>( - contents, client, app_locale, enable_download_manager, - std::move(autofill_manager_factory_callback))); + contents, client, app_locale, enable_download_manager, provider)); } // static @@ -112,14 +107,12 @@ const std::string& app_locale, BrowserAutofillManager::AutofillDownloadManagerState enable_download_manager, - AutofillManager::AutofillManagerFactoryCallback - autofill_manager_factory_callback) + AutofillProvider* provider) : AutofillDriverFactory(client), content::WebContentsObserver(web_contents), app_locale_(app_locale), enable_download_manager_(enable_download_manager), - autofill_manager_factory_callback_( - std::move(autofill_manager_factory_callback)) {} + provider_(provider) {} ContentAutofillDriver* ContentAutofillDriverFactory::DriverForFrame( content::RenderFrameHost* render_frame_host) { @@ -127,10 +120,10 @@ // ContentAutofillDriver are created on demand here. if (!driver) { - AddForKey(render_frame_host, - base::BindRepeating(CreateDriver, render_frame_host, client(), - app_locale_, enable_download_manager_, - autofill_manager_factory_callback_)); + AddForKey( + render_frame_host, + base::BindRepeating(CreateDriver, render_frame_host, client(), + app_locale_, enable_download_manager_, provider_)); driver = DriverForKey(render_frame_host); }
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.h b/components/autofill/content/browser/content_autofill_driver_factory.h index 58c3da4..186879e 100644 --- a/components/autofill/content/browser/content_autofill_driver_factory.h +++ b/components/autofill/content/browser/content_autofill_driver_factory.h
@@ -10,7 +10,6 @@ #include "base/supports_user_data.h" #include "components/autofill/content/common/mojom/autofill_driver.mojom.h" #include "components/autofill/core/browser/autofill_driver_factory.h" -#include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/browser_autofill_manager.h" #include "content/public/browser/web_contents_observer.h" #include "mojo/public/cpp/bindings/pending_associated_receiver.h" @@ -22,6 +21,7 @@ namespace autofill { class ContentAutofillDriver; +class AutofillProvider; // Manages lifetime of ContentAutofillDriver. One Factory per WebContents // creates one Driver per RenderFrame. @@ -37,8 +37,7 @@ const std::string& app_locale, BrowserAutofillManager::AutofillDownloadManagerState enable_download_manager, - AutofillManager::AutofillManagerFactoryCallback - autofill_manager_factory_callback); + AutofillProvider* provider); ~ContentAutofillDriverFactory() override; @@ -55,8 +54,7 @@ const std::string& app_locale, BrowserAutofillManager::AutofillDownloadManagerState enable_download_manager, - AutofillManager::AutofillManagerFactoryCallback - autofill_manager_factory_callback); + AutofillProvider* provider); static ContentAutofillDriverFactory* FromWebContents( content::WebContents* contents); @@ -82,8 +80,7 @@ private: std::string app_locale_; BrowserAutofillManager::AutofillDownloadManagerState enable_download_manager_; - AutofillManager::AutofillManagerFactoryCallback - autofill_manager_factory_callback_; + AutofillProvider* provider_; }; } // namespace autofill
diff --git a/components/autofill/content/browser/content_autofill_driver_unittest.cc b/components/autofill/content/browser/content_autofill_driver_unittest.cc index ddeafa755..94bb308 100644 --- a/components/autofill/content/browser/content_autofill_driver_unittest.cc +++ b/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -284,12 +284,11 @@ public: TestContentAutofillDriver(content::RenderFrameHost* rfh, AutofillClient* client) - : ContentAutofillDriver( - rfh, - client, - kAppLocale, - kDownloadState, - AutofillManager::AutofillManagerFactoryCallback()) { + : ContentAutofillDriver(rfh, + client, + kAppLocale, + kDownloadState, + nullptr) { std::unique_ptr<BrowserAutofillManager> autofill_manager( new MockBrowserAutofillManager(this, client)); SetBrowserAutofillManager(std::move(autofill_manager));
diff --git a/components/autofill/core/browser/android_autofill_manager.cc b/components/autofill/core/browser/android_autofill_manager.cc index 43a0106..5710567 100644 --- a/components/autofill/core/browser/android_autofill_manager.cc +++ b/components/autofill/core/browser/android_autofill_manager.cc
@@ -4,24 +4,12 @@ #include "components/autofill/core/browser/android_autofill_manager.h" -#include "base/memory/ptr_util.h" #include "components/autofill/core/browser/autofill_provider.h" namespace autofill { using base::TimeTicks; -// static -std::unique_ptr<AutofillManager> AndroidAutofillManager::Create( - AutofillProvider* provider, - AutofillDriver* driver, - AutofillClient* client, - const std::string& /*app_locale*/, - AutofillManager::AutofillDownloadManagerState enable_download_manager) { - return base::WrapUnique(new AndroidAutofillManager(driver, client, provider, - enable_download_manager)); -} - AndroidAutofillManager::AndroidAutofillManager( AutofillDriver* driver, AutofillClient* client, @@ -33,7 +21,7 @@ version_info::Channel::UNKNOWN), provider_(provider) {} -AndroidAutofillManager::~AndroidAutofillManager() = default; +AndroidAutofillManager::~AndroidAutofillManager() {} void AndroidAutofillManager::OnFormSubmittedImpl( const FormData& form,
diff --git a/components/autofill/core/browser/android_autofill_manager.h b/components/autofill/core/browser/android_autofill_manager.h index 17c7ef8..71b0c4d 100644 --- a/components/autofill/core/browser/android_autofill_manager.h +++ b/components/autofill/core/browser/android_autofill_manager.h
@@ -16,13 +16,11 @@ // This class forwards AutofillManager calls to AutofillProvider. class AndroidAutofillManager : public AutofillManager { public: - static std::unique_ptr<AutofillManager> Create( - AutofillProvider* provider, + AndroidAutofillManager( AutofillDriver* driver, AutofillClient* client, - const std::string& app_locale, + AutofillProvider* provider, AutofillManager::AutofillDownloadManagerState enable_download_manager); - ~AndroidAutofillManager() override; void OnFocusNoLongerOnForm(bool had_interacted_form) override; @@ -44,12 +42,6 @@ bool has_server_prediction() const { return has_server_prediction_; } protected: - AndroidAutofillManager( - AutofillDriver* driver, - AutofillClient* client, - AutofillProvider* provider, - AutofillManager::AutofillDownloadManagerState enable_download_manager); - void OnFormSubmittedImpl(const FormData& form, bool known_success, mojom::SubmissionSource source) override;
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h index 963b907..81553596 100644 --- a/components/autofill/core/browser/autofill_manager.h +++ b/components/autofill/core/browser/autofill_manager.h
@@ -57,15 +57,6 @@ virtual void OnFormParsed() = 0; }; - // The factory method for the embedder to create the subclass of - // AutofillManager in ContentAutofillDriver. - using AutofillManagerFactoryCallback = - base::RepeatingCallback<std::unique_ptr<AutofillManager>( - AutofillDriver*, - AutofillClient*, - const std::string& app_locale, - AutofillManager::AutofillDownloadManagerState)>; - // Raw metadata uploading enabled iff this Chrome instance is on Canary or Dev // channel. static bool IsRawMetadataUploadingEnabled(version_info::Channel channel);
diff --git a/components/autofill/core/browser/payments/strike_database.cc b/components/autofill/core/browser/payments/strike_database.cc index a4acdfc..69e80fe 100644 --- a/components/autofill/core/browser/payments/strike_database.cc +++ b/components/autofill/core/browser/payments/strike_database.cc
@@ -46,7 +46,7 @@ weak_ptr_factory_.GetWeakPtr())); } -StrikeDatabase::~StrikeDatabase() {} +StrikeDatabase::~StrikeDatabase() = default; int StrikeDatabase::AddStrikes(int strikes_increase, const std::string& key) { DCHECK(strikes_increase > 0); @@ -76,16 +76,28 @@ ClearAllProtoStrikesForKey(key, base::DoNothing()); } -void StrikeDatabase::ClearAllStrikesForProject( +std::vector<std::string> StrikeDatabase::GetAllStrikeKeysForProject( const std::string& project_prefix) { - std::vector<std::string> keys_to_delete; + std::vector<std::string> project_keys; for (std::pair<std::string, StrikeData> entry : strike_map_cache_) { if (entry.first.find(project_prefix) == 0) { - keys_to_delete.push_back(entry.first); + project_keys.push_back(entry.first); } } - for (std::string key : keys_to_delete) - ClearStrikes(key); + return project_keys; +} + +void StrikeDatabase::ClearAllStrikesForProject( + const std::string& project_prefix) { + ClearStrikesForKeys(GetAllStrikeKeysForProject(project_prefix)); +} + +void StrikeDatabase::ClearStrikesForKeys( + const std::vector<std::string>& keys_to_remove) { + for (const auto& key : keys_to_remove) { + strike_map_cache_.erase(key); + } + ClearAllProtoStrikesForKeys(keys_to_remove, base::DoNothing()); } void StrikeDatabase::ClearAllStrikes() { @@ -161,8 +173,8 @@ outer_callback); } -void StrikeDatabase::ClearAllProtoStrikesForKey( - const std::string& key, +void StrikeDatabase::ClearAllProtoStrikesForKeys( + const std::vector<std::string>& keys, const ClearStrikesCallback& outer_callback) { if (!database_initialized_) { outer_callback.Run(false); @@ -170,13 +182,20 @@ } std::unique_ptr<std::vector<std::string>> keys_to_remove( new std::vector<std::string>()); - keys_to_remove->push_back(key); + *keys_to_remove = keys; db_->UpdateEntries( /*entries_to_save=*/std::make_unique< leveldb_proto::ProtoDatabase<StrikeData>::KeyEntryVector>(), /*keys_to_remove=*/std::move(keys_to_remove), outer_callback); } +void StrikeDatabase::ClearAllProtoStrikesForKey( + const std::string& key, + const ClearStrikesCallback& outer_callback) { + std::vector<std::string> keys_to_delete({key}); + ClearAllProtoStrikesForKeys(keys_to_delete, outer_callback); +} + void StrikeDatabase::GetProtoStrikeData(const std::string& key, const GetValueCallback& callback) { if (!database_initialized_) {
diff --git a/components/autofill/core/browser/payments/strike_database.h b/components/autofill/core/browser/payments/strike_database.h index 0a2dd30..d28f29b5 100644 --- a/components/autofill/core/browser/payments/strike_database.h +++ b/components/autofill/core/browser/payments/strike_database.h
@@ -72,6 +72,15 @@ // ProtoDatabase. void ClearStrikes(const std::string& key); + // Returns all strike keys for |project_prefix|. + // The returned keys still contain the |project_prefix|. + std::vector<std::string> GetAllStrikeKeysForProject( + const std::string& project_prefix); + + // Removes database entry for keys in |keys_to_remove| from in-memory cache + // and the underlying ProtoDatabase. + void ClearStrikesForKeys(const std::vector<std::string>& keys_to_remove); + // Removes all database entries from in-memory cache and underlying // ProtoDatabase for the whole project. void ClearAllStrikesForProject(const std::string& project_prefix); @@ -138,6 +147,11 @@ const std::string& key, const ClearStrikesCallback& outer_callback); + // Same as |ClearAllProtoStrikesForKey()| but for a vector of |keys|. + virtual void ClearAllProtoStrikesForKeys( + const std::vector<std::string>& keys, + const ClearStrikesCallback& outer_callback); + // Passes success status and StrikeData entry for |key| to |inner_callback|. void GetProtoStrikeData(const std::string& key, const GetValueCallback& inner_callback);
diff --git a/components/autofill/core/browser/payments/strike_database_unittest.cc b/components/autofill/core/browser/payments/strike_database_unittest.cc index 1fa2338..ddbda726 100644 --- a/components/autofill/core/browser/payments/strike_database_unittest.cc +++ b/components/autofill/core/browser/payments/strike_database_unittest.cc
@@ -57,7 +57,7 @@ // ProtoDatabase. class StrikeDatabaseTest : public ::testing::Test { public: - StrikeDatabaseTest() {} + StrikeDatabaseTest() = default; void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); @@ -114,6 +114,20 @@ run_loop.Run(); } + void OnClearAllProtoStrikesForKeys(base::RepeatingClosure run_loop_closure, + bool success) { + run_loop_closure.Run(); + } + + void ClearAllProtoStrikesForKeys(const std::vector<std::string>& keys) { + base::RunLoop run_loop; + strike_database_->ClearAllProtoStrikesForKeys( + keys, + base::BindRepeating(&StrikeDatabaseTest::OnClearAllProtoStrikesForKeys, + base::Unretained(this), run_loop.QuitClosure())); + run_loop.Run(); + } + void OnClearAllProtoStrikes(base::RepeatingClosure run_loop_closure, bool success) { run_loop_closure.Run(); @@ -152,7 +166,7 @@ std::vector<std::pair<std::string, StrikeData>> entries; StrikeData data; data.set_num_strikes(3); - entries.push_back(std::make_pair(key, data)); + entries.emplace_back(key, data); AddProtoEntries(entries); int strikes = GetProtoStrikes(key); @@ -172,7 +186,7 @@ std::vector<std::pair<std::string, StrikeData>> entries; StrikeData data; data.set_num_strikes(3); - entries.push_back(std::make_pair(key, data)); + entries.emplace_back(key, data); AddProtoEntries(entries); int strikes = GetProtoStrikes(key); @@ -182,6 +196,30 @@ EXPECT_EQ(0, strikes); } +TEST_F(StrikeDatabaseTest, ClearStrikesForMultipleNonZeroStrikesTest) { + // Set up database with 3 pre-existing strikes for three different keys. + const std::string key1 = "12345"; + const std::string key2 = "67890"; + const std::string key3 = "99000"; + std::vector<std::pair<std::string, StrikeData>> entries; + StrikeData data; + data.set_num_strikes(3); + entries.emplace_back(key1, data); + entries.emplace_back(key2, data); + entries.emplace_back(key3, data); + AddProtoEntries(entries); + + EXPECT_EQ(3, GetProtoStrikes(key1)); + EXPECT_EQ(3, GetProtoStrikes(key2)); + EXPECT_EQ(3, GetProtoStrikes(key3)); + std::vector<std::string> keys_to_clear({key1, key2}); + ClearAllProtoStrikesForKeys(keys_to_clear); + EXPECT_EQ(0, GetProtoStrikes(key1)); + EXPECT_EQ(0, GetProtoStrikes(key2)); + // The strikes for the third key should not have been reset. + EXPECT_EQ(3, GetProtoStrikes(key3)); +} + TEST_F(StrikeDatabaseTest, ClearStrikesForMultipleNonZeroStrikesEntriesTest) { // Set up database with 3 pre-existing strikes at |key1|, and 5 pre-existing // strikes at |key2|. @@ -190,10 +228,10 @@ std::vector<std::pair<std::string, StrikeData>> entries; StrikeData data1; data1.set_num_strikes(3); - entries.push_back(std::make_pair(key1, data1)); + entries.emplace_back(key1, data1); StrikeData data2; data2.set_num_strikes(5); - entries.push_back(std::make_pair(key2, data2)); + entries.emplace_back(key2, data2); AddProtoEntries(entries); int strikes = GetProtoStrikes(key1); @@ -228,4 +266,37 @@ EXPECT_EQ(0, GetProtoStrikes(key2)); } +TEST_F(StrikeDatabaseTest, GetAllStrikeKeysForProject) { + const std::string key1 = "project_12345"; + const std::string key2 = "project_13579"; + const std::string key3 = "otherproject_13579"; + strike_database_->AddStrikes(1, key1); + strike_database_->AddStrikes(2, key2); + strike_database_->AddStrikes(2, key3); + std::vector<std::string> expected_keys({key1, key2}); + EXPECT_EQ(strike_database_->GetAllStrikeKeysForProject("project"), + expected_keys); + expected_keys = {key3}; + EXPECT_EQ(strike_database_->GetAllStrikeKeysForProject("otherproject"), + expected_keys); + ClearAllProtoStrikes(); +} + +TEST_F(StrikeDatabaseTest, ClearStrikesForKeys) { + const std::string key1 = "project_12345"; + const std::string key2 = "project_13579"; + const std::string key3 = "otherproject_13579"; + strike_database_->AddStrikes(1, key1); + strike_database_->AddStrikes(2, key2); + strike_database_->AddStrikes(2, key3); + strike_database_->ClearStrikesForKeys(std::vector<std::string>({key1, key2})); + std::vector<std::string> expected_keys({}); + EXPECT_EQ(strike_database_->GetAllStrikeKeysForProject("project"), + expected_keys); + expected_keys.emplace_back(key3); + EXPECT_EQ(strike_database_->GetAllStrikeKeysForProject("otherproject"), + expected_keys); + ClearAllProtoStrikes(); +} + } // namespace autofill
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn index 9fae369..cc682e2f 100644 --- a/components/autofill_assistant/browser/BUILD.gn +++ b/components/autofill_assistant/browser/BUILD.gn
@@ -198,6 +198,8 @@ "service/simple_url_loader_factory.h", "starter.cc", "starter.h", + "starter_heuristic.cc", + "starter_heuristic.h", "starter_platform_delegate.h", "startup_util.cc", "startup_util.h", @@ -405,6 +407,7 @@ "service/service_impl_unittest.cc", "service/service_request_sender_impl_unittest.cc", "service/service_request_sender_local_impl_unittest.cc", + "starter_heuristic_unittest.cc", "starter_unittest.cc", "startup_util_unittest.cc", "string_conversions_util_unittest.cc",
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc b/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc index c801ae1..e57bc649 100644 --- a/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc +++ b/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
@@ -20,6 +20,8 @@ #include "components/autofill_assistant/browser/test_util.h" #include "components/autofill_assistant/browser/user_model.h" #include "components/strings/grit/components_strings.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_browser_context.h" #include "content/public/test/test_renderer_host.h" #include "content/public/test/web_contents_tester.h" #include "testing/gmock/include/gmock/gmock.h" @@ -54,10 +56,13 @@ using ::testing::StrEq; using ::testing::UnorderedElementsAre; -class CollectUserDataActionTest : public content::RenderViewHostTestHarness { +class CollectUserDataActionTest : public testing::Test { public: void SetUp() override { - RenderViewHostTestHarness::SetUp(); + web_contents_ = content::WebContentsTester::CreateTestWebContents( + &browser_context_, nullptr); + content::WebContentsTester::For(web_contents_.get()) + ->SetLastCommittedURL(GURL(kFakeUrl)); ON_CALL(mock_action_delegate_, GetPersonalDataManager) .WillByDefault(Return(&mock_personal_data_manager_)); @@ -78,21 +83,21 @@ std::move(collect_user_data_options->confirm_callback) .Run(&user_data_, &user_model_); })); - ON_CALL(mock_website_login_manager_, OnGetLoginsForUrl(_, _)) .WillByDefault( RunOnceCallback<1>(std::vector<WebsiteLoginManager::Login>{ WebsiteLoginManager::Login(GURL(kFakeUrl), kFakeUsername)})); ON_CALL(mock_website_login_manager_, OnGetPasswordForLogin(_, _)) .WillByDefault(RunOnceCallback<1>(true, kFakePassword)); - - content::WebContentsTester::For(web_contents()) - ->SetLastCommittedURL(GURL(kFakeUrl)); ON_CALL(mock_action_delegate_, GetWebContents()) - .WillByDefault(Return(web_contents())); + .WillByDefault(Return(web_contents_.get())); } protected: + content::BrowserTaskEnvironment task_environment_; + content::RenderViewHostTestEnabler rvh_test_enabler_; + content::TestBrowserContext browser_context_; + std::unique_ptr<content::WebContents> web_contents_; base::MockCallback<Action::ProcessActionCallback> callback_; MockPersonalDataManager mock_personal_data_manager_; MockWebsiteLoginManager mock_website_login_manager_;
diff --git a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc index 74c693f..1368c06e 100644 --- a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc +++ b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
@@ -336,7 +336,7 @@ action_delegate_->GetWebController()->SelectOption( re2, /* case_sensitive= */ false, option_comparison_attribute, - *element_ptr, std::move(on_set_field_value)); + /* strict= */ true, *element_ptr, std::move(on_set_field_value)); return; }
diff --git a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc index fcc8f10c..a39f0616 100644 --- a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc +++ b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc
@@ -490,9 +490,9 @@ GetElementTag(EqualsElement(expected_element), _)) .WillOnce(RunOnceCallback<1>(OkClientStatus(), "SELECT")); EXPECT_CALL(mock_web_controller_, - SelectOption("^2050", false, SelectOptionProto::LABEL, + SelectOption("^2050", false, SelectOptionProto::LABEL, true, EqualsElement(expected_element), _)) - .WillOnce(RunOnceCallback<4>(OkClientStatus())); + .WillOnce(RunOnceCallback<5>(OkClientStatus())); // Second validation succeeds. EXPECT_CALL(mock_web_controller_,
diff --git a/components/autofill_assistant/browser/actions/select_option_action.cc b/components/autofill_assistant/browser/actions/select_option_action.cc index da352dda..e194a08f 100644 --- a/components/autofill_assistant/browser/actions/select_option_action.cc +++ b/components/autofill_assistant/browser/actions/select_option_action.cc
@@ -92,7 +92,8 @@ base::BindOnce(&WebController::SelectOption, delegate_->GetWebController()->GetWeakPtr(), value_, case_sensitive_, - proto_.select_option().option_comparison_attribute()), + proto_.select_option().option_comparison_attribute(), + proto_.select_option().strict()), base::BindOnce(&SelectOptionAction::EndAction, weak_ptr_factory_.GetWeakPtr())); }
diff --git a/components/autofill_assistant/browser/actions/select_option_action_unittest.cc b/components/autofill_assistant/browser/actions/select_option_action_unittest.cc index 81100d4..a8a2a4f 100644 --- a/components/autofill_assistant/browser/actions/select_option_action_unittest.cc +++ b/components/autofill_assistant/browser/actions/select_option_action_unittest.cc
@@ -111,6 +111,7 @@ Selector selector({"#select"}); *proto_.mutable_element() = selector.proto; proto_.mutable_text_filter_value()->set_re2("option"); + proto_.set_strict(true); Selector expected_selector = selector; EXPECT_CALL(mock_action_delegate_, @@ -120,9 +121,9 @@ auto expected_element = test_util::MockFindElement(mock_action_delegate_, expected_selector); EXPECT_CALL(mock_web_controller_, - SelectOption("option", false, SelectOptionProto::VALUE, + SelectOption("option", false, SelectOptionProto::VALUE, true, EqualsElement(expected_element), _)) - .WillOnce(RunOnceCallback<4>(OkClientStatus())); + .WillOnce(RunOnceCallback<5>(OkClientStatus())); EXPECT_CALL( callback_, @@ -191,11 +192,11 @@ .WillOnce(RunOnceCallback<1>(OkClientStatus(), base::TimeDelta::FromSeconds(0))); EXPECT_CALL(mock_web_controller_, - SelectOption("John", false, SelectOptionProto::VALUE, + SelectOption("John", false, SelectOptionProto::VALUE, false, EqualsElement(test_util::MockFindElement( mock_action_delegate_, expected_selector)), _)) - .WillOnce(RunOnceCallback<4>(OkClientStatus())); + .WillOnce(RunOnceCallback<5>(OkClientStatus())); EXPECT_CALL( callback_, @@ -219,9 +220,9 @@ auto expected_element = test_util::MockFindElement(mock_action_delegate_, expected_selector); EXPECT_CALL(mock_web_controller_, - SelectOption("^option$", true, SelectOptionProto::VALUE, + SelectOption("^option$", true, SelectOptionProto::VALUE, false, EqualsElement(expected_element), _)) - .WillOnce(RunOnceCallback<4>(OkClientStatus())); + .WillOnce(RunOnceCallback<5>(OkClientStatus())); EXPECT_CALL( callback_, @@ -255,12 +256,13 @@ OnShortWaitForElement(expected_selector, _)) .WillOnce(RunOnceCallback<1>(OkClientStatus(), base::TimeDelta::FromSeconds(0))); - EXPECT_CALL(mock_web_controller_, - SelectOption("^\\+41791234567$", true, SelectOptionProto::VALUE, - EqualsElement(test_util::MockFindElement( - mock_action_delegate_, expected_selector)), - _)) - .WillOnce(RunOnceCallback<4>(OkClientStatus())); + EXPECT_CALL( + mock_web_controller_, + SelectOption("^\\+41791234567$", true, SelectOptionProto::VALUE, false, + EqualsElement(test_util::MockFindElement( + mock_action_delegate_, expected_selector)), + _)) + .WillOnce(RunOnceCallback<5>(OkClientStatus())); EXPECT_CALL( callback_,
diff --git a/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc b/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc index 4ada277..d701343 100644 --- a/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc +++ b/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc
@@ -14,6 +14,8 @@ #include "components/autofill_assistant/browser/service.pb.h" #include "components/autofill_assistant/browser/user_model.h" #include "components/autofill_assistant/browser/value_util.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_browser_context.h" #include "content/public/test/test_renderer_host.h" #include "content/public/test/web_contents_tester.h" #include "testing/gmock/include/gmock/gmock.h" @@ -36,12 +38,13 @@ using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAreArray; -class ShowGenericUiActionTest : public content::RenderViewHostTestHarness { +class ShowGenericUiActionTest : public testing::Test { public: - ShowGenericUiActionTest() {} - void SetUp() override { - RenderViewHostTestHarness::SetUp(); + web_contents_ = content::WebContentsTester::CreateTestWebContents( + &browser_context_, nullptr); + content::WebContentsTester::For(web_contents_.get()) + ->SetLastCommittedURL(GURL(kFakeUrl)); ON_CALL(mock_action_delegate_, SetGenericUi(_, _, _)) .WillByDefault( @@ -67,10 +70,8 @@ .WillByDefault( RunOnceCallback<1>(std::vector<WebsiteLoginManager::Login>{ WebsiteLoginManager::Login(GURL(kFakeUrl), kFakeUsername)})); - content::WebContentsTester::For(web_contents()) - ->SetLastCommittedURL(GURL(kFakeUrl)); ON_CALL(mock_action_delegate_, GetWebContents()) - .WillByDefault(Return(web_contents())); + .WillByDefault(Return(web_contents_.get())); } protected: @@ -85,6 +86,10 @@ return action; } + content::BrowserTaskEnvironment task_environment_; + content::RenderViewHostTestEnabler rvh_test_enabler_; + content::TestBrowserContext browser_context_; + std::unique_ptr<content::WebContents> web_contents_; UserData user_data_; UserModel user_model_; MockPersonalDataManager mock_personal_data_manager_;
diff --git a/components/autofill_assistant/browser/client_status.cc b/components/autofill_assistant/browser/client_status.cc index 6e833a16..4ff1de094 100644 --- a/components/autofill_assistant/browser/client_status.cc +++ b/components/autofill_assistant/browser/client_status.cc
@@ -142,6 +142,12 @@ case ProcessedActionStatusProto::PASSWORD_ORIGIN_MISMATCH: out << "PASSWORD_ORIGIN_MISMATCH"; break; + case ProcessedActionStatusProto::TOO_MANY_OPTION_VALUES_FOUND: + out << "TOO_MANY_OPTION_VALUES_FOUND"; + break; + case ProcessedActionStatusProto::INVALID_TARGET: + out << "INVALID_TARGET"; + break; // Intentionally no default case to make compilation fail if a new value // was added to the enum but not to this list.
diff --git a/components/autofill_assistant/browser/devtools/value_conversions.h b/components/autofill_assistant/browser/devtools/value_conversions.h index 18d08347f..078d799 100644 --- a/components/autofill_assistant/browser/devtools/value_conversions.h +++ b/components/autofill_assistant/browser/devtools/value_conversions.h
@@ -11,6 +11,7 @@ #include <memory> +#include "base/values.h" #include "components/autofill_assistant/browser/devtools/error_reporter.h" namespace autofill_assistant { @@ -135,7 +136,7 @@ struct FromValue<base::Value> { static std::unique_ptr<base::Value> Parse(const base::Value& value, ErrorReporter* errors) { - return value.CreateDeepCopy(); + return base::Value::ToUniquePtrValue(value.Clone()); } };
diff --git a/components/autofill_assistant/browser/fake_starter_platform_delegate.cc b/components/autofill_assistant/browser/fake_starter_platform_delegate.cc index cec341f..3ae3df5a 100644 --- a/components/autofill_assistant/browser/fake_starter_platform_delegate.cc +++ b/components/autofill_assistant/browser/fake_starter_platform_delegate.cc
@@ -19,6 +19,16 @@ return std::move(trigger_script_request_sender_for_test_); } +void FakeStarterPlatformDelegate::StartRegularScript( + GURL url, + std::unique_ptr<TriggerContext> trigger_context, + const base::Optional<TriggerScriptProto>& trigger_script) { + if (start_regular_script_callback_) { + std::move(start_regular_script_callback_) + .Run(url, std::move(trigger_context), trigger_script); + } +} + WebsiteLoginManager* FakeStarterPlatformDelegate::GetWebsiteLoginManager() const { return website_login_manager_;
diff --git a/components/autofill_assistant/browser/fake_starter_platform_delegate.h b/components/autofill_assistant/browser/fake_starter_platform_delegate.h index c1658fd..472f03e 100644 --- a/components/autofill_assistant/browser/fake_starter_platform_delegate.h +++ b/components/autofill_assistant/browser/fake_starter_platform_delegate.h
@@ -22,6 +22,10 @@ CreateTriggerScriptUiDelegate() override; std::unique_ptr<ServiceRequestSender> GetTriggerScriptRequestSenderToInject() override; + void StartRegularScript( + GURL url, + std::unique_ptr<TriggerContext> trigger_context, + const base::Optional<TriggerScriptProto>& trigger_script) override; WebsiteLoginManager* GetWebsiteLoginManager() const override; version_info::Channel GetChannel() const override; bool GetFeatureModuleInstalled() const override; @@ -63,6 +67,11 @@ bool proactive_help_enabled_ = true; bool msbb_enabled_ = true; bool is_custom_tab_ = true; + base::OnceCallback<void( + GURL url, + std::unique_ptr<TriggerContext> trigger_context, + const base::Optional<TriggerScriptProto>& trigger_script)> + start_regular_script_callback_; int num_install_feature_module_called_ = 0; int num_show_onboarding_called_ = 0;
diff --git a/components/autofill_assistant/browser/metrics.h b/components/autofill_assistant/browser/metrics.h index 5cef460a..ab4dbc5 100644 --- a/components/autofill_assistant/browser/metrics.h +++ b/components/autofill_assistant/browser/metrics.h
@@ -277,6 +277,11 @@ LITE_SCRIPT_BASE64_DECODING_ERROR = 24, // The user rejected the bottom sheet onboarding LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED = 25, + // Transitioning from CCT to regular tab is currently not supported. + LITE_SCRIPT_CCT_TO_TAB_NOT_SUPPORTED = 26, + // The current trigger script was canceled. This typically happens when a + // new startup request takes precedence. + LITE_SCRIPT_CANCELED = 27, // NOTE: All values in this block are DEPRECATED and will only be sent by // Chrome M-86 and M-87. @@ -307,7 +312,7 @@ // Since Chrome M-88. The bottom sheet was swipe-dismissed by the user. LITE_SCRIPT_PROMPT_SWIPE_DISMISSED = 16, - kMaxValue = LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED + kMaxValue = LITE_SCRIPT_CANCELED }; // The different ways a user who has successfully completed a light script may @@ -584,6 +589,13 @@ break; case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SWIPE_DISMISSED: out << "LITE_SCRIPT_PROMPT_SWIPE_DISMISSED"; + break; + case LiteScriptFinishedState::LITE_SCRIPT_CCT_TO_TAB_NOT_SUPPORTED: + out << "LITE_SCRIPT_CCT_TO_TAB_NOT_SUPPORTED"; + break; + case LiteScriptFinishedState::LITE_SCRIPT_CANCELED: + out << "LITE_SCRIPT_CANCELED"; + break; // Do not add default case to force compilation error for new values. } return out;
diff --git a/components/autofill_assistant/browser/model.proto b/components/autofill_assistant/browser/model.proto index 8f5ea7c..dc107d2b 100644 --- a/components/autofill_assistant/browser/model.proto +++ b/components/autofill_assistant/browser/model.proto
@@ -210,6 +210,13 @@ // password's origin. PASSWORD_ORIGIN_MISMATCH = 29; + // Selecting an option failed because more than one option matched. + TOO_MANY_OPTION_VALUES_FOUND = 30; + + // The action's target did not fit the action. E.g. a |SelectOption| being + // called on any element other than <select>. + INVALID_TARGET = 31; + reserved 15, 23, 25; }
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto index 7b91504..757d5b25 100644 --- a/components/autofill_assistant/browser/service.proto +++ b/components/autofill_assistant/browser/service.proto
@@ -1393,6 +1393,11 @@ } optional OptionComparisonAttribute option_comparison_attribute = 6; + // If |strict|, only one match is allowed. Multiple matches will return a + // |TOO_MANY_OPTION_VALUES_FOUND| error. If not |strict| and multiple matches + // are found, the first one is selected. + optional bool strict = 9; + reserved 1, 3 to 5; }
diff --git a/components/autofill_assistant/browser/starter.cc b/components/autofill_assistant/browser/starter.cc index cbc4f7ae..5fccde24 100644 --- a/components/autofill_assistant/browser/starter.cc +++ b/components/autofill_assistant/browser/starter.cc
@@ -4,6 +4,8 @@ #include "components/autofill_assistant/browser/starter.h" +#include <map> + #include "base/base64url.h" #include "base/bind.h" #include "base/callback.h" @@ -11,7 +13,9 @@ #include "base/feature_list.h" #include "base/logging.h" #include "base/metrics/field_trial.h" +#include "base/no_destructor.h" #include "components/autofill_assistant/browser/features.h" +#include "components/autofill_assistant/browser/intent_strings.h" #include "components/autofill_assistant/browser/service/api_key_fetcher.h" #include "components/autofill_assistant/browser/service/server_url_fetcher.h" #include "components/autofill_assistant/browser/service/service_request_sender.h" @@ -21,6 +25,9 @@ #include "components/autofill_assistant/browser/switches.h" #include "components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h" #include "components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.h" +#include "components/autofill_assistant/browser/url_utils.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" namespace autofill_assistant { @@ -62,6 +69,15 @@ /* disable_auth_if_no_access_token = */ true); } +// The heuristic is shared across all instances and initialized on first use. As +// such, we do not support updating the heuristic while Chrome is running. +const scoped_refptr<StarterHeuristic> GetOrCreateStarterHeuristic() { + static const base::NoDestructor<scoped_refptr<StarterHeuristic>> + starter_heuristic( + [] { return base::MakeRefCounted<StarterHeuristic>(); }()); + return *starter_heuristic; +} + } // namespace Starter::Starter(content::WebContents* web_contents, @@ -71,7 +87,8 @@ : content::WebContentsObserver(web_contents), platform_delegate_(platform_delegate), ukm_recorder_(ukm_recorder), - runtime_manager_(runtime_manager) { + runtime_manager_(runtime_manager), + starter_heuristic_(GetOrCreateStarterHeuristic()) { CheckSettings(); } @@ -82,7 +99,7 @@ // User-initiated navigations during non-trigger-script startups will cancel // the startup. This is mostly intended for navigations while the onboarding // is being shown. - if (pending_callback_ && !navigation_handle->WasServerRedirect() && + if (IsStartupPending() && !navigation_handle->WasServerRedirect() && !trigger_script_coordinator_ && navigation_handle->GetURL() != StartupUtil().ChooseStartupUrlForIntent(*pending_trigger_context_)) { @@ -91,14 +108,61 @@ : Metrics::DropOutReason::NAVIGATION, pending_trigger_context_->GetScriptParameters().GetIntent().value_or( std::string())); - CancelPendingStartup(); + CancelPendingStartup( + Metrics::LiteScriptFinishedState::LITE_SCRIPT_CANCELED); } - if (!fetch_trigger_scripts_on_navigation_) { + if (!navigation_handle->HasCommitted() || navigation_handle->IsErrorPage() || + navigation_handle->WasServerRedirect()) { return; } - // TODO(arbesser): fetch trigger scripts when appropriate. + MaybeStartImplicitlyForUrl(navigation_handle->GetURL()); +} + +void Starter::MaybeStartImplicitlyForUrl(const GURL& url) { + if (!fetch_trigger_scripts_on_navigation_ || IsStartupPending() || + !url.is_valid()) { + return; + } + + // Run the heuristic in a separate task. + starter_heuristic_->RunHeuristicAsync( + url, base::BindOnce(&Starter::OnHeuristicMatch, + weak_ptr_factory_.GetWeakPtr(), url)); +} + +void Starter::OnHeuristicMatch(const GURL& url, bool result) { + if (!result || IsStartupPending() || !fetch_trigger_scripts_on_navigation_) { + return; + } + + // TODO(arbesser): add new command line switches to allow adding debug script + // parameters, like DEBUG_SOCKET_ID + Start(std::make_unique<TriggerContext>( + std::make_unique<ScriptParameters>(std::map<std::string, std::string>{ + {"ENABLED", "true"}, + {"START_IMMEDIATELY", "false"}, + {"REQUEST_TRIGGER_SCRIPT", "true"}, + {"ORIGINAL_DEEPLINK", url.spec()}, + {"INTENT", kShoppingAssistedCheckout}}), + TriggerContext::Options{/* experiment_ids = */ std::string(), + /* is_cct = */ is_custom_tab_, + /* onboarding_shown = */ false, + /* is_direct_action = */ false, + /* initial_url = */ std::string()})); +} + +bool Starter::IsStartupPending() const { + return pending_trigger_context_ != nullptr || + trigger_script_coordinator_ != nullptr; +} + +void Starter::OnTabInteractabilityChanged(bool is_interactable) { + CheckSettings(); + if (trigger_script_coordinator_) { + trigger_script_coordinator_->OnTabInteractabilityChanged(is_interactable); + } } void Starter::CheckSettings() { @@ -111,6 +175,8 @@ platform_delegate_->GetMakeSearchesAndBrowsingBetterEnabled(); bool feature_module_installed = platform_delegate_->GetFeatureModuleInstalled(); + bool prev_fetch_trigger_scripts_on_navigation = + fetch_trigger_scripts_on_navigation_; fetch_trigger_scripts_on_navigation_ = base::FeatureList::IsEnabled( features::kAutofillAssistantInChromeTriggering) && @@ -118,7 +184,7 @@ // If there is a pending startup, re-check that the settings are still // allowing the startup to proceed. If not, cancel the startup. - if (pending_callback_) { + if (IsStartupPending()) { StartupMode startup_mode = StartupUtil().ChooseStartupModeForIntent( trigger_script_coordinator_ != nullptr ? trigger_script_coordinator_->GetTriggerContext() @@ -135,22 +201,25 @@ } // Trigger scripts are not allowed to persist when transitioning from // CCT to regular tab. - CancelPendingStartup(); + CancelPendingStartup(Metrics::LiteScriptFinishedState:: + LITE_SCRIPT_CCT_TO_TAB_NOT_SUPPORTED); return; default: - CancelPendingStartup(); + CancelPendingStartup(Metrics::LiteScriptFinishedState:: + LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING); return; } + } else if (!prev_fetch_trigger_scripts_on_navigation && + fetch_trigger_scripts_on_navigation_) { + MaybeStartImplicitlyForUrl(web_contents()->GetLastCommittedURL()); } } -void Starter::Start(std::unique_ptr<TriggerContext> trigger_context, - StarterResultCallback callback) { +void Starter::Start(std::unique_ptr<TriggerContext> trigger_context) { DCHECK(trigger_context); DCHECK(!trigger_context->GetDirectAction()); - CancelPendingStartup(); + CancelPendingStartup(Metrics::LiteScriptFinishedState::LITE_SCRIPT_CANCELED); pending_trigger_context_ = std::move(trigger_context); - pending_callback_ = std::move(callback); if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kAutofillAssistantForceOnboarding) == "true") { @@ -184,7 +253,7 @@ case StartupMode::MANDATORY_PARAMETERS_MISSING: case StartupMode::SETTING_DISABLED: case StartupMode::NO_INITIAL_URL: - RunCallback(/* start_regular_script = */ false); + OnStartDone(/* start_regular_script = */ false); return; case StartupMode::START_BASE64_TRIGGER_SCRIPT: case StartupMode::START_RPC_TRIGGER_SCRIPT: @@ -194,8 +263,8 @@ } } -void Starter::CancelPendingStartup() { - if (!pending_callback_) { +void Starter::CancelPendingStartup(Metrics::LiteScriptFinishedState state) { + if (!IsStartupPending()) { return; } platform_delegate_->HideOnboarding(); @@ -204,7 +273,10 @@ Metrics::RecordOnboardingResult(Metrics::OnBoarding::OB_SHOWN); waiting_for_onboarding_ = false; } - RunCallback(/* start_regular_script = */ false); + OnStartDone(/* start_regular_script = */ false); + if (trigger_script_coordinator_) { + trigger_script_coordinator_->Stop(state); + } trigger_script_coordinator_.reset(); pending_trigger_context_.reset(); } @@ -234,7 +306,7 @@ Metrics::DropOutReason::DFM_INSTALL_FAILED, pending_trigger_context_->GetScriptParameters().GetIntent().value_or( std::string())); - RunCallback(/* start_regular_script = */ false); + OnStartDone(/* start_regular_script = */ false); return; } @@ -248,7 +320,7 @@ return; default: DCHECK(false); - RunCallback(/* start_regular_script = */ false); + OnStartDone(/* start_regular_script = */ false); return; } } @@ -284,7 +356,7 @@ } else { // Should never happen. DCHECK(false); - RunCallback(false); + OnStartDone(/* start_regular_script = */ false); return; } } @@ -315,8 +387,14 @@ Metrics::LiteScriptFinishedState state, std::unique_ptr<TriggerContext> trigger_context, base::Optional<TriggerScriptProto> trigger_script) { + // Delete the coordinator asynchronously, to give this notification time to + // end gracefully. + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&Starter::DeleteTriggerScriptCoordinator, + weak_ptr_factory_.GetWeakPtr())); + if (state != Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED) { - RunCallback(/* start_regular_script = */ false); + OnStartDone(/* start_regular_script = */ false); return; } @@ -327,7 +405,7 @@ // different metric for the result. We need to be careful to only run the // regular onboarding if necessary to avoid logging metrics more than once. if (platform_delegate_->GetOnboardingAccepted()) { - RunCallback(/* start_regular_script = */ true, trigger_script); + OnStartDone(/* start_regular_script = */ true, trigger_script); return; } else { MaybeShowOnboarding(trigger_script); @@ -385,37 +463,35 @@ if (result != OnboardingResult::ACCEPTED) { runtime_manager_->SetUIState(UIState::kNotShown); - RunCallback(/* start_regular_script = */ false); + OnStartDone(/* start_regular_script = */ false); return; } // Onboarding is the last step before regular startup. platform_delegate_->SetOnboardingAccepted(true); pending_trigger_context_->SetOnboardingShown(shown); - RunCallback(/* start_regular_script = */ true, trigger_script); + OnStartDone(/* start_regular_script = */ true, trigger_script); } -void Starter::RunCallback(bool start_regular_script, +void Starter::OnStartDone(bool start_regular_script, base::Optional<TriggerScriptProto> trigger_script) { - DCHECK(pending_callback_); if (!start_regular_script) { // Catch-all to ensure that after a failed startup attempt we no longer // register as visible to runtime observers. runtime_manager_->SetUIState(UIState::kNotShown); - - pending_trigger_context_ = nullptr; - std::move(pending_callback_) - .Run(/* start_regular_script = */ false, GURL(), nullptr, - base::nullopt); + pending_trigger_context_.reset(); return; } auto startup_url = StartupUtil().ChooseStartupUrlForIntent(*pending_trigger_context_); DCHECK(startup_url.has_value()); - std::move(pending_callback_) - .Run(/* start_regular_script = */ true, *startup_url, - std::move(pending_trigger_context_), trigger_script); + platform_delegate_->StartRegularScript( + *startup_url, std::move(pending_trigger_context_), trigger_script); } -} // namespace autofill_assistant \ No newline at end of file +void Starter::DeleteTriggerScriptCoordinator() { + trigger_script_coordinator_.reset(); +} + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/starter.h b/components/autofill_assistant/browser/starter.h index 3aff25a..ba51a96 100644 --- a/components/autofill_assistant/browser/starter.h +++ b/components/autofill_assistant/browser/starter.h
@@ -7,12 +7,13 @@ #include <memory> -#include "base/callback_forward.h" +#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "components/autofill_assistant/browser/controller.h" #include "components/autofill_assistant/browser/metrics.h" #include "components/autofill_assistant/browser/public/runtime_manager_impl.h" +#include "components/autofill_assistant/browser/starter_heuristic.h" #include "components/autofill_assistant/browser/starter_platform_delegate.h" #include "components/autofill_assistant/browser/startup_util.h" #include "components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h" @@ -25,14 +26,6 @@ // access platform-dependent features. class Starter : public content::WebContentsObserver { public: - // Note: parameters are only valid and not null if |start_regular_script| is - // true. - using StarterResultCallback = base::OnceCallback<void( - bool start_regular_script, - GURL url, - std::unique_ptr<TriggerContext> trigger_context, - const base::Optional<TriggerScriptProto>& trigger_script)>; - explicit Starter(content::WebContents* web_contents, StarterPlatformDelegate* platform_delegate, ukm::UkmRecorder* ukm_recorder, @@ -47,27 +40,36 @@ // - Install feature module if necessary // - Run and wait for trigger script to finish if necessary // - Show onboarding if necessary - // - Invoke |callback| with the result. On success, the caller should start - // the regular script. TODO(mcarlen): client startup should also be in - // handled here, rather than in the caller. + // - Request the platform_delegate to start the regular script. + // TODO(mcarlen): client startup should also be handled here, rather than in + // the platform_delegate. // // Only one call to |Start| can be processed at any time. If this method is // called before the previous call has finished, the previous call is // cancelled. - void Start(std::unique_ptr<TriggerContext> trigger_context, - StarterResultCallback callback); + void Start(std::unique_ptr<TriggerContext> trigger_context); // content::WebContentsObserver: void DidFinishNavigation( content::NavigationHandle* navigation_handle) override; + // Invoked when the tab interactability has changed. + void OnTabInteractabilityChanged(bool is_interactable); + // Re-check settings. This may cancel ongoing startup requests if the required // settings are no longer enabled. void CheckSettings(); private: - // Cancels the currently pending startup request, if any. - void CancelPendingStartup(); + // Starts a flow for |url| if possible. Will fail (do nothing) if the feature + // is disabled or if there is already a pending startup. + void MaybeStartImplicitlyForUrl(const GURL& url); + + // Cancels the currently pending startup request, if any. If a trigger script + // is currently running, this will record |state| as the reason for stopping. + // This will also hide any currently shown UI (such as a trigger script or the + // onboarding). + void CancelPendingStartup(Metrics::LiteScriptFinishedState state); // Installs the feature module if necessary, otherwise directly invokes // |OnFeatureModuleInstalled|. @@ -100,11 +102,19 @@ bool shown, OnboardingResult result); - // Internal helper to invoke the pending callback. - void RunCallback( + // Called at the end of each |Start| invocation. + void OnStartDone( bool start_regular_script, base::Optional<TriggerScriptProto> trigger_script = base::nullopt); + // Called when the heuristic result for |url| is available. + void OnHeuristicMatch(const GURL& url, bool result); + + // Returns whether there is a currently pending call to |Start| or not. + bool IsStartupPending() const; + + void DeleteTriggerScriptCoordinator(); + bool waiting_for_onboarding_ = false; bool is_custom_tab_ = false; StarterPlatformDelegate* platform_delegate_ = nullptr; @@ -112,8 +122,8 @@ base::WeakPtr<RuntimeManagerImpl> runtime_manager_; bool fetch_trigger_scripts_on_navigation_ = false; std::unique_ptr<TriggerContext> pending_trigger_context_; - StarterResultCallback pending_callback_; std::unique_ptr<TriggerScriptCoordinator> trigger_script_coordinator_; + const scoped_refptr<StarterHeuristic> starter_heuristic_; base::WeakPtrFactory<Starter> weak_ptr_factory_{this}; };
diff --git a/components/autofill_assistant/browser/starter_heuristic.cc b/components/autofill_assistant/browser/starter_heuristic.cc new file mode 100644 index 0000000..ec80770 --- /dev/null +++ b/components/autofill_assistant/browser/starter_heuristic.cc
@@ -0,0 +1,35 @@ +// 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 "components/autofill_assistant/browser/starter_heuristic.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "third_party/re2/src/re2/re2.h" + +namespace autofill_assistant { + +const char kStubCartHeuristic[] = "cart"; + +StarterHeuristic::StarterHeuristic() = default; +StarterHeuristic::~StarterHeuristic() = default; + +bool StarterHeuristic::IsHeuristicMatch(const GURL& url) const { + const re2::RE2 re(kStubCartHeuristic); + // TODO(arbesser): implement the heuristic. + return re2::RE2::PartialMatch(url.spec(), re); +} + +void StarterHeuristic::RunHeuristicAsync( + const GURL& url, + base::OnceCallback<void(bool result)> callback) const { + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, + base::BindOnce(&StarterHeuristic::IsHeuristicMatch, + base::RetainedRef(this), url), + std::move(callback)); +} + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/starter_heuristic.h b/components/autofill_assistant/browser/starter_heuristic.h new file mode 100644 index 0000000..6d8ec03 --- /dev/null +++ b/components/autofill_assistant/browser/starter_heuristic.h
@@ -0,0 +1,42 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_STARTER_HEURISTIC_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_STARTER_HEURISTIC_H_ + +#include "base/callback_forward.h" +#include "base/memory/ref_counted.h" +#include "url/gurl.h" + +namespace autofill_assistant { + +// Utility that implements a heuristic for autofill-assistant URLs. +// +// This class inherits from RefCountedThreadSafe to allow safe evaluation on +// worker threads. +class StarterHeuristic : public base::RefCountedThreadSafe<StarterHeuristic> { + public: + StarterHeuristic(); + StarterHeuristic(const StarterHeuristic&) = delete; + StarterHeuristic& operator=(const StarterHeuristic&) = delete; + + // Runs the heuristic against |url|. Returns true if a trigger script might be + // available for |url|. This method runs on a worker thread and notifies the + // caller via |callback| when done. + void RunHeuristicAsync(const GURL& url, + base::OnceCallback<void(bool result)> callback) const; + + private: + friend class base::RefCountedThreadSafe<StarterHeuristic>; + friend class StarterHeuristicTest; + ~StarterHeuristic(); + + // Runs the heuristic against |url|. Returns true if a trigger script might be + // available for |url|. + bool IsHeuristicMatch(const GURL& url) const; +}; + +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_STARTER_HEURISTIC_H_
diff --git a/components/autofill_assistant/browser/starter_heuristic_unittest.cc b/components/autofill_assistant/browser/starter_heuristic_unittest.cc new file mode 100644 index 0000000..0e1ac255 --- /dev/null +++ b/components/autofill_assistant/browser/starter_heuristic_unittest.cc
@@ -0,0 +1,43 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/starter_heuristic.h" + +#include "base/memory/ref_counted.h" +#include "base/test/gmock_callback_support.h" +#include "base/test/mock_callback.h" +#include "base/test/task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace autofill_assistant { + +class StarterHeuristicTest : public testing::Test { + public: + StarterHeuristicTest() + : starter_heuristic_(base::MakeRefCounted<StarterHeuristic>()) {} + + // Synchronous evaluation of the heuristic for easier testing. + bool IsHeuristicMatchForTest(const GURL& url) { + return starter_heuristic_->IsHeuristicMatch(url); + } + + protected: + scoped_refptr<StarterHeuristic> starter_heuristic_; +}; + +TEST_F(StarterHeuristicTest, SmokeTest) { + EXPECT_TRUE(IsHeuristicMatchForTest(GURL("https://www.example.com/cart"))); + EXPECT_FALSE(IsHeuristicMatchForTest(GURL("https://www.example.com"))); +} + +TEST_F(StarterHeuristicTest, RunHeuristicAsync) { + base::test::TaskEnvironment task_environment; + base::MockCallback<base::OnceCallback<void(bool result)>> callback; + EXPECT_CALL(callback, Run(true)); + starter_heuristic_->RunHeuristicAsync(GURL("https://www.example.com/cart"), + callback.Get()); + task_environment.RunUntilIdle(); +} + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/starter_platform_delegate.h b/components/autofill_assistant/browser/starter_platform_delegate.h index aff4d97b..d5003ac7 100644 --- a/components/autofill_assistant/browser/starter_platform_delegate.h +++ b/components/autofill_assistant/browser/starter_platform_delegate.h
@@ -31,6 +31,12 @@ virtual std::unique_ptr<ServiceRequestSender> GetTriggerScriptRequestSenderToInject() = 0; + // Requests the platform delegate to start the regular script. + virtual void StartRegularScript( + GURL url, + std::unique_ptr<TriggerContext> trigger_context, + const base::Optional<TriggerScriptProto>& trigger_script) = 0; + // Access to the login manager. virtual WebsiteLoginManager* GetWebsiteLoginManager() const = 0; // Returns the channel for the installation (canary, dev, beta, stable).
diff --git a/components/autofill_assistant/browser/starter_unittest.cc b/components/autofill_assistant/browser/starter_unittest.cc index fe26ae0..01509019 100644 --- a/components/autofill_assistant/browser/starter_unittest.cc +++ b/components/autofill_assistant/browser/starter_unittest.cc
@@ -47,7 +47,7 @@ using ::testing::WithArg; using ::testing::WithArgs; -const char kExampleUrl[] = "https://www.example.com"; +const char kExampleDeeplink[] = "https://www.example.com"; class StarterTest : public content::RenderViewHostTestHarness { public: @@ -55,27 +55,9 @@ RenderViewHostTestHarness::SetUp(); ukm::InitializeSourceUrlRecorderForWebContents(web_contents()); content::WebContentsTester::For(web_contents()) - ->NavigateAndCommit(GURL(kExampleUrl)); - auto mock_trigger_script_ui_delegate = - std::make_unique<NiceMock<MockTriggerScriptUiDelegate>>(); - mock_trigger_script_ui_delegate_ = mock_trigger_script_ui_delegate.get(); - fake_platform_delegate_.trigger_script_ui_delegate_ = - std::move(mock_trigger_script_ui_delegate); - - ON_CALL(*mock_trigger_script_ui_delegate_, Attach) - .WillByDefault(WithArg<0>( - [&](TriggerScriptCoordinator* trigger_script_coordinator) { - trigger_script_coordinator_ = trigger_script_coordinator; - })); - ON_CALL(*mock_trigger_script_ui_delegate_, Detach).WillByDefault([&]() { - trigger_script_coordinator_ = nullptr; - }); - auto mock_trigger_script_service_request_sender = - std::make_unique<NiceMock<MockServiceRequestSender>>(); - mock_trigger_script_service_request_sender_ = - mock_trigger_script_service_request_sender.get(); - fake_platform_delegate_.trigger_script_request_sender_for_test_ = - std::move(mock_trigger_script_service_request_sender); + ->NavigateAndCommit(GURL(kExampleDeeplink)); + PrepareTriggerScriptUiDelegate(); + PrepareTriggerScriptRequestSender(); fake_platform_delegate_.website_login_manager_ = &mock_website_login_manager_; ON_CALL(mock_website_login_manager_, OnGetLoginsForUrl) @@ -112,15 +94,11 @@ fake_platform_delegate_.onboarding_accepted_ = true; } - // Returns a base64-encoded GetTriggerScriptsResponseProto containing a single - // trigger script without any trigger conditions. As such, it will be shown - // immediately upon startup. + // Returns a base64-encoded trigger script response, as created by + // |CreateTriggerScriptResponseForTest|. std::string CreateBase64TriggerScriptResponseForTest() { - GetTriggerScriptsResponseProto get_trigger_scripts_response; - get_trigger_scripts_response.add_trigger_scripts(); - std::string serialized_get_trigger_scripts_response; - get_trigger_scripts_response.SerializeToString( - &serialized_get_trigger_scripts_response); + std::string serialized_get_trigger_scripts_response = + CreateTriggerScriptResponseForTest(); std::string base64_get_trigger_scripts_response; base::Base64UrlEncode(serialized_get_trigger_scripts_response, base::Base64UrlEncodePolicy::INCLUDE_PADDING, @@ -128,17 +106,29 @@ return base64_get_trigger_scripts_response; } + // Returns a serialized GetTriggerScriptsResponseProto containing a single + // trigger script without any trigger conditions. As such, it will be shown + // immediately upon startup. + std::string CreateTriggerScriptResponseForTest() { + GetTriggerScriptsResponseProto get_trigger_scripts_response; + get_trigger_scripts_response.add_trigger_scripts(); + std::string serialized_get_trigger_scripts_response; + get_trigger_scripts_response.SerializeToString( + &serialized_get_trigger_scripts_response); + return serialized_get_trigger_scripts_response; + } + // Returns true if a specific |state| was recorded for |entry_name| and // |metric_name|. bool RecordedUkmMetric(base::StringPiece entry_name, base::StringPiece metric_name, - int64_t expected_state) { + int64_t expected_state, + const GURL& source_url) { auto entries = ukm_recorder_.GetEntriesByName(entry_name); if (entries.size() != 1) { return false; } - ukm_recorder_.ExpectEntrySourceHasUrl( - entries[0], web_contents()->GetLastCommittedURL()); + ukm_recorder_.ExpectEntrySourceHasUrl(entries[0], source_url); const int64_t* actual_state = ukm_recorder_.GetEntryMetric(entries[0], metric_name); return actual_state != nullptr && *actual_state == expected_state; @@ -149,20 +139,26 @@ return !ukm_recorder_.GetEntriesByName(entry_name).empty(); } - bool UkmLiteScriptStarted(Metrics::LiteScriptStarted state) { + bool UkmLiteScriptStarted(Metrics::LiteScriptStarted state, + const GURL& source_url = GURL(kExampleDeeplink)) { return RecordedUkmMetric("AutofillAssistant.LiteScriptStarted", - "LiteScriptStarted", static_cast<int64_t>(state)); + "LiteScriptStarted", static_cast<int64_t>(state), + source_url); } - bool UkmLiteScriptFinished(Metrics::LiteScriptFinishedState state) { + bool UkmLiteScriptFinished(Metrics::LiteScriptFinishedState state, + const GURL& source_url = GURL(kExampleDeeplink)) { return RecordedUkmMetric("AutofillAssistant.LiteScriptFinished", - "LiteScriptFinished", static_cast<int64_t>(state)); + "LiteScriptFinished", static_cast<int64_t>(state), + source_url); } - bool UkmLiteScriptOnboarding(Metrics::LiteScriptOnboarding result) { + bool UkmLiteScriptOnboarding( + Metrics::LiteScriptOnboarding result, + const GURL& source_url = GURL(kExampleDeeplink)) { return RecordedUkmMetric("AutofillAssistant.LiteScriptOnboarding", "LiteScriptOnboarding", - static_cast<int64_t>(result)); + static_cast<int64_t>(result), source_url); } bool UkmLiteScriptStarted() { @@ -192,6 +188,38 @@ simulator->Commit(); } + // Each request sender is only good for one trigger script. This call will + // create a new mock and prepare it to be used in the next call. + void PrepareTriggerScriptRequestSender() { + auto mock_trigger_script_service_request_sender = + std::make_unique<NiceMock<MockServiceRequestSender>>(); + mock_trigger_script_service_request_sender_ = + mock_trigger_script_service_request_sender.get(); + fake_platform_delegate_.trigger_script_request_sender_for_test_ = + std::move(mock_trigger_script_service_request_sender); + } + + // Each trigger script UI delegate is only good for one trigger script and + // must be prepared anew if a test needs to show more than one trigger script. + void PrepareTriggerScriptUiDelegate() { + auto mock_trigger_script_ui_delegate = + std::make_unique<NiceMock<MockTriggerScriptUiDelegate>>(); + mock_trigger_script_ui_delegate_ = mock_trigger_script_ui_delegate.get(); + fake_platform_delegate_.trigger_script_ui_delegate_ = + std::move(mock_trigger_script_ui_delegate); + fake_platform_delegate_.start_regular_script_callback_ = + mock_start_regular_script_callback_.Get(); + + ON_CALL(*mock_trigger_script_ui_delegate_, Attach) + .WillByDefault(WithArg<0>( + [&](TriggerScriptCoordinator* trigger_script_coordinator) { + trigger_script_coordinator_ = trigger_script_coordinator; + })); + ON_CALL(*mock_trigger_script_ui_delegate_, Detach).WillByDefault([&]() { + trigger_script_coordinator_ = nullptr; + }); + } + NiceMock<MockTriggerScriptUiDelegate>* mock_trigger_script_ui_delegate_ = nullptr; NiceMock<MockServiceRequestSender>* @@ -204,18 +232,21 @@ MockRuntimeManager mock_runtime_manager_; std::unique_ptr<Starter> starter_; base::HistogramTester histogram_tester_; - base::MockCallback<Starter::StarterResultCallback> mock_callback_; + base::MockCallback<base::OnceCallback<void( + GURL url, + std::unique_ptr<TriggerContext> trigger_context, + const base::Optional<TriggerScriptProto>& trigger_script)>> + mock_start_regular_script_callback_; }; TEST_F(StarterTest, RegularScriptFailsWithoutInitialUrl) { std::map<std::string, std::string> params = {{"ENABLED", "true"}, {"START_IMMEDIATELY", "true"}}; TriggerContext::Options options; - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(params), options), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(params), options)); EXPECT_FALSE(UkmLiteScriptStarted()); EXPECT_FALSE(UkmLiteScriptFinished()); @@ -232,11 +263,10 @@ {"START_IMMEDIATELY", "false"}, {"TRIGGER_SCRIPTS_BASE64", "abc"}}; TriggerContext::Options options; - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(params), options), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(params), options)); EXPECT_TRUE(UkmLiteScriptStarted( Metrics::LiteScriptStarted::LITE_SCRIPT_NO_INITIAL_URL)); @@ -253,12 +283,11 @@ std::map<std::string, std::string> params = { {"START_IMMEDIATELY", "false"}, {"TRIGGER_SCRIPTS_BASE64", "abc"}}; TriggerContext::Options options; - options.initial_url = "https://www.example.com"; - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + options.initial_url = kExampleDeeplink; + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(params), options), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(params), options)); EXPECT_TRUE(UkmLiteScriptStarted( Metrics::LiteScriptStarted::LITE_SCRIPT_MANDATORY_PARAMETER_MISSING)); @@ -280,11 +309,10 @@ auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>(); scoped_feature_list->InitAndDisableFeature( features::kAutofillAssistantProactiveHelp); - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(params), options), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(params), options)); EXPECT_TRUE(UkmLiteScriptStarted( Metrics::LiteScriptStarted::LITE_SCRIPT_FEATURE_DISABLED)); @@ -304,16 +332,14 @@ {"ORIGINAL_DEEPLINK", "https://www.example.com"}}; TriggerContext::Options options; options.initial_url = "https://redirect.com/to/www/example/com"; - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ true, - GURL("https://www.example.com"), _, _)) - .WillOnce(WithArg<2>([](std::unique_ptr<TriggerContext> trigger_context) { + EXPECT_CALL(mock_start_regular_script_callback_, + Run(GURL(kExampleDeeplink), _, _)) + .WillOnce(WithArg<1>([](std::unique_ptr<TriggerContext> trigger_context) { EXPECT_THAT(trigger_context->GetOnboardingShown(), Eq(false)); })); - starter_->Start( - std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), options), - mock_callback_.Get()); + starter_->Start(std::make_unique<TriggerContext>( + std::make_unique<ScriptParameters>(script_parameters), options)); EXPECT_THAT(fake_platform_delegate_.num_install_feature_module_called_, Eq(0)); @@ -339,16 +365,14 @@ {"ORIGINAL_DEEPLINK", "https://www.example.com"}}; TriggerContext::Options options; options.initial_url = "https://redirect.com/to/www/example/com"; - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ true, - GURL("https://www.example.com"), _, _)) - .WillOnce(WithArg<2>([](std::unique_ptr<TriggerContext> trigger_context) { + EXPECT_CALL(mock_start_regular_script_callback_, + Run(GURL(kExampleDeeplink), _, _)) + .WillOnce(WithArg<1>([](std::unique_ptr<TriggerContext> trigger_context) { EXPECT_THAT(trigger_context->GetOnboardingShown(), Eq(true)); })); - starter_->Start( - std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), options), - mock_callback_.Get()); + starter_->Start(std::make_unique<TriggerContext>( + std::make_unique<ScriptParameters>(script_parameters), options)); EXPECT_THAT(fake_platform_delegate_.num_install_feature_module_called_, Eq(1)); @@ -369,37 +393,22 @@ TEST_F(StarterTest, ForceOnboardingFlagForReturningUsersSucceeds) { SetupPlatformDelegateForReturningUser(); - fake_platform_delegate_.show_onboarding_result_shown_ = true; - fake_platform_delegate_.show_onboarding_result_ = OnboardingResult::ACCEPTED; + base::MockCallback<base::OnceCallback<void( + base::OnceCallback<void(bool, OnboardingResult)>)>> + mock_onboarding_callback; + fake_platform_delegate_.on_show_onboarding_callback_ = + mock_onboarding_callback.Get(); + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( switches::kAutofillAssistantForceOnboarding, "true"); std::map<std::string, std::string> script_parameters = { {"ENABLED", "true"}, {"START_IMMEDIATELY", "true"}, {"ORIGINAL_DEEPLINK", "https://www.example.com"}}; - EXPECT_CALL( - mock_callback_, - Run(/* start_regular_script = */ true, GURL("https://www.example.com"), - Pointee(Property(&TriggerContext::GetOnboardingShown, true)), _)); - + EXPECT_CALL(mock_onboarding_callback, Run); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options()), - mock_callback_.Get()); - - EXPECT_THAT(fake_platform_delegate_.num_install_feature_module_called_, - Eq(0)); - EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(1)); - EXPECT_FALSE(UkmLiteScriptStarted()); - EXPECT_FALSE(UkmLiteScriptFinished()); - EXPECT_FALSE(UkmLiteScriptOnboarding()); - histogram_tester_.ExpectUniqueSample( - "Android.AutofillAssistant.FeatureModuleInstallation", - Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u); - histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding", - Metrics::OnBoarding::OB_ACCEPTED, 1u); - histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding", - Metrics::OnBoarding::OB_SHOWN, 1u); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options())); } TEST_F(StarterTest, ForceFirstTimeUserExperienceForReturningUser) { @@ -440,9 +449,8 @@ EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript(first_time_user_script->user_interface())); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options()), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options())); } TEST_F(StarterTest, RegularStartupFailsIfDfmInstallationFails) { @@ -455,12 +463,10 @@ {"ORIGINAL_DEEPLINK", "https://www.example.com"}}; TriggerContext::Options options; options.initial_url = "https://redirect.com/to/www/example/com"; - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); - starter_->Start( - std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), options), - mock_callback_.Get()); + starter_->Start(std::make_unique<TriggerContext>( + std::make_unique<ScriptParameters>(script_parameters), options)); EXPECT_THAT(fake_platform_delegate_.num_install_feature_module_called_, Eq(1)); @@ -488,12 +494,10 @@ {"INTENT", "SHOPPING_ASSISTED_CHECKOUT"}}; TriggerContext::Options options; options.initial_url = "https://redirect.com/to/www/example/com"; - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); - starter_->Start( - std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), options), - mock_callback_.Get()); + starter_->Start(std::make_unique<TriggerContext>( + std::make_unique<ScriptParameters>(script_parameters), options)); EXPECT_THAT(fake_platform_delegate_.GetOnboardingAccepted(), Eq(false)); EXPECT_FALSE(UkmLiteScriptStarted()); @@ -519,12 +523,11 @@ EXPECT_CALL(*mock_trigger_script_ui_delegate_, Attach).Times(0); EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest) .Times(0); - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options()), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options())); EXPECT_TRUE(UkmLiteScriptStarted( Metrics::LiteScriptStarted::LITE_SCRIPT_PROACTIVE_TRIGGERING_DISABLED)); @@ -547,12 +550,11 @@ EXPECT_CALL(*mock_trigger_script_ui_delegate_, Attach).Times(0); EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest) .Times(0); - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options()), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options())); EXPECT_TRUE(UkmLiteScriptStarted( Metrics::LiteScriptStarted::LITE_SCRIPT_PROACTIVE_TRIGGERING_DISABLED)); @@ -565,15 +567,6 @@ } TEST_F(StarterTest, RpcTriggerScriptSucceeds) { - // A trigger script without trigger conditions will be shown immediately. - GetTriggerScriptsResponseProto get_trigger_scripts_response; - get_trigger_scripts_response.add_trigger_scripts() - ->mutable_user_interface() - ->set_status_message("trigger script"); - std::string serialized_get_trigger_scripts_response; - get_trigger_scripts_response.SerializeToString( - &serialized_get_trigger_scripts_response); - SetupPlatformDelegateForFirstTimeUser(); fake_platform_delegate_.feature_module_installed_ = true; std::map<std::string, std::string> script_parameters = { @@ -602,18 +595,18 @@ ASSERT_TRUE(request.ParseFromString(request_body)); EXPECT_THAT(request.url(), Eq(GURL("https://www.example.com"))); std::move(callback).Run(net::HTTP_OK, - serialized_get_trigger_scripts_response); + CreateTriggerScriptResponseForTest()); })); - EXPECT_CALL( - mock_callback_, - Run(/* start_regular_script = */ true, GURL("https://www.example.com"), - Pointee(Property(&TriggerContext::GetOnboardingShown, true)), - Optional(get_trigger_scripts_response.trigger_scripts(0)))); + GetTriggerScriptsResponseProto get_trigger_scripts_response; + get_trigger_scripts_response.ParseFromString( + CreateTriggerScriptResponseForTest()); + EXPECT_CALL(mock_start_regular_script_callback_, + Run(GURL(kExampleDeeplink), + Pointee(Property(&TriggerContext::GetOnboardingShown, true)), + Optional(get_trigger_scripts_response.trigger_scripts(0)))); - starter_->Start( - std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), options), - mock_callback_.Get()); + starter_->Start(std::make_unique<TriggerContext>( + std::make_unique<ScriptParameters>(script_parameters), options)); EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(1)); EXPECT_TRUE(UkmLiteScriptStarted( @@ -640,12 +633,11 @@ {"TRIGGER_SCRIPTS_BASE64", "#invalid_hashtag"}, {"ORIGINAL_DEEPLINK", "https://www.example.com"}}; EXPECT_CALL(*mock_trigger_script_ui_delegate_, Attach).Times(0); - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options()), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options())); EXPECT_TRUE(UkmLiteScriptStarted( Metrics::LiteScriptStarted::LITE_SCRIPT_RETURNING_USER)); @@ -671,12 +663,11 @@ {"TRIGGER_SCRIPTS_BASE64", CreateBase64TriggerScriptResponseForTest()}, {"ORIGINAL_DEEPLINK", "https://www.example.com"}}; EXPECT_CALL(*mock_trigger_script_ui_delegate_, Attach).Times(0); - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options()), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options())); EXPECT_TRUE(UkmLiteScriptStarted( Metrics::LiteScriptStarted::LITE_SCRIPT_PROACTIVE_TRIGGERING_DISABLED)); @@ -712,16 +703,13 @@ trigger_script_coordinator_->PerformTriggerScriptAction( TriggerScriptProto::ACCEPT); }); - EXPECT_CALL( - mock_callback_, - Run(/* start_regular_script = */ true, GURL("https://www.example.com"), - Pointee(Property(&TriggerContext::GetOnboardingShown, true)), - testing::Ne(base::nullopt))); + EXPECT_CALL(mock_start_regular_script_callback_, + Run(GURL(kExampleDeeplink), + Pointee(Property(&TriggerContext::GetOnboardingShown, true)), + testing::Ne(base::nullopt))); - starter_->Start( - std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), options), - mock_callback_.Get()); + starter_->Start(std::make_unique<TriggerContext>( + std::make_unique<ScriptParameters>(script_parameters), options)); EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(1)); EXPECT_TRUE(UkmLiteScriptStarted( @@ -749,15 +737,46 @@ {"TRIGGER_SCRIPTS_BASE64", CreateBase64TriggerScriptResponseForTest()}, {"ORIGINAL_DEEPLINK", "https://www.example.com"}}; + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options{}), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options{})); - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + EXPECT_CALL(*mock_trigger_script_ui_delegate_, HideTriggerScript); fake_platform_delegate_.is_custom_tab_ = false; starter_->CheckSettings(); + EXPECT_TRUE(UkmLiteScriptStarted( + Metrics::LiteScriptStarted::LITE_SCRIPT_RETURNING_USER)); + EXPECT_TRUE(UkmLiteScriptFinished( + Metrics::LiteScriptFinishedState::LITE_SCRIPT_CCT_TO_TAB_NOT_SUPPORTED)); + EXPECT_FALSE(UkmLiteScriptOnboarding()); +} + +TEST_F(StarterTest, CancelPendingTriggerScriptWhenHandlingNewStartupRequest) { + SetupPlatformDelegateForReturningUser(); + fake_platform_delegate_.trigger_script_request_sender_for_test_ = nullptr; + mock_trigger_script_service_request_sender_ = nullptr; + + std::map<std::string, std::string> script_parameters = { + {"ENABLED", "true"}, + {"START_IMMEDIATELY", "false"}, + {"TRIGGER_SCRIPTS_BASE64", CreateBase64TriggerScriptResponseForTest()}, + {"ORIGINAL_DEEPLINK", kExampleDeeplink}}; + + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); + EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript); + starter_->Start(std::make_unique<TriggerContext>( + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options{})); + + EXPECT_CALL(*mock_trigger_script_ui_delegate_, HideTriggerScript); + PrepareTriggerScriptUiDelegate(); + starter_->Start(std::make_unique<TriggerContext>( + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options{})); + EXPECT_TRUE(UkmLiteScriptFinished( + Metrics::LiteScriptFinishedState::LITE_SCRIPT_CANCELED)); } TEST_F(StarterTest, RegularStartupFailsIfNavigationDuringOnboarding) { @@ -767,19 +786,17 @@ fake_platform_delegate_.on_show_onboarding_callback_ = base::DoNothing::Once<base::OnceCallback<void(bool, OnboardingResult)>>(); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); std::map<std::string, std::string> script_parameters = { {"ENABLED", "true"}, {"START_IMMEDIATELY", "true"}, {"ORIGINAL_DEEPLINK", "https://www.example.com"}}; starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options{}), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options{})); - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); content::WebContentsTester::For(web_contents()) ->NavigateAndCommit(GURL("https://www.different.com")); - EXPECT_FALSE(UkmLiteScriptStarted()); EXPECT_FALSE(UkmLiteScriptFinished()); EXPECT_FALSE(UkmLiteScriptOnboarding()); @@ -812,12 +829,14 @@ trigger_script_coordinator_->PerformTriggerScriptAction( TriggerScriptProto::ACCEPT); }); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options{}), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options{})); - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); + content::WebContentsTester::For(web_contents()) + ->NavigateAndCommit(GURL("https://www.different.com")); + EXPECT_TRUE(UkmLiteScriptStarted( Metrics::LiteScriptStarted::LITE_SCRIPT_FIRST_TIME_USER)); @@ -826,10 +845,12 @@ // TODO(b/185476714): Fix lite script metrics to record for ORIGINAL_DEEPLINK // instead of the current URL. EXPECT_TRUE(UkmLiteScriptFinished( - Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE)); + Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE, + GURL("https://www.different.com"))); EXPECT_TRUE(UkmLiteScriptOnboarding( Metrics::LiteScriptOnboarding:: - LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION)); + LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION, + GURL("https://www.different.com"))); histogram_tester_.ExpectUniqueSample( "Android.AutofillAssistant.FeatureModuleInstallation", Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u); @@ -848,21 +869,19 @@ {"ENABLED", "true"}, {"START_IMMEDIATELY", "true"}, {"ORIGINAL_DEEPLINK", "https://www.example.com"}}; + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options{}), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options{})); // Expect that the onboarding is not interrupted by a redirect to the // ORIGINAL_DEEPLINK. - EXPECT_CALL(mock_callback_, Run).Times(0); SimulateRedirectToUrl(GURL("https://www.example.com"), GURL("http://redirect.example.com")); histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding", 0u); // Redirecting to a different URL will cancel the onboarding. - EXPECT_CALL(mock_callback_, Run(/* start_regular_script = */ false, _, _, _)); SimulateRedirectToUrl(GURL("https://www.different.com"), GURL("http://redirect.example.com")); @@ -894,11 +913,10 @@ {"ENABLED", "true"}, {"START_IMMEDIATELY", "true"}, {"ORIGINAL_DEEPLINK", "https://www.example.com"}}; - EXPECT_CALL(mock_callback_, Run).Times(0); + EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0); starter_->Start(std::make_unique<TriggerContext>( - std::make_unique<ScriptParameters>(script_parameters), - TriggerContext::Options{}), - mock_callback_.Get()); + std::make_unique<ScriptParameters>(script_parameters), + TriggerContext::Options{})); EXPECT_FALSE(UkmLiteScriptStarted()); EXPECT_FALSE(UkmLiteScriptFinished()); @@ -910,5 +928,154 @@ 0u); } +TEST_F(StarterTest, ImplicitStartupOnSupportedDomain) { + SetupPlatformDelegateForReturningUser(); + auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>(); + scoped_feature_list->InitAndEnableFeature( + features::kAutofillAssistantInChromeTriggering); + starter_->CheckSettings(); + + EXPECT_CALL(*mock_trigger_script_service_request_sender_, + OnSendRequest( + GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _)) + .WillOnce( + WithArgs<1, 2>([&](const std::string& request_body, + ServiceRequestSender::ResponseCallback& callback) { + GetTriggerScriptsRequestProto request; + ASSERT_TRUE(request.ParseFromString(request_body)); + EXPECT_THAT(request.url(), + Eq(GURL("https://www.some-website.com/cart"))); + std::move(callback).Run(net::HTTP_OK, + CreateTriggerScriptResponseForTest()); + })); + EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript) + .WillOnce([&]() { + ASSERT_TRUE(trigger_script_coordinator_ != nullptr); + trigger_script_coordinator_->PerformTriggerScriptAction( + TriggerScriptProto::ACCEPT); + }); + EXPECT_CALL(mock_start_regular_script_callback_, + Run(GURL("https://www.some-website.com/cart"), + Pointee(Property(&TriggerContext::GetOnboardingShown, false)), + testing::Ne(base::nullopt))); + + // Implicit startup by navigating to an autofill-assistant-enabled site. + content::WebContentsTester::For(web_contents()) + ->NavigateAndCommit(GURL("https://www.some-website.com/cart")); + task_environment()->RunUntilIdle(); + + EXPECT_TRUE(UkmLiteScriptStarted( + Metrics::LiteScriptStarted::LITE_SCRIPT_RETURNING_USER, + GURL("https://www.some-website.com/cart"))); + EXPECT_TRUE(UkmLiteScriptFinished( + Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED, + GURL("https://www.some-website.com/cart"))); + EXPECT_TRUE(UkmLiteScriptOnboarding( + Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_ALREADY_ACCEPTED, + GURL("https://www.some-website.com/cart"))); + histogram_tester_.ExpectUniqueSample( + "Android.AutofillAssistant.FeatureModuleInstallation", + Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u); + histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding", + 0u); +} + +TEST_F(StarterTest, DoNotStartImplicitlyIfSettingDisabled) { + SetupPlatformDelegateForReturningUser(); + auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>(); + scoped_feature_list->InitAndEnableFeature( + features::kAutofillAssistantInChromeTriggering); + fake_platform_delegate_.proactive_help_enabled_ = false; + starter_->CheckSettings(); + + EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest) + .Times(0); + content::WebContentsTester::For(web_contents()) + ->NavigateAndCommit(GURL("https://www.some-website.com/cart")); + task_environment()->RunUntilIdle(); +} + +TEST_F(StarterTest, ImplicitStartupOnCurrentUrlAfterSettingEnabled) { + SetupPlatformDelegateForReturningUser(); + fake_platform_delegate_.proactive_help_enabled_ = false; + auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>(); + scoped_feature_list->InitAndEnableFeature( + features::kAutofillAssistantInChromeTriggering); + starter_->CheckSettings(); + + EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest) + .Times(0); + content::WebContentsTester::For(web_contents()) + ->NavigateAndCommit(GURL("https://www.some-website.com/cart")); + + EXPECT_CALL(*mock_trigger_script_service_request_sender_, + OnSendRequest( + GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _)) + .WillOnce(RunOnceCallback<2>(net::HTTP_OK, + CreateTriggerScriptResponseForTest())); + EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript).Times(1); + + // Implicit startup by enabling proactive help while already on an + // autofill-assistant-enabled site. + fake_platform_delegate_.proactive_help_enabled_ = true; + starter_->CheckSettings(); + task_environment()->RunUntilIdle(); + + EXPECT_TRUE(UkmLiteScriptStarted( + Metrics::LiteScriptStarted::LITE_SCRIPT_RETURNING_USER, + GURL("https://www.some-website.com/cart"))); + EXPECT_FALSE(UkmLiteScriptFinished()); + EXPECT_FALSE(UkmLiteScriptOnboarding()); + histogram_tester_.ExpectUniqueSample( + "Android.AutofillAssistant.FeatureModuleInstallation", + Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u); + histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding", + 0u); +} + +TEST(MultipleStarterTest, HeuristicUsedByMultipleInstances) { + content::BrowserTaskEnvironment task_environment; + content::RenderViewHostTestEnabler rvh_test_enabler; + content::TestBrowserContext browser_context; + ukm::TestAutoSetUkmRecorder ukm_recorder; + FakeStarterPlatformDelegate fake_platform_delegate_01; + FakeStarterPlatformDelegate fake_platform_delegate_02; + MockRuntimeManager mock_runtime_manager; + + auto web_contents_01 = content::WebContentsTester::CreateTestWebContents( + &browser_context, nullptr); + ukm::InitializeSourceUrlRecorderForWebContents(web_contents_01.get()); + auto web_contents_02 = content::WebContentsTester::CreateTestWebContents( + &browser_context, nullptr); + ukm::InitializeSourceUrlRecorderForWebContents(web_contents_02.get()); + + auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>(); + scoped_feature_list->InitAndEnableFeature( + features::kAutofillAssistantInChromeTriggering); + Starter starter_01(web_contents_01.get(), &fake_platform_delegate_01, + &ukm_recorder, mock_runtime_manager.GetWeakPtr()); + Starter starter_02(web_contents_02.get(), &fake_platform_delegate_02, + &ukm_recorder, mock_runtime_manager.GetWeakPtr()); + + auto service_request_sender_01 = + std::make_unique<NiceMock<MockServiceRequestSender>>(); + auto* service_request_sender_01_ptr = service_request_sender_01.get(); + fake_platform_delegate_01.trigger_script_request_sender_for_test_ = + std::move(service_request_sender_01); + auto service_request_sender_02 = + std::make_unique<NiceMock<MockServiceRequestSender>>(); + auto* service_request_sender_02_ptr = service_request_sender_02.get(); + fake_platform_delegate_02.trigger_script_request_sender_for_test_ = + std::move(service_request_sender_02); + + EXPECT_CALL(*service_request_sender_01_ptr, OnSendRequest).Times(1); + EXPECT_CALL(*service_request_sender_02_ptr, OnSendRequest).Times(1); + content::WebContentsTester::For(web_contents_01.get()) + ->NavigateAndCommit(GURL("https://www.some-website.com/cart")); + content::WebContentsTester::For(web_contents_02.get()) + ->NavigateAndCommit(GURL("https://www.some-other-website.com/cart")); + task_environment.RunUntilIdle(); +} + } // namespace -} // namespace autofill_assistant \ No newline at end of file +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc index ae2db88..5a25a2f 100644 --- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc +++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
@@ -349,6 +349,10 @@ return *trigger_context_; } +const GURL& TriggerScriptCoordinator::GetDeeplink() const { + return deeplink_url_; +} + void TriggerScriptCoordinator::OnEffectiveVisibilityChanged() { bool visible = web_contents_visible_ && web_contents_interactable_; if (visible) {
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h index 0ceec42..fb3e878 100644 --- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h +++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h
@@ -83,6 +83,11 @@ std::unique_ptr<TriggerContext> trigger_context, base::Optional<TriggerScriptProto> trigger_script)> callback); + // Stops the currently running trigger script. Hides any currently shown UI + // (both trigger script UI and onboarding, if applicable) and returns |state| + // as the reason for stopping in the pending callback. + void Stop(Metrics::LiteScriptFinishedState state); + // Performs |action|. This is usually invoked by the UI as a result of user // interactions. void PerformTriggerScriptAction( @@ -111,6 +116,9 @@ // Const access to the trigger context associated with this coordinator. const TriggerContext& GetTriggerContext() const; + // Returns the deeplink that this coordinator was started on. + const GURL& GetDeeplink() const; + private: friend class TriggerScriptCoordinatorTest; @@ -127,7 +135,6 @@ void CheckDynamicTriggerConditions(); void OnDynamicTriggerConditionsEvaluated(bool is_out_of_schedule); void OnGetTriggerScripts(int http_status, const std::string& response); - void Stop(Metrics::LiteScriptFinishedState state); GURL GetCurrentURL() const; void OnEffectiveVisibilityChanged(); void OnOnboardingFinished(bool onboardingShown, OnboardingResult result);
diff --git a/components/autofill_assistant/browser/url_utils.cc b/components/autofill_assistant/browser/url_utils.cc index ebf070b..677ae8b8 100644 --- a/components/autofill_assistant/browser/url_utils.cc +++ b/components/autofill_assistant/browser/url_utils.cc
@@ -18,12 +18,6 @@ base::CompareCase::INSENSITIVE_ASCII); } -std::string GetRegistryControlledDomain(const GURL& signon_realm) { - return net::registry_controlled_domains::GetDomainAndRegistry( - signon_realm, - net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); -} - } // namespace namespace autofill_assistant { @@ -55,9 +49,8 @@ return true; } - auto domain1 = GetRegistryControlledDomain(url1); - auto domain2 = GetRegistryControlledDomain(url2); - + auto domain1 = GetOrganizationIdentifyingDomain(url1); + auto domain2 = GetOrganizationIdentifyingDomain(url2); if (domain1.empty() || domain2.empty()) { return false; } @@ -65,5 +58,10 @@ return url1.scheme() == url2.scheme() && domain1 == domain2; } +std::string GetOrganizationIdentifyingDomain(const GURL& url) { + return net::registry_controlled_domains::GetDomainAndRegistry( + url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); +} + } // namespace url_utils } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/url_utils.h b/components/autofill_assistant/browser/url_utils.h index 7df2997..55fc1b8 100644 --- a/components/autofill_assistant/browser/url_utils.h +++ b/components/autofill_assistant/browser/url_utils.h
@@ -27,6 +27,10 @@ // false. bool IsSamePublicSuffixDomain(const GURL& url1, const GURL& url2); +// Returns the organization-identifying domain for |url|. Returns the empty +// string for invalid urls. +std::string GetOrganizationIdentifyingDomain(const GURL& url); + } // namespace url_utils } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/url_utils_unittest.cc b/components/autofill_assistant/browser/url_utils_unittest.cc index e76d9a3..d75fa044 100644 --- a/components/autofill_assistant/browser/url_utils_unittest.cc +++ b/components/autofill_assistant/browser/url_utils_unittest.cc
@@ -9,6 +9,8 @@ namespace url_utils { namespace { +using testing::Eq; + TEST(UrlUtilsTest, IsInDomainOrSubDomain) { std::vector<std::string> allowed_domains = {"example.com", "other-example.com"}; @@ -57,6 +59,16 @@ EXPECT_FALSE(IsSamePublicSuffixDomain(GURL("invalid"), GURL("invalid"))); } +TEST(UrlUtilsTest, GetOrganizationIdentifyingDomain) { + EXPECT_THAT(GetOrganizationIdentifyingDomain(GURL("https://www.example.com")), + Eq("example.com")); + EXPECT_THAT( + GetOrganizationIdentifyingDomain(GURL("https://subdomain.example.com")), + Eq("example.com")); + EXPECT_THAT(GetOrganizationIdentifyingDomain(GURL("https://example.com")), + Eq("example.com")); +} + } // namespace } // namespace url_utils } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web/element_store_unittest.cc b/components/autofill_assistant/browser/web/element_store_unittest.cc index 23b61827..f638f592 100644 --- a/components/autofill_assistant/browser/web/element_store_unittest.cc +++ b/components/autofill_assistant/browser/web/element_store_unittest.cc
@@ -9,6 +9,8 @@ #include "components/autofill_assistant/browser/actions/action_test_utils.h" #include "components/autofill_assistant/browser/client_status.h" #include "components/autofill_assistant/browser/web/element_finder.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_browser_context.h" #include "content/public/test/test_renderer_host.h" #include "content/public/test/web_contents_tester.h" #include "testing/gmock/include/gmock/gmock.h" @@ -16,18 +18,12 @@ namespace autofill_assistant { namespace { -class ElementStoreTest : public content::RenderViewHostTestHarness { +class ElementStoreTest : public testing::Test { public: - ElementStoreTest() - : RenderViewHostTestHarness( - base::test::TaskEnvironment::MainThreadType::UI, - base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} - ~ElementStoreTest() override {} - void SetUp() override { - RenderViewHostTestHarness::SetUp(); - - element_store_ = std::make_unique<ElementStore>(web_contents()); + web_contents_ = content::WebContentsTester::CreateTestWebContents( + &browser_context_, nullptr); + element_store_ = std::make_unique<ElementStore>(web_contents_.get()); } protected: @@ -36,7 +32,7 @@ auto element = std::make_unique<ElementFinder::Result>(); element->dom_object.object_data.object_id = object_id; element->dom_object.object_data.node_frame_id = - web_contents()->GetMainFrame()->GetDevToolsFrameToken().ToString(); + web_contents_->GetMainFrame()->GetDevToolsFrameToken().ToString(); return element; } @@ -47,6 +43,10 @@ element_store_->AddElement(client_id, element->dom_object); } + content::BrowserTaskEnvironment task_environment_; + content::RenderViewHostTestEnabler rvh_test_enabler_; + content::TestBrowserContext browser_context_; + std::unique_ptr<content::WebContents> web_contents_; std::unique_ptr<ElementStore> element_store_; }; @@ -87,7 +87,7 @@ ElementFinder::Result result; EXPECT_EQ(ACTION_APPLIED, element_store_->GetElement("1", &result).proto_status()); - EXPECT_EQ(web_contents()->GetMainFrame(), result.container_frame_host); + EXPECT_EQ(web_contents_->GetMainFrame(), result.container_frame_host); } TEST_F(ElementStoreTest, AddElementToStoreOverwrites) {
diff --git a/components/autofill_assistant/browser/web/mock_web_controller.h b/components/autofill_assistant/browser/web/mock_web_controller.h index 99ba41b4..6decdf2 100644 --- a/components/autofill_assistant/browser/web/mock_web_controller.h +++ b/components/autofill_assistant/browser/web/mock_web_controller.h
@@ -42,11 +42,12 @@ MOCK_METHOD2(CheckOnTop, void(const ElementFinder::Result&, base::OnceCallback<void(const ClientStatus&)>)); - MOCK_METHOD5(SelectOption, + MOCK_METHOD6(SelectOption, void(const std::string& re2, bool case_sensitive, SelectOptionProto::OptionComparisonAttribute option_comparison_attribute, + bool strict, const ElementFinder::Result& element, base::OnceCallback<void(const ClientStatus&)> callback)); MOCK_METHOD3(CheckSelectedOptionElement,
diff --git a/components/autofill_assistant/browser/web/web_controller.cc b/components/autofill_assistant/browser/web/web_controller.cc index 8c1f29b..e956567 100644 --- a/components/autofill_assistant/browser/web/web_controller.cc +++ b/components/autofill_assistant/browser/web/web_controller.cc
@@ -84,47 +84,53 @@ // Javascript to select a value from a select box. Also fires a "change" event // to trigger any listeners. Changing the index directly does not trigger this. +// See |WebController::OnSelectOptionJavascriptResult| for result handling. const char* const kSelectOptionScript = - R"(function(re2, valueSourceAttribute, caseSensitive) { - if (this.options == null) return false; + R"(function(re2, valueSourceAttribute, caseSensitive, strict) { + if (this.options == null) return -1; const regexp = RegExp(re2, caseSensitive ? '' : 'i'); - let found = false; + let numResults = 0; + let newIndex = -1; for (let i = 0; i < this.options.length; ++i) { if (regexp.test(this.options[i][valueSourceAttribute])) { - this.options.selectedIndex = i; - found = true; - break; + ++numResults; + if (newIndex === -1) { + newIndex = i; + } } } - if (!found) { - return false; + if (numResults == 1 || (numResults > 1 && !strict)) { + this.options.selectedIndex = newIndex; + const e = document.createEvent('HTMLEvents'); + e.initEvent('change', true, true); + this.dispatchEvent(e); + return 1; } - const e = document.createEvent('HTMLEvents'); - e.initEvent('change', true, true); - this.dispatchEvent(e); - return true; + return numResults; })"; // Javascript to select the option element in a select element. This does *not* // fire a "change" event. +// See |WebController::OnSelectOptionJavascriptResult| for result handling. const char* const kSelectOptionElementScript = R"(function(option) { - if (this.options == null) return false; + if (this.options == null) return -1; for (let i = 0; i < this.options.length; ++i) { if (this.options[i] === option) { this.options.selectedIndex = i; - return true; + return 1; } } - return false; + return 0; })"; // Javascript to check the option element in a select element against an // expected match. +// See |WebController::OnSelectOptionJavascriptResult| for result handling. const char* const kCheckOptionElementScript = R"(function(option) { - if (this.options == null) return false; - return this.options[this.options.selectedIndex] === option; + if (this.options == null) return -1; + return (this.options[this.options.selectedIndex] === option) ? 1 : 0; })"; // Javascript to highlight an element. @@ -924,6 +930,7 @@ const std::string& re2, bool case_sensitive, SelectOptionProto::OptionComparisonAttribute option_comparison_attribute, + bool strict, const ElementFinder::Result& element, base::OnceCallback<void(const ClientStatus&)> callback) { #ifdef NDEBUG @@ -953,6 +960,7 @@ return; } AddRuntimeCallArgument(case_sensitive, &arguments); + AddRuntimeCallArgument(strict, &arguments); devtools_client_->GetRuntime()->CallFunctionOn( runtime::CallFunctionOnParams::Builder() @@ -962,7 +970,7 @@ .SetReturnByValue(true) .Build(), element.node_frame_id(), - base::BindOnce(&WebController::OnJavascriptResultExpectingTrue, + base::BindOnce(&WebController::OnSelectOptionJavascriptResult, weak_ptr_factory_.GetWeakPtr(), base::BindOnce(&DecorateWebControllerStatus, WebControllerErrorInfoProto::SELECT_OPTION, @@ -985,7 +993,7 @@ .Build(), element.node_frame_id(), base::BindOnce( - &WebController::OnJavascriptResultExpectingTrue, + &WebController::OnSelectOptionJavascriptResult, weak_ptr_factory_.GetWeakPtr(), base::BindOnce(&DecorateWebControllerStatus, WebControllerErrorInfoProto::SELECT_OPTION_ELEMENT, @@ -1008,7 +1016,7 @@ .Build(), element.node_frame_id(), base::BindOnce( - &WebController::OnJavascriptResultExpectingTrue, + &WebController::OnSelectOptionJavascriptResult, weak_ptr_factory_.GetWeakPtr(), base::BindOnce(&DecorateWebControllerStatus, WebControllerErrorInfoProto::CHECK_OPTION_ELEMENT, @@ -1016,9 +1024,9 @@ /* status_if_false= */ ELEMENT_MISMATCH)); } -void WebController::OnJavascriptResultExpectingTrue( +void WebController::OnSelectOptionJavascriptResult( base::OnceCallback<void(const ClientStatus&)> callback, - ProcessedActionStatusProto status_if_false, + ProcessedActionStatusProto status_if_zero, const DevtoolsClient::ReplyStatus& reply_status, std::unique_ptr<runtime::CallFunctionOnResult> result) { ClientStatus status = @@ -1027,14 +1035,22 @@ std::move(callback).Run(status); return; } - bool bool_result; - if (!SafeGetBool(result->GetResult(), &bool_result)) { + int int_result; + if (!SafeGetIntValue(result->GetResult(), &int_result)) { std::move(callback).Run( UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__)); return; } - if (!bool_result) { - std::move(callback).Run(ClientStatus(status_if_false)); + if (int_result < 0) { + std::move(callback).Run(ClientStatus(INVALID_TARGET)); + return; + } + if (int_result == 0) { + std::move(callback).Run(ClientStatus(status_if_zero)); + return; + } + if (int_result > 1) { + std::move(callback).Run(ClientStatus(TOO_MANY_OPTION_VALUES_FOUND)); return; } std::move(callback).Run(OkClientStatus());
diff --git a/components/autofill_assistant/browser/web/web_controller.h b/components/autofill_assistant/browser/web/web_controller.h index 3c85c82..de67524 100644 --- a/components/autofill_assistant/browser/web/web_controller.h +++ b/components/autofill_assistant/browser/web/web_controller.h
@@ -151,6 +151,7 @@ const std::string& re2, bool case_sensitive, SelectOptionProto::OptionComparisonAttribute option_comparison_attribute, + bool strict, const ElementFinder::Result& element, base::OnceCallback<void(const ClientStatus&)> callback); @@ -465,9 +466,15 @@ autofill::ContentAutofillDriver* driver, const autofill::FormData& form_data, const autofill::FormFieldData& form_field); - void OnJavascriptResultExpectingTrue( + // Handling a JS result for a "SelectOption" action. This expects the JS + // result to contain an integer and returns the following status: + // * -1 -> INVALID_TARGET + // * 0 -> OPTION_ELEMENT_NOT_FOUND + // * 1 -> ACTION_APPLIED + // * n -> TOO_MANY_OPTION_VALUES_FOUND + void OnSelectOptionJavascriptResult( base::OnceCallback<void(const ClientStatus&)> callback, - ProcessedActionStatusProto status_if_false, + ProcessedActionStatusProto status_if_zero, const DevtoolsClient::ReplyStatus& reply_status, std::unique_ptr<runtime::CallFunctionOnResult> result);
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc index db9eb00..8c6ae96 100644 --- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc +++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -322,11 +322,12 @@ std::move(done_callback), result_output)); } - ClientStatus SelectOption(const Selector& selector, - const std::string& re2, - bool case_sensitive, - SelectOptionProto::OptionComparisonAttribute - option_comparison_attribute) { + ClientStatus SelectOption( + const Selector& selector, + const std::string& re2, + bool case_sensitive, + SelectOptionProto::OptionComparisonAttribute option_comparison_attribute, + bool strict) { base::RunLoop run_loop; ClientStatus result; @@ -335,7 +336,8 @@ base::BindOnce( &WebControllerBrowserTest::FindSelectOptionElementCallback, base::Unretained(this), re2, case_sensitive, - option_comparison_attribute, run_loop.QuitClosure(), &result)); + option_comparison_attribute, strict, run_loop.QuitClosure(), + &result)); run_loop.Run(); return result; @@ -345,6 +347,7 @@ const std::string& re2, bool case_sensitive, SelectOptionProto::OptionComparisonAttribute option_comparison_attribute, + bool strict, base::OnceClosure done_callback, ClientStatus* result_output, const ClientStatus& status, @@ -358,7 +361,8 @@ ASSERT_TRUE(element_result != nullptr); const ElementFinder::Result* element_result_ptr = element_result.get(); web_controller_->SelectOption( - re2, case_sensitive, option_comparison_attribute, *element_result_ptr, + re2, case_sensitive, option_comparison_attribute, strict, + *element_result_ptr, base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback, base::Unretained(this), std::move(element_result), std::move(done_callback), result_output)); @@ -2053,48 +2057,61 @@ )"; // Selecting on a non-<select> element. - EXPECT_EQ(OPTION_VALUE_NOT_FOUND, + EXPECT_EQ(INVALID_TARGET, SelectOption(Selector({"#input1"}), std::string(), - /* case_sensitive= */ false, SelectOptionProto::LABEL) + /* case_sensitive= */ false, SelectOptionProto::LABEL, + /* strict= */ true) .proto_status()); // Fails if no comparison attribute is set. EXPECT_EQ(INVALID_ACTION, SelectOption(selector, "one", /* case_sensitive= */ false, - SelectOptionProto::NOT_SET) + SelectOptionProto::NOT_SET, /* strict= */ true) .proto_status()); // Select value not matching anything. EXPECT_EQ(OPTION_VALUE_NOT_FOUND, SelectOption(selector, "incorrect label", - /* case_sensitive= */ false, SelectOptionProto::LABEL) + /* case_sensitive= */ false, SelectOptionProto::LABEL, + /* strict= */ true) .proto_status()); + // Select value matching everything. + EXPECT_EQ(TOO_MANY_OPTION_VALUES_FOUND, + SelectOption(selector, ".*", /* case_sensitive= */ false, + SelectOptionProto::LABEL, /* strict= */ true) + .proto_status()); + EXPECT_EQ(ACTION_APPLIED, + SelectOption(selector, ".*", /* case_sensitive= */ false, + SelectOptionProto::LABEL, /* strict= */ false) + .proto_status()); + EXPECT_EQ("One", content::EvalJs(shell(), javascript)); + // Select value matching the option's label. EXPECT_EQ(ACTION_APPLIED, SelectOption(selector, "^ZÜRICH", /* case_sensitive= */ false, - SelectOptionProto::LABEL) + SelectOptionProto::LABEL, /* strict= */ true) .proto_status()); EXPECT_EQ("Zürich Hauptbahnhof", content::EvalJs(shell(), javascript)); // Select value matching the option's value. EXPECT_EQ(ACTION_APPLIED, SelectOption(selector, "^Aü万𠜎$", /* case_sensitive= */ false, - SelectOptionProto::VALUE) + SelectOptionProto::VALUE, /* strict= */ true) .proto_status()); EXPECT_EQ("Character Test Entry", content::EvalJs(shell(), javascript)); // With a regular expression matching the option's value. EXPECT_EQ(ACTION_APPLIED, SelectOption(selector, "^O.E$", /* case_sensitive= */ false, - SelectOptionProto::VALUE) + SelectOptionProto::VALUE, /* strict= */ true) .proto_status()); EXPECT_EQ("One", content::EvalJs(shell(), javascript)); // With a regular expression matching the option's value case sensitive. EXPECT_EQ(OPTION_VALUE_NOT_FOUND, SelectOption(selector, "^O.E$", /* case_sensitive= */ true, - SelectOptionProto::VALUE) + SelectOptionProto::VALUE, /* strict= */ true) .proto_status()); EXPECT_EQ("One", content::EvalJs(shell(), javascript)); } @@ -2104,7 +2121,7 @@ Selector select_selector({"#iframe", "select[name=state]"}); EXPECT_EQ(ACTION_APPLIED, SelectOption(select_selector, "^NY", /* case_sensitive= */ false, - SelectOptionProto::LABEL) + SelectOptionProto::LABEL, /* strict= */ true) .proto_status()); const std::string javascript = R"( @@ -2119,7 +2136,7 @@ select_selector = Selector({"#iframeExternal", "select[name=pet]"}); EXPECT_EQ(ACTION_APPLIED, SelectOption(select_selector, "^Cat", /* case_sensitive= */ false, - SelectOptionProto::LABEL) + SelectOptionProto::LABEL, /* strict= */ true) .proto_status()); Selector result_selector({"#iframeExternal", "#myPet"}); @@ -2929,7 +2946,7 @@ GetFieldsValue({selector}, {"two"}); // Using on a non-<select> element. - EXPECT_EQ(OPTION_VALUE_NOT_FOUND, + EXPECT_EQ(INVALID_TARGET, SelectOptionElement(Selector({"#input1"}), option).proto_status()); // Random element that is certainly not an option in the <select>. @@ -2967,7 +2984,7 @@ CheckSelectedOptionElement(select, not_selected_option).proto_status()); // Using on a non-<select> element. - EXPECT_EQ(ELEMENT_MISMATCH, + EXPECT_EQ(INVALID_TARGET, CheckSelectedOptionElement(input, selected_option).proto_status()); }
diff --git a/components/consent_auditor/OWNERS b/components/consent_auditor/OWNERS index 0e2c1661..745d3ad 100644 --- a/components/consent_auditor/OWNERS +++ b/components/consent_auditor/OWNERS
@@ -1,4 +1,3 @@ dullweber@chromium.org markusheintz@chromium.org msramek@chromium.org -vitaliii@chromium.org
diff --git a/components/content_settings/core/browser/content_settings_pref.cc b/components/content_settings/core/browser/content_settings_pref.cc index 633f352..933dcb4 100644 --- a/components/content_settings/core/browser/content_settings_pref.cc +++ b/components/content_settings/core/browser/content_settings_pref.cc
@@ -14,6 +14,7 @@ #include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" +#include "base/value_iterators.h" #include "components/content_settings/core/browser/content_settings_info.h" #include "components/content_settings/core/browser/content_settings_registry.h" #include "components/content_settings/core/browser/content_settings_rule.h" @@ -410,8 +411,8 @@ settings_dictionary->RemoveWithoutPathExpansion(kSessionModelPath, nullptr); } else { - settings_dictionary->SetWithoutPathExpansion(kSettingPath, - value->CreateDeepCopy()); + settings_dictionary->SetWithoutPathExpansion( + kSettingPath, base::Value::ToUniquePtrValue(value->Clone())); settings_dictionary->SetKey( kLastModifiedPath, base::Value(base::NumberToString(
diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc index 2cbf0058..c3b028c 100644 --- a/components/content_settings/core/browser/host_content_settings_map.cc +++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -964,7 +964,7 @@ *secondary_pattern = rule.secondary_pattern; if (session_model) *session_model = rule.session_model; - return rule.value.CreateDeepCopy(); + return base::Value::ToUniquePtrValue(rule.value.Clone()); } } }
diff --git a/components/cronet/stale_host_resolver_unittest.cc b/components/cronet/stale_host_resolver_unittest.cc index 64702a98..16392f3 100644 --- a/components/cronet/stale_host_resolver_unittest.cc +++ b/components/cronet/stale_host_resolver_unittest.cc
@@ -188,10 +188,13 @@ if (dns_client) { inner_resolver->GetManagerForTesting()->SetDnsClientForTesting( std::move(dns_client)); - inner_resolver->GetManagerForTesting()->SetInsecureDnsClientEnabled(true); + inner_resolver->GetManagerForTesting()->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/true); } else { inner_resolver->GetManagerForTesting()->SetInsecureDnsClientEnabled( - false); + /*enabled=*/false, + /*additional_dns_types_enabled=*/false); } return inner_resolver; }
diff --git a/components/password_manager/core/browser/form_fetcher_impl.cc b/components/password_manager/core/browser/form_fetcher_impl.cc index f6f9f2f..d2bb626 100644 --- a/components/password_manager/core/browser/form_fetcher_impl.cc +++ b/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -126,6 +126,12 @@ // The desktop bubble needs this information. password_store->GetMatchingInsecureCredentials(form_digest_.signon_realm, this); +#else + if (base::FeatureList::IsEnabled(features::kMutingCompromisedCredentials)) { + // We need this information to mute leak detection warming. + password_store->GetMatchingInsecureCredentials(form_digest_.signon_realm, + this); + } #endif }
diff --git a/components/password_manager/core/browser/form_fetcher_impl_unittest.cc b/components/password_manager/core/browser/form_fetcher_impl_unittest.cc index 2dcf7d8..7afd341 100644 --- a/components/password_manager/core/browser/form_fetcher_impl_unittest.cc +++ b/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
@@ -536,10 +536,30 @@ } TEST_P(FormFetcherImplTest, DontFetchInsecure) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatureState(features::kMutingCompromisedCredentials, + false); EXPECT_CALL(*mock_store_, GetMatchingInsecureCredentialsImpl).Times(0); form_fetcher_->Fetch(); task_environment_.RunUntilIdle(); } + +TEST_P(FormFetcherImplTest, FetchInsecure) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatureState(features::kMutingCompromisedCredentials, + true); + std::vector<InsecureCredential> list = {InsecureCredential( + form_digest_.signon_realm, u"username_value", base::Time::FromTimeT(1), + InsecureType::kLeaked, IsMuted(false))}; + EXPECT_CALL(*mock_store_, + GetMatchingInsecureCredentialsImpl(form_digest_.signon_realm)) + .WillOnce(Return(list)); + form_fetcher_->Fetch(); + task_environment_.RunUntilIdle(); + + EXPECT_THAT(form_fetcher_->GetInsecureCredentials(), + UnorderedElementsAreArray(list)); +} #endif // Test that ensures HTTP passwords are not migrated on HTTP sites.
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc index 8828f86..ec056841 100644 --- a/components/password_manager/core/browser/password_manager.cc +++ b/components/password_manager/core/browser/password_manager.cc
@@ -192,6 +192,15 @@ return form_data; } +bool HasMutedCredentials(base::span<const InsecureCredential> credentials, + const std::u16string& username) { + return base::ranges::any_of(credentials, [&username](const auto& credential) { + return credential.username == username && credential.is_muted && + (credential.insecure_type == InsecureType::kLeaked || + credential.insecure_type == InsecureType::kPhished); + }); +} + } // namespace // static @@ -950,7 +959,13 @@ DCHECK(submitted_manager->GetSubmittedForm()); client_->GetStoreResultFilter()->ReportFormLoginSuccess(*submitted_manager); - leak_delegate_.StartLeakCheck(submitted_manager->GetPendingCredentials()); + // Check for leaks only if there are no muted credentials. + if (!HasMutedCredentials( + submitted_manager->GetInsecureCredentials(), + submitted_manager->GetSubmittedForm()->username_value) || + !base::FeatureList::IsEnabled(features::kMutingCompromisedCredentials)) { + leak_delegate_.StartLeakCheck(submitted_manager->GetPendingCredentials()); + } auto submission_event = submitted_manager->GetSubmittedForm()->submission_event;
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc index 2e9e73f..2df3ed92 100644 --- a/components/password_manager/core/browser/password_manager_unittest.cc +++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -4088,6 +4088,85 @@ EXPECT_FALSE(manager()->GetSubmittedManagerForTest()); } +// Check that on successful login the credentials are checked for leak depending +// on mute state of insecure credential. +TEST_P(PasswordManagerTest, DontStartLeakDetectionWhenMuted) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatureState(features::kMutingCompromisedCredentials, + true); + + auto mock_factory = + std::make_unique<testing::StrictMock<MockLeakDetectionCheckFactory>>(); + manager()->set_leak_factory(std::move(mock_factory)); + + const PasswordForm form = MakeSimpleForm(); + std::vector<FormData> observed = {form.form_data}; + EXPECT_CALL(*store_, GetLogins) + .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get()))); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); + + // Add muted insecure credentials. + std::vector<InsecureCredential> insecure_credentials = {InsecureCredential( + form.signon_realm, form.username_value, base::Time::FromTimeT(1), + InsecureType::kLeaked, IsMuted(true))}; + EXPECT_CALL(*store_, GetMatchingInsecureCredentialsImpl(form.signon_realm)) + .WillOnce(Return(insecure_credentials)); + task_environment_.RunUntilIdle(); + + EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true)); + OnPasswordFormSubmitted(form.form_data); + + auto check_instance = std::make_unique<MockLeakDetectionCheck>(); + EXPECT_CALL(*check_instance, Start).Times(0); + + // Now the password manager waits for the navigation to complete. + observed.clear(); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); +} + +// Tests that check for leaks happens even if there are muted credentials for +// the same domain, but with different username. +TEST_P(PasswordManagerTest, StartLeakCheckWhenForUsernameNotMuted) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatureState(features::kMutingCompromisedCredentials, + true); + + auto mock_factory = + std::make_unique<testing::StrictMock<MockLeakDetectionCheckFactory>>(); + MockLeakDetectionCheckFactory* weak_factory = mock_factory.get(); + manager()->set_leak_factory(std::move(mock_factory)); + + const PasswordForm form = MakeSimpleForm(); + std::vector<FormData> observed = {form.form_data}; + EXPECT_CALL(*store_, GetLogins) + .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get()))); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); + + // Add muted insecure credentials. + std::vector<InsecureCredential> insecure_credentials = {InsecureCredential( + form.signon_realm, u"different_username", base::Time::FromTimeT(1), + InsecureType::kLeaked, IsMuted(true))}; + EXPECT_CALL(*store_, GetMatchingInsecureCredentialsImpl(form.signon_realm)) + .WillOnce(Return(insecure_credentials)); + task_environment_.RunUntilIdle(); + + EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true)); + OnPasswordFormSubmitted(form.form_data); + + auto check_instance = std::make_unique<MockLeakDetectionCheck>(); + EXPECT_CALL(*check_instance, Start); + EXPECT_CALL(*weak_factory, TryCreateLeakCheck) + .WillOnce(Return(ByMove(std::move(check_instance)))); + + // Now the password manager waits for the navigation to complete. + observed.clear(); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); +} + INSTANTIATE_TEST_SUITE_P(, PasswordManagerTest, testing::Bool()); } // namespace password_manager
diff --git a/components/policy/core/common/cloud/cloud_policy_store.cc b/components/policy/core/common/cloud/cloud_policy_store.cc index d4a10da..f06b8df 100644 --- a/components/policy/core/common/cloud/cloud_policy_store.cc +++ b/components/policy/core/common/cloud/cloud_policy_store.cc
@@ -49,7 +49,8 @@ void CloudPolicyStore::NotifyStoreLoaded() { is_initialized_ = true; - first_policies_loaded_ |= has_policy(); + UpdateFirstPoliciesLoaded(); + // The |external_data_manager_| must be notified first so that when other // observers are informed about the changed policies and try to fetch external // data referenced by these, the |external_data_manager_| has the required @@ -60,9 +61,14 @@ observer.OnStoreLoaded(this); } +void CloudPolicyStore::UpdateFirstPoliciesLoaded() { + first_policies_loaded_ |= has_policy(); +} + void CloudPolicyStore::NotifyStoreError() { is_initialized_ = true; - first_policies_loaded_ |= has_policy(); + UpdateFirstPoliciesLoaded(); + for (auto& observer : observers_) observer.OnStoreError(this); }
diff --git a/components/policy/core/common/cloud/cloud_policy_store.h b/components/policy/core/common/cloud/cloud_policy_store.h index 7ed3dfc..25b1e1e 100644 --- a/components/policy/core/common/cloud/cloud_policy_store.h +++ b/components/policy/core/common/cloud/cloud_policy_store.h
@@ -170,6 +170,9 @@ void NotifyStoreLoaded(); void NotifyStoreError(); + // Updates whether or not the first policies were loaded. + virtual void UpdateFirstPoliciesLoaded(); + // Assert non-concurrent usage in debug builds. SEQUENCE_CHECKER(sequence_checker_);
diff --git a/components/power_scheduler/power_mode_arbiter.cc b/components/power_scheduler/power_mode_arbiter.cc index db926ae3..87c0254d6 100644 --- a/components/power_scheduler/power_mode_arbiter.cc +++ b/components/power_scheduler/power_mode_arbiter.cc
@@ -37,17 +37,31 @@ // power_scheduler component. class PowerModeArbiter::ChargingPowerModeVoter : base::PowerStateObserver { public: - ChargingPowerModeVoter() - : charging_voter_(PowerModeArbiter::GetInstance()->NewVoter( - "PowerModeVoter.Charging")) { - const bool on_battery = - base::PowerMonitor::AddPowerStateObserverAndReturnOnBatteryState(this); - if (base::PowerMonitor::IsInitialized()) - OnPowerStateChange(on_battery); + explicit ChargingPowerModeVoter(PowerModeArbiter* arbiter) + : charging_voter_(arbiter->NewVoter("PowerModeVoter.Charging")) { + // Start out in charging mode until we can register the observer with + // PowerMonitor, which itself also starts out in charging mode. + charging_voter_->VoteFor(PowerMode::kCharging); } ~ChargingPowerModeVoter() override { - base::PowerMonitor::RemovePowerStateObserver(this); + if (was_setup_) + base::PowerMonitor::RemovePowerStateObserver(this); + } + + void Setup() { + if (was_setup_) + return; + was_setup_ = true; + + const bool on_battery = + base::PowerMonitor::AddPowerStateObserverAndReturnOnBatteryState(this); + OnPowerStateChange(on_battery); + } + + void SetOnBatteryPowerForTesting(bool on_battery_power) { + OnPowerStateChange(on_battery_power); + was_setup_ = true; // Prevent real setup in the test. } void OnPowerStateChange(bool on_battery_power) override { @@ -57,6 +71,7 @@ private: std::unique_ptr<PowerModeVoter> charging_voter_; + bool was_setup_ = false; }; PowerModeArbiter::Observer::~Observer() = default; @@ -73,7 +88,8 @@ : trace_observer_(std::make_unique<TraceObserver>()), active_mode_("PowerModeArbiter", this), observers_( - base::MakeRefCounted<base::ObserverListThreadSafe<Observer>>()) { + base::MakeRefCounted<base::ObserverListThreadSafe<Observer>>()), + charging_voter_(std::make_unique<ChargingPowerModeVoter>(this)) { base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this); } @@ -111,10 +127,10 @@ // Create the charging voter on the task runner sequence, so that charging // state notifications are received there. - task_runner->PostTask(FROM_HERE, base::BindOnce([] { - PowerModeArbiter::GetInstance()->charging_voter_ = - std::make_unique<ChargingPowerModeVoter>(); - })); + task_runner->PostTask( + FROM_HERE, base::BindOnce([] { + PowerModeArbiter::GetInstance()->charging_voter_->Setup(); + })); } std::unique_ptr<PowerModeVoter> PowerModeArbiter::NewVoter(const char* name) { @@ -313,6 +329,10 @@ return active_mode_.mode(); } +void PowerModeArbiter::SetOnBatteryPowerForTesting(bool on_battery_power) { + charging_voter_->SetOnBatteryPowerForTesting(on_battery_power); // IN-TEST +} + void PowerModeArbiter::OnTraceLogEnabled() { { base::AutoLock lock(lock_);
diff --git a/components/power_scheduler/power_mode_arbiter.h b/components/power_scheduler/power_mode_arbiter.h index d685ca8..644b4d5 100644 --- a/components/power_scheduler/power_mode_arbiter.h +++ b/components/power_scheduler/power_mode_arbiter.h
@@ -66,8 +66,8 @@ // pool is available. void OnThreadPoolAvailable(); - // Returns the currently active PowerMode. Public for testing. PowerMode GetActiveModeForTesting(); + void SetOnBatteryPowerForTesting(bool on_battery_power); private: FRIEND_TEST_ALL_PREFIXES(PowerModeArbiterTest, ResetVoteAfterTimeout);
diff --git a/components/power_scheduler/power_mode_arbiter_unittest.cc b/components/power_scheduler/power_mode_arbiter_unittest.cc index feaaadc8..3b4349e 100644 --- a/components/power_scheduler/power_mode_arbiter_unittest.cc +++ b/components/power_scheduler/power_mode_arbiter_unittest.cc
@@ -12,6 +12,10 @@ TEST(PowerModeArbiterTest, SingleVote) { PowerModeArbiter arbiter; + EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kCharging); + + // Clear the initial kCharging vote. + arbiter.SetOnBatteryPowerForTesting(/*on_battery_power=*/true); EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kIdle); std::unique_ptr<PowerModeVoter> voter1 = arbiter.NewVoter("voter1"); @@ -29,6 +33,12 @@ TEST(PowerModeArbiterTest, MultipleVotes) { PowerModeArbiter arbiter; + EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kCharging); + + // Clear the initial kCharging vote. + arbiter.SetOnBatteryPowerForTesting(/*on_battery_power=*/true); + EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kIdle); + EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kIdle); std::unique_ptr<PowerModeVoter> voter1 = arbiter.NewVoter("voter1"); @@ -119,6 +129,9 @@ PowerModeArbiter arbiter; MockObserver observer; + // Clear the initial kCharging vote. + arbiter.SetOnBatteryPowerForTesting(/*on_battery_power=*/true); + // Observer is notified of initial mode right away. EXPECT_CALL(observer, OnPowerModeChanged(PowerMode::kIdle, PowerMode::kIdle)); @@ -163,6 +176,12 @@ env.AdvanceClock(target_time - env.NowTicks()); PowerModeArbiter arbiter; + EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kCharging); + + // Clear the initial kCharging vote. + arbiter.SetOnBatteryPowerForTesting(/*on_battery_power=*/true); + EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kIdle); + // Add a fake observer to enable reset tasks. FakeObserver observer; arbiter.AddObserver(&observer); @@ -261,6 +280,12 @@ env.AdvanceClock(target_time - env.NowTicks()); PowerModeArbiter arbiter; + EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kCharging); + + // Clear the initial kCharging vote. + arbiter.SetOnBatteryPowerForTesting(/*on_battery_power=*/true); + EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kIdle); + FakeObserver observer; base::TimeDelta delta1s = base::TimeDelta::FromSeconds(1);
diff --git a/components/send_tab_to_self/BUILD.gn b/components/send_tab_to_self/BUILD.gn index 67f5f6d6..d53f76f 100644 --- a/components/send_tab_to_self/BUILD.gn +++ b/components/send_tab_to_self/BUILD.gn
@@ -8,6 +8,8 @@ "fake_send_tab_to_self_model.h", "features.cc", "features.h", + "metrics_util.cc", + "metrics_util.h", "pref_names.cc", "pref_names.h", "send_tab_to_self_bridge.cc",
diff --git a/components/send_tab_to_self/metrics_util.cc b/components/send_tab_to_self/metrics_util.cc new file mode 100644 index 0000000..724f2d08 --- /dev/null +++ b/components/send_tab_to_self/metrics_util.cc
@@ -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. + +#include "components/send_tab_to_self/metrics_util.h" + +#include "base/metrics/histogram_functions.h" +#include "base/strings/strcat.h" + +namespace send_tab_to_self { + +namespace { + +// State of the send tab to self option in the UI. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +enum class ClickResult { + // kShowItem = 0, + kClickItem = 1, + // kShowDeviceList = 2, + kMaxValue = kClickItem, +}; + +std::string GetEntryPointHistogramString(ShareEntryPoint entry_point) { + switch (entry_point) { + case ShareEntryPoint::kShareSheet: + return "ShareSheet"; + case ShareEntryPoint::kOmniboxIcon: + return "OmniboxIcon"; + case ShareEntryPoint::kContentMenu: + return "ContentMenu"; + case ShareEntryPoint::kLinkMenu: + return "LinkMenu"; + case ShareEntryPoint::kOmniboxMenu: + return "OmniboxMenu"; + case ShareEntryPoint::kTabMenu: + return "TabMenu"; + case ShareEntryPoint::kShareMenu: + return "ShareMenu"; + } +} + +} // namespace + +void RecordDeviceClicked(ShareEntryPoint entry_point) { + // TODO(crbug.com/956722): Only kClickItem is used today, so we should replace + // this with a histogram which doesn't use the ClickResult enum. + base::UmaHistogramEnumeration( + base::StrCat({"SendTabToSelf.", GetEntryPointHistogramString(entry_point), + ".ClickResult"}), + ClickResult::kClickItem); +} + +} // namespace send_tab_to_self
diff --git a/components/send_tab_to_self/metrics_util.h b/components/send_tab_to_self/metrics_util.h new file mode 100644 index 0000000..c791969 --- /dev/null +++ b/components/send_tab_to_self/metrics_util.h
@@ -0,0 +1,27 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SEND_TAB_TO_SELF_METRICS_UTIL_H_ +#define COMPONENTS_SEND_TAB_TO_SELF_METRICS_UTIL_H_ + +#include <string> + +namespace send_tab_to_self { + +enum class ShareEntryPoint { + kContentMenu, + kLinkMenu, + kOmniboxIcon, + kOmniboxMenu, + kShareMenu, + kShareSheet, + kTabMenu, +}; + +// Records whether the user clicked to send a tab to a device. +void RecordDeviceClicked(ShareEntryPoint entry_point); + +} // namespace send_tab_to_self + +#endif // COMPONENTS_SEND_TAB_TO_SELF_METRICS_UTIL_H_
diff --git a/components/signin/public/android/BUILD.gn b/components/signin/public/android/BUILD.gn index dd15ee8e..ed854c6 100644 --- a/components/signin/public/android/BUILD.gn +++ b/components/signin/public/android/BUILD.gn
@@ -24,7 +24,6 @@ "java/src/org/chromium/components/signin/AccountManagerFacade.java", "java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java", "java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java", - "java/src/org/chromium/components/signin/AccountManagerResult.java", "java/src/org/chromium/components/signin/AccountRenameChecker.java", "java/src/org/chromium/components/signin/AccountRestrictionPatternReceiver.java", "java/src/org/chromium/components/signin/AccountUtils.java",
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java index b975c0b4..e67d3c54 100644 --- a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java +++ b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
@@ -50,19 +50,18 @@ private final AccountManagerDelegate mDelegate; private final AccountRestrictionPatternReceiver mAccountRestrictionPatternReceiver; - private final AtomicReference<List<PatternMatcher>> mAccountRestrictionPatterns = - new AtomicReference<>(); private final ObserverList<AccountsChangeObserver> mObservers = new ObserverList<>(); - private AccountManagerResult<List<Account>> mAllAccounts; - - private final AtomicReference<AccountManagerResult<List<Account>>> mFilteredAccounts = + private final AtomicReference<List<Account>> mAllAccounts = new AtomicReference<>(); + private final AtomicReference<List<PatternMatcher>> mAccountRestrictionPatterns = new AtomicReference<>(); + private final AtomicReference<List<Account>> mFilteredAccounts = new AtomicReference<>(); private final CountDownLatch mPopulateAccountCacheLatch = new CountDownLatch(1); private int mUpdateTasksCounter; - private final Queue<Runnable> mCallbacksWaitingForAccountsFetch = new ArrayDeque<>(); + private final Queue<Callback<List<Account>>> mCallbacksWaitingForAccountsFetch = + new ArrayDeque<>(); /** * @param delegate the AccountManagerDelegate to use as a backend @@ -113,8 +112,9 @@ return mFilteredAccounts.get() != null; } - private List<Account> getGoogleAccounts() throws AccountManagerDelegateException { - AccountManagerResult<List<Account>> maybeAccounts = mFilteredAccounts.get(); + @Override + public List<Account> tryGetGoogleAccounts() { + List<Account> maybeAccounts = mFilteredAccounts.get(); if (maybeAccounts == null) { try { // First call to update hasn't finished executing yet, should wait for it @@ -130,16 +130,7 @@ throw new RuntimeException("Interrupted waiting for accounts", e); } } - return maybeAccounts.get(); - } - - @Override - public List<Account> tryGetGoogleAccounts() { - try { - return getGoogleAccounts(); - } catch (AccountManagerDelegateException e) { - return Collections.emptyList(); - } + return maybeAccounts; } /** @@ -147,7 +138,12 @@ */ @Override public void tryGetGoogleAccounts(Callback<List<Account>> callback) { - runAfterCacheIsPopulated(() -> callback.onResult(tryGetGoogleAccounts())); + ThreadUtils.assertOnUiThread(); + if (isCachePopulated()) { + ThreadUtils.postOnUiThread(callback.bind(tryGetGoogleAccounts())); + } else { + mCallbacksWaitingForAccountsFetch.add(callback); + } } /** @@ -265,38 +261,25 @@ return mDelegate.isGooglePlayServicesAvailable(); } - /** - * Runs a callback after the account list cache is populated. - */ - private void runAfterCacheIsPopulated(Runnable runnable) { - ThreadUtils.assertOnUiThread(); - if (isCachePopulated()) { - ThreadUtils.postOnUiThread(runnable); - } else { - mCallbacksWaitingForAccountsFetch.add(runnable); - } - } - private void updateAccounts() { ThreadUtils.assertOnUiThread(); new UpdateAccountsTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); } - private AccountManagerResult<List<Account>> getAllAccounts() { + private List<Account> getAllAccounts() { try { - List<Account> accounts = Arrays.asList(mDelegate.getAccountsSync()); - return new AccountManagerResult<>(Collections.unmodifiableList(accounts)); + return Collections.unmodifiableList(Arrays.asList(mDelegate.getAccountsSync())); } catch (AccountManagerDelegateException ex) { - return new AccountManagerResult<>(ex); + return Collections.emptyList(); } } - private AccountManagerResult<List<Account>> getFilteredAccounts() { - if (mAllAccounts.hasException() || mAccountRestrictionPatterns.get().isEmpty()) { - return mAllAccounts; + private List<Account> getFilteredAccounts() { + if (mAccountRestrictionPatterns.get().isEmpty()) { + return mAllAccounts.get(); } - ArrayList<Account> filteredAccounts = new ArrayList<>(); - for (Account account : mAllAccounts.getValue()) { + final List<Account> filteredAccounts = new ArrayList<>(); + for (Account account : mAllAccounts.get()) { for (PatternMatcher pattern : mAccountRestrictionPatterns.get()) { if (pattern.matches(account.name)) { filteredAccounts.add(account); @@ -304,7 +287,7 @@ } } } - return new AccountManagerResult<>(Collections.unmodifiableList(filteredAccounts)); + return Collections.unmodifiableList(filteredAccounts); } private void onAccountRestrictionPatternsUpdated(List<PatternMatcher> patternMatchers) { @@ -313,8 +296,8 @@ fireOnAccountsChangedNotification(); } - private void setAllAccounts(AccountManagerResult<List<Account>> allAccounts) { - mAllAccounts = allAccounts; + private void setAllAccounts(List<Account> allAccounts) { + mAllAccounts.set(allAccounts); mFilteredAccounts.set(getFilteredAccounts()); fireOnAccountsChangedNotification(); } @@ -335,8 +318,8 @@ if (--mUpdateTasksCounter > 0) return; while (!mCallbacksWaitingForAccountsFetch.isEmpty()) { - final Runnable runnable = mCallbacksWaitingForAccountsFetch.remove(); - runnable.run(); + final Callback<List<Account>> callback = mCallbacksWaitingForAccountsFetch.remove(); + callback.onResult(tryGetGoogleAccounts()); } } @@ -350,7 +333,7 @@ protected Void doInBackground() { mAccountRestrictionPatterns.set( mAccountRestrictionPatternReceiver.getRestrictionPatterns()); - mAllAccounts = getAllAccounts(); + mAllAccounts.set(getAllAccounts()); mFilteredAccounts.set(getFilteredAccounts()); // It's important that countDown() is called on background thread and not in // onPostExecute, as UI thread may be blocked in getGoogleAccounts waiting on the latch. @@ -361,27 +344,27 @@ @Override protected void onPostExecute(Void v) { while (!mCallbacksWaitingForAccountsFetch.isEmpty()) { - final Runnable runnable = mCallbacksWaitingForAccountsFetch.remove(); - runnable.run(); + final Callback<List<Account>> callback = mCallbacksWaitingForAccountsFetch.remove(); + callback.onResult(tryGetGoogleAccounts()); } fireOnAccountsChangedNotification(); decrementUpdateCounter(); } } - private class UpdateAccountsTask extends AsyncTask<AccountManagerResult<List<Account>>> { + private class UpdateAccountsTask extends AsyncTask<List<Account>> { @Override protected void onPreExecute() { incrementUpdateCounter(); } @Override - protected AccountManagerResult<List<Account>> doInBackground() { + protected List<Account> doInBackground() { return getAllAccounts(); } @Override - protected void onPostExecute(AccountManagerResult<List<Account>> allAccounts) { + protected void onPostExecute(List<Account> allAccounts) { setAllAccounts(allAccounts); decrementUpdateCounter(); }
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerResult.java b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerResult.java deleted file mode 100644 index aadf43d..0000000 --- a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerResult.java +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.signin; - -import androidx.annotation.Nullable; - -/** - * AccountManagerResult encapsulates result of {@link AccountManagerFacade} method call. It is a - * holder that contains either a value or an AccountManagerDelegateException that occurred during - * the call. - * - * @param <T> The type of value this class should contain. - */ -class AccountManagerResult<T> { - /** - * Two possible states of AccountManagerResult are distinguished by mException field. If - * mException is null, then this instance is in 'value' state. If mException is non-null, - * then this instance is in 'exception' state. Please note that mException and mValue can both - * be null - it corresponds to 'value' state with the value being null. Both mValue and - * mException can't be non-null, though: this invariant is enforced by constructors. - */ - @Nullable - private final T mValue; - @Nullable - private final AccountManagerDelegateException mException; - - public AccountManagerResult(@Nullable T value) { - mValue = value; - mException = null; - } - - public AccountManagerResult(AccountManagerDelegateException ex) { - assert ex != null; - mValue = null; - mException = ex; - } - - @Nullable - public T get() throws AccountManagerDelegateException { - if (mException != null) { - throw mException; - } - return mValue; - } - - public boolean hasValue() { - return mException == null; - } - - public boolean hasException() { - return mException != null; - } - - @Nullable - public T getValue() { - assert hasValue(); - return mValue; - } - - public AccountManagerDelegateException getException() { - assert hasException(); - return mException; - } -}
diff --git a/components/signin/public/base/signin_switches.cc b/components/signin/public/base/signin_switches.cc index a946027..1708728 100644 --- a/components/signin/public/base/signin_switches.cc +++ b/components/signin/public/base/signin_switches.cc
@@ -4,6 +4,7 @@ #include "components/signin/public/base/signin_switches.h" +#include "base/feature_list.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -35,4 +36,7 @@ const base::Feature kUseAccountManagerFacade{"kUseAccountManagerFacade", base::FEATURE_ENABLED_BY_DEFAULT}; #endif + +const base::Feature kMinorModeSupport{"MinorModeSupport", + base::FEATURE_DISABLED_BY_DEFAULT}; } // namespace switches
diff --git a/components/signin/public/base/signin_switches.h b/components/signin/public/base/signin_switches.h index c95c07a..a396c9a 100644 --- a/components/signin/public/base/signin_switches.h +++ b/components/signin/public/base/signin_switches.h
@@ -37,6 +37,9 @@ // Killswitch for PO2TS migration to AccountManagerFacade. extern const base::Feature kUseAccountManagerFacade; #endif + +// Support for the minor mode. +extern const base::Feature kMinorModeSupport; } // namespace switches #endif // COMPONENTS_SIGNIN_PUBLIC_BASE_SIGNIN_SWITCHES_H_
diff --git a/components/signin/public/identity_manager/identity_manager.h b/components/signin/public/identity_manager/identity_manager.h index ce7d2a4c..4c1364fef 100644 --- a/components/signin/public/identity_manager/identity_manager.h +++ b/components/signin/public/identity_manager/identity_manager.h
@@ -486,10 +486,8 @@ private: // These test helpers need to use some of the private methods below. friend CoreAccountInfo SetPrimaryAccount(IdentityManager* identity_manager, - const std::string& email); - friend CoreAccountInfo SetUnconsentedPrimaryAccount( - IdentityManager* identity_manager, - const std::string& email); + const std::string& email, + ConsentLevel consent_level); friend void SetRefreshTokenForPrimaryAccount( IdentityManager* identity_manager, const std::string& token_value);
diff --git a/components/signin/public/identity_manager/identity_manager_unittest.cc b/components/signin/public/identity_manager/identity_manager_unittest.cc index 0599721..4bbec9e8 100644 --- a/components/signin/public/identity_manager/identity_manager_unittest.cc +++ b/components/signin/public/identity_manager/identity_manager_unittest.cc
@@ -562,7 +562,7 @@ TEST_F(IdentityManagerTest, PrimaryAccountInfoAfterSignin) { ClearPrimaryAccount(identity_manager()); - SetPrimaryAccount(identity_manager(), kTestEmail); + SetPrimaryAccount(identity_manager(), kTestEmail, ConsentLevel::kSync); auto event = identity_manager_observer()->GetPrimaryAccountChangedEvent(); EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, event.GetEventTypeFor(ConsentLevel::kSync)); @@ -598,7 +598,7 @@ ClearPrimaryAccount(identity_manager()); // First ensure that the user is signed in from the POV of the // IdentityManager. - SetPrimaryAccount(identity_manager(), kTestEmail); + SetPrimaryAccount(identity_manager(), kTestEmail, ConsentLevel::kSync); // Sign the user out and check that the IdentityManager responds // appropriately. @@ -642,7 +642,7 @@ ClearPrimaryAccount(identity_manager()); // First ensure that the user is signed in from the POV of the // IdentityManager. - SetPrimaryAccount(identity_manager(), kTestEmail); + SetPrimaryAccount(identity_manager(), kTestEmail, ConsentLevel::kSync); identity_manager()->account_fetcher_service_->EnableAccountRemovalForTest(); // Revoke the primary's account credentials from the token service and
diff --git a/components/signin/public/identity_manager/identity_test_environment.cc b/components/signin/public/identity_manager/identity_test_environment.cc index 1d9eac7..e08bc67 100644 --- a/components/signin/public/identity_manager/identity_test_environment.cc +++ b/components/signin/public/identity_manager/identity_test_environment.cc
@@ -376,12 +376,14 @@ CoreAccountInfo IdentityTestEnvironment::SetPrimaryAccount( const std::string& email) { - return signin::SetPrimaryAccount(identity_manager(), email); + return signin::SetPrimaryAccount(identity_manager(), email, + signin::ConsentLevel::kSync); } CoreAccountInfo IdentityTestEnvironment::SetUnconsentedPrimaryAccount( const std::string& email) { - return signin::SetUnconsentedPrimaryAccount(identity_manager(), email); + return signin::SetPrimaryAccount(identity_manager(), email, + signin::ConsentLevel::kSignin); } void IdentityTestEnvironment::SetRefreshTokenForPrimaryAccount() {
diff --git a/components/signin/public/identity_manager/identity_test_utils.cc b/components/signin/public/identity_manager/identity_test_utils.cc index 5562e06..f5aa574 100644 --- a/components/signin/public/identity_manager/identity_test_utils.cc +++ b/components/signin/public/identity_manager/identity_test_utils.cc
@@ -16,7 +16,6 @@ #include "components/signin/internal/identity_manager/profile_oauth2_token_service.h" #include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h" #include "components/signin/public/base/list_accounts_test_utils.h" -#include "components/signin/public/identity_manager/consent_level.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/primary_account_mutator.h" #include "components/signin/public/identity_manager/test_identity_manager_observer.h" @@ -132,26 +131,9 @@ } CoreAccountInfo SetPrimaryAccount(IdentityManager* identity_manager, - const std::string& email) { - DCHECK(!identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)); - PrimaryAccountManager* primary_account_manager = - identity_manager->GetPrimaryAccountManager(); - DCHECK(!primary_account_manager->HasPrimaryAccount(ConsentLevel::kSync)); - - AccountInfo account_info = - EnsureAccountExists(identity_manager->GetAccountTrackerService(), email); - DCHECK(!account_info.gaia.empty()); - - primary_account_manager->SetSyncPrimaryAccountInfo(account_info); - - DCHECK(primary_account_manager->HasPrimaryAccount(ConsentLevel::kSync)); - DCHECK(identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)); - return identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); -} - -CoreAccountInfo SetUnconsentedPrimaryAccount(IdentityManager* identity_manager, - const std::string& email) { - DCHECK(!identity_manager->HasPrimaryAccount(ConsentLevel::kSignin)); + const std::string& email, + ConsentLevel consent_level) { + DCHECK(!identity_manager->HasPrimaryAccount(consent_level)); AccountInfo account_info = EnsureAccountExists(identity_manager->GetAccountTrackerService(), email); @@ -159,46 +141,51 @@ PrimaryAccountManager* primary_account_manager = identity_manager->GetPrimaryAccountManager(); - primary_account_manager->SetUnconsentedPrimaryAccountInfo(account_info); + switch (consent_level) { + case ConsentLevel::kSync: + primary_account_manager->SetSyncPrimaryAccountInfo(account_info); + break; + case ConsentLevel::kSignin: + primary_account_manager->SetUnconsentedPrimaryAccountInfo(account_info); + } - DCHECK(identity_manager->HasPrimaryAccount(ConsentLevel::kSignin)); - DCHECK_EQ( - account_info.gaia, - identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin) - .gaia); - return identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin); + DCHECK(identity_manager->HasPrimaryAccount(consent_level)); + DCHECK_EQ(account_info.gaia, + identity_manager->GetPrimaryAccountInfo(consent_level).gaia); + return identity_manager->GetPrimaryAccountInfo(consent_level); } void SetRefreshTokenForPrimaryAccount(IdentityManager* identity_manager, const std::string& token_value) { - DCHECK(identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)); + DCHECK(identity_manager->HasPrimaryAccount(ConsentLevel::kSync)); CoreAccountId account_id = - identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSync); + identity_manager->GetPrimaryAccountId(ConsentLevel::kSync); SetRefreshTokenForAccount(identity_manager, account_id, token_value); } void SetInvalidRefreshTokenForPrimaryAccount( IdentityManager* identity_manager) { - DCHECK(identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)); + DCHECK(identity_manager->HasPrimaryAccount(ConsentLevel::kSync)); CoreAccountId account_id = - identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSync); + identity_manager->GetPrimaryAccountId(ConsentLevel::kSync); SetInvalidRefreshTokenForAccount(identity_manager, account_id); } void RemoveRefreshTokenForPrimaryAccount(IdentityManager* identity_manager) { - if (!identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)) + if (!identity_manager->HasPrimaryAccount(ConsentLevel::kSync)) return; CoreAccountId account_id = - identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSync); + identity_manager->GetPrimaryAccountId(ConsentLevel::kSync); RemoveRefreshTokenForAccount(identity_manager, account_id); } AccountInfo MakePrimaryAccountAvailable(IdentityManager* identity_manager, const std::string& email) { - CoreAccountInfo account_info = SetPrimaryAccount(identity_manager, email); + CoreAccountInfo account_info = + SetPrimaryAccount(identity_manager, email, ConsentLevel::kSync); SetRefreshTokenForPrimaryAccount(identity_manager); base::Optional<AccountInfo> primary_account_info = identity_manager
diff --git a/components/signin/public/identity_manager/identity_test_utils.h b/components/signin/public/identity_manager/identity_test_utils.h index 619d83b..1c58c025 100644 --- a/components/signin/public/identity_manager/identity_test_utils.h +++ b/components/signin/public/identity_manager/identity_test_utils.h
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "build/build_config.h" #include "components/signin/public/identity_manager/account_info.h" +#include "components/signin/public/identity_manager/consent_level.h" namespace network { class TestURLLoaderFactory; @@ -39,18 +40,15 @@ void WaitForRefreshTokensLoaded(IdentityManager* identity_manager); // Sets the primary account (which must not already be set) to the given email -// address, generating a GAIA ID that corresponds uniquely to that email -// address. On non-ChromeOS, results in the firing of the IdentityManager and -// PrimaryAccountManager callbacks for signin success. Blocks until the primary -// account is set. Returns the CoreAccountInfo of the newly-set account. +// address with corresponding consent level, generating a GAIA ID that +// corresponds uniquely to that email address. On non-ChromeOS, results in the +// firing of the IdentityManager and PrimaryAccountManager callbacks for signin +// success. Blocks until the primary account is set. Returns the CoreAccountInfo +// of the newly-set account. // NOTE: See disclaimer at top of file re: direct usage. CoreAccountInfo SetPrimaryAccount(IdentityManager* identity_manager, - const std::string& email); - -// As above, but adds an "unconsented" primary account. See ./README.md for -// the distinction between primary and unconsented primary accounts. -CoreAccountInfo SetUnconsentedPrimaryAccount(IdentityManager* identity_manager, - const std::string& email); + const std::string& email, + ConsentLevel consent_level); // Sets a refresh token for the primary account (which must already be set). // Blocks until the refresh token is set. If |token_value| is empty a default
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc index 68018a6b2..22168e2 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -90,7 +90,6 @@ void ContentSubresourceFilterThrottleManager::CreateForWebContents( content::WebContents* web_contents, SubresourceFilterProfileContext* profile_context, - infobars::ContentInfoBarManager* infobar_manager, scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager, VerifiedRulesetDealer::Handle* dealer_handle) { if (!base::FeatureList::IsEnabled(kSafeBrowsingSubresourceFilter)) @@ -102,8 +101,7 @@ web_contents->SetUserData( kContentSubresourceFilterThrottleManagerWebContentsUserDataKey, std::make_unique<ContentSubresourceFilterThrottleManager>( - profile_context, infobar_manager, database_manager, dealer_handle, - web_contents)); + profile_context, database_manager, dealer_handle, web_contents)); } // static @@ -118,7 +116,6 @@ ContentSubresourceFilterThrottleManager:: ContentSubresourceFilterThrottleManager( SubresourceFilterProfileContext* profile_context, - infobars::ContentInfoBarManager* infobar_manager, scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager, VerifiedRulesetDealer::Handle* dealer_handle, @@ -130,8 +127,7 @@ profile_interaction_manager_( std::make_unique<subresource_filter::ProfileInteractionManager>( web_contents, - profile_context, - infobar_manager)) { + profile_context)) { SubresourceFilterObserverManager::CreateForWebContents(web_contents); scoped_observation_.Observe( SubresourceFilterObserverManager::FromWebContents(web_contents));
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h index ccf1d3d..64707b3 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h +++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
@@ -34,10 +34,6 @@ class RenderFrameHost; } // namespace content -namespace infobars { -class ContentInfoBarManager; -} - namespace subresource_filter { class AsyncDocumentSubresourceFilter; @@ -97,7 +93,6 @@ static void CreateForWebContents( content::WebContents* web_contents, SubresourceFilterProfileContext* profile_context, - infobars::ContentInfoBarManager* infobar_manager, scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager, VerifiedRulesetDealer::Handle* dealer_handle); @@ -107,7 +102,6 @@ ContentSubresourceFilterThrottleManager( SubresourceFilterProfileContext* profile_context, - infobars::ContentInfoBarManager* infobar_manager, scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager, VerifiedRulesetDealer::Handle* dealer_handle,
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc index f50c2a2..7c41686 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
@@ -211,13 +211,10 @@ // ShowNotification() being invoked. throttle_manager_test_support_->SetShouldUseSmartUI(false); - infobar_manager_ = - std::make_unique<infobars::ContentInfoBarManager>(web_contents); throttle_manager_ = std::make_unique<ContentSubresourceFilterThrottleManager>( throttle_manager_test_support_->profile_context(), - infobar_manager_.get(), /*database_manager=*/nullptr, - dealer_handle_.get(), web_contents); + /*database_manager=*/nullptr, dealer_handle_.get(), web_contents); Observe(web_contents); } @@ -286,14 +283,16 @@ return content_settings->IsContentBlocked(ContentSettingsType::ADS); } - bool presenting_ads_blocked_infobar() const { - if (infobar_manager_->infobar_count() == 0) + bool presenting_ads_blocked_infobar() { + auto* infobar_manager = infobars::ContentInfoBarManager::FromWebContents( + content::RenderViewHostTestHarness::web_contents()); + if (infobar_manager->infobar_count() == 0) return false; // No infobars other than the ads blocked infobar should be displayed in the // context of these tests. - EXPECT_EQ(infobar_manager_->infobar_count(), 1u); - auto* infobar = infobar_manager_->infobar_at(0); + EXPECT_EQ(infobar_manager->infobar_count(), 1u); + auto* infobar = infobar_manager->infobar_at(0); EXPECT_EQ(infobar->delegate()->GetIdentifier(), infobars::InfoBarDelegate::ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID); @@ -371,7 +370,6 @@ testing::TestRulesetCreator test_ruleset_creator_; testing::TestRulesetPair test_ruleset_pair_; std::unique_ptr<ThrottleManagerTestSupport> throttle_manager_test_support_; - std::unique_ptr<infobars::ContentInfoBarManager> infobar_manager_; std::unique_ptr<VerifiedRulesetDealer::Handle> dealer_handle_; @@ -411,6 +409,27 @@ #endif } +#if defined(OS_ANDROID) +TEST_P(ContentSubresourceFilterThrottleManagerTest, + NoCrashWhenInfoBarManagerIsNotPresent) { + auto* web_contents = RenderViewHostTestHarness::web_contents(); + web_contents->RemoveUserData(infobars::ContentInfoBarManager::UserDataKey()); + + // Commit a navigation that triggers page level activation. + NavigateAndCommitMainFrame(GURL(kTestURLWithActivation)); + ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */); + + // A disallowed subframe navigation should be successfully filtered, and the + // lack of infobar manager should not cause a crash. + CreateSubframeWithTestNavigation( + GURL("https://www.example.com/disallowed.html"), main_rfh()); + EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE, + SimulateStartAndGetResult(navigation_simulator())); + + EXPECT_TRUE(ads_blocked_in_content_settings()); +} +#endif + TEST_P(ContentSubresourceFilterThrottleManagerTest, NoPageActivation) { // This test assumes that we're not in DryRun mode. base::test::ScopedFeatureList scoped_feature; @@ -916,8 +935,6 @@ ThrottleManagerTestSupport throttle_manager_test_support(web_contents.get()); SubresourceFilterProfileContext* profile_context = throttle_manager_test_support.profile_context(); - auto infobar_manager = - std::make_unique<infobars::ContentInfoBarManager>(web_contents.get()); { base::test::ScopedFeatureList scoped_feature; @@ -926,8 +943,8 @@ // CreateForWebContents() should not do anything if the subresource filter // feature is not enabled. ContentSubresourceFilterThrottleManager::CreateForWebContents( - web_contents.get(), profile_context, infobar_manager.get(), - /*database_manager=*/nullptr, dealer_handle()); + web_contents.get(), profile_context, /*database_manager=*/nullptr, + dealer_handle()); EXPECT_EQ(ContentSubresourceFilterThrottleManager::FromWebContents( web_contents.get()), nullptr); @@ -936,7 +953,7 @@ // If the subresource filter feature is enabled (as it is by default), // CreateForWebContents() should create and attach an instance. ContentSubresourceFilterThrottleManager::CreateForWebContents( - web_contents.get(), profile_context, infobar_manager.get(), + web_contents.get(), profile_context, /*database_manager=*/nullptr, dealer_handle()); auto* throttle_manager = ContentSubresourceFilterThrottleManager::FromWebContents( @@ -945,7 +962,7 @@ // A second call should not attach a different instance. ContentSubresourceFilterThrottleManager::CreateForWebContents( - web_contents.get(), profile_context, infobar_manager.get(), + web_contents.get(), profile_context, /*database_manager=*/nullptr, dealer_handle()); EXPECT_EQ(ContentSubresourceFilterThrottleManager::FromWebContents( web_contents.get()),
diff --git a/components/subresource_filter/content/browser/profile_interaction_manager.cc b/components/subresource_filter/content/browser/profile_interaction_manager.cc index 6b8321109..f3a96572b 100644 --- a/components/subresource_filter/content/browser/profile_interaction_manager.cc +++ b/components/subresource_filter/content/browser/profile_interaction_manager.cc
@@ -17,6 +17,7 @@ #include "content/public/browser/web_contents.h" #if defined(OS_ANDROID) +#include "components/infobars/content/content_infobar_manager.h" // nogncheck #include "components/subresource_filter/content/browser/ads_blocked_infobar_delegate.h" #endif @@ -24,15 +25,9 @@ ProfileInteractionManager::ProfileInteractionManager( content::WebContents* web_contents, - SubresourceFilterProfileContext* profile_context, - infobars::ContentInfoBarManager* infobar_manager) + SubresourceFilterProfileContext* profile_context) : content::WebContentsObserver(web_contents), - profile_context_(profile_context) -#if defined(OS_ANDROID) - , - infobar_manager_(infobar_manager) -#endif -{ + profile_context_(profile_context) { DCHECK(web_contents); } @@ -133,7 +128,12 @@ if (profile_context_->settings_manager()->ShouldShowUIForSite( top_level_url)) { #if defined(OS_ANDROID) - subresource_filter::AdsBlockedInfobarDelegate::Create(infobar_manager_); + // NOTE: It is acceptable for the embedder to not have installed an infobar + // manager. + if (auto* infobar_manager = + infobars::ContentInfoBarManager::FromWebContents(web_contents())) { + subresource_filter::AdsBlockedInfobarDelegate::Create(infobar_manager); + } #endif // TODO(https://crbug.com/1103176): Plumb the actual frame reference here
diff --git a/components/subresource_filter/content/browser/profile_interaction_manager.h b/components/subresource_filter/content/browser/profile_interaction_manager.h index 2724fec..c976b122 100644 --- a/components/subresource_filter/content/browser/profile_interaction_manager.h +++ b/components/subresource_filter/content/browser/profile_interaction_manager.h
@@ -16,10 +16,6 @@ class WebContents; } // namespace content -namespace infobars { -class ContentInfoBarManager; -} - namespace subresource_filter { class SubresourceFilterProfileContext; @@ -32,8 +28,7 @@ public SubresourceFilterSafeBrowsingActivationThrottle::Delegate { public: ProfileInteractionManager(content::WebContents* web_contents, - SubresourceFilterProfileContext* profile_context, - infobars::ContentInfoBarManager* infobar_manager); + SubresourceFilterProfileContext* profile_context); ~ProfileInteractionManager() override; ProfileInteractionManager(const ProfileInteractionManager&) = delete; @@ -54,7 +49,9 @@ // Invoked when a notification should potentially be shown to the user that // ads are being blocked on this page. Will make the final determination as to - // whether the notification should be shown. + // whether the notification should be shown. On Android this will show an + // infobar if appropriate and if an infobar::ContentInfoBarManager instance + // has been installed in web_contents() by the embedder. void MaybeShowNotification(); // SubresourceFilterSafeBrowsingActivationThrottle::Delegate: @@ -67,11 +64,6 @@ // Unowned and must outlive this object. SubresourceFilterProfileContext* profile_context_ = nullptr; -#if defined(OS_ANDROID) - // Unowned and must outlive this object. - infobars::ContentInfoBarManager* infobar_manager_ = nullptr; -#endif - bool ads_violation_triggered_for_last_committed_navigation_ = false; };
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc index 77be7de..af6c7f8 100644 --- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc +++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
@@ -166,13 +166,10 @@ auto* contents = RenderViewHostTestHarness::web_contents(); throttle_manager_test_support_ = std::make_unique<ThrottleManagerTestSupport>(contents); - infobar_manager_ = - std::make_unique<infobars::ContentInfoBarManager>(contents); throttle_manager_ = std::make_unique<ContentSubresourceFilterThrottleManager>( throttle_manager_test_support_->profile_context(), - infobar_manager_.get(), /*database_manager=*/nullptr, - ruleset_dealer_.get(), contents); + /*database_manager=*/nullptr, ruleset_dealer_.get(), contents); fake_safe_browsing_database_ = new FakeSafeBrowsingDatabaseManager(); NavigateAndCommit(GURL("https://test.com")); Observe(contents); @@ -341,14 +338,16 @@ return &scoped_configuration_; } - bool presenting_ads_blocked_infobar() const { - if (infobar_manager_->infobar_count() == 0) + bool presenting_ads_blocked_infobar() { + auto* infobar_manager = infobars::ContentInfoBarManager::FromWebContents( + content::RenderViewHostTestHarness::web_contents()); + if (infobar_manager->infobar_count() == 0) return false; // No infobars other than the ads blocked infobar should be displayed in the // context of these tests. - EXPECT_EQ(infobar_manager_->infobar_count(), 1u); - auto* infobar = infobar_manager_->infobar_at(0); + EXPECT_EQ(infobar_manager->infobar_count(), 1u); + auto* infobar = infobar_manager->infobar_at(0); EXPECT_EQ(infobar->delegate()->GetIdentifier(), infobars::InfoBarDelegate::ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID); @@ -369,7 +368,6 @@ std::unique_ptr<content::NavigationSimulator> navigation_simulator_; std::unique_ptr<ThrottleManagerTestSupport> throttle_manager_test_support_; - std::unique_ptr<infobars::ContentInfoBarManager> infobar_manager_; std::unique_ptr<TestSubresourceFilterObserver> observer_; scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_safe_browsing_database_; base::HistogramTester tester_;
diff --git a/components/subresource_filter/content/browser/subresource_filter_test_harness.cc b/components/subresource_filter/content/browser/subresource_filter_test_harness.cc index ce55742..8a73fed7 100644 --- a/components/subresource_filter/content/browser/subresource_filter_test_harness.cc +++ b/components/subresource_filter/content/browser/subresource_filter_test_harness.cc
@@ -92,11 +92,10 @@ throttle_manager_test_support_ = std::make_unique<ThrottleManagerTestSupport>(web_contents()); database_manager_ = base::MakeRefCounted<FakeSafeBrowsingDatabaseManager>(); - infobar_manager_ = - std::make_unique<infobars::ContentInfoBarManager>(web_contents()); + infobars::ContentInfoBarManager::CreateForWebContents(web_contents()); ContentSubresourceFilterThrottleManager::CreateForWebContents( web_contents(), throttle_manager_test_support_->profile_context(), - infobar_manager_.get(), database_manager_, dealer); + database_manager_, dealer); // Observe web_contents() to add subresource filter navigation throttles at // the start of navigations.
diff --git a/components/subresource_filter/content/browser/throttle_manager_test_support.cc b/components/subresource_filter/content/browser/throttle_manager_test_support.cc index d4ab654..ed5402c8b 100644 --- a/components/subresource_filter/content/browser/throttle_manager_test_support.cc +++ b/components/subresource_filter/content/browser/throttle_manager_test_support.cc
@@ -7,6 +7,7 @@ #include "components/content_settings/browser/page_specific_content_settings.h" #include "components/content_settings/browser/test_page_specific_content_settings_delegate.h" #include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/infobars/content/content_infobar_manager.h" #include "components/safe_browsing/core/db/database_manager.h" #include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h" #include "components/subresource_filter/content/browser/subresource_filter_profile_context.h" @@ -30,6 +31,7 @@ std::make_unique< content_settings::TestPageSpecificContentSettingsDelegate>( /*prefs=*/nullptr, settings_map_.get())); + infobars::ContentInfoBarManager::CreateForWebContents(web_contents); } ThrottleManagerTestSupport::~ThrottleManagerTestSupport() {
diff --git a/components/sync/driver/sync_service_crypto.cc b/components/sync/driver/sync_service_crypto.cc index d7758b3..68748ca 100644 --- a/components/sync/driver/sync_service_crypto.cc +++ b/components/sync/driver/sync_service_crypto.cc
@@ -392,8 +392,7 @@ ModelTypeSet SyncServiceCrypto::GetEncryptedDataTypes() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(state_.encrypted_types.Has(PASSWORDS)); - DCHECK(state_.encrypted_types.Has(WIFI_CONFIGURATIONS)); + DCHECK(state_.encrypted_types.HasAll(AlwaysEncryptedUserTypes())); // We may be called during the setup process before we're // initialized. In this case, we default to the sensitive types. return state_.encrypted_types; @@ -526,8 +525,7 @@ << ModelTypeSetToString(state_.encrypted_types) << " (encrypt everything is set to " << (state_.encrypt_everything ? "true" : "false") << ")"; - DCHECK(state_.encrypted_types.Has(PASSWORDS)); - DCHECK(state_.encrypted_types.Has(WIFI_CONFIGURATIONS)); + DCHECK(state_.encrypted_types.HasAll(AlwaysEncryptedUserTypes())); delegate_->CryptoStateChanged(); }
diff --git a/components/sync/driver/sync_user_settings_impl.cc b/components/sync/driver/sync_user_settings_impl.cc index dbbfa3a..b391e3d 100644 --- a/components/sync/driver/sync_user_settings_impl.cc +++ b/components/sync/driver/sync_user_settings_impl.cc
@@ -270,7 +270,7 @@ return true; const ModelTypeSet preferred_types = GetPreferredDataTypes(); const ModelTypeSet encrypted_types = GetEncryptedDataTypes(); - DCHECK(encrypted_types.Has(PASSWORDS)); + DCHECK(encrypted_types.HasAll(AlwaysEncryptedUserTypes())); return !Intersection(preferred_types, encrypted_types).Empty(); }
diff --git a/components/sync/engine/get_updates_processor.cc b/components/sync/engine/get_updates_processor.cc index 058cca5..6ba5fb1 100644 --- a/components/sync/engine/get_updates_processor.cc +++ b/components/sync/engine/get_updates_processor.cc
@@ -5,8 +5,10 @@ #include "components/sync/engine/get_updates_processor.h" #include <stddef.h> +#include <map> #include <string> #include <utility> +#include <vector> #include "base/logging.h" #include "base/trace_event/trace_event.h" @@ -347,12 +349,9 @@ context.CopyFrom(gu_response.context_mutations(context_iter->second)); if (update_handler_iter != update_handler_map_->end()) { - SyncerError result = - update_handler_iter->second->ProcessGetUpdatesResponse( - gu_response.new_progress_marker(progress_marker_iter->second), - context, updates_iter->second, status_controller); - if (result.value() != SyncerError::SYNCER_OK) - return result; + update_handler_iter->second->ProcessGetUpdatesResponse( + gu_response.new_progress_marker(progress_marker_iter->second), + context, updates_iter->second, status_controller); } else { DLOG(WARNING) << "Ignoring received updates of a type we can't handle. " << "Type is: " << ModelTypeToString(type);
diff --git a/components/sync/engine/model_type_registry.cc b/components/sync/engine/model_type_registry.cc index 9b6606ff..24913feeb 100644 --- a/components/sync/engine/model_type_registry.cc +++ b/components/sync/engine/model_type_registry.cc
@@ -12,8 +12,6 @@ #include "base/logging.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "components/sync/engine/commit_queue.h" #include "components/sync/engine/data_type_activation_response.h" #include "components/sync/engine/model_type_processor.h" #include "components/sync/engine/model_type_worker.h" @@ -22,35 +20,6 @@ namespace syncer { -namespace { - -class CommitQueueProxy : public CommitQueue { - public: - CommitQueueProxy(const base::WeakPtr<CommitQueue>& worker, - const scoped_refptr<base::SequencedTaskRunner>& sync_thread); - ~CommitQueueProxy() override; - - void NudgeForCommit() override; - - private: - base::WeakPtr<CommitQueue> worker_; - scoped_refptr<base::SequencedTaskRunner> sync_thread_; -}; - -CommitQueueProxy::CommitQueueProxy( - const base::WeakPtr<CommitQueue>& worker, - const scoped_refptr<base::SequencedTaskRunner>& sync_thread) - : worker_(worker), sync_thread_(sync_thread) {} - -CommitQueueProxy::~CommitQueueProxy() {} - -void CommitQueueProxy::NudgeForCommit() { - sync_thread_->PostTask(FROM_HERE, - base::BindOnce(&CommitQueue::NudgeForCommit, worker_)); -} - -} // namespace - ModelTypeRegistry::ModelTypeRegistry( NudgeHandler* nudge_handler, CancelationSignal* cancelation_signal, @@ -73,20 +42,11 @@ DCHECK(commit_contributor_map_.find(type) == commit_contributor_map_.end()); DVLOG(1) << "Enabling an off-thread sync type: " << ModelTypeToString(type); - // Save a raw pointer to the processor for connecting later. - ModelTypeProcessor* type_processor = - activation_response->type_processor.get(); - - bool initial_sync_done = - activation_response->model_type_state.initial_sync_done(); - auto worker = std::make_unique<ModelTypeWorker>( type, activation_response->model_type_state, - /*trigger_initial_sync=*/!initial_sync_done, sync_encryption_handler_->GetCryptographer(), /*encryption_enabled=*/encrypted_types_.Has(type), passphrase_type_, - nudge_handler_, std::move(activation_response->type_processor), - cancelation_signal_); + nudge_handler_, cancelation_signal_); // Save a raw pointer and add the worker to our structures. ModelTypeWorker* worker_ptr = worker.get(); @@ -94,9 +54,7 @@ update_handler_map_.insert(std::make_pair(type, worker_ptr)); commit_contributor_map_.insert(std::make_pair(type, worker_ptr)); - // Initialize Processor -> Worker communication channel. - type_processor->ConnectSync(std::make_unique<CommitQueueProxy>( - worker_ptr->AsWeakPtr(), base::SequencedTaskRunnerHandle::Get())); + worker_ptr->ConnectSync(std::move(activation_response->type_processor)); } void ModelTypeRegistry::DisconnectDataType(ModelType type) { @@ -189,23 +147,11 @@ const KeyDerivationParams& key_derivation_params, const sync_pb::EncryptedData& pending_keys) {} -void ModelTypeRegistry::OnPassphraseAccepted() { - for (const auto& worker : connected_model_type_workers_) { - if (encrypted_types_.Has(worker->GetModelType())) { - worker->EncryptionAcceptedMaybeApplyUpdates(); - } - } -} +void ModelTypeRegistry::OnPassphraseAccepted() {} void ModelTypeRegistry::OnTrustedVaultKeyRequired() {} -void ModelTypeRegistry::OnTrustedVaultKeyAccepted() { - for (const auto& worker : connected_model_type_workers_) { - if (encrypted_types_.Has(worker->GetModelType())) { - worker->EncryptionAcceptedMaybeApplyUpdates(); - } - } -} +void ModelTypeRegistry::OnTrustedVaultKeyAccepted() {} void ModelTypeRegistry::OnBootstrapTokenUpdated( const std::string& bootstrap_token,
diff --git a/components/sync/engine/model_type_worker.cc b/components/sync/engine/model_type_worker.cc index 1d137c4..2b3b5d1c8 100644 --- a/components/sync/engine/model_type_worker.cc +++ b/components/sync/engine/model_type_worker.cc
@@ -19,6 +19,7 @@ #include "base/strings/strcat.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/thread_restrictions.h" #include "base/trace_event/memory_usage_estimator.h" #include "components/sync/base/client_tag_hash.h" @@ -49,6 +50,26 @@ const int kMinGuResponsesToIgnoreKey = 50; +// A proxy which can be called from any sequence and delegates the work to the +// commit queue injected on construction. +class CommitQueueProxy : public CommitQueue { + public: + // Must be called from the sequence where |commit_queue| lives. + explicit CommitQueueProxy(const base::WeakPtr<CommitQueue>& commit_queue) + : commit_queue_(commit_queue) {} + ~CommitQueueProxy() override = default; + + void NudgeForCommit() override { + commit_queue_thread_->PostTask( + FROM_HERE, base::BindOnce(&CommitQueue::NudgeForCommit, commit_queue_)); + } + + private: + const base::WeakPtr<CommitQueue> commit_queue_; + const scoped_refptr<base::SequencedTaskRunner> commit_queue_thread_ = + base::SequencedTaskRunnerHandle::Get(); +}; + void AdaptClientTagForFullUpdateData(ModelType model_type, syncer::EntityData* data) { // Server does not send any client tags for wallet data entities or offer data @@ -150,15 +171,12 @@ ModelTypeWorker::ModelTypeWorker( ModelType type, const sync_pb::ModelTypeState& initial_state, - bool trigger_initial_sync, Cryptographer* cryptographer, bool encryption_enabled, PassphraseType passphrase_type, NudgeHandler* nudge_handler, - std::unique_ptr<ModelTypeProcessor> model_type_processor, CancelationSignal* cancelation_signal) : type_(type), - model_type_processor_(std::move(model_type_processor)), cryptographer_(cryptographer), nudge_handler_(nudge_handler), cancelation_signal_(cancelation_signal), @@ -167,33 +185,12 @@ passphrase_type_(passphrase_type), min_gu_responses_to_ignore_key_(kMinGuResponsesToIgnoreKey) { DCHECK(cryptographer_); - DCHECK(model_type_processor_); - DCHECK(type_ != PASSWORDS || encryption_enabled_); + DCHECK(!AlwaysEncryptedUserTypes().Has(type_) || encryption_enabled_); if (!CommitOnlyTypes().Has(GetModelType())) { DCHECK_EQ(type, GetModelTypeFromSpecificsFieldNumber( initial_state.progress_marker().data_type_id())); } - - // Request an initial sync if it hasn't been completed yet. - if (trigger_initial_sync) { - nudge_handler_->NudgeForInitialDownload(type_); - } - - // The persisted ModelTypeState might not have the most recent encryption - // key name, e.g. due to disk corruption, or because the cryptographer was - // updated before this worker was constructed. There will be no calls to - // EncryptionAcceptedMaybeApplyUpdates() or OnCryptographerChange() to update - // the key name in this case, so do it manually here. - bool had_outdated_key_name = UpdateTypeEncryptionKeyName(); - // If the key was outdated and initial sync is already done, the processor - // risks relying on the incorrect key, so call ApplyPendingUpdates() to push - // the correct one. If initial sync isn't done yet, there's no risk and the - // first call to ApplyUpdates() will push the now-updated key. - if (had_outdated_key_name && model_type_state_.initial_sync_done()) { - // Might be a no-op as per BlockForEncryption(). - ApplyPendingUpdates(); - } } ModelTypeWorker::~ModelTypeWorker() { @@ -201,7 +198,40 @@ std::string("Sync.UndecryptedEntitiesOnDataTypeDisabled.") + ModelTypeToHistogramSuffix(type_), entries_pending_decryption_.size()); - model_type_processor_->DisconnectSync(); + if (model_type_processor_) { + // This will always be the case in production today. + model_type_processor_->DisconnectSync(); + } +} + +void ModelTypeWorker::ConnectSync( + std::unique_ptr<ModelTypeProcessor> model_type_processor) { + DCHECK(!model_type_processor_); + DCHECK(model_type_processor); + + model_type_processor_ = std::move(model_type_processor); + // TODO(victorvianna): CommitQueueProxy is only needed by the + // ModelTypeProcessorProxy implementation, so it could possibly be moved + // there % changing ConnectSync() to take a raw pointer. This then allows + // removing base::test::SingleThreadTaskEnvironment from the unit test. + model_type_processor_->ConnectSync( + std::make_unique<CommitQueueProxy>(weak_ptr_factory_.GetWeakPtr())); + + if (!model_type_state_.initial_sync_done()) { + nudge_handler_->NudgeForInitialDownload(type_); + } + + // |model_type_state_| might have an outdated encryption key name, e.g. + // because |cryptographer_| was updated before this worker was constructed. + // OnCryptographerChange() might never be called, so update the key manually + // here and push it to the processor. Only push if initial sync is done, + // otherwise this violates some of the processor assumptions; if initial sync + // isn't done, the now-updated key will be pushed on the first ApplyUpdates() + // call anyway. + bool had_outdated_key_name = UpdateTypeEncryptionKeyName(); + if (had_outdated_key_name && model_type_state_.initial_sync_done()) { + SendPendingUpdatesToProcessorIfReady(); + } } ModelType ModelTypeWorker::GetModelType() const { @@ -211,15 +241,33 @@ void ModelTypeWorker::EnableEncryption() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (encryption_enabled_) { + // No-op. + return; + } + encryption_enabled_ = true; - UpdateTypeEncryptionKeyName(); + // UpdateTypeEncryptionKeyName() might return false if the cryptographer does + // not have a default key yet. + if (UpdateTypeEncryptionKeyName()) { + // Push the new key name to the processor. + SendPendingUpdatesToProcessorIfReady(); + } } void ModelTypeWorker::OnCryptographerChange() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - UpdateTypeEncryptionKeyName(); - // Always try to decrypt, regardless of |encryption_enabled_|. + // Always try to decrypt, regardless of |encryption_enabled_|. This might + // add some elements to |pending_updates_|. DecryptStoredEntities(); + bool had_oudated_key_name = UpdateTypeEncryptionKeyName(); + if (had_oudated_key_name || !pending_updates_.empty()) { + // Push the newly decrypted updates and/or the new key name to the + // processor. + SendPendingUpdatesToProcessorIfReady(); + } + // If the worker couldn't commit before due to BlockForEncryption(), this + // might now be resolved. The call is a no-op if there's nothing to commit. NudgeIfReadyToCommit(); } @@ -228,7 +276,6 @@ passphrase_type_ = type; } -// UpdateHandler implementation. bool ModelTypeWorker::IsInitialSyncEnded() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return model_type_state_.initial_sync_done(); @@ -245,7 +292,7 @@ return model_type_state_.type_context(); } -SyncerError ModelTypeWorker::ProcessGetUpdatesResponse( +void ModelTypeWorker::ProcessGetUpdatesResponse( const sync_pb::DataTypeProgressMarker& progress_marker, const sync_pb::DataTypeContext& mutated_context, const SyncEntityList& applicable_updates, @@ -333,8 +380,6 @@ MaybeDropPendingUpdatesEncryptedWith(key_and_info.first); } } - - return SyncerError(SyncerError::SYNCER_OK); } // static @@ -421,37 +466,25 @@ // Indicate to the processor that the initial download is done. The initial // sync technically isn't done yet but by the time this value is persisted to // disk on the model thread it will be. - // - // This should be mostly relevant for the call from ApplyUpdates(), but in - // rare cases we may end up receiving initial updates outside configuration - // cycles (e.g. polling cycles). model_type_state_.set_initial_sync_done(true); // Download cycle is done, pass all updates to the processor. - ApplyPendingUpdates(); + SendPendingUpdatesToProcessorIfReady(); } -void ModelTypeWorker::EncryptionAcceptedMaybeApplyUpdates() { - // TODO(crbug.com/1109221): Consider always trying to apply updates in - // EnableEncryption() and OnCryptographerChange() instead of having this - // method. If so, the enable_encryption argument in the constructor can be - // replaced with an immediate call to EnableEncryption() without losing the - // edge case ApplyUpdates() in the constructor body. - DCHECK(encryption_enabled_); - DCHECK(cryptographer_->CanEncrypt()); +void ModelTypeWorker::SendPendingUpdatesToProcessorIfReady() { + DCHECK(model_type_processor_); - // Only push the encryption to the processor if we're already connected. - // Otherwise this information can wait for the initial sync's first apply. - if (model_type_state_.initial_sync_done()) { - // Reuse ApplyUpdates(...) to get its DCHECKs as well. - ApplyUpdates(nullptr); + if (!model_type_state_.initial_sync_done()) { + return; } -} -void ModelTypeWorker::ApplyPendingUpdates() { if (BlockForEncryption()) { return; } + DCHECK(!AlwaysEncryptedUserTypes().Has(type_) || encryption_enabled_); + DCHECK(!encryption_enabled_ || + !model_type_state_.encryption_key_name().empty()); DCHECK(entries_pending_decryption_.empty()); DVLOG(1) << ModelTypeToString(type_) << ": " @@ -486,15 +519,16 @@ // existing behaviour. But perhaps there is no need to nudge for commit if all // known changes are already in flight. if (has_local_changes_state_ != kNoNudgedLocalChanges && CanCommitItems()) { - nudge_handler_->NudgeForCommit(GetModelType()); + nudge_handler_->NudgeForCommit(type_); } } -// CommitContributor implementation. std::unique_ptr<CommitContribution> ModelTypeWorker::GetContribution( size_t max_entries) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(model_type_state_.initial_sync_done()); + DCHECK(model_type_processor_); + // Early return if type is not ready to commit (initial sync isn't done or // cryptographer has pending keys). if (!CanCommitItems()) { @@ -536,14 +570,18 @@ has_local_changes_state_ = kAllNudgedLocalChangesInFlight; } + DCHECK(!AlwaysEncryptedUserTypes().Has(type_) || encryption_enabled_); + DCHECK(!encryption_enabled_ || + (model_type_state_.encryption_key_name() == + cryptographer_->GetDefaultEncryptionKeyName())); return std::make_unique<CommitContributionImpl>( - GetModelType(), model_type_state_.type_context(), std::move(response), + type_, model_type_state_.type_context(), std::move(response), base::BindOnce(&ModelTypeWorker::OnCommitResponse, weak_ptr_factory_.GetWeakPtr()), base::BindOnce(&ModelTypeWorker::OnFullCommitFailure, weak_ptr_factory_.GetWeakPtr()), encryption_enabled_ ? cryptographer_ : nullptr, passphrase_type_, - CommitOnlyTypes().Has(GetModelType())); + CommitOnlyTypes().Has(type_)); } bool ModelTypeWorker::HasLocalChangesForTest() const { @@ -582,10 +620,6 @@ return memory_usage; } -base::WeakPtr<ModelTypeWorker> ModelTypeWorker::AsWeakPtr() { - return weak_ptr_factory_.GetWeakPtr(); -} - bool ModelTypeWorker::IsTypeInitialized() const { return model_type_state_.initial_sync_done(); }
diff --git a/components/sync/engine/model_type_worker.h b/components/sync/engine/model_type_worker.h index ad5e4c7..a2ee15b 100644 --- a/components/sync/engine/model_type_worker.h +++ b/components/sync/engine/model_type_worker.h
@@ -75,15 +75,14 @@ }; // |cryptographer|, |nudge_handler| and |cancelation_signal| must be non-null - // and outlive this object. + // and outlive the worker. Calling this will construct the object but not + // more, ConnectSync() must be called immediately afterwards. ModelTypeWorker(ModelType type, const sync_pb::ModelTypeState& initial_state, - bool trigger_initial_sync, Cryptographer* cryptographer, bool encryption_enabled, PassphraseType passphrase_type, NudgeHandler* nudge_handler, - std::unique_ptr<ModelTypeProcessor> model_type_processor, CancelationSignal* cancelation_signal); ~ModelTypeWorker() override; @@ -95,6 +94,15 @@ const sync_pb::SyncEntity& update_entity, UpdateResponseData* response_data); + // Initializes the two relevant communication channels: ModelTypeWorker -> + // ModelTypeProcessor (GetUpdates) and ModelTypeProcessor -> ModelTypeWorker + // (Commit). Both channels are closed when the worker is destroyed. This is + // done outside of the constructor to avoid the object being used while it's + // still being built. + // Must be called immediately after the constructor, prior to using other + // methods. + void ConnectSync(std::unique_ptr<ModelTypeProcessor> model_type_processor); + ModelType GetModelType() const; // Makes this an encrypted type, which means: @@ -118,7 +126,7 @@ bool IsInitialSyncEnded() const override; const sync_pb::DataTypeProgressMarker& GetDownloadProgress() const override; const sync_pb::DataTypeContext& GetDataTypeContext() const override; - SyncerError ProcessGetUpdatesResponse( + void ProcessGetUpdatesResponse( const sync_pb::DataTypeProgressMarker& progress_marker, const sync_pb::DataTypeContext& mutated_context, const SyncEntityList& applicable_updates, @@ -132,10 +140,6 @@ std::unique_ptr<CommitContribution> GetContribution( size_t max_entries) override; - // An alternative way to drive sending data to the processor, that should be - // called when a new encryption mechanism is ready. - void EncryptionAcceptedMaybeApplyUpdates(); - // Public for testing. // Returns true if this type should stop communicating because of outstanding // encryption issues and must wait for keys to be updated. @@ -144,8 +148,6 @@ // Returns the estimate of dynamically allocated memory in bytes. size_t EstimateMemoryUsage() const; - base::WeakPtr<ModelTypeWorker> AsWeakPtr(); - bool HasLocalChangesForTest() const; void SetMinGuResponsesToIgnoreKeyForTest(int min_gu_responses_to_ignore_key) { @@ -161,8 +163,14 @@ int gu_responses_while_should_have_been_known = 0; }; - // Helper function to actually send |pending_updates_| to the processor. - void ApplyPendingUpdates(); + // Sends |pending_updates_| and |model_type_state_| to the processor if there + // are no encryption pendencies and initial sync is done. This is called in + // ApplyUpdates() during a GetUpdates cycle, but also if the processor must be + // informed of a new encryption key, or the worker just managed to decrypt + // some pending updates. + // If initial sync isn't done yet, the first ApplyUpdates() will take care of + // pushing the data in such cases instead (the processor relies on this). + void SendPendingUpdatesToProcessorIfReady(); // Returns true if this type has successfully fetched all available updates // from the server at least once. Our state may or may not be stale, but at @@ -229,9 +237,6 @@ const ModelType type_; - // Pointer to the ModelTypeProcessor associated with this worker. Never null. - const std::unique_ptr<ModelTypeProcessor> model_type_processor_; - Cryptographer* const cryptographer_; // Interface used to access and send nudges to the sync scheduler. Not owned. @@ -241,6 +246,10 @@ // shutdown. CancelationSignal* const cancelation_signal_; + // Pointer to the ModelTypeProcessor associated with this worker. Initialized + // with ConnectSync(). + std::unique_ptr<ModelTypeProcessor> model_type_processor_; + // State that applies to the entire model type. sync_pb::ModelTypeState model_type_state_;
diff --git a/components/sync/engine/model_type_worker_unittest.cc b/components/sync/engine/model_type_worker_unittest.cc index 6b7afd6..f1df964 100644 --- a/components/sync/engine/model_type_worker_unittest.cc +++ b/components/sync/engine/model_type_worker_unittest.cc
@@ -15,6 +15,7 @@ #include "base/strings/string_number_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "base/test/task_environment.h" #include "base/threading/thread.h" #include "components/sync/base/client_tag_hash.h" #include "components/sync/base/unique_position.h" @@ -123,11 +124,7 @@ ModelTypeWorkerTest(ModelType model_type, bool is_encrypted_type) : model_type_(model_type), is_encrypted_type_(is_encrypted_type), - encryption_keys_count_(0), - update_encryption_filter_index_(0), - mock_type_processor_(nullptr), - mock_server_(std::make_unique<SingleTypeMockServer>(model_type)), - is_processor_disconnected_(false) {} + mock_server_(std::make_unique<SingleTypeMockServer>(model_type)) {} ~ModelTypeWorkerTest() override {} @@ -173,36 +170,18 @@ // Initialize with a custom initial ModelTypeState and pending updates. void InitializeWithState(const ModelType type, const ModelTypeState& state) { - DCHECK(!worker()); + DCHECK(!worker_); + worker_ = std::make_unique<ModelTypeWorker>( + type, state, &cryptographer_, is_encrypted_type_, + PassphraseType::kImplicitPassphrase, &mock_nudge_handler_, + &cancelation_signal_); // We don't get to own this object. The |worker_| keeps a unique_ptr to it. auto processor = std::make_unique<MockModelTypeProcessor>(); mock_type_processor_ = processor.get(); processor->SetDisconnectCallback(base::BindOnce( &ModelTypeWorkerTest::DisconnectProcessor, base::Unretained(this))); - - worker_ = std::make_unique<ModelTypeWorker>( - type, state, !state.initial_sync_done(), &cryptographer_, - is_encrypted_type_, PassphraseType::kImplicitPassphrase, - &mock_nudge_handler_, std::move(processor), &cancelation_signal_); - } - - // If the type isn't encrypted yet, makes the cryptographer available to the - // worker and marks the type as encrypted. Otherwise, just notifies a change - // in the cryptographer state. - void EnableEncryptionOrNotify() { - if (!worker()) { - // No worker to notify, just ensure |is_encrypted_type_| is true. - is_encrypted_type_ = true; - return; - } - - if (is_encrypted_type_) { - worker()->OnCryptographerChange(); - } else { - is_encrypted_type_ = true; - worker()->EnableEncryption(); - } + worker_->ConnectSync(std::move(processor)); } // Mimic a Nigori update with a keybag that cannot be decrypted, which means @@ -236,12 +215,8 @@ cryptographer_.AddEncryptionKey(last_key_name); cryptographer_.SelectDefaultEncryptionKey(last_key_name); - if (!worker()) { - return; - } - worker()->OnCryptographerChange(); - if (is_encrypted_type_) { - worker()->EncryptionAcceptedMaybeApplyUpdates(); + if (worker()) { + worker()->OnCryptographerChange(); } } @@ -437,22 +412,23 @@ } private: + base::test::SingleThreadTaskEnvironment task_environment_; + const ModelType model_type_; FakeCryptographer cryptographer_; // Determines whether |worker_| has access to the cryptographer or not. - // Can be set to true via EnableEncryptionOrNotify(). - bool is_encrypted_type_; + bool is_encrypted_type_ = false; // The number of encryption keys known to the cryptographer. Keys are // identified by an index from 1 to |encryption_keys_count_| and the last one // might not have been decrypted yet. - int encryption_keys_count_; + int encryption_keys_count_ = 0; // The number of the encryption key used to encrypt incoming updates. A zero // value implies no encryption. - int update_encryption_filter_index_; + int update_encryption_filter_index_ = 0; CancelationSignal cancelation_signal_; @@ -461,7 +437,7 @@ // Non-owned, possibly null pointer. This object belongs to the // ModelTypeWorker under test. - MockModelTypeProcessor* mock_type_processor_; + MockModelTypeProcessor* mock_type_processor_ = nullptr; // A mock that emulates enough of the sync server that it can be used // a single UpdateHandler and CommitContributor pair. In this test @@ -472,7 +448,7 @@ // sync. MockNudgeHandler mock_nudge_handler_; - bool is_processor_disconnected_; + bool is_processor_disconnected_ = false; StatusController status_controller_; };
diff --git a/components/sync/engine/nudge_handler.h b/components/sync/engine/nudge_handler.h index 17522c98..6b03d256 100644 --- a/components/sync/engine/nudge_handler.h +++ b/components/sync/engine/nudge_handler.h
@@ -15,7 +15,9 @@ NudgeHandler() = default; virtual ~NudgeHandler() = default; + // Schedules initial sync for |type| and returns. virtual void NudgeForInitialDownload(ModelType type) = 0; + // Schedules a commit for |type| and returns. virtual void NudgeForCommit(ModelType type) = 0; };
diff --git a/components/sync/engine/update_handler.h b/components/sync/engine/update_handler.h index 8dffadba..e1ef57a 100644 --- a/components/sync/engine/update_handler.h +++ b/components/sync/engine/update_handler.h
@@ -46,10 +46,7 @@ // // In this context, "applicable_updates" means the set of updates belonging to // this type. - // - // Returns SYNCER_OK if the all data was processed successfully, a syncer - // error otherwise. - virtual SyncerError ProcessGetUpdatesResponse( + virtual void ProcessGetUpdatesResponse( const sync_pb::DataTypeProgressMarker& progress_marker, const sync_pb::DataTypeContext& mutated_context, const SyncEntityList& applicable_updates,
diff --git a/components/sync/model/sync_change.cc b/components/sync/model/sync_change.cc index 8d2b13b..f28edd07 100644 --- a/components/sync/model/sync_change.cc +++ b/components/sync/model/sync_change.cc
@@ -15,7 +15,7 @@ SyncChangeType change_type, const SyncData& sync_data) : location_(from_here), change_type_(change_type), sync_data_(sync_data) { - DCHECK(IsValid()); + DCHECK(IsValid()) << " from " << from_here.ToString(); } SyncChange::~SyncChange() {} @@ -31,21 +31,11 @@ return false; } - // Data from the syncer must always have valid specifics. - if (!sync_data_.IsLocal()) { - return true; - } - - // Local changes must always have a unique tag. + // Changes must always have a unique tag. if (sync_data_.GetClientTagHash().value().empty()) { return false; } - // Adds and updates must have a non-unique-title. - if (change_type_ == ACTION_ADD || change_type_ == ACTION_UPDATE) { - return !sync_data_.GetTitle().empty(); - } - return true; }
diff --git a/components/sync/model/sync_data.cc b/components/sync/model/sync_data.cc index a13a908..9e0b9bc 100644 --- a/components/sync/model/sync_data.cc +++ b/components/sync/model/sync_data.cc
@@ -39,14 +39,14 @@ t1->Swap(t2); } -SyncData::SyncData() : is_local_(false), is_valid_(false) {} +SyncData::SyncData() : is_valid_(false) {} -SyncData::SyncData(bool is_local, sync_pb::SyncEntity* entity) - : immutable_entity_(entity), is_local_(is_local), is_valid_(true) {} +SyncData::SyncData(sync_pb::SyncEntity* entity) + : immutable_entity_(entity), is_valid_(true) {} SyncData::SyncData(const SyncData& other) = default; -SyncData::~SyncData() {} +SyncData::~SyncData() = default; // Static. SyncData SyncData::CreateLocalDelete(const std::string& client_tag_unhashed, @@ -72,7 +72,7 @@ entity.set_non_unique_name(non_unique_title); entity.mutable_specifics()->CopyFrom(specifics); - return SyncData(/*is_local=*/true, &entity); + return SyncData(&entity); } // Static. @@ -81,7 +81,7 @@ sync_pb::SyncEntity entity; *entity.mutable_specifics() = std::move(specifics); entity.set_client_defined_unique_tag(client_tag_hash.value()); - return SyncData(/*is_local=*/false, &entity); + return SyncData(&entity); } bool SyncData::IsValid() const { @@ -105,10 +105,6 @@ return immutable_entity_.Get().non_unique_name(); } -bool SyncData::IsLocal() const { - return is_local_; -} - std::string SyncData::ToString() const { if (!IsValid()) return "<Invalid SyncData>"; @@ -118,11 +114,9 @@ base::JSONWriter::WriteWithOptions(*EntitySpecificsToValue(GetSpecifics()), base::JSONWriter::OPTIONS_PRETTY_PRINT, &specifics); - std::string is_local_string = IsLocal() ? "true" : "false"; - return "{ isLocal: " + is_local_string + ", type: " + type + - ", tagHash: " + GetClientTagHash().value() + ", title: " + GetTitle() + - ", specifics: " + specifics + "}"; + return "{ type: " + type + ", tagHash: " + GetClientTagHash().value() + + ", title: " + GetTitle() + ", specifics: " + specifics + "}"; } void PrintTo(const SyncData& sync_data, std::ostream* os) {
diff --git a/components/sync/model/sync_data.h b/components/sync/model/sync_data.h index 54f547582..afccb15c 100644 --- a/components/sync/model/sync_data.h +++ b/components/sync/model/sync_data.h
@@ -72,9 +72,6 @@ // going TO the syncer, not from. const std::string& GetTitle() const; - // Whether this sync data is for local data or data coming from the syncer. - bool IsLocal() const; - std::string ToString() const; private: @@ -100,14 +97,11 @@ // The actual shared sync entity being held. ImmutableSyncEntity immutable_entity_; - // Whether this SyncData represents a local change. - bool is_local_; - // Whether this SyncData holds valid data. bool is_valid_; // Clears |entity|. - SyncData(bool is_local_, sync_pb::SyncEntity* entity); + explicit SyncData(sync_pb::SyncEntity* entity); }; // gmock printer helper.
diff --git a/components/sync/model/sync_data_unittest.cc b/components/sync/model/sync_data_unittest.cc index 39b85e1..a34fb79a 100644 --- a/components/sync/model/sync_data_unittest.cc +++ b/components/sync/model/sync_data_unittest.cc
@@ -37,7 +37,6 @@ TEST_F(SyncDataTest, CreateLocalDelete) { SyncData data = SyncData::CreateLocalDelete(kSyncTag, kDatatype); EXPECT_TRUE(data.IsValid()); - EXPECT_TRUE(data.IsLocal()); EXPECT_EQ(ClientTagHash::FromUnhashed(PREFERENCES, kSyncTag), data.GetClientTagHash()); EXPECT_EQ(kDatatype, data.GetDataType()); @@ -48,7 +47,6 @@ SyncData data = SyncData::CreateLocalData(kSyncTag, kNonUniqueTitle, specifics); EXPECT_TRUE(data.IsValid()); - EXPECT_TRUE(data.IsLocal()); EXPECT_EQ(ClientTagHash::FromUnhashed(PREFERENCES, kSyncTag), data.GetClientTagHash()); EXPECT_EQ(kDatatype, data.GetDataType()); @@ -62,7 +60,6 @@ SyncData data = SyncData::CreateRemoteData( specifics, ClientTagHash::FromUnhashed(PREFERENCES, kSyncTag)); EXPECT_TRUE(data.IsValid()); - EXPECT_FALSE(data.IsLocal()); EXPECT_EQ(ClientTagHash::FromUnhashed(PREFERENCES, kSyncTag), data.GetClientTagHash()); EXPECT_TRUE(data.GetSpecifics().has_preference());
diff --git a/components/sync/model/syncable_service_based_bridge.cc b/components/sync/model/syncable_service_based_bridge.cc index 94e52e93..6cd71a4 100644 --- a/components/sync/model/syncable_service_based_bridge.cc +++ b/components/sync/model/syncable_service_based_bridge.cc
@@ -52,7 +52,6 @@ sync_pb::PersistedEntityData CreatePersistedFromLocalData( const SyncData& sync_data) { - DCHECK(sync_data.IsLocal()); DCHECK(sync_data.IsValid()); DCHECK(!sync_data.GetTitle().empty()); @@ -139,10 +138,11 @@ case SyncChange::ACTION_ADD: case SyncChange::ACTION_UPDATE: { DCHECK_EQ(type_, change.sync_data().GetDataType()); - DCHECK(change.sync_data().IsLocal()) - << " from " << change.location().ToString(); DCHECK(change.sync_data().IsValid()) << " from " << change.location().ToString(); + // Local adds and updates must have a non-unique-title. + DCHECK(!change.sync_data().GetTitle().empty()) + << " from " << change.location().ToString(); const ClientTagHash client_tag_hash = change.sync_data().GetClientTagHash();
diff --git a/components/sync/model/syncable_service_based_bridge_unittest.cc b/components/sync/model/syncable_service_based_bridge_unittest.cc index 6e1e7fd..9cbb24a 100644 --- a/components/sync/model/syncable_service_based_bridge_unittest.cc +++ b/components/sync/model/syncable_service_based_bridge_unittest.cc
@@ -48,8 +48,8 @@ return specifics; } -MATCHER_P(SyncDataRemoteMatches, name, "") { - return arg.IsValid() && !arg.IsLocal() && arg.GetDataType() == kModelType && +MATCHER_P(SyncDataMatches, name, "") { + return arg.IsValid() && arg.GetDataType() == kModelType && arg.GetSpecifics().preference().name() == name; } @@ -207,9 +207,9 @@ // Once the initial data is fetched from the server, // MergeDataAndStartSyncing() should be exercised. EXPECT_CALL(syncable_service_, - MergeDataAndStartSyncing( - kModelType, ElementsAre(SyncDataRemoteMatches("name1")), - NotNull(), NotNull())); + MergeDataAndStartSyncing(kModelType, + ElementsAre(SyncDataMatches("name1")), + NotNull(), NotNull())); worker_->UpdateFromServer(kClientTagHash, GetTestSpecifics("name1")); EXPECT_THAT(GetAllData(), ElementsAre(Pair(kClientTagHash.value(), _))); } @@ -336,9 +336,9 @@ InitializeBridge(); EXPECT_CALL(syncable_service_, - MergeDataAndStartSyncing( - kModelType, ElementsAre(SyncDataRemoteMatches("name1")), - NotNull(), NotNull())); + MergeDataAndStartSyncing(kModelType, + ElementsAre(SyncDataMatches("name1")), + NotNull(), NotNull())); StartSyncing(); }
diff --git a/components/sync/test/engine/mock_update_handler.cc b/components/sync/test/engine/mock_update_handler.cc index ea20332..2ba3b4af 100644 --- a/components/sync/test/engine/mock_update_handler.cc +++ b/components/sync/test/engine/mock_update_handler.cc
@@ -30,13 +30,12 @@ return kEmptyDataTypeContext; } -SyncerError MockUpdateHandler::ProcessGetUpdatesResponse( +void MockUpdateHandler::ProcessGetUpdatesResponse( const sync_pb::DataTypeProgressMarker& progress_marker, const sync_pb::DataTypeContext& mutated_context, const SyncEntityList& applicable_updates, StatusController* status) { progress_marker_.CopyFrom(progress_marker); - return SyncerError(SyncerError::SYNCER_OK); } void MockUpdateHandler::ApplyUpdates(StatusController* status) {
diff --git a/components/sync/test/engine/mock_update_handler.h b/components/sync/test/engine/mock_update_handler.h index 81938a0..b201e8e 100644 --- a/components/sync/test/engine/mock_update_handler.h +++ b/components/sync/test/engine/mock_update_handler.h
@@ -21,7 +21,7 @@ bool IsInitialSyncEnded() const override; const sync_pb::DataTypeProgressMarker& GetDownloadProgress() const override; const sync_pb::DataTypeContext& GetDataTypeContext() const override; - SyncerError ProcessGetUpdatesResponse( + void ProcessGetUpdatesResponse( const sync_pb::DataTypeProgressMarker& progress_marker, const sync_pb::DataTypeContext& mutated_context, const SyncEntityList& applicable_updates,
diff --git a/components/test/data/autofill_assistant/html/cart.html b/components/test/data/autofill_assistant/html/cart.html new file mode 100644 index 0000000..69e217cb --- /dev/null +++ b/components/test/data/autofill_assistant/html/cart.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> + +<!-- +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. +--> +<html> + <head> + <title>Example shopping cart</title> + </head> +</html> \ No newline at end of file
diff --git a/components/tracing/test/trace_event_perftest.cc b/components/tracing/test/trace_event_perftest.cc index c2317ce..9416550e 100644 --- a/components/tracing/test/trace_event_perftest.cc +++ b/components/tracing/test/trace_event_perftest.cc
@@ -49,7 +49,7 @@ base::RunLoop run_loop; TraceLog::GetInstance()->SetDisabled(); TraceLog::GetInstance()->Flush( - Bind(&OnTraceDataCollected, run_loop.QuitClosure())); + BindRepeating(&OnTraceDataCollected, run_loop.QuitClosure())); run_loop.Run(); }
diff --git a/components/variations/variations_crash_keys.cc b/components/variations/variations_crash_keys.cc index e0df470..9ff3f31 100644 --- a/components/variations/variations_crash_keys.cc +++ b/components/variations/variations_crash_keys.cc
@@ -104,11 +104,11 @@ UpdateCrashKeys(); ui_thread_task_runner_ = base::SequencedTaskRunnerHandle::Get(); - base::FieldTrialList::AddObserver(this); + base::FieldTrialList::SetSynchronousObserver(this); } VariationsCrashKeys::~VariationsCrashKeys() { - base::FieldTrialList::RemoveObserver(this); + base::FieldTrialList::RemoveSynchronousObserver(this); g_num_variations_crash_key.Clear(); g_variations_crash_key.Clear(); }
diff --git a/components/variations/variations_ids_provider.cc b/components/variations/variations_ids_provider.cc index f04b45d63..7237221 100644 --- a/components/variations/variations_ids_provider.cc +++ b/components/variations/variations_ids_provider.cc
@@ -7,6 +7,7 @@ #include <algorithm> #include "base/base64.h" +#include "base/memory/singleton.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -43,8 +44,7 @@ // static VariationsIdsProvider* VariationsIdsProvider::GetInstance() { - static base::NoDestructor<VariationsIdsProvider> instance; - return instance.get(); + return base::Singleton<VariationsIdsProvider>::get(); } variations::mojom::VariationsHeadersPtr
diff --git a/components/variations/variations_ids_provider.h b/components/variations/variations_ids_provider.h index 273407b..2c63f04 100644 --- a/components/variations/variations_ids_provider.h +++ b/components/variations/variations_ids_provider.h
@@ -14,7 +14,6 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/metrics/field_trial.h" -#include "base/no_destructor.h" #include "base/observer_list.h" #include "base/synchronization/lock.h" #include "components/variations/proto/study.pb.h" @@ -22,6 +21,11 @@ #include "components/variations/variations.mojom.h" #include "components/variations/variations_associated_data.h" +namespace base { +template <typename T> +struct DefaultSingletonTraits; +} + namespace variations { class VariationsClient; @@ -127,7 +131,7 @@ void ResetForTesting(); private: - friend class base::NoDestructor<VariationsIdsProvider>; + friend struct base::DefaultSingletonTraits<VariationsIdsProvider>; typedef std::pair<VariationID, IDCollectionKey> VariationIDEntry;
diff --git a/components/webxr/android/java/src/org/chromium/components/webxr/ArImmersiveOverlay.java b/components/webxr/android/java/src/org/chromium/components/webxr/ArImmersiveOverlay.java index 88e4966b..05a84a8f 100644 --- a/components/webxr/android/java/src/org/chromium/components/webxr/ArImmersiveOverlay.java +++ b/components/webxr/android/java/src/org/chromium/components/webxr/ArImmersiveOverlay.java
@@ -6,15 +6,20 @@ import android.annotation.SuppressLint; import android.app.Activity; +import android.app.Dialog; +import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.PixelFormat; import android.graphics.Point; +import android.os.Build; import android.view.Display; +import android.view.Gravity; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import androidx.annotation.NonNull; @@ -24,6 +29,7 @@ import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.ui.display.DisplayAndroidManager; +import org.chromium.ui.widget.Toast; import java.util.HashMap; import java.util.Map; @@ -42,9 +48,8 @@ private boolean mSurfaceReportedReady; private Integer mRestoreOrientation; private boolean mCleanupInProgress; - private ArSurfaceView mArSurfaceView; + private SurfaceUiWrapper mSurfaceUi; private WebContents mWebContents; - private boolean mUseOverlay; // Set containing all currently touching pointers. private HashMap<Integer, PointerData> mPointerIdToData; @@ -65,11 +70,95 @@ mPointerIdToData = new HashMap<Integer, PointerData>(); mPrimaryPointerId = null; - mUseOverlay = useOverlay; - // Choose a concrete implementation to create a drawable Surface and make it fullscreen. // It forwards SurfaceHolder callbacks and touch events to this ArImmersiveOverlay object. - mArSurfaceView = new ArSurfaceView(canRenderDomContent); + if (useOverlay) { + mSurfaceUi = new SurfaceUiCompositor(canRenderDomContent); + } else { + mSurfaceUi = new SurfaceUiDialog(); + } + } + + private interface SurfaceUiWrapper { + public void onSurfaceVisible(); + public void forwardMotionEvent(MotionEvent ev); + public void destroy(); + } + + // The default Dialog cancellation behavior destroys the Surface before we get notified via the + // Cancelation callback. This is unfortunate, because we need to ensure that the compositor is + // stopped before the surface is destroyed. This class allows us to override the default + // cancellation behavior to properly shutdown the compositor before the surface is destroyed. It + // is unclear why the SurfaceHolder callbacks are not triggered. + private class ArDialog extends Dialog { + public ArDialog(Context context, int themeResId) { + super(context, themeResId); + } + + @Override + public void cancel() { + ArCoreJavaUtils.onBackPressed(); + super.cancel(); + } + } + + private class SurfaceUiDialog implements SurfaceUiWrapper { + private Toast mNotificationToast; + private ArDialog mDialog; + // Android supports multiple variants of fullscreen applications. Use fully-immersive + // "sticky" mode without navigation or status bars, and show a toast with a "pull from top + // and press back button to exit" prompt. + private static final int VISIBILITY_FLAGS_IMMERSIVE = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + + public SurfaceUiDialog() { + // Create a fullscreen dialog and use its backing Surface for drawing. + mDialog = new ArDialog(mActivity, android.R.style.Theme_NoTitleBar_Fullscreen); + mDialog.getWindow().setBackgroundDrawable(null); + mDialog.getWindow().takeSurface(ArImmersiveOverlay.this); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + // Use maximum fullscreen, ignoring a notch if present. This code path is used + // for non-DOM-Overlay mode where the browser compositor view isn't visible. + // In DOM Overlay mode (SurfaceUiCompositor), Blink configures this separately + // via ViewportData::SetExpandIntoDisplayCutout. + mDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + mDialog.getWindow().getAttributes().layoutInDisplayCutoutMode = + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; + } + View view = mDialog.getWindow().getDecorView(); + view.setSystemUiVisibility(VISIBILITY_FLAGS_IMMERSIVE); + view.setOnTouchListener(ArImmersiveOverlay.this); + view.setKeepScreenOn(true); + mDialog.getWindow().setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + mDialog.show(); + } + + @Override // SurfaceUiWrapper + public void onSurfaceVisible() { + if (mNotificationToast != null) { + mNotificationToast.cancel(); + } + int resId = R.string.immersive_fullscreen_api_notification; + mNotificationToast = Toast.makeText(mActivity, resId, Toast.LENGTH_LONG); + mNotificationToast.setGravity(Gravity.TOP | Gravity.CENTER, 0, 0); + mNotificationToast.show(); + } + + @Override // SurfaceUiWrapper + public void forwardMotionEvent(MotionEvent ev) {} + + @Override // SurfaceUiWrapper + public void destroy() { + if (mNotificationToast != null) { + mNotificationToast.cancel(); + mNotificationToast = null; + } + mDialog.dismiss(); + } } private class PointerData { @@ -84,18 +173,17 @@ } } - private class ArSurfaceView { + private class SurfaceUiCompositor implements SurfaceUiWrapper { private SurfaceView mSurfaceView; private WebContentsObserver mWebContentsObserver; private boolean mDomSurfaceNeedsConfiguring; @SuppressLint("ClickableViewAccessibility") - public ArSurfaceView(boolean canRenderDomContent) { - // If we need to show the dom content, but can't render it on top of the camera/gl - // layers manually, then we need to configure the DOM content's surface view to - // overlay ours. We need to track this so that we ensure we teardown everything - // we need to teardown as well. - mDomSurfaceNeedsConfiguring = mUseOverlay && !canRenderDomContent; + public SurfaceUiCompositor(boolean canRenderDomContent) { + // If we can't render the dom content on top of the camera/gl layers manually, then + // we need to configure the DOM content's surface view to overlay ours. We need to + // track this so that we ensure we teardown everything we need to teardown as well. + mDomSurfaceNeedsConfiguring = !canRenderDomContent; // Enable alpha channel for the compositor and make the background transparent. // Note that this needs to happen before we create and parent our SurfaceView, so that @@ -103,10 +191,6 @@ if (DEBUG_LOGS) { Log.i(TAG, "calling mArCompositorDelegate.setOverlayImmersiveArMode(true)"); } - - // While it's fine to omit if the page does not use DOMOverlay, once the page does - // use DOMOverlay, something appears to have changed such that it becomes required, - // otherwies the DOM SurfaceView will be in front of the XR content. mArCompositorDelegate.setOverlayImmersiveArMode(true, mDomSurfaceNeedsConfiguring); mSurfaceView = new SurfaceView(mActivity); @@ -142,6 +226,15 @@ mWebContents.addObserver(mWebContentsObserver); } + @Override // SurfaceUiWrapper + public void onSurfaceVisible() {} + + @Override // SurfaceUiWrapper + public void forwardMotionEvent(MotionEvent ev) { + mArCompositorDelegate.dispatchTouchEvent(ev); + } + + @Override // SurfaceUiWrapper public void destroy() { mWebContents.removeObserver(mWebContentsObserver); View content = mActivity.getWindow().findViewById(android.R.id.content); @@ -307,9 +400,7 @@ // We need to consume the touch (returning true) to ensure that we get // followup events such as MOVE and UP. DOM Overlay mode needs to forward // the touch to the content view so that its UI elements keep working. - if (mUseOverlay) { - mArCompositorDelegate.dispatchTouchEvent(ev); - } + mSurfaceUi.forwardMotionEvent(ev); return true; } @@ -389,7 +480,7 @@ // // While it would be preferable to wait until the surface is at the desired fullscreen // resolution, i.e. via mActivity.getFullscreenManager().getPersistentFullscreenMode(), that - // causes a chicken-and-egg problem for ArSurfaceView mode as used for DOM overlay. + // causes a chicken-and-egg problem for SurfaceUiCompositor mode as used for DOM overlay. // Chrome's fullscreen mode is triggered by the Blink side setting an element fullscreen // after the session starts, but the session doesn't start until we report the drawing // surface being ready (including a configured size), so we use this reported size assuming @@ -414,6 +505,10 @@ mArCoreJavaUtils.onDrawingSurfaceReady(holder.getSurface(), mWebContents.getTopLevelNativeWindow(), rotation, width, height); mSurfaceReportedReady = true; + + // Show the toast with instructions how to exit fullscreen mode now if necessary. + // Not needed in DOM overlay mode which uses FullscreenHtmlApiHandler to do so. + mSurfaceUi.onSurfaceVisible(); } @Override // SurfaceHolder.Callback2 @@ -438,7 +533,7 @@ // the destroy callbacks to ensure consistent state after non-exiting lifecycle events. mArCoreJavaUtils.onDrawingSurfaceDestroyed(); - mArSurfaceView.destroy(); + mSurfaceUi.destroy(); // The JS app may have put an element into fullscreen mode during the immersive session, // even if this wasn't visible to the user. Ensure that we fully exit out of any active
diff --git a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc index 9e4534f0..48d8e16 100644 --- a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc +++ b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
@@ -30,6 +30,7 @@ using device::BluetoothUUID; using UUIDSet = device::BluetoothDevice::UUIDSet; +using ManufacturerDataMap = device::BluetoothDevice::ManufacturerDataMap; using blink::mojom::WebBluetoothResult; namespace { @@ -88,6 +89,10 @@ namespace { +#if DCHECK_IS_ON() +void LogRequestDeviceOptions( + const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) {} +#else void LogRequestDeviceOptions( const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) { DVLOG(1) << "requestDevice called with the following filters: "; @@ -106,17 +111,37 @@ DVLOG(1) << "Name Prefix: " << filter->name_prefix.value(); if (filter->services) { - DVLOG(1) << "Services: "; - DVLOG(1) << "\t["; + base::Value services_list(base::Value::Type::LIST); for (const auto& service : filter->services.value()) - DVLOG(1) << "\t\t" << service.canonical_value(); - DVLOG(1) << "\t]"; + services_list.Append(service.canonical_value()); + DVLOG(1) << "Services: " << services_list; + } + + if (filter->manufacturer_data) { + base::Value manufacturer_data_list(base::Value::Type::LIST); + for (const auto& manufacturer_data : filter->manufacturer_data.value()) { + base::Value filter_data_list(base::Value::Type::LIST); + base::Value filter_mask_list(base::Value::Type::LIST); + for (const auto& data_filter : manufacturer_data.second) { + filter_data_list.Append(base::Value(data_filter->data)); + filter_mask_list.Append(base::Value(data_filter->mask)); + } + base::Value data_filter_dict(base::Value::Type::DICTIONARY); + data_filter_dict.SetKey("Company Identifier", + base::Value(manufacturer_data.first->id)); + data_filter_dict.SetKey("Data", std::move(filter_data_list)); + data_filter_dict.SetKey("Mask", std::move(filter_mask_list)); + manufacturer_data_list.Append(std::move(data_filter_dict)); + } + DVLOG(1) << "Manufacturer Data: " << manufacturer_data_list; } } } +#endif bool MatchesFilter(const std::string* device_name, const UUIDSet& device_uuids, + const ManufacturerDataMap& device_manufacturer_data, const blink::mojom::WebBluetoothLeScanFilterPtr& filter) { if (filter->name) { if (device_name == nullptr) @@ -141,17 +166,41 @@ } } + if (filter->manufacturer_data) { + for (const auto& filter_data : filter->manufacturer_data.value()) { + // Check the company identifier. + auto it = device_manufacturer_data.find(filter_data.first->id); + if (it == device_manufacturer_data.end()) + return false; + // Check data filter size is less than device manufacturer data size. + const auto& device_data = it->second; + if (filter_data.second.size() > device_data.size()) + return false; + // For each bit in mask, check the corresponding bit in device + // manufacturer data is equal to the corresponding bit in expected data. + size_t i = 0; + for (const auto& filter_byte : filter_data.second) { + if ((filter_byte->mask & filter_byte->data) != + (filter_byte->mask & device_data.at(i++))) { + return false; + } + } + } + } + return true; } bool MatchesFilters( const std::string* device_name, const UUIDSet& device_uuids, + const ManufacturerDataMap& device_manufacturer_data, const base::Optional< std::vector<blink::mojom::WebBluetoothLeScanFilterPtr>>& filters) { DCHECK(HasValidFilter(filters)); for (const auto& filter : filters.value()) { - if (MatchesFilter(device_name, device_uuids, filter)) { + if (MatchesFilter(device_name, device_uuids, device_manufacturer_data, + filter)) { return true; } } @@ -292,7 +341,8 @@ if (chooser_.get()) { if (options_->accept_all_devices || MatchesFilters(device_name ? &device_name.value() : nullptr, - device.GetUUIDs(), options_->filters)) { + device.GetUUIDs(), device.GetManufacturerData(), + options_->filters)) { base::Optional<int8_t> rssi = device.GetInquiryRSSI(); std::string device_id = device.GetAddress(); device_ids_.insert(device_id);
diff --git a/content/browser/bluetooth/bluetooth_util.cc b/content/browser/bluetooth/bluetooth_util.cc index ce002db..4f768c4 100644 --- a/content/browser/bluetooth/bluetooth_util.cc +++ b/content/browser/bluetooth/bluetooth_util.cc
@@ -39,6 +39,9 @@ return false; } + if (filter_1.manufacturer_data != filter_2.manufacturer_data) + return false; + return true; }
diff --git a/content/browser/bluetooth/bluetooth_util_unittest.cc b/content/browser/bluetooth/bluetooth_util_unittest.cc index 8f686860..7545c8a8 100644 --- a/content/browser/bluetooth/bluetooth_util_unittest.cc +++ b/content/browser/bluetooth/bluetooth_util_unittest.cc
@@ -7,6 +7,10 @@ #include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" +using WebBluetoothManufacturerDataMap = + base::flat_map<blink::mojom::WebBluetoothCompanyPtr, + std::vector<blink::mojom::WebBluetoothDataFilterPtr>>; + namespace content { namespace { @@ -14,6 +18,20 @@ const char kBatteryServiceUUIDString[] = "0000180f-0000-1000-8000-00805f9b34fb"; const char kCyclingPowerUUIDString[] = "00001818-0000-1000-8000-00805f9b34fb"; +std::vector<blink::mojom::WebBluetoothDataFilterPtr> CreateDataFilters( + std::vector<uint8_t> filter_data, + std::vector<uint8_t> filter_mask) { + EXPECT_EQ(filter_data.size(), filter_mask.size()); + std::vector<blink::mojom::WebBluetoothDataFilterPtr> data_filters; + for (size_t i = 0; i < filter_data.size(); ++i) { + auto data_filter = blink::mojom::WebBluetoothDataFilter::New(); + data_filter->data = filter_data[i]; + data_filter->mask = filter_mask[i]; + data_filters.push_back(std::move(data_filter)); + } + return data_filters; +} + } // namespace class BluetoothUtilTest : public testing::Test { @@ -29,10 +47,22 @@ base::Optional<std::vector<device::BluetoothUUID>> services; services.emplace(); services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); - auto filter_1 = - blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", "a"); - auto filter_2 = - blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", "a"); + + std::vector<uint8_t> filter_data = {0x01, 0x02, 0x03, 0x04}; + std::vector<uint8_t> filter_mask = {0xff, 0xff, 0xff, 0xff}; + + WebBluetoothManufacturerDataMap manufacturer_data_1; + manufacturer_data_1.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters(filter_data, filter_mask)}); + + WebBluetoothManufacturerDataMap manufacturer_data_2; + manufacturer_data_2.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters(filter_data, filter_mask)}); + + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_1)); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_2)); EXPECT_TRUE(AreScanFiltersSame(*filter_1, *filter_2)); } @@ -40,10 +70,12 @@ base::Optional<std::vector<device::BluetoothUUID>> services; services.emplace(); services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); - auto filter_1 = - blink::mojom::WebBluetoothLeScanFilter::New(services, base::nullopt, "a"); - auto filter_2 = - blink::mojom::WebBluetoothLeScanFilter::New(services, base::nullopt, "a"); + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, /*name=*/base::nullopt, "a", + /*manufacturer_data=*/base::nullopt); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, /*name=*/base::nullopt, "a", + /*manufacturer_data=*/base::nullopt); EXPECT_TRUE(AreScanFiltersSame(*filter_1, *filter_2)); } @@ -51,10 +83,11 @@ base::Optional<std::vector<device::BluetoothUUID>> services; services.emplace(); services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); - auto filter_1 = - blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", "a"); - auto filter_2 = - blink::mojom::WebBluetoothLeScanFilter::New(services, base::nullopt, "a"); + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", /*manufacturer_data=*/base::nullopt); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, /*name=*/base::nullopt, "a", + /*manufacturer_data=*/base::nullopt); EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); } @@ -62,10 +95,10 @@ base::Optional<std::vector<device::BluetoothUUID>> services; services.emplace(); services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); - auto filter_1 = - blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", "a"); - auto filter_2 = - blink::mojom::WebBluetoothLeScanFilter::New(services, "cd", "a"); + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", /*manufacturer_data=*/base::nullopt); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "cd", "a", /*manufacturer_data=*/base::nullopt); EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); } @@ -73,10 +106,12 @@ base::Optional<std::vector<device::BluetoothUUID>> services; services.emplace(); services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); - auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", - base::nullopt); - auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", - base::nullopt); + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", /*name_prefix=*/base::nullopt, + /*manufacturer_data=*/base::nullopt); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", /*name_prefix=*/base::nullopt, + /*manufacturer_data=*/base::nullopt); EXPECT_TRUE(AreScanFiltersSame(*filter_1, *filter_2)); } @@ -84,10 +119,11 @@ base::Optional<std::vector<device::BluetoothUUID>> services; services.emplace(); services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); - auto filter_1 = - blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", "a"); - auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", - base::nullopt); + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", /*manufacturer_data=*/base::nullopt); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", /*name_prefix=*/base::nullopt, + /*manufacturer_data=*/base::nullopt); EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); } @@ -95,18 +131,20 @@ base::Optional<std::vector<device::BluetoothUUID>> services; services.emplace(); services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); - auto filter_1 = - blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", "a"); - auto filter_2 = - blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", "ab"); + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", /*manufacturer_data=*/base::nullopt); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "ab", /*manufacturer_data=*/base::nullopt); EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); } TEST_F(BluetoothUtilTest, BothNoServicesUUID) { - auto filter_1 = - blink::mojom::WebBluetoothLeScanFilter::New(base::nullopt, "ab", "a"); - auto filter_2 = - blink::mojom::WebBluetoothLeScanFilter::New(base::nullopt, "ab", "a"); + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + /*services=*/base::nullopt, "ab", "a", + /*manufacturer_data=*/base::nullopt); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + /*services=*/base::nullopt, "ab", "a", + /*manufacturer_data=*/base::nullopt); EXPECT_TRUE(AreScanFiltersSame(*filter_1, *filter_2)); } @@ -114,10 +152,11 @@ base::Optional<std::vector<device::BluetoothUUID>> services; services.emplace(); services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); - auto filter_1 = - blink::mojom::WebBluetoothLeScanFilter::New(services, "ab", "a"); - auto filter_2 = - blink::mojom::WebBluetoothLeScanFilter::New(base::nullopt, "ab", "ab"); + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", /*manufacturer_data=*/base::nullopt); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + /*services=*/base::nullopt, "ab", "ab", + /*manufacturer_data=*/base::nullopt); EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); } @@ -125,14 +164,14 @@ base::Optional<std::vector<device::BluetoothUUID>> services_1; services_1.emplace(); services_1->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); - auto filter_1 = - blink::mojom::WebBluetoothLeScanFilter::New(services_1, "ab", "a"); + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services_1, "ab", "a", /*manufacturer_data=*/base::nullopt); base::Optional<std::vector<device::BluetoothUUID>> services_2; services_2.emplace(); services_2->push_back(device::BluetoothUUID(kCyclingPowerUUIDString)); - auto filter_2 = - blink::mojom::WebBluetoothLeScanFilter::New(services_2, "ab", "a"); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services_2, "ab", "a", /*manufacturer_data=*/base::nullopt); EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); } @@ -142,17 +181,160 @@ services_1.emplace(); services_1->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); services_1->push_back(device::BluetoothUUID(kCyclingPowerUUIDString)); - auto filter_1 = - blink::mojom::WebBluetoothLeScanFilter::New(services_1, "ab", "a"); + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services_1, "ab", "a", /*manufacturer_data=*/base::nullopt); base::Optional<std::vector<device::BluetoothUUID>> services_2; services_2.emplace(); - services_2->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); services_2->push_back(device::BluetoothUUID(kCyclingPowerUUIDString)); - auto filter_2 = - blink::mojom::WebBluetoothLeScanFilter::New(services_2, "ab", "a"); + services_2->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services_2, "ab", "a", /*manufacturer_data=*/base::nullopt); EXPECT_TRUE(AreScanFiltersSame(*filter_1, *filter_2)); } +TEST_F(BluetoothUtilTest, BothNoManufacturerData) { + base::Optional<std::vector<device::BluetoothUUID>> services; + services.emplace(); + services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); + + WebBluetoothManufacturerDataMap manufacturer_data_1; + WebBluetoothManufacturerDataMap manufacturer_data_2; + + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_1)); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_2)); + EXPECT_TRUE(AreScanFiltersSame(*filter_1, *filter_2)); +} + +TEST_F(BluetoothUtilTest, OnlyOneHasManufacturerData) { + base::Optional<std::vector<device::BluetoothUUID>> services; + services.emplace(); + services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); + + WebBluetoothManufacturerDataMap manufacturer_data; + + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data)); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", /*manufacturer_data=*/base::nullopt); + EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); +} + +TEST_F(BluetoothUtilTest, DifferentManufacturerDataSize) { + base::Optional<std::vector<device::BluetoothUUID>> services; + services.emplace(); + services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); + + WebBluetoothManufacturerDataMap manufacturer_data_1; + manufacturer_data_1.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters({}, {})}); + + WebBluetoothManufacturerDataMap manufacturer_data_2; + manufacturer_data_2.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters({}, {})}); + manufacturer_data_2.insert({blink::mojom::WebBluetoothCompany::New(0x0002), + CreateDataFilters({}, {})}); + + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_1)); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_2)); + EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); +} + +TEST_F(BluetoothUtilTest, DifferentManufacturerDataCompanyIdentifier) { + base::Optional<std::vector<device::BluetoothUUID>> services; + services.emplace(); + services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); + + WebBluetoothManufacturerDataMap manufacturer_data_1; + manufacturer_data_1.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters({}, {})}); + + WebBluetoothManufacturerDataMap manufacturer_data_2; + manufacturer_data_2.insert({blink::mojom::WebBluetoothCompany::New(0x0002), + CreateDataFilters({}, {})}); + + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_1)); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_2)); + EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); +} + +TEST_F(BluetoothUtilTest, DifferentManufacturerDataFilterSize) { + base::Optional<std::vector<device::BluetoothUUID>> services; + services.emplace(); + services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); + + WebBluetoothManufacturerDataMap manufacturer_data_1; + std::vector<uint8_t> filter_data_1 = {0x01}; + std::vector<uint8_t> filter_mask_1 = {0xff}; + manufacturer_data_1.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters(filter_data_1, filter_mask_1)}); + + WebBluetoothManufacturerDataMap manufacturer_data_2; + std::vector<uint8_t> filter_data_2 = {0x01, 0x02}; + std::vector<uint8_t> filter_mask_2 = {0xff, 0xff}; + manufacturer_data_2.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters(filter_data_2, filter_mask_2)}); + + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_1)); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_2)); + EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); +} + +TEST_F(BluetoothUtilTest, DifferentManufacturerData) { + base::Optional<std::vector<device::BluetoothUUID>> services; + services.emplace(); + services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); + + std::vector<uint8_t> filter_mask = {0xff, 0xff, 0xff, 0xff}; + + WebBluetoothManufacturerDataMap manufacturer_data_1; + std::vector<uint8_t> filter_data_1 = {0x01, 0x02, 0x03, 0x04}; + manufacturer_data_1.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters(filter_data_1, filter_mask)}); + + WebBluetoothManufacturerDataMap manufacturer_data_2; + std::vector<uint8_t> filter_data_2 = {0x05, 0x06, 0x07, 0x08}; + manufacturer_data_2.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters(filter_data_2, filter_mask)}); + + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_1)); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_2)); + EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); +} + +TEST_F(BluetoothUtilTest, DifferentManufacturerDataMask) { + base::Optional<std::vector<device::BluetoothUUID>> services; + services.emplace(); + services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); + + std::vector<uint8_t> filter_data = {0x01, 0x02, 0x03, 0x04}; + + WebBluetoothManufacturerDataMap manufacturer_data_1; + std::vector<uint8_t> filter_mask_1 = {0xff, 0xff, 0xff, 0xff}; + manufacturer_data_1.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters(filter_data, filter_mask_1)}); + + WebBluetoothManufacturerDataMap manufacturer_data_2; + std::vector<uint8_t> filter_mask_2 = {0xff, 0xff, 0xff, 0x00}; + manufacturer_data_2.insert({blink::mojom::WebBluetoothCompany::New(0x0001), + CreateDataFilters(filter_data, filter_mask_2)}); + + auto filter_1 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_1)); + auto filter_2 = blink::mojom::WebBluetoothLeScanFilter::New( + services, "ab", "a", std::move(manufacturer_data_2)); + EXPECT_FALSE(AreScanFiltersSame(*filter_1, *filter_2)); +} + } // namespace content
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.cc b/content/browser/bluetooth/web_bluetooth_service_impl.cc index ef657ad3..dba28aae 100644 --- a/content/browser/bluetooth/web_bluetooth_service_impl.cc +++ b/content/browser/bluetooth/web_bluetooth_service_impl.cc
@@ -128,7 +128,13 @@ bool IsValidFilter(const blink::mojom::WebBluetoothLeScanFilterPtr& filter) { // At least one member needs to be present. - if (!filter->name && !filter->name_prefix && !filter->services) + if (!filter->name && !filter->name_prefix && !filter->services && + !filter->manufacturer_data) { + return false; + } + + // The |services| should not be empty. + if (filter->services && filter->services->empty()) return false; // The renderer will never send a |name| or a |name_prefix| longer than @@ -140,10 +146,14 @@ filter->name_prefix->size() > kMaxLengthForDeviceName) return false; - // The |name_prefix| should not be empty + // The |name_prefix| should not be empty. if (filter->name_prefix && filter->name_prefix->empty()) return false; + // The |manufacturer_data| should not be empty. + if (filter->manufacturer_data && filter->manufacturer_data->empty()) + return false; + return true; }
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc b/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc index f002398a..5ca9d40 100644 --- a/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc +++ b/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc
@@ -259,8 +259,8 @@ base::Optional<std::vector<device::BluetoothUUID>> services; services.emplace(); services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString)); - return blink::mojom::WebBluetoothLeScanFilter::New(services, name, - name_prefix); + return blink::mojom::WebBluetoothLeScanFilter::New( + services, name, name_prefix, /*manufacturer_data=*/base::nullopt); } blink::mojom::WebBluetoothResult RequestScanningStartAndSimulatePromptEvent( @@ -272,7 +272,9 @@ client_impl->BindReceiver(client.InitWithNewEndpointAndPassReceiver()); auto options = blink::mojom::WebBluetoothRequestLEScanOptions::New(); options->filters.emplace(); - auto filter_ptr = blink::mojom::WebBluetoothLeScanFilter::New(filter); + auto filter_ptr = blink::mojom::WebBluetoothLeScanFilter::New( + filter.services, filter.name, filter.name_prefix, + /*manufacturer_data=*/base::nullopt); options->filters->push_back(std::move(filter_ptr)); // Use two RunLoops to guarantee the order of operations for this test. @@ -351,8 +353,7 @@ auto options = blink::mojom::WebBluetoothRequestLEScanOptions::New(); options->filters.emplace(); - auto filter_ptr = blink::mojom::WebBluetoothLeScanFilter::New(*filter); - options->filters->push_back(std::move(filter_ptr)); + options->filters->push_back(std::move(filter)); // Use two RunLoops to guarantee the order of operations for this test. // |callback_loop| guarantees that RequestScanningStartCallback has finished
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index eaf7363a..db9fd6f 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -1168,7 +1168,7 @@ HistogramSynchronizer::GetInstance(); - FieldTrialSynchronizer::CreateInstance(); + field_trial_synchronizer_ = base::MakeRefCounted<FieldTrialSynchronizer>(); // cc assumes a single client name for metrics in a process, which is // is inconsistent with single process mode where both the renderer and
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h index e116a3d..69b0916 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h
@@ -91,6 +91,7 @@ class BrowserMainParts; class BrowserOnlineStateObserver; class BrowserThreadImpl; +class FieldTrialSynchronizer; class MediaKeysListenerManagerImpl; class MediaStreamManager; class SaveFileManager; @@ -350,6 +351,12 @@ std::unique_ptr<mojo::core::ScopedIPCSupport> mojo_ipc_support_; std::unique_ptr<MediaKeysListenerManagerImpl> media_keys_listener_manager_; + // The FieldTrialSynchronizer tells child processes when a trial gets + // activated. This is mostly an optimization, as a consequence if renderers + // know a trial is already active they don't need to send anything to the + // browser. + scoped_refptr<FieldTrialSynchronizer> field_trial_synchronizer_; + // |user_input_monitor_| has to outlive |audio_manager_|, so declared first. std::unique_ptr<media::UserInputMonitor> user_input_monitor_;
diff --git a/content/browser/field_trial_synchronizer.cc b/content/browser/field_trial_synchronizer.cc index 0af9ed30..98643ff5 100644 --- a/content/browser/field_trial_synchronizer.cc +++ b/content/browser/field_trial_synchronizer.cc
@@ -20,20 +20,33 @@ namespace { -FieldTrialSynchronizer* g_instance = nullptr; - -// Notifies all renderer processes about the |group_name| that is finalized for -// the given field trail (|field_trial_name|). This is called on UI thread. -void NotifyAllRenderersOfFieldTrial(const std::string& field_trial_name, - const std::string& group_name) { - // To iterate over RenderProcessHosts, or to send messages to the hosts, we - // need to be on the UI thread. - DCHECK_CURRENTLY_ON(BrowserThread::UI); - +void AddFieldTrialToPersistentSystemProfile(const std::string& field_trial_name, + const std::string& group_name) { // Note this in the persistent profile as it will take a while for a new // "complete" profile to be generated. metrics::GlobalPersistentSystemProfile::GetInstance()->AddFieldTrial( field_trial_name, group_name); +} + +} // namespace + +FieldTrialSynchronizer::FieldTrialSynchronizer() { + bool success = base::FieldTrialList::AddObserver(this); + // Ensure the observer was actually registered. + DCHECK(success); + + variations::VariationsIdsProvider::GetInstance()->AddObserver(this); + NotifyAllRenderersOfVariationsHeader(); +} + +void FieldTrialSynchronizer::NotifyAllRenderersOfFieldTrial( + const std::string& field_trial_name, + const std::string& group_name) { + // To iterate over RenderProcessHosts, or to send messages to the hosts, we + // need to be on the UI thread. + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + AddFieldTrialToPersistentSystemProfile(field_trial_name, group_name); for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); !it.IsAtEnd(); it.Advance()) { @@ -50,30 +63,23 @@ } } -} // namespace - -// static -void FieldTrialSynchronizer::CreateInstance() { - // Only 1 instance is allowed per process. - DCHECK(!g_instance); - g_instance = new FieldTrialSynchronizer(); -} - -FieldTrialSynchronizer::FieldTrialSynchronizer() { - bool success = base::FieldTrialList::AddObserver(this); - // Ensure the observer was actually registered. - DCHECK(success); - - variations::VariationsIdsProvider::GetInstance()->AddObserver(this); - NotifyAllRenderersOfVariationsHeader(); -} - void FieldTrialSynchronizer::OnFieldTrialGroupFinalized( const std::string& field_trial_name, const std::string& group_name) { - RunOrPostTaskOnThread(FROM_HERE, BrowserThread::UI, - base::BindOnce(&NotifyAllRenderersOfFieldTrial, - field_trial_name, group_name)); + // The FieldTrialSynchronizer may have been created before any BrowserThread + // is created, so we don't need to synchronize with child processes in which + // case there are no child processes to notify yet. But we want to update the + // persistent system profile, thus the histogram data recorded in the reduced + // mode will be tagged to its corresponding field trial experiment. + if (!BrowserThread::IsThreadInitialized(BrowserThread::UI)) { + AddFieldTrialToPersistentSystemProfile(field_trial_name, group_name); + return; + } + + RunOrPostTaskOnThread( + FROM_HERE, BrowserThread::UI, + base::BindOnce(&FieldTrialSynchronizer::NotifyAllRenderersOfFieldTrial, + this, field_trial_name, group_name)); } // static @@ -122,7 +128,8 @@ } FieldTrialSynchronizer::~FieldTrialSynchronizer() { - NOTREACHED(); + base::FieldTrialList::RemoveObserver(this); + variations::VariationsIdsProvider::GetInstance()->RemoveObserver(this); } } // namespace content
diff --git a/content/browser/field_trial_synchronizer.h b/content/browser/field_trial_synchronizer.h index 47c8264..9a6bd7c5 100644 --- a/content/browser/field_trial_synchronizer.h +++ b/content/browser/field_trial_synchronizer.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/metrics/field_trial.h" #include "components/variations/variations_ids_provider.h" @@ -20,24 +21,26 @@ // renderers. // // This class registers itself as an observer of FieldTrialList. FieldTrialList -// notifies this class by calling its OnFieldTrialGroupFinalized method when a +// notifies this class by calling it's OnFieldTrialGroupFinalized method when a // group is selected (finalized) for a FieldTrial and OnFieldTrialGroupFinalized // method sends the FieldTrial's name and the group to all renderer processes. // Each renderer process creates the FieldTrial, and by using a 100% probability -// for the FieldTrial, forces the FieldTrial to have the same group string. This -// is mostly an optimization so that renderers don't send anything to the -// browser when they know that a trial is already active. -// -// This class also registers itself as a VariationsIdsProvider Observer and -// updates the renderers if the variations header changes. +// for the FieldTrial, forces the FieldTrial to have the same group string. +// This class also registers itself as a VariationsIdsProvider Observer +// and updates the renderers if the variations header changes. + class FieldTrialSynchronizer - : public base::FieldTrialList::Observer, + : public base::RefCountedThreadSafe<FieldTrialSynchronizer>, + public base::FieldTrialList::Observer, public variations::VariationsIdsProvider::Observer { public: - // Creates the global FieldTrialSynchronizer instance for this process. After - // this is invoked, renderers are notified whenever a field trial group is - // finalized. - static void CreateInstance(); + // Construction also sets up the global singleton instance. This instance is + // used to communicate between the UI and other threads, and is destroyed only + // as the main thread (browser_main) terminates, which means all other threads + // have completed, and will not need this instance any further. It adds itself + // as an observer of FieldTrialList so that it gets notified whenever a group + // is finalized in the browser process. + FieldTrialSynchronizer(); // FieldTrialList::Observer methods: @@ -55,11 +58,16 @@ static void UpdateRendererVariationsHeader(RenderProcessHost* host); private: - FieldTrialSynchronizer(); - ~FieldTrialSynchronizer() override; + // Notify all renderer processes about the |group_name| that is finalized for + // the given field trail (|field_trial_name|). This is called on UI thread. + void NotifyAllRenderersOfFieldTrial(const std::string& field_trial_name, + const std::string& group_name); static void NotifyAllRenderersOfVariationsHeader(); + friend class base::RefCountedThreadSafe<FieldTrialSynchronizer>; + ~FieldTrialSynchronizer() override; + DISALLOW_COPY_AND_ASSIGN(FieldTrialSynchronizer); };
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc index 0769c21e..0258315 100644 --- a/content/browser/webid/federated_auth_request_impl_unittest.cc +++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -42,6 +42,7 @@ namespace { +constexpr char kRpTestOrigin[] = "https://rp.example"; constexpr char kIdpTestOrigin[] = "https://idp.example"; constexpr char kIdpEndpoint[] = "https://idp.example/webid"; constexpr char kAccountsEndpoint[] = "https://idp.example/accounts"; @@ -362,8 +363,8 @@ auth_request_impl_ = std::make_unique<FederatedAuthRequestImpl>( main_rfh(), request_remote_.BindNewPipeAndPassReceiver()); mock_request_manager_ = - std::make_unique<NiceMock<MockIdpNetworkRequestManager>>(provider, - main_rfh()); + std::make_unique<NiceMock<MockIdpNetworkRequestManager>>( + provider, url::Origin::Create(GURL(kRpTestOrigin))); mock_dialog_controller_ = std::make_unique<NiceMock<MockIdentityRequestDialogController>>();
diff --git a/content/browser/webid/idp_network_request_manager.cc b/content/browser/webid/idp_network_request_manager.cc index 00634e5d..884792bec 100644 --- a/content/browser/webid/idp_network_request_manager.cc +++ b/content/browser/webid/idp_network_request_manager.cc
@@ -79,11 +79,6 @@ })"); } -scoped_refptr<network::SharedURLLoaderFactory> GetUrlLoaderFactory( - content::RenderFrameHost* host) { - return host->GetStoragePartition()->GetURLLoaderFactoryForBrowserProcess(); -} - std::unique_ptr<network::ResourceRequest> CreateCredentialedResourceRequest( GURL target_url, url::Origin initiator) { @@ -123,6 +118,24 @@ picture ? *picture : ""); } +// Parses accounts from given Value. Returns true if parse is successful and +// adds parsed accounts to the |account_list|. +bool ParseAccounts(const base::Value* accounts, + IdpNetworkRequestManager::AccountList& account_list) { + if (!accounts->is_list()) + return false; + + for (auto& account : accounts->GetList()) { + if (!account.is_dict()) + return false; + + auto parsed_account = ParseAccount(account); + if (parsed_account) + account_list.push_back(parsed_account.value()); + } + return true; +} + } // namespace // static @@ -136,12 +149,20 @@ if (!network::IsOriginPotentiallyTrustworthy(url::Origin::Create(provider))) return nullptr; - return std::make_unique<IdpNetworkRequestManager>(provider, host); + // Use the browser process URL loader factory because it has cross-origin + // read blocking disabled. + return std::make_unique<IdpNetworkRequestManager>( + provider, host->GetLastCommittedOrigin(), + host->GetStoragePartition()->GetURLLoaderFactoryForBrowserProcess()); } -IdpNetworkRequestManager::IdpNetworkRequestManager(const GURL& provider, - RenderFrameHost* host) - : provider_(provider), render_frame_host_(host) {} +IdpNetworkRequestManager::IdpNetworkRequestManager( + const GURL& provider, + const url::Origin& relying_party_origin, + scoped_refptr<network::SharedURLLoaderFactory> loader_factory) + : provider_(provider), + relying_party_origin_(relying_party_origin), + loader_factory_(loader_factory) {} IdpNetworkRequestManager::~IdpNetworkRequestManager() = default; @@ -174,8 +195,7 @@ // this bypasses CORB. Ensure there is a test added. // https://crbug.com/1155312. resource_request->redirect_mode = network::mojom::RedirectMode::kError; - resource_request->request_initiator = - render_frame_host_->GetLastCommittedOrigin(); + resource_request->request_initiator = relying_party_origin_; resource_request->trusted_params = network::ResourceRequest::TrustedParams(); resource_request->trusted_params->isolation_info = net::IsolationInfo::Create(net::IsolationInfo::RequestType::kOther, @@ -184,12 +204,8 @@ url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), traffic_annotation); - // Use the browser process URL loader factory because it has cross-origin - // read blocking disabled. - auto loader_factory = GetUrlLoaderFactory(render_frame_host_); - url_loader_->DownloadToString( - loader_factory.get(), + loader_factory_.get(), base::BindOnce(&IdpNetworkRequestManager::OnWellKnownLoaded, weak_ptr_factory_.GetWeakPtr()), maxResponseSizeInKiB * 1024); @@ -214,17 +230,14 @@ // TODO: Should this be a POST, rather than a GET using query parameters? // https://crbug.com/1141125. GURL target_url = GURL(signin_url.spec() + "?" + encoded_request); - auto resource_request = CreateCredentialedResourceRequest( - target_url, render_frame_host_->GetLastCommittedOrigin()); + auto resource_request = + CreateCredentialedResourceRequest(target_url, relying_party_origin_); auto traffic_annotation = CreateTrafficAnnotation(); // TODO(kenrb): Make this not send cookies. https://crbug.com/1141125. url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), traffic_annotation); - - auto loader_factory = GetUrlLoaderFactory(render_frame_host_); - url_loader_->DownloadToString( - loader_factory.get(), + loader_factory_.get(), base::BindOnce(&IdpNetworkRequestManager::OnSigninRequestResponse, weak_ptr_factory_.GetWeakPtr()), maxResponseSizeInKiB * 1024); @@ -237,8 +250,8 @@ DCHECK(!accounts_request_callback_); accounts_request_callback_ = std::move(callback); - auto resource_request = CreateCredentialedResourceRequest( - accounts_url, render_frame_host_->GetLastCommittedOrigin()); + auto resource_request = + CreateCredentialedResourceRequest(accounts_url, relying_party_origin_); // Use ReferrerPolicy::NO_REFERRER for this request so that relying party // identity is not exposed to the Identity provider via referror. resource_request->referrer_policy = net::ReferrerPolicy::NO_REFERRER; @@ -247,10 +260,8 @@ url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), traffic_annotation); - auto loader_factory = GetUrlLoaderFactory(render_frame_host_); - url_loader_->DownloadToString( - loader_factory.get(), + loader_factory_.get(), base::BindOnce(&IdpNetworkRequestManager::OnAccountsRequestResponse, weak_ptr_factory_.GetWeakPtr()), maxResponseSizeInKiB * 1024); @@ -295,8 +306,8 @@ return; } - auto resource_request = CreateCredentialedResourceRequest( - token_url, render_frame_host_->GetLastCommittedOrigin()); + auto resource_request = + CreateCredentialedResourceRequest(token_url, relying_party_origin_); resource_request->method = net::HttpRequestHeaders::kPostMethod; resource_request->headers.SetHeader(net::HttpRequestHeaders::kContentType, kJSONMimeType); @@ -307,10 +318,8 @@ traffic_annotation); url_loader_->AttachStringForUpload(token_request_body, kJSONMimeType); - auto loader_factory = GetUrlLoaderFactory(render_frame_host_); - url_loader_->DownloadToString( - loader_factory.get(), + loader_factory_.get(), base::BindOnce(&IdpNetworkRequestManager::OnTokenRequestResponse, weak_ptr_factory_.GetWeakPtr()), maxResponseSizeInKiB * 1024); @@ -325,8 +334,8 @@ logout_callback_ = std::move(callback); - auto resource_request = CreateCredentialedResourceRequest( - logout_url, render_frame_host_->GetLastCommittedOrigin()); + auto resource_request = + CreateCredentialedResourceRequest(logout_url, relying_party_origin_); resource_request->headers.SetHeader(net::HttpRequestHeaders::kAccept, "*/*"); auto traffic_annotation = CreateTrafficAnnotation(); @@ -334,33 +343,13 @@ url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), traffic_annotation); - auto loader_factory = GetUrlLoaderFactory(render_frame_host_); - url_loader_->DownloadToString( - loader_factory.get(), + loader_factory_.get(), base::BindOnce(&IdpNetworkRequestManager::OnLogoutCompleted, weak_ptr_factory_.GetWeakPtr()), maxResponseSizeInKiB * 1024); } -// static -bool IdpNetworkRequestManager::ParseAccounts( - const base::Value* accounts, - IdpNetworkRequestManager::AccountList& account_list) { - if (!accounts->is_list()) - return false; - - for (auto& account : accounts->GetList()) { - if (!account.is_dict()) - return false; - - auto parsed_account = ParseAccount(account); - if (parsed_account) - account_list.push_back(parsed_account.value()); - } - return true; -} - void IdpNetworkRequestManager::OnWellKnownLoaded( std::unique_ptr<std::string> response_body) { int response_code = -1;
diff --git a/content/browser/webid/idp_network_request_manager.h b/content/browser/webid/idp_network_request_manager.h index a90c741a..61c0cdb1e6 100644 --- a/content/browser/webid/idp_network_request_manager.h +++ b/content/browser/webid/idp_network_request_manager.h
@@ -13,7 +13,9 @@ #include "content/common/content_export.h" #include "content/public/browser/identity_request_dialog_controller.h" #include "services/data_decoder/public/cpp/data_decoder.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "url/gurl.h" +#include "url/origin.h" namespace network { class SimpleURLLoader; @@ -108,7 +110,10 @@ const GURL& provider, RenderFrameHost* host); - IdpNetworkRequestManager(const GURL& provider, RenderFrameHost* host); + IdpNetworkRequestManager( + const GURL& provider, + const url::Origin& relying_party, + scoped_refptr<network::SharedURLLoaderFactory> loader_factory); virtual ~IdpNetworkRequestManager(); @@ -136,15 +141,6 @@ // Send logout request to a single target. virtual void SendLogout(const GURL& logout_url, LogoutCallback); - // Parses accounts from given Value. Returns true if parse is successful and - // adds parsed accounts to the |account_list|. - // TODO(majidvp): Make this function private and update tests to test the - // actual public interface of this class rather than its implementation - // details such as this. - static bool ParseAccounts( - const base::Value* accounts, - IdpNetworkRequestManager::AccountList& account_list); - private: void OnWellKnownLoaded(std::unique_ptr<std::string> response_body); void OnWellKnownParsed(data_decoder::DataDecoder::ValueOrError result); @@ -159,7 +155,9 @@ // URL of the Identity Provider. GURL provider_; - RenderFrameHost* render_frame_host_; + url::Origin relying_party_origin_; + + scoped_refptr<network::SharedURLLoaderFactory> loader_factory_; FetchWellKnownCallback idp_well_known_callback_; SigninRequestCallback signin_request_callback_;
diff --git a/content/browser/webid/idp_network_request_manager_unittest.cc b/content/browser/webid/idp_network_request_manager_unittest.cc index f17082d..0274e52 100644 --- a/content/browser/webid/idp_network_request_manager_unittest.cc +++ b/content/browser/webid/idp_network_request_manager_unittest.cc
@@ -6,135 +6,256 @@ #include <array> #include <string> +#include <tuple> +#include "base/strings/stringprintf.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" #include "base/values.h" +#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" using AccountList = content::IdpNetworkRequestManager::AccountList; +using AccountsResponse = content::IdpNetworkRequestManager::AccountsResponse; +using AccountsRequestCallback = + content::IdpNetworkRequestManager::AccountsRequestCallback; namespace content { namespace { -base::Value CreateTestAccount(const std::string& sub) { - base::Value::DictStorage storage; - storage.emplace("sub", sub); - storage.emplace("email", "email@idp.test"); - storage.emplace("name", "Ken R. Example"); - storage.emplace("given_name", "Ken"); - storage.emplace("picture", "https://idp.test/profile"); +const char kTestIdpUrl[] = "https://idp.test"; +const char kTestRpUrl[] = "https://rp.test"; +const char kTestAccountsEndpoint[] = "https://idp.test/accounts_endpoint"; - return base::Value(storage); -} +class IdpNetworkRequestManagerTest : public ::testing::Test { + public: + void SetUp() override { + manager_ = std::make_unique<IdpNetworkRequestManager>( + GURL(kTestIdpUrl), url::Origin::Create(GURL(kTestRpUrl)), + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_)); + } -TEST(AccountsParseTest, EmptyAccounts) { - base::ListValue empty_list; - AccountList parsed_accounts; - EXPECT_TRUE( - IdpNetworkRequestManager::ParseAccounts(&empty_list, parsed_accounts)); - EXPECT_TRUE(parsed_accounts.empty()); -} + void TearDown() override { manager_.reset(); } -TEST(AccountsParseTest, SingleAccount) { - base::Value::ListStorage accounts; - accounts.emplace_back(CreateTestAccount("1234")); - base::Value single_account_value(accounts); - AccountList parsed_accounts; - EXPECT_TRUE(IdpNetworkRequestManager::ParseAccounts(&single_account_value, - parsed_accounts)); - EXPECT_EQ(1UL, parsed_accounts.size()); - EXPECT_EQ("1234", parsed_accounts[0].sub); -} + std::tuple<AccountsResponse, AccountList> + SendAccountsRequestAndWaitForResponse(const char* test_accounts) { + GURL accounts_endpoint(kTestAccountsEndpoint); + test_url_loader_factory().AddResponse(accounts_endpoint.spec(), + test_accounts); -TEST(AccountsParseTest, MultipleAccounts) { - base::Value::ListStorage accounts; - accounts.emplace_back(CreateTestAccount("1234")); - accounts.emplace_back(CreateTestAccount("5678")); - base::Value single_account_value(accounts); - AccountList parsed_accounts; - EXPECT_TRUE(IdpNetworkRequestManager::ParseAccounts(&single_account_value, - parsed_accounts)); - EXPECT_EQ(2UL, parsed_accounts.size()); - EXPECT_EQ("1234", parsed_accounts[0].sub); - EXPECT_EQ("5678", parsed_accounts[1].sub); -} - -TEST(AccountsParseTest, OptionalFields) { - auto account = CreateTestAccount("1234"); - account.RemoveKey("given_name"); - account.RemoveKey("family_name"); - account.RemoveKey("picture"); - // given_name and picture are optional - base::Value::ListStorage accounts; - accounts.emplace_back(std::move(account)); - base::Value single_account_value(accounts); - - AccountList parsed_accounts; - EXPECT_TRUE(IdpNetworkRequestManager::ParseAccounts(&single_account_value, - parsed_accounts)); - EXPECT_EQ(1UL, parsed_accounts.size()); - EXPECT_EQ("1234", parsed_accounts[0].sub); -} - -TEST(AccountsParseTest, RequiredFields) { - auto TestAccountWithMissingField = [](const std::string& removed_key) { - auto account = CreateTestAccount("1234"); - account.RemoveKey(removed_key); - base::Value::ListStorage accounts; - accounts.emplace_back(std::move(account)); - return base::Value(accounts); - }; - - { - auto account_value = TestAccountWithMissingField("sub"); + base::RunLoop run_loop; + AccountsResponse parsed_accounts_response; AccountList parsed_accounts; - EXPECT_TRUE(IdpNetworkRequestManager::ParseAccounts(&account_value, - parsed_accounts)); - EXPECT_TRUE(parsed_accounts.empty()); + auto callback = base::BindLambdaForTesting( + [&](AccountsResponse response, const AccountList& accounts) { + parsed_accounts_response = response; + parsed_accounts = accounts; + run_loop.Quit(); + }); + manager().SendAccountsRequest(accounts_endpoint, std::move(callback)); + run_loop.Run(); + + return {parsed_accounts_response, parsed_accounts}; + } + + IdpNetworkRequestManager& manager() { return *manager_; } + + network::TestURLLoaderFactory& test_url_loader_factory() { + return test_url_loader_factory_; + } + + private: + base::test::SingleThreadTaskEnvironment task_environment_; + network::TestURLLoaderFactory test_url_loader_factory_; + std::unique_ptr<IdpNetworkRequestManager> manager_; + data_decoder::test::InProcessDataDecoder in_process_data_decoder; +}; + +TEST_F(IdpNetworkRequestManagerTest, ParseAccountEmpty) { + const auto* test_empty_account_json = R"({ + "accounts" : [] + })"; + + AccountsResponse accounts_response; + AccountList accounts; + std::tie(accounts_response, accounts) = + SendAccountsRequestAndWaitForResponse(test_empty_account_json); + + EXPECT_EQ(AccountsResponse::kSuccess, accounts_response); + EXPECT_TRUE(accounts.empty()); +} + +TEST_F(IdpNetworkRequestManagerTest, ParseAccountSingle) { + const auto* test_single_account_json = R"({ + "accounts" : [ + { + "sub" : "1234", + "email": "ken@idp.test", + "name": "Ken R. Example", + "given_name": "Ken", + "picture": "https://idp.test/profile/1" + } + ] + })"; + + AccountsResponse accounts_response; + AccountList accounts; + std::tie(accounts_response, accounts) = + SendAccountsRequestAndWaitForResponse(test_single_account_json); + + EXPECT_EQ(AccountsResponse::kSuccess, accounts_response); + EXPECT_EQ(1UL, accounts.size()); + EXPECT_EQ("1234", accounts[0].sub); +} + +TEST_F(IdpNetworkRequestManagerTest, ParseAccountMultiple) { + const auto* test_accounts_json = R"({ + "accounts" : [ + { + "sub" : "1234", + "email": "ken@idp.test", + "name": "Ken R. Example", + "given_name": "Ken", + "picture": "https://idp.test/profile/1" + }, + { + "sub" : "5678", + "email": "sam@idp.test", + "name": "Sam G. Test", + "given_name": "Sam", + "picture": "https://idp.test/profile/2" + } + ] + })"; + AccountsResponse accounts_response; + AccountList accounts; + std::tie(accounts_response, accounts) = + SendAccountsRequestAndWaitForResponse(test_accounts_json); + + EXPECT_EQ(AccountsResponse::kSuccess, accounts_response); + EXPECT_EQ(2UL, accounts.size()); + EXPECT_EQ("1234", accounts[0].sub); + EXPECT_EQ("5678", accounts[1].sub); +} + +TEST_F(IdpNetworkRequestManagerTest, ParseAccountOptionalFields) { + // given_name and picture fields are optional + const auto* test_accounts_json = R"({ + "accounts" : [ + { + "sub" : "1234", + "email": "ken@idp.test", + "name": "Ken R. Example" + } + ] + })"; + + AccountsResponse accounts_response; + AccountList accounts; + std::tie(accounts_response, accounts) = + SendAccountsRequestAndWaitForResponse(test_accounts_json); + + EXPECT_EQ(AccountsResponse::kSuccess, accounts_response); + EXPECT_EQ("1234", accounts[0].sub); +} + +TEST_F(IdpNetworkRequestManagerTest, ParseAccountRequiredFields) { + { + const auto* test_accounts_missing_sub_json = R"({"accounts" : [{ + "email": "ken@idp.test", + "name": "Ken R. Example" + }]})"; + AccountsResponse accounts_response; + AccountList accounts; + std::tie(accounts_response, accounts) = + SendAccountsRequestAndWaitForResponse(test_accounts_missing_sub_json); + + EXPECT_EQ(AccountsResponse::kSuccess, accounts_response); + EXPECT_TRUE(accounts.empty()); } { - auto account_value = TestAccountWithMissingField("email"); - AccountList parsed_accounts; - EXPECT_TRUE(IdpNetworkRequestManager::ParseAccounts(&account_value, - parsed_accounts)); - EXPECT_TRUE(parsed_accounts.empty()); + const auto* test_accounts_missing_email_json = R"({"accounts" : [{ + "sub" : "1234", + "name": "Ken R. Example" + }]})"; + AccountsResponse accounts_response; + AccountList accounts; + std::tie(accounts_response, accounts) = + SendAccountsRequestAndWaitForResponse(test_accounts_missing_email_json); + + EXPECT_EQ(AccountsResponse::kSuccess, accounts_response); + EXPECT_TRUE(accounts.empty()); } { - auto account_value = TestAccountWithMissingField("name"); - AccountList parsed_accounts; - EXPECT_TRUE(IdpNetworkRequestManager::ParseAccounts(&account_value, - parsed_accounts)); - EXPECT_TRUE(parsed_accounts.empty()); + const auto* test_accounts_missing_name_json = R"({"accounts" : [{ + "sub" : "1234", + "email": "ken@idp.test" + }]})"; + AccountsResponse accounts_response; + AccountList accounts; + std::tie(accounts_response, accounts) = + SendAccountsRequestAndWaitForResponse(test_accounts_missing_name_json); + + EXPECT_EQ(AccountsResponse::kSuccess, accounts_response); + EXPECT_TRUE(accounts.empty()); } } -TEST(AccountsParseTest, Unicode) { +TEST_F(IdpNetworkRequestManagerTest, ParseAccountUnicode) { auto TestAccountWithKeyValue = [](const std::string& key, const std::string& value) { - auto account = CreateTestAccount("1234"); - account.SetStringKey(key, value); - base::Value::ListStorage accounts; - accounts.emplace_back(std::move(account)); - return base::Value(accounts); + const auto* json = R"({ + "accounts" : [ + { + "sub" : "1234", + "email": "ken@idp.test", + "%s": "%s" + } + ] + })"; + return base::StringPrintf(json, key.c_str(), value.c_str()); }; std::array<std::string, 3> test_values{"ascii", "🦖", "مجید"}; for (auto& test_value : test_values) { - const auto& account_value = TestAccountWithKeyValue("name", test_value); - AccountList parsed_accounts; - EXPECT_TRUE(IdpNetworkRequestManager::ParseAccounts(&account_value, - parsed_accounts)); - EXPECT_EQ(1UL, parsed_accounts.size()); - EXPECT_EQ(test_value, parsed_accounts[0].name); + const auto& accounts_json = TestAccountWithKeyValue("name", test_value); + + AccountsResponse accounts_response; + AccountList accounts; + std::tie(accounts_response, accounts) = + SendAccountsRequestAndWaitForResponse(accounts_json.c_str()); + + EXPECT_EQ(1UL, accounts.size()); + EXPECT_EQ(test_value, accounts[0].name); } } -TEST(AccountsParseTest, InvalidAccounts) { - const base::DictionaryValue dictionary_value; - AccountList parsed_accounts; - EXPECT_FALSE(IdpNetworkRequestManager::ParseAccounts(&dictionary_value, - parsed_accounts)); - EXPECT_TRUE(parsed_accounts.empty()); +TEST_F(IdpNetworkRequestManagerTest, ParseAccountInvalid) { + const auto* test_invalid_account_json = "{}"; + + AccountsResponse accounts_response; + AccountList accounts; + std::tie(accounts_response, accounts) = + SendAccountsRequestAndWaitForResponse(test_invalid_account_json); + + EXPECT_EQ(AccountsResponse::kInvalidResponseError, accounts_response); + EXPECT_TRUE(accounts.empty()); +} + +TEST_F(IdpNetworkRequestManagerTest, ParseAccountMalformed) { + const auto* test_invalid_account_json = "malformed_json"; + + AccountsResponse accounts_response; + AccountList accounts; + std::tie(accounts_response, accounts) = + SendAccountsRequestAndWaitForResponse(test_invalid_account_json); + + EXPECT_EQ(AccountsResponse::kInvalidResponseError, accounts_response); + EXPECT_TRUE(accounts.empty()); } } // namespace
diff --git a/content/browser/webid/test/mock_idp_network_request_manager.cc b/content/browser/webid/test/mock_idp_network_request_manager.cc index f55c541..9c30d82 100644 --- a/content/browser/webid/test/mock_idp_network_request_manager.cc +++ b/content/browser/webid/test/mock_idp_network_request_manager.cc
@@ -8,8 +8,8 @@ MockIdpNetworkRequestManager::MockIdpNetworkRequestManager( const GURL& provider, - RenderFrameHost* host) - : IdpNetworkRequestManager(provider, host) {} + const url::Origin& relying_party) + : IdpNetworkRequestManager(provider, relying_party, nullptr) {} MockIdpNetworkRequestManager::~MockIdpNetworkRequestManager() = default;
diff --git a/content/browser/webid/test/mock_idp_network_request_manager.h b/content/browser/webid/test/mock_idp_network_request_manager.h index 6bedb488..20adf91 100644 --- a/content/browser/webid/test/mock_idp_network_request_manager.h +++ b/content/browser/webid/test/mock_idp_network_request_manager.h
@@ -12,7 +12,8 @@ class MockIdpNetworkRequestManager : public IdpNetworkRequestManager { public: - MockIdpNetworkRequestManager(const GURL& provider, RenderFrameHost* host); + MockIdpNetworkRequestManager(const GURL& provider, + const url::Origin& relaying_party_origin); ~MockIdpNetworkRequestManager() override;
diff --git a/content/public/renderer/render_view.h b/content/public/renderer/render_view.h index f3a7d177..f88ac5e 100644 --- a/content/public/renderer/render_view.h +++ b/content/public/renderer/render_view.h
@@ -9,7 +9,6 @@ #include "build/build_config.h" #include "content/common/content_export.h" -#include "ipc/ipc_sender.h" #include "ui/gfx/native_widget_types.h" namespace blink { @@ -35,7 +34,7 @@ // agnostic of frames and document content or structure. For more context, // please see https://crbug.com/467770 and // https://www.chromium.org/developers/design-documents/site-isolation. -class CONTENT_EXPORT RenderView : public IPC::Sender { +class CONTENT_EXPORT RenderView { public: // Returns the RenderView containing the given WebView. static RenderView* FromWebView(blink::WebView* webview); @@ -57,7 +56,7 @@ virtual blink::WebView* GetWebView() = 0; protected: - ~RenderView() override {} + virtual ~RenderView() {} private: // This interface should only be implemented inside content.
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 386a38dd..b3dfc05 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -124,8 +124,6 @@ scoped_refptr<base::SingleThreadTaskRunner> task_runner) { DCHECK(RenderThread::IsMainThread()); - agent_scheduling_group_.AddRoute(routing_id_, this); - WebFrame* opener_frame = nullptr; if (params->opener_frame_token) opener_frame = WebFrame::FromFrameToken(params->opener_frame_token.value()); @@ -183,7 +181,6 @@ DCHECK(destroying_); // Always deleted through Destroy(). g_routing_id_view_map.Get().erase(routing_id_); - agent_scheduling_group_.RemoveRoute(routing_id_); #ifndef NDEBUG // Make sure we are no longer referenced by the ViewMap or RoutingIDViewMap. @@ -269,12 +266,6 @@ frames_with_pending_state_.clear(); } -// IPC::Listener ------------------------------------------------------------- - -bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) { - return false; -} - // blink::WebViewClient ------------------------------------------------------ // TODO(csharrison): Migrate this method to WebLocalFrameClient / @@ -540,14 +531,6 @@ // RenderView implementation --------------------------------------------------- -bool RenderViewImpl::Send(IPC::Message* message) { - // No messages sent through RenderView come without a routing id, yay. Let's - // keep that up. - CHECK_NE(message->routing_id(), MSG_ROUTING_NONE); - - return agent_scheduling_group_.Send(message); -} - RenderFrameImpl* RenderViewImpl::GetMainRenderFrame() { return main_render_frame_; }
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 1d8ffde..b855cc7 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -81,7 +81,6 @@ // the owner of it. Thus a tab may have multiple RenderViewImpls, one for the // main frame, and one for each other frame tree generated. class CONTENT_EXPORT RenderViewImpl : public blink::WebViewClient, - public IPC::Listener, public RenderView { public: // Creates a new RenderView. Note that if the original opener has been closed, @@ -145,9 +144,6 @@ // Returns the current instance of blink::RendererPreferences. const blink::RendererPreferences& GetRendererPreferences() const; - // IPC::Listener implementation. - bool OnMessageReceived(const IPC::Message& msg) override; - // blink::WebViewClient implementation -------------------------------------- blink::WebView* CreateView( @@ -170,7 +166,6 @@ // RenderView implementation ------------------------------------------------- - bool Send(IPC::Message* message) override; RenderFrameImpl* GetMainRenderFrame() override; int GetRoutingID() override; blink::WebView* GetWebView() override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index fc872e6..b7743969 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -2566,6 +2566,7 @@ "//gpu/command_buffer/service:android_texture_owner_test_support", "//media/capture/content/android", "//media/capture/content/android:screen_capture_java", + "//services/data_decoder/public/cpp/android:safe_json_java", "//third_party/blink/public/common", "//third_party/blink/public/common:font_unique_name_table_proto", "//ui/android:android",
diff --git a/content/web_test/browser/web_test_bluetooth_adapter_provider.cc b/content/web_test/browser/web_test_bluetooth_adapter_provider.cc index 126e70c..aa2bb430 100644 --- a/content/web_test/browser/web_test_bluetooth_adapter_provider.cc +++ b/content/web_test/browser/web_test_bluetooth_adapter_provider.cc
@@ -1373,7 +1373,11 @@ uuids.push_back(BluetoothUUID(kGlucoseServiceUUID)); uuids.push_back(BluetoothUUID(kTxPowerServiceUUID)); - return GetBaseDevice(adapter, "Glucose Device", uuids, makeMACAddress(0x2)); + auto device = + GetBaseDevice(adapter, "Glucose Device", uuids, makeMACAddress(0x2)); + device->SetManufacturerData({{0x0001, {1, 2}}, {0x0002, {3, 4}}}); + + return device; } // static
diff --git a/content/web_test/browser/web_test_bluetooth_adapter_provider.h b/content/web_test/browser/web_test_bluetooth_adapter_provider.h index 6c16cdd..564891e 100644 --- a/content/web_test/browser/web_test_bluetooth_adapter_provider.h +++ b/content/web_test/browser/web_test_bluetooth_adapter_provider.h
@@ -555,6 +555,9 @@ // - Generic Access (0x1800) // - Glucose UUID (0x1808) // - Tx Power (0x1804) + // Manufacturer Data added: + // - 0x0001 : { 1, 2 } + // - 0x0002 : { 3, 4 } // Services added: // None. static std::unique_ptr<testing::NiceMock<device::MockBluetoothDevice>>
diff --git a/device/bluetooth/public/mojom/test/fake_bluetooth.mojom b/device/bluetooth/public/mojom/test/fake_bluetooth.mojom index cd13311..b2d87dd 100644 --- a/device/bluetooth/public/mojom/test/fake_bluetooth.mojom +++ b/device/bluetooth/public/mojom/test/fake_bluetooth.mojom
@@ -150,6 +150,7 @@ // the connection alive. SimulatePreconnectedPeripheral(string address, string name, + map<uint16, array<uint8>> manufacturer_data, array<UUID> known_service_uuids) => (); // Simulates an advertisement packet described in |result| being received by
diff --git a/device/bluetooth/test/fake_central.cc b/device/bluetooth/test/fake_central.cc index 6928cdd..2cb87e2 100644 --- a/device/bluetooth/test/fake_central.cc +++ b/device/bluetooth/test/fake_central.cc
@@ -45,6 +45,7 @@ void FakeCentral::SimulatePreconnectedPeripheral( const std::string& address, const std::string& name, + const base::flat_map<uint16_t, std::vector<uint8_t>>& manufacturer_data, const std::vector<device::BluetoothUUID>& known_service_uuids, SimulatePreconnectedPeripheralCallback callback) { FakePeripheral* fake_peripheral = GetFakePeripheral(address); @@ -57,6 +58,9 @@ fake_peripheral->SetName(name); fake_peripheral->SetSystemConnected(true); + fake_peripheral->SetManufacturerData( + device::BluetoothDevice::ManufacturerDataMap(manufacturer_data.begin(), + manufacturer_data.end())); fake_peripheral->SetServiceUUIDs(device::BluetoothDevice::UUIDSet( known_service_uuids.begin(), known_service_uuids.end()));
diff --git a/device/bluetooth/test/fake_central.h b/device/bluetooth/test/fake_central.h index 03eb7aa7..820c80ff 100644 --- a/device/bluetooth/test/fake_central.h +++ b/device/bluetooth/test/fake_central.h
@@ -37,6 +37,7 @@ void SimulatePreconnectedPeripheral( const std::string& address, const std::string& name, + const base::flat_map<uint16_t, std::vector<uint8_t>>& manufacturer_data, const std::vector<device::BluetoothUUID>& known_service_uuids, SimulatePreconnectedPeripheralCallback callback) override; void SimulateAdvertisementReceived(
diff --git a/device/bluetooth/test/fake_peripheral.cc b/device/bluetooth/test/fake_peripheral.cc index 8c997a26..940c109d 100644 --- a/device/bluetooth/test/fake_peripheral.cc +++ b/device/bluetooth/test/fake_peripheral.cc
@@ -54,6 +54,11 @@ device_uuids_.ReplaceServiceUUIDs(gatt_services); } +void FakePeripheral::SetManufacturerData( + ManufacturerDataMap manufacturer_data) { + manufacturer_data_ = std::move(manufacturer_data); +} + void FakePeripheral::SetNextGATTConnectionResponse(uint16_t code) { DCHECK(!next_connection_response_); DCHECK(create_gatt_connection_error_callbacks_.empty());
diff --git a/device/bluetooth/test/fake_peripheral.h b/device/bluetooth/test/fake_peripheral.h index ca936ac3..af6e2589 100644 --- a/device/bluetooth/test/fake_peripheral.h +++ b/device/bluetooth/test/fake_peripheral.h
@@ -42,6 +42,10 @@ // BluetoothDevice::GetUUIDs(). void SetServiceUUIDs(UUIDSet service_uuids); + // Updates the peripheral's Manufacturer Data that are returned by + // BluetoothDevice::GetManufacturerData(). + void SetManufacturerData(ManufacturerDataMap manufacturer_data); + // If |code| is kHCISuccess calls a pending success callback for // CreateGattConnection. Otherwise calls a pending error callback // with the ConnectErrorCode corresponding to |code|.
diff --git a/device/bluetooth/test/mock_bluetooth_device.h b/device/bluetooth/test/mock_bluetooth_device.h index 53ea37a..dd224e0 100644 --- a/device/bluetooth/test/mock_bluetooth_device.h +++ b/device/bluetooth/test/mock_bluetooth_device.h
@@ -151,6 +151,12 @@ void AddUUID(const BluetoothUUID& uuid) { uuids_.insert(uuid); } + // Updates the device's Manufacturer Data that are returned by + // BluetoothDevice::GetManufacturerData(). + void SetManufacturerData(ManufacturerDataMap manufacturer_data) { + manufacturer_data_ = std::move(manufacturer_data); + } + // Functions to save and run callbacks from this device. Useful when // trying to run callbacks in response to other actions e.g. run a read // value callback in response to a connection request.
diff --git a/device/vr/android/arcore/ar_compositor_frame_sink.cc b/device/vr/android/arcore/ar_compositor_frame_sink.cc index f3c435d..a54b3b09 100644 --- a/device/vr/android/arcore/ar_compositor_frame_sink.cc +++ b/device/vr/android/arcore/ar_compositor_frame_sink.cc
@@ -357,13 +357,7 @@ // First the DOM, if it's enabled if (should_composite_dom_overlay_) { auto dom_surface_id = xr_frame_sink_client_->GetDOMSurface(); - bool can_composite_dom_overlay = - dom_surface_id && dom_surface_id->is_valid(); - DVLOG(3) - << __func__ - << " Attempting to composite DOMOverlay, can_composite_dom_overlay=" - << can_composite_dom_overlay; - if (can_composite_dom_overlay) { + if (dom_surface_id && dom_surface_id->is_valid()) { viz::SharedQuadState* dom_quad_state = render_pass->CreateAndAppendSharedQuadState(); dom_quad_state->SetAll(
diff --git a/device/vr/android/arcore/arcore_gl.cc b/device/vr/android/arcore/arcore_gl.cc index bda6598..6eee07b 100644 --- a/device/vr/android/arcore/arcore_gl.cc +++ b/device/vr/android/arcore/arcore_gl.cc
@@ -1654,9 +1654,7 @@ } // Save the touch point for use in Blink's XR input event deduplication. - if (IsFeatureEnabled(device::mojom::XRSessionFeature::DOM_OVERLAY)) { - state->overlay_pointer_position = screen_last_touch; - } + state->overlay_pointer_position = screen_last_touch; state->description = device::mojom::XRInputSourceDescription::New();
diff --git a/ios/chrome/app/app_metrics_app_state_agent.mm b/ios/chrome/app/app_metrics_app_state_agent.mm index 0c73896..0e6051f 100644 --- a/ios/chrome/app/app_metrics_app_state_agent.mm +++ b/ios/chrome/app/app_metrics_app_state_agent.mm
@@ -40,11 +40,14 @@ [sceneState addObserver:self]; } -- (void)appStateDidExitSafeMode:(AppState*)appState { - DCHECK(self.appState.lastTimeInForeground.is_null()); - // Log session start. This normally happens in - // sceneState:transitionedToActivationLevel:, but is skipped in safe mode. - [self handleSessionStart]; +- (void)appState:(AppState*)appState + didTransitionFromInitStage:(InitStage)previousInitStage { + if (previousInitStage == InitStageSafeMode) { + // Log session start if the app is already foreground + if (self.appState.foregroundScenes.count > 0) { + [self handleSessionStart]; + } + } } #pragma mark - SceneStateObserver @@ -52,8 +55,6 @@ - (void)sceneState:(SceneState*)sceneState transitionedToActivationLevel:(SceneActivationLevel)level { if (self.appState.initStage <= InitStageSafeMode) { - // Don't log any metrics at safe mode. Wait for the transition out of safe - // mode to log session start. return; } @@ -61,19 +62,17 @@ self.appState.lastTimeInForeground.is_null()) { [self handleSessionStart]; } else if (level <= SceneActivationLevelBackground) { - for (SceneState* scene in self.appState.connectedScenes) { - if (scene.activationLevel > SceneActivationLevelBackground) { - // One scene has gone background, but at least one other is still - // foreground. Consider the session ongoing. - return; - } + // Do not consider the app as brackgrounded when there are still scenes on + // the foreground. + if (self.appState.foregroundScenes.count > 0) { + return; } - if (self.appState.lastTimeInForeground.is_null()) { // This method will be called multiple times, once per scene, if multiple // scenes go background simulatneously (for example, if two windows were // in split screen and the user swiped to go home). Only log the session - // duration once. + // duration once. This also makes sure that the first scene that ramps up + // to foreground doesn't end the session. return; }
diff --git a/ios/chrome/app/app_metrics_app_state_agent_unittest.mm b/ios/chrome/app/app_metrics_app_state_agent_unittest.mm index e3a8d07..ae511d2 100644 --- a/ios/chrome/app/app_metrics_app_state_agent_unittest.mm +++ b/ios/chrome/app/app_metrics_app_state_agent_unittest.mm
@@ -95,6 +95,14 @@ browser_state_.get())); } + void SimulateTransitionToCurrentStage() { + InitStage previousStage = + app_state_.initStage == InitStageStart + ? InitStageStart + : static_cast<InitStage>(app_state_.initStage - 1); + [agent_ appState:app_state_ didTransitionFromInitStage:previousStage]; + } + AppMetricsAppStateAgent* agent_; std::unique_ptr<TestChromeBrowserState> browser_state_; FakeAppState* app_state_; @@ -114,6 +122,8 @@ EXPECT_EQ(0, getProfileSessionDurationsService()->session_started_count()); EXPECT_EQ(0, getProfileSessionDurationsService()->session_ended_count()); + SimulateTransitionToCurrentStage(); + // Going foreground starts the session. scene.activationLevel = SceneActivationLevelForegroundInactive; EXPECT_EQ(1, getProfileSessionDurationsService()->session_started_count()); @@ -135,6 +145,8 @@ EXPECT_EQ(0, getProfileSessionDurationsService()->session_started_count()); EXPECT_EQ(0, getProfileSessionDurationsService()->session_ended_count()); + SimulateTransitionToCurrentStage(); + // One scene is enough to start a session. sceneA.activationLevel = SceneActivationLevelForegroundInactive; EXPECT_EQ(1, getProfileSessionDurationsService()->session_started_count()); @@ -165,6 +177,8 @@ EXPECT_EQ(0, getProfileSessionDurationsService()->session_started_count()); EXPECT_EQ(0, getProfileSessionDurationsService()->session_ended_count()); + SimulateTransitionToCurrentStage(); + // Going to background at app start doesn't log anything. scene.activationLevel = SceneActivationLevelBackground; EXPECT_EQ(0, getProfileSessionDurationsService()->session_started_count()); @@ -177,7 +191,7 @@ // Session starts when safe mode completes. app_state_.initStageForTesting = InitStageFinal; - [agent_ appStateDidExitSafeMode:app_state_]; + SimulateTransitionToCurrentStage(); EXPECT_EQ(1, getProfileSessionDurationsService()->session_started_count()); EXPECT_EQ(0, getProfileSessionDurationsService()->session_ended_count());
diff --git a/ios/chrome/app/application_delegate/app_state.h b/ios/chrome/app/application_delegate/app_state.h index 49673067..2ba13886 100644 --- a/ios/chrome/app/application_delegate/app_state.h +++ b/ios/chrome/app/application_delegate/app_state.h
@@ -158,6 +158,10 @@ // Returns a list of all connected scenes. - (NSArray<SceneState*>*)connectedScenes; +// Returns a list of all scenes in the foreground that are not necessarly +// active. +- (NSArray<SceneState*>*)foregroundScenes; + // Adds an observer to this app state. The observers will be notified about // app state changes per AppStateObserver protocol. - (void)addObserver:(id<AppStateObserver>)observer;
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm index 2c790265..ed927f9 100644 --- a/ios/chrome/app/application_delegate/app_state.mm +++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -629,6 +629,15 @@ return @[]; } +- (NSArray<SceneState*>*)foregroundScenes { + return [self.connectedScenes + filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL( + SceneState* scene, + NSDictionary* bindings) { + return scene.activationLevel >= SceneActivationLevelForegroundInactive; + }]]; +} + - (void)setLastTappedWindow:(UIWindow*)window { if (_lastTappedWindow == window) { return; @@ -654,9 +663,6 @@ } - (void)initializeUIPostSafeMode { - // Cache the safe mode status which is needed later on to complete the - // post-safemode initialization. - BOOL wasInSafeMode = self.inSafeMode; // Make sure that safe mode is turned off before moving further with the // browser startup. self.inSafeMode = NO; @@ -667,12 +673,6 @@ DCHECK([self.startupInformation isColdStart]); [_browserLauncher startUpBrowserToStage:INITIALIZATION_STAGE_FOREGROUND]; - if (wasInSafeMode) { - // Complete the transition out of safe mode if the app was really in safe - // mode. - [self.observers appStateDidExitSafeMode:self]; - } - if (EnableSyntheticCrashReportsForUte()) { // Must be called after sequenced context creation, which happens in // startUpBrowserToStage: method called above.
diff --git a/ios/chrome/app/application_delegate/app_state_observer.h b/ios/chrome/app/application_delegate/app_state_observer.h index 8658b0e..3adecbc 100644 --- a/ios/chrome/app/application_delegate/app_state_observer.h +++ b/ios/chrome/app/application_delegate/app_state_observer.h
@@ -39,9 +39,6 @@ - (void)appState:(AppState*)appState firstSceneHasInitializedUI:(SceneState*)sceneState; -// Called after the app exits safe mode. -- (void)appStateDidExitSafeMode:(AppState*)appState; - // Called when |AppState.lastTappedWindow| changes. - (void)appState:(AppState*)appState lastTappedWindowChanged:(UIWindow*)window;
diff --git a/ios/chrome/app/application_delegate/app_state_unittest.mm b/ios/chrome/app/application_delegate/app_state_unittest.mm index 8f7f667a..0e9b5397 100644 --- a/ios/chrome/app/application_delegate/app_state_unittest.mm +++ b/ios/chrome/app/application_delegate/app_state_unittest.mm
@@ -523,8 +523,7 @@ id browserLauncherMock = getBrowserLauncherMock(); [[browserLauncherMock expect] setLaunchOptions:launchOptions]; - // Expected calls on AppState#coordinatorDidExitSafeMode. - [[appStateObserverMock expect] appStateDidExitSafeMode:appState]; + // Expected calls after safe mode. [[browserLauncherMock expect] startUpBrowserToStage:INITIALIZATION_STAGE_FOREGROUND];
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index ea5bd1567..ca7bcb9d 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -734,6 +734,11 @@ flag_descriptions::kIncognitoBrandConsistencyForIOSName, flag_descriptions::kIncognitoBrandConsistencyForIOSDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kIncognitoBrandConsistencyForIOS)}, + {"update-history-entry-points-in-incognito", + flag_descriptions::kUpdateHistoryEntryPointsInIncognitoName, + flag_descriptions::kUpdateHistoryEntryPointsInIncognitoDescription, + flags_ui::kOsIos, + FEATURE_VALUE_TYPE(kUpdateHistoryEntryPointsInIncognito)}, }; bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index 5ed1ab32..add5970a 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -434,6 +434,12 @@ "When enabled, the toolbars and their fullscreen animations will be " "managed by the toolbar container coordinator rather than BVC."; +const char kUpdateHistoryEntryPointsInIncognitoName[] = + "Update history entry points in Incongito."; +const char kUpdateHistoryEntryPointsInIncognitoDescription[] = + "When enabled, the entry points to history UI from Incognito mode will be " + "removed."; + const char kURLBlocklistIOSName[] = "URL Blocklist Policy"; const char kURLBlocklistIOSDescription[] = "When enabled, URLs can be blocked/allowed by the URLBlocklist/URLAllowlist"
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index feb71a42..95f99d17 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -378,6 +378,11 @@ extern const char kToolbarContainerName[]; extern const char kToolbarContainerDescription[]; +// Title and description for the flag to enable removing any entry points to the +// history UI from Incognito mode. +extern const char kUpdateHistoryEntryPointsInIncognitoName[]; +extern const char kUpdateHistoryEntryPointsInIncognitoDescription[]; + // Title and description for the flag to enable URLBlocklist/URLAllowlist // enterprise policy. extern const char kURLBlocklistIOSName[];
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn index bfd1ab7..0534159 100644 --- a/ios/chrome/browser/ui/bookmarks/BUILD.gn +++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -228,6 +228,7 @@ testonly = true sources = [ "bookmark_home_view_controller_unittest.mm", + "bookmark_model_bridge_observer_unittest.mm", "bookmark_path_cache_unittest.mm", "bookmark_utils_ios_unittest.mm", ]
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.mm b/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.mm index 87a6211..bebb5ab2 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.mm
@@ -62,8 +62,12 @@ size_t old_index, const BookmarkNode* node, const std::set<GURL>& removed_urls) { - [observer_ bookmarkNodeDeleted:node fromFolder:parent]; - [observer_ bookmarkNodeChildrenChanged:parent]; + // Hold a non-weak reference to |observer_|, in case the first event below + // destroys |this|. + id<BookmarkModelBridgeObserver> observer = observer_; + + [observer bookmarkNodeDeleted:node fromFolder:parent]; + [observer bookmarkNodeChildrenChanged:parent]; } void BookmarkModelBridge::BookmarkNodeChanged(BookmarkModel* model,
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer_unittest.mm b/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer_unittest.mm new file mode 100644 index 0000000..120d6a5 --- /dev/null +++ b/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer_unittest.mm
@@ -0,0 +1,102 @@ +// 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 "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h" + +#include <memory> + +#include "components/bookmarks/browser/bookmark_model.h" +#include "ios/chrome/browser/ui/bookmarks/bookmark_ios_unittest.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@class TestBookmarkModelBridgeObserver; + +@interface TestOwner : NSObject { + @public + std::unique_ptr<bookmarks::BookmarkModelBridge> bridge; +} + +@property(nonatomic, strong) TestBookmarkModelBridgeObserver* observer; + +- (void)bookmarkNodeDeleted; +@end + +@implementation TestOwner +- (void)bookmarkNodeDeleted { + bridge.reset(); + self.observer = nil; +} +@end + +@interface TestBookmarkModelBridgeObserver + : NSObject <BookmarkModelBridgeObserver> { + id owner; +} + +- (void)setOwner:(id)newOwner; +@end + +@implementation TestBookmarkModelBridgeObserver + +- (void)setOwner:(id)newOwner { + owner = newOwner; +} + +#pragma mark - BookmarkModelBridgeObserver + +- (void)bookmarkNodeChildrenChanged: + (const bookmarks::BookmarkNode*)bookmarkNode { +} + +- (void)bookmarkModelRemovedAllNodes { +} + +- (void)bookmarkModelLoaded { +} + +- (void)bookmarkNodeChanged:(const bookmarks::BookmarkNode*)bookmarkNode { +} + +- (void)bookmarkNode:(const bookmarks::BookmarkNode*)bookmarkNode + movedFromParent:(const bookmarks::BookmarkNode*)oldParent + toParent:(const bookmarks::BookmarkNode*)newParent { +} + +- (void)bookmarkNodeDeleted:(const bookmarks::BookmarkNode*)node + fromFolder:(const bookmarks::BookmarkNode*)folder { + [owner bookmarkNodeDeleted]; +} + +@end + +namespace bookmarks { + +namespace { + +using BookmarkModelBridgeObserverTest = BookmarkIOSUnitTest; + +TEST_F(BookmarkModelBridgeObserverTest, + NotifyBookmarkNodeChildrenChangedDespiteSelfDestruction) { + @autoreleasepool { + const BookmarkNode* mobile_node = bookmark_model_->mobile_node(); + const BookmarkNode* folder = AddFolder(mobile_node, @"title"); + + TestOwner* owner = [[TestOwner alloc] init]; + owner.observer = [[TestBookmarkModelBridgeObserver alloc] init]; + [owner.observer setOwner:owner]; + + owner->bridge = + std::make_unique<BookmarkModelBridge>(owner.observer, bookmark_model_); + + // Deleting the folder should not cause a crash. + bookmark_model_->Remove(folder); + } +} + +} // namespace + +} // namespace bookmarks
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_coordinator.mm b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_coordinator.mm index ac1c81f1..17a45a7 100644 --- a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_coordinator.mm +++ b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_coordinator.mm
@@ -120,7 +120,13 @@ } - (void)infobarBannerWillBeDismissed:(BOOL)userInitiated { - // No-op. + if (userInitiated) { + SceneState* sceneState = + SceneStateBrowserAgent::FromBrowser(self.browser)->GetSceneState(); + DefaultBrowserSceneAgent* agent = + [DefaultBrowserSceneAgent agentFromScene:sceneState]; + [agent.nonModalScheduler logUserDismissedPromo]; + } } - (void)infobarWasDismissed {
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.h b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.h index 51a82bb0..afb832086 100644 --- a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.h +++ b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.h
@@ -45,6 +45,9 @@ // Handles the user performing the promo action. - (void)logUserPerformedPromoAction; +// Handles the user manually dismissing the promo. +- (void)logUserDismissedPromo; + @end #endif // IOS_CHROME_BROWSER_UI_DEFAULT_PROMO_DEFAULT_BROWSER_PROMO_NON_MODAL_SCHEDULER_H_
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.mm b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.mm index 8f7c50bf..1dd2e05 100644 --- a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.mm +++ b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.mm
@@ -27,6 +27,14 @@ // This should allow any initial overlays to be presented first. const NSTimeInterval kShowPromoWebpageLoadWaitTime = 3; +// Number of times to show the promo to a user. +const int kPromoShownTimesLimit = 2; + +bool PromoCanBeDisplayed() { + return !UserInPromoCooldown() && + UserInteractionWithNonModalPromoCount() < kPromoShownTimesLimit; +} + } // namespace @interface DefaultBrowserPromoNonModalScheduler () <WebStateListObserving, @@ -95,6 +103,7 @@ } - (void)logUserPerformedPromoAction { + LogUserInteractionWithNonModalPromo(); if (NonModalPromosInstructionsEnabled()) { id<ApplicationSettingsCommands> handler = HandlerForProtocol(self.dispatcher, ApplicationSettingsCommands); @@ -108,6 +117,10 @@ } } +- (void)logUserDismissedPromo { + LogUserInteractionWithNonModalPromo(); +} + - (void)dismissPromoAnimated:(BOOL)animated { [self cancelDismissPromoTimer]; [self.handler dismissDefaultBrowserNonModalPromoAnimated:animated]; @@ -183,7 +196,7 @@ #pragma mark - Timer Management - (void)startShowPromoTimer { - if (self.promoIsShowing || self.showPromoTimer) { + if (!PromoCanBeDisplayed() || self.promoIsShowing || self.showPromoTimer) { return; } self.showPromoTimer = @@ -200,7 +213,7 @@ } - (void)showPromoTimerFinished { - if (self.promoIsShowing) { + if (!PromoCanBeDisplayed() || self.promoIsShowing) { return; } self.showPromoTimer = nil; @@ -228,7 +241,10 @@ - (void)dismissPromoTimerFinished { self.dismissPromoTimer = nil; - [self.handler dismissDefaultBrowserNonModalPromoAnimated:YES]; + if (self.promoIsShowing) { + LogUserInteractionWithNonModalPromo(); + [self.handler dismissDefaultBrowserNonModalPromoAnimated:YES]; + } } @end
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_utils.h b/ios/chrome/browser/ui/default_promo/default_browser_utils.h index da12631..b40547d 100644 --- a/ios/chrome/browser/ui/default_promo/default_browser_utils.h +++ b/ios/chrome/browser/ui/default_promo/default_browser_utils.h
@@ -101,12 +101,19 @@ // previously. Returns false otherwise. bool HasUserInteractedWithTailoredFullscreenPromoBefore(); +// Returns the number of times the user has seen and interacted with the +// non-modal promo before. +int UserInteractionWithNonModalPromoCount(); + // Logs that the user has interacted with the Fullscreen Promo. void LogUserInteractionWithFullscreenPromo(); // Logs that the user has interacted with a Tailored Fullscreen Promo. void LogUserInteractionWithTailoredFullscreenPromo(); +// Logs that the user has interacted with a Non-Modals Promo. +void LogUserInteractionWithNonModalPromo(); + // Returns true if the last URL open is within the time threshold that would // indicate Chrome is likely still the default browser. Returns false otherwise. bool IsChromeLikelyDefaultBrowser(); @@ -121,8 +128,8 @@ // true, this type of promo will be ignored. DefaultPromoType MostRecentInterestDefaultPromoType(BOOL skipAllTabsPromo); -// Return YES if the user has seen a fullscreen promo recently, and shouldn't +// Return YES if the user has seen a promo recently, and shouldn't // see another one. -BOOL UserInFullscreenPromoCooldown(); +BOOL UserInPromoCooldown(); #endif // IOS_CHROME_BROWSER_UI_DEFAULT_PROMO_DEFAULT_BROWSER_UTILS_H_
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_utils.mm b/ios/chrome/browser/ui/default_promo/default_browser_utils.mm index f8f6f68..dc5cf2b 100644 --- a/ios/chrome/browser/ui/default_promo/default_browser_utils.mm +++ b/ios/chrome/browser/ui/default_promo/default_browser_utils.mm
@@ -41,8 +41,10 @@ @"lastSignificantUserEventAllTabs"; // Key for NSUserDefaults containing an NSDate indicating the last time a user -// interacted with ANY fullscreen promo. -NSString* const kLastTimeUserInteractedWithFullscreenPromo = +// interacted with ANY promo. The string value is kept from when the promos +// first launched to avoid changing the behavior for users that have already +// seen the promo. +NSString* const kLastTimeUserInteractedWithPromo = @"lastTimeUserInteractedWithFullscreenPromo"; // Key for NSUserDefaults containing a bool indicating if the user has @@ -55,6 +57,11 @@ NSString* const kUserHasInteractedWithTailoredFullscreenPromo = @"userHasInteractedWithTailoredFullscreenPromo"; +// Key for NSUserDefaults containing an int indicating the number of times the +// user has interacted with a non-modal promo. +NSString* const kUserInteractedWithNonModalPromoCount = + @"userInteractedWithNonModalPromoCount"; + NSString* const kRemindMeLaterPromoActionInteraction = @"remindMeLaterPromoActionInteraction"; @@ -248,11 +255,16 @@ boolForKey:kUserHasInteractedWithTailoredFullscreenPromo]; } +int UserInteractionWithNonModalPromoCount() { + NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; + return [standardDefaults integerForKey:kUserInteractedWithNonModalPromoCount]; +} + void LogUserInteractionWithFullscreenPromo() { NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; [standardDefaults setBool:YES forKey:kUserHasInteractedWithFullscreenPromo]; [standardDefaults setObject:[NSDate date] - forKey:kLastTimeUserInteractedWithFullscreenPromo]; + forKey:kLastTimeUserInteractedWithPromo]; if (IsInRemindMeLaterGroup()) { // Clear any possible Remind Me Later timestamp saved. @@ -265,7 +277,17 @@ [standardDefaults setBool:YES forKey:kUserHasInteractedWithTailoredFullscreenPromo]; [standardDefaults setObject:[NSDate date] - forKey:kLastTimeUserInteractedWithFullscreenPromo]; + forKey:kLastTimeUserInteractedWithPromo]; +} + +void LogUserInteractionWithNonModalPromo() { + NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; + int currentInteractionCount = + [standardDefaults integerForKey:kUserInteractedWithNonModalPromoCount]; + [standardDefaults setInteger:currentInteractionCount + 1 + forKey:kUserInteractedWithNonModalPromoCount]; + [standardDefaults setObject:[NSDate date] + forKey:kLastTimeUserInteractedWithPromo]; } bool IsChromeLikelyDefaultBrowser() { @@ -329,10 +351,10 @@ return mostRecentType; } -BOOL UserInFullscreenPromoCooldown() { +BOOL UserInPromoCooldown() { NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; - NSDate* lastFullscreenInteraction = ObjCCast<NSDate>([standardDefaults - objectForKey:kLastTimeUserInteractedWithFullscreenPromo]); + NSDate* lastFullscreenInteraction = ObjCCast<NSDate>( + [standardDefaults objectForKey:kLastTimeUserInteractedWithPromo]); if (lastFullscreenInteraction) { NSDate* coolDownDate = [NSDate dateWithTimeIntervalSinceNow:-kFullscreenPromoCoolDown];
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_utils_unittest.mm b/ios/chrome/browser/ui/default_promo/default_browser_utils_unittest.mm index e906a48..390e02a 100644 --- a/ios/chrome/browser/ui/default_promo/default_browser_utils_unittest.mm +++ b/ios/chrome/browser/ui/default_promo/default_browser_utils_unittest.mm
@@ -123,11 +123,11 @@ return; } LogUserInteractionWithFullscreenPromo(); - EXPECT_TRUE(UserInFullscreenPromoCooldown()); + EXPECT_TRUE(UserInPromoCooldown()); ClearUserDefaults(); LogUserInteractionWithTailoredFullscreenPromo(); - EXPECT_TRUE(UserInFullscreenPromoCooldown()); + EXPECT_TRUE(UserInPromoCooldown()); } // Tests no 2 tailored promos are not shown.
diff --git a/ios/chrome/browser/ui/first_run/signin/BUILD.gn b/ios/chrome/browser/ui/first_run/signin/BUILD.gn index 0db8c97..145eb124 100644 --- a/ios/chrome/browser/ui/first_run/signin/BUILD.gn +++ b/ios/chrome/browser/ui/first_run/signin/BUILD.gn
@@ -13,6 +13,7 @@ ] deps = [ ":signin_ui", + "//components/prefs", "//ios/chrome/browser", "//ios/chrome/browser/first_run", "//ios/chrome/browser/main:public",
diff --git a/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm b/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm index d386f10..6a5971c 100644 --- a/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm +++ b/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm
@@ -10,6 +10,7 @@ #include "ios/chrome/browser/signin/identity_manager_factory.h" #import "ios/chrome/browser/ui/authentication/authentication_flow.h" #import "ios/chrome/browser/ui/authentication/signin/add_account_signin/add_account_signin_coordinator.h" +#import "ios/chrome/browser/ui/authentication/signin/signin_utils.h" #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator.h" #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator_delegate.h" #import "ios/chrome/browser/ui/commands/browsing_data_commands.h" @@ -68,10 +69,14 @@ } - (void)start { - // TODO(crbug.com/1189836): Check if sign-in screen need to be shown. - // if not: - // [self.delegate willFinishPresenting] - // if yes: + // TODO(crbug.com/1189836): The kSigninAllowed pref should be observed in case + // the policy is applied while this screen is presented. + + if (!signin::IsSigninAllowed(self.browser->GetBrowserState()->GetPrefs())) { + self.attemptStatus = first_run::SignInAttemptStatus::SKIPPED_BY_POLICY; + [self finishPresentingAndSkipRemainingScreens:NO]; + return; + } self.hadIdentitiesAtStartup = ios::GetChromeBrowserProvider() ->GetChromeIdentityService() ->HasIdentities(); @@ -125,6 +130,10 @@ } } +- (void)didTapSecondaryActionButton { + [self finishPresentingAndSkipRemainingScreens:NO]; +} + #pragma mark - IdentityChooserCoordinatorDelegate - (void)identityChooserCoordinatorDidClose:
diff --git a/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.mm b/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.mm index 958ee76..b470e410 100644 --- a/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.mm +++ b/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.mm
@@ -153,8 +153,6 @@ } else { [self.consumer noIdentityAvailable]; } - - // TODO(crbug.com/1189836): Update the buttons. } // Callback used when the sign in flow is complete, with |success|.
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm index 60ac3973..279b6ca 100644 --- a/ios/chrome/browser/ui/history/history_ui_egtest.mm +++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -461,8 +461,7 @@ performAction:grey_longPress()]; [ChromeEarlGrey - verifyShareActionWithURL:_URL1 - pageTitle:[NSString stringWithUTF8String:kTitle1]]; + verifyShareActionWithPageTitle:[NSString stringWithUTF8String:kTitle1]]; } // Tests the Delete context menu action for a History entry.
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index 6817b95..df96950 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -378,107 +378,99 @@ self.sceneState.presentingModalOverlay) { return; } - if (base::ios::IsSceneStartupSupported()) { - if (@available(iOS 13, *)) { - // Handle URL opening from - // |UIWindowSceneDelegate scene:willConnectToSession:options:|. - for (UIOpenURLContext* context in self.sceneState.connectionOptions - .URLContexts) { - URLOpenerParams* params = - [[URLOpenerParams alloc] initWithUIOpenURLContext:context]; - [self openTabFromLaunchWithParams:params - startupInformation:self.sceneState.appState - .startupInformation - appState:self.sceneState.appState]; - } - if (self.sceneState.connectionOptions.shortcutItem) { - [UserActivityHandler - performActionForShortcutItem:self.sceneState.connectionOptions - .shortcutItem - completionHandler:nil - tabOpener:self - connectionInformation:self - startupInformation:self.sceneState.appState - .startupInformation - interfaceProvider:self.interfaceProvider]; - } - // See if this scene launched as part of a multiwindow URL opening. - // If so, load that URL (this also creates a new tab to load the URL - // in). No other UI will show in this case. - NSUserActivity* activityWithCompletion; - for (NSUserActivity* activity in self.sceneState.connectionOptions - .userActivities) { - if (ActivityIsURLLoad(activity)) { - UrlLoadParams params = LoadParamsFromActivity(activity); - ApplicationMode mode = params.in_incognito - ? ApplicationMode::INCOGNITO - : ApplicationMode::NORMAL; - [self openOrReuseTabInMode:mode - withUrlLoadParams:params - tabOpenedCompletion:nil]; - } else if (ActivityIsTabMove(activity)) { - NSString* tabID = GetTabIDFromActivity(activity); - MoveTabToBrowser(tabID, self.mainInterface.browser, - /*destination_tab_index=*/0); - } else if (!activityWithCompletion) { - // Completion involves user interaction. - // Only one can be triggered. - activityWithCompletion = activity; - } - } - if (activityWithCompletion) { - // This function is called when the scene is activated (or unblocked). - // Consider the scene as still not active at this point as the handling - // of startup parameters is not yet done (and will be later in this - // function). - [UserActivityHandler - continueUserActivity:activityWithCompletion - applicationIsActive:NO - tabOpener:self - connectionInformation:self - startupInformation:self.sceneState.appState.startupInformation - browserState:self.currentInterface.browserState]; - } - self.sceneState.connectionOptions = nil; + if (!base::ios::IsSceneStartupSupported()) { + return; + } + + if (@available(iOS 13, *)) { + // Handle URL opening from + // |UIWindowSceneDelegate scene:willConnectToSession:options:|. + for (UIOpenURLContext* context in self.sceneState.connectionOptions + .URLContexts) { + URLOpenerParams* params = + [[URLOpenerParams alloc] initWithUIOpenURLContext:context]; + [self openTabFromLaunchWithParams:params + startupInformation:self.sceneState.appState + .startupInformation + appState:self.sceneState.appState]; } - - if (self.startupParameters) { - if ([self isIncognitoForced]) { - [self.startupParameters - setUnexpectedMode:!self.startupParameters.launchInIncognito]; - // When only incognito mode is available. - [self.startupParameters setLaunchInIncognito:YES]; - } else if ([self isIncognitoDisabled]) { - [self.startupParameters - setUnexpectedMode:self.startupParameters.launchInIncognito]; - // When incognito mode is disabled. - [self.startupParameters setLaunchInIncognito:NO]; - } - + if (self.sceneState.connectionOptions.shortcutItem) { [UserActivityHandler - handleStartupParametersWithTabOpener:self - connectionInformation:self - startupInformation:self.sceneState.appState - .startupInformation - browserState:self.currentInterface - .browserState]; - - // Show a toast if the browser is opened in an unexpected mode. - if (self.startupParameters.isUnexpectedMode) { - [self showToastWhenOpenExternalIntentInUnexpectedMode]; - } + performActionForShortcutItem:self.sceneState.connectionOptions + .shortcutItem + completionHandler:nil + tabOpener:self + connectionInformation:self + startupInformation:self.sceneState.appState + .startupInformation + interfaceProvider:self.interfaceProvider]; } - } else { - NSDictionary* launchOptions = - self.sceneState.appState.startupInformation.launchOptions; - URLOpenerParams* params = - [[URLOpenerParams alloc] initWithLaunchOptions:launchOptions]; - [self - openTabFromLaunchWithParams:params - startupInformation:self.sceneState.appState.startupInformation - appState:self.sceneState.appState]; + // See if this scene launched as part of a multiwindow URL opening. + // If so, load that URL (this also creates a new tab to load the URL + // in). No other UI will show in this case. + NSUserActivity* activityWithCompletion; + for (NSUserActivity* activity in self.sceneState.connectionOptions + .userActivities) { + if (ActivityIsURLLoad(activity)) { + UrlLoadParams params = LoadParamsFromActivity(activity); + ApplicationMode mode = params.in_incognito ? ApplicationMode::INCOGNITO + : ApplicationMode::NORMAL; + [self openOrReuseTabInMode:mode + withUrlLoadParams:params + tabOpenedCompletion:nil]; + } else if (ActivityIsTabMove(activity)) { + NSString* tabID = GetTabIDFromActivity(activity); + MoveTabToBrowser(tabID, self.mainInterface.browser, + /*destination_tab_index=*/0); + } else if (!activityWithCompletion) { + // Completion involves user interaction. + // Only one can be triggered. + activityWithCompletion = activity; + } + } + if (activityWithCompletion) { + // This function is called when the scene is activated (or unblocked). + // Consider the scene as still not active at this point as the handling + // of startup parameters is not yet done (and will be later in this + // function). + [UserActivityHandler + continueUserActivity:activityWithCompletion + applicationIsActive:NO + tabOpener:self + connectionInformation:self + startupInformation:self.sceneState.appState.startupInformation + browserState:self.currentInterface.browserState]; + } + self.sceneState.connectionOptions = nil; + } + + if (self.startupParameters) { + if ([self isIncognitoForced]) { + [self.startupParameters + setUnexpectedMode:!self.startupParameters.launchInIncognito]; + // When only incognito mode is available. + [self.startupParameters setLaunchInIncognito:YES]; + } else if ([self isIncognitoDisabled]) { + [self.startupParameters + setUnexpectedMode:self.startupParameters.launchInIncognito]; + // When incognito mode is disabled. + [self.startupParameters setLaunchInIncognito:NO]; + } + + [UserActivityHandler + handleStartupParametersWithTabOpener:self + connectionInformation:self + startupInformation:self.sceneState.appState + .startupInformation + browserState:self.currentInterface + .browserState]; + + // Show a toast if the browser is opened in an unexpected mode. + if (self.startupParameters.isUnexpectedMode) { + [self showToastWhenOpenExternalIntentInUnexpectedMode]; + } } } @@ -967,7 +959,7 @@ if (!firstRun && self.sceneState.appState.initStage > InitStageSafeMode && postOpeningAction == NO_ACTION && !self.sceneState.appState.postCrashLaunch && - !IsChromeLikelyDefaultBrowser() && !UserInFullscreenPromoCooldown()) { + !IsChromeLikelyDefaultBrowser() && !UserInPromoCooldown()) { // Show the Default Browser promo UI if the user's past behavior fits // the categorization of potentially interested users or if the user is // signed in. Do not show if it is determined that Chrome is already the
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm index 5a9a85bf..b4b7af8 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -1117,6 +1117,11 @@ CreateTableViewItem(IDS_IOS_TOOLS_MENU_SETTINGS, PopupMenuActionSettings, @"popup_menu_settings", kToolsMenuSettingsId); + if (self.isIncognito && + base::FeatureList::IsEnabled(kUpdateHistoryEntryPointsInIncognito)) { + return @[ bookmarks, self.readingListItem, downloadsFolder, settings ]; + } + return @[ bookmarks, self.readingListItem, recentTabs, history, downloadsFolder, settings
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm index f52df71b..7679eb2 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -1280,8 +1280,7 @@ [self addURLToReadingList:distillablePageURL]; LongPressEntry(kDistillableTitle); - [ChromeEarlGrey verifyShareActionWithURL:distillablePageURL - pageTitle:kDistillableTitle]; + [ChromeEarlGrey verifyShareActionWithPageTitle:kDistillableTitle]; } // Tests the Delete context menu action for a reading list entry.
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm index 844047a..b6ed001 100644 --- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm +++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
@@ -392,9 +392,7 @@ OpenRecentTabsPanel(); [self longPressTestURLTab]; - const GURL testPageURL = web::test::HttpServer::MakeUrl(kURLOfTestPage); - [ChromeEarlGrey verifyShareActionWithURL:testPageURL - pageTitle:kTitleOfTestPage]; + [ChromeEarlGrey verifyShareActionWithPageTitle:kTitleOfTestPage]; } #pragma mark Helper Methods
diff --git a/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm b/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm index 72f36ac..4c6b87d0 100644 --- a/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm +++ b/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm
@@ -6,9 +6,9 @@ #include "base/check.h" #include "base/mac/foundation_util.h" -#include "base/metrics/histogram_functions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/sys_string_conversions.h" +#include "components/send_tab_to_self/metrics_util.h" #include "components/send_tab_to_self/send_tab_to_self_model.h" #include "components/send_tab_to_self/target_device_info.h" #import "ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_image_detail_text_item.h" @@ -37,21 +37,6 @@ NSString* const kSendTabToSelfModalSendButton = @"kSendTabToSelfModalSendButton"; -// Per histograms.xml this records whether the user has clicked the item when it -// is shown. -const char kClickResultHistogramName[] = "SendTabToSelf.ShareMenu.ClickResult"; - -// TODO(crbug.com/970886): Move to a directory accessible on all platforms. -// State of the send tab to self option in the context menu. -// These values are persisted to logs. Entries should not be renumbered and -// numeric values should never be reused. -enum class SendTabToSelfClickResult { - kShowItem = 0, - kClickItem = 1, - kShowDeviceList = 2, - kMaxValue = kShowDeviceList, -}; - } // namespace typedef NS_ENUM(NSInteger, SectionIdentifier) { @@ -222,8 +207,8 @@ #pragma mark - Helpers - (void)sendTabWhenPressed:(UIButton*)sender { - base::UmaHistogramEnumeration(kClickResultHistogramName, - SendTabToSelfClickResult::kClickItem); + send_tab_to_self::RecordDeviceClicked( + send_tab_to_self::ShareEntryPoint::kShareMenu); [self.delegate sendTabToTargetDeviceCacheGUID:self.selectedItem.cacheGuid targetDeviceName:self.selectedItem.text]; [self.delegate dismissViewControllerAnimated:YES completion:nil];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm index 88fdf5e..e3bd4cb 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm
@@ -290,8 +290,7 @@ [self longPressTabWithTitle:[NSString stringWithUTF8String:kTitle1]]; [ChromeEarlGrey - verifyShareActionWithURL:_URL1 - pageTitle:[NSString stringWithUTF8String:kTitle1]]; + verifyShareActionWithPageTitle:[NSString stringWithUTF8String:kTitle1]]; } #pragma mark - Tab Grid Item Context Menu @@ -312,8 +311,7 @@ [self longPressTabWithTitle:[NSString stringWithUTF8String:kTitle1]]; [ChromeEarlGrey - verifyShareActionWithURL:_URL1 - pageTitle:[NSString stringWithUTF8String:kTitle1]]; + verifyShareActionWithPageTitle:[NSString stringWithUTF8String:kTitle1]]; } // Tests the Add to Reading list action on a tab grid item's context menu.
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc index c649bc64..8aa1b57 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.cc +++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -73,3 +73,6 @@ const base::Feature kSearchHistoryLinkIOS{"SearchHistoryLinkIOS", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kUpdateHistoryEntryPointsInIncognito{ + "UpdateHistoryEntryPointsInIncognito", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h index 7bfd037..5328622 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.h +++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -80,4 +80,8 @@ // Enables the Search History Link in Clear Browsing Data for iOS. extern const base::Feature kSearchHistoryLinkIOS; +// Feature flag to enable removing any entry points to the history UI from +// Incognito mode. +extern const base::Feature kUpdateHistoryEntryPointsInIncognito; + #endif // IOS_CHROME_BROWSER_UI_UI_FEATURE_FLAGS_H_
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.h b/ios/chrome/test/earl_grey/chrome_earl_grey.h index 4eb35e0..a888941 100644 --- a/ios/chrome/test/earl_grey/chrome_earl_grey.h +++ b/ios/chrome/test/earl_grey/chrome_earl_grey.h
@@ -704,10 +704,8 @@ useNewString:(BOOL)useNewString; // Taps on the Share context menu action and validates that the ActivityView -// was brought up with the correct title in its header. The title starts as the -// host of the loaded |URL| and is then updated to the page title |pageTitle|. -- (void)verifyShareActionWithURL:(const GURL&)URL - pageTitle:(NSString*)pageTitle; +// was brought up with |pageTitle| in its header. +- (void)verifyShareActionWithPageTitle:(NSString*)pageTitle; #pragma mark - Unified Consent utilities
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.mm b/ios/chrome/test/earl_grey/chrome_earl_grey.mm index 39ecfed9..d8cfdd6 100644 --- a/ios/chrome/test/earl_grey/chrome_earl_grey.mm +++ b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
@@ -1323,13 +1323,11 @@ assertWithMatcher:grey_notNil()]; } -- (void)verifyShareActionWithURL:(const GURL&)URL - pageTitle:(NSString*)pageTitle { +- (void)verifyShareActionWithPageTitle:(NSString*)pageTitle { [[EarlGrey selectElementWithMatcher:ShareButton()] performAction:grey_tap()]; // Page title is added asynchronously, so wait for its appearance. - NSString* hostString = base::SysUTF8ToNSString(URL.host()); - [self waitForMatcher:grey_allOf(ActivityViewHeader(hostString, pageTitle), + [self waitForMatcher:grey_allOf(ActivityViewHeader(pageTitle), grey_sufficientlyVisible(), nil)]; // Dismiss the Activity View by tapping outside its bounds.
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h index 100eb95a..709dbaf 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers.h +++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -568,7 +568,7 @@ id<GREYMatcher> ManualFallbackCreditCardTableViewWindowMatcher(); // Returns the matcher for the iOS 13+ Activity View header. -id<GREYMatcher> ActivityViewHeader(NSString* url_host, NSString* page_title); +id<GREYMatcher> ActivityViewHeader(NSString* page_title); // Returns a matcher for the button to trigger password generation on manual // fallback.
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm index fb1cf413c..4af257e 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers.mm +++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -715,9 +715,8 @@ manualFallbackCreditCardTableViewWindowMatcher]; } -id<GREYMatcher> ActivityViewHeader(NSString* url_host, NSString* page_title) { - return [ChromeMatchersAppInterface activityViewHeaderWithURLHost:url_host - title:page_title]; +id<GREYMatcher> ActivityViewHeader(NSString* page_title) { + return [ChromeMatchersAppInterface activityViewHeaderWithTitle:page_title]; } id<GREYMatcher> ManualFallbackSuggestPasswordMatcher() {
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h index cf32ca7..a0452d0 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h +++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
@@ -559,8 +559,7 @@ + (id<GREYMatcher>)manualFallbackCreditCardTableViewWindowMatcher; // Returns the matcher for the Activity View header. -+ (id<GREYMatcher>)activityViewHeaderWithURLHost:(NSString*)host - title:(NSString*)pageTitle; ++ (id<GREYMatcher>)activityViewHeaderWithTitle:(NSString*)pageTitle; // Returns a matcher for the button to trigger password generation on manual // fallback.
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm index 3e508d70..6efcf73 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm +++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
@@ -1074,19 +1074,12 @@ return grey_allOf(classMatcher, parentMatcher, nil); } -+ (id<GREYMatcher>)activityViewHeaderWithURLHost:(NSString*)host - title:(NSString*)pageTitle { - return grey_allOf( - // The title of the activity view starts as the URL, then asynchronously - // changes to the page title. Sometimes, the activity view fails to update - // the text to the page title, causing test flake. Allow matcher to pass - // with either value for the activity view title. - grey_anyOf(grey_accessibilityLabel(host), - grey_accessibilityLabel(pageTitle), nil), - grey_ancestor( - grey_allOf(grey_accessibilityTrait(UIAccessibilityTraitHeader), - grey_kindOfClassName(@"LPLinkView"), nil)), - nil); ++ (id<GREYMatcher>)activityViewHeaderWithTitle:(NSString*)pageTitle { + return grey_allOf(grey_accessibilityLabel(pageTitle), + grey_ancestor(grey_allOf( + grey_accessibilityTrait(UIAccessibilityTraitHeader), + grey_kindOfClassName(@"LPLinkView"), nil)), + nil); } + (id<GREYMatcher>)manualFallbackSuggestPasswordMatcher {
diff --git a/net/dns/context_host_resolver_unittest.cc b/net/dns/context_host_resolver_unittest.cc index 3354b5b09..6792f13 100644 --- a/net/dns/context_host_resolver_unittest.cc +++ b/net/dns/context_host_resolver_unittest.cc
@@ -76,7 +76,9 @@ dns_client->set_ignore_system_config_changes(true); dns_client_ = dns_client.get(); manager_->SetDnsClientForTesting(std::move(dns_client)); - manager_->SetInsecureDnsClientEnabled(true); + manager_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/true); // Ensure DnsClient is fully usable. EXPECT_TRUE(dns_client_->CanUseInsecureDnsTransactions());
diff --git a/net/dns/dns_client.cc b/net/dns/dns_client.cc index dfb6407..5401176 100644 --- a/net/dns/dns_client.cc +++ b/net/dns/dns_client.cc
@@ -105,8 +105,18 @@ !config->unhandled_options && !config->dns_over_tls_active; } - void SetInsecureEnabled(bool enabled) override { + bool CanQueryAdditionalTypesViaInsecureDns() const override { + // Only useful information if insecure DNS is usable, so expect this to + // never be called if that is not the case. + DCHECK(CanUseInsecureDnsTransactions()); + + return can_query_additional_types_via_insecure_; + } + + void SetInsecureEnabled(bool enabled, + bool additional_types_enabled) override { insecure_enabled_ = enabled; + can_query_additional_types_via_insecure_ = additional_types_enabled; } bool FallbackFromSecureTransactionPreferred( @@ -256,6 +266,7 @@ } bool insecure_enabled_ = false; + bool can_query_additional_types_via_insecure_ = false; int insecure_fallback_failures_ = 0; base::Optional<DnsConfig> system_config_;
diff --git a/net/dns/dns_client.h b/net/dns/dns_client.h index a0ad590..5ad6fe29b 100644 --- a/net/dns/dns_client.h +++ b/net/dns/dns_client.h
@@ -42,7 +42,9 @@ // transactions. If false, insecure transactions should not be created. Will // always be false unless SetInsecureEnabled(true) has been called. virtual bool CanUseInsecureDnsTransactions() const = 0; - virtual void SetInsecureEnabled(bool enabled) = 0; + virtual bool CanQueryAdditionalTypesViaInsecureDns() const = 0; + virtual void SetInsecureEnabled(bool enabled, + bool additional_types_enabled) = 0; // When true, DoH should not be used in AUTOMATIC mode since no DoH servers // have a successful probe state.
diff --git a/net/dns/dns_client_unittest.cc b/net/dns/dns_client_unittest.cc index 85a3a0a..80922bb 100644 --- a/net/dns/dns_client_unittest.cc +++ b/net/dns/dns_client_unittest.cc
@@ -80,7 +80,8 @@ }; TEST_F(DnsClientTest, NoConfig) { - client_->SetInsecureEnabled(true); + client_->SetInsecureEnabled(/*enabled=*/true, + /*additional_types_enabled=*/true); EXPECT_FALSE(client_->CanUseSecureDnsTransactions()); EXPECT_TRUE( @@ -95,7 +96,8 @@ } TEST_F(DnsClientTest, InvalidConfig) { - client_->SetInsecureEnabled(true); + client_->SetInsecureEnabled(/*enabled=*/true, + /*additional_types_enabled=*/true); client_->SetSystemConfig(DnsConfig()); EXPECT_FALSE(client_->CanUseSecureDnsTransactions()); @@ -111,13 +113,15 @@ } TEST_F(DnsClientTest, CanUseSecureDnsTransactions_NoDohServers) { - client_->SetInsecureEnabled(true); + client_->SetInsecureEnabled(/*enabled=*/true, + /*additional_types_enabled=*/true); client_->SetSystemConfig(BasicValidConfig()); EXPECT_FALSE(client_->CanUseSecureDnsTransactions()); EXPECT_TRUE( client_->FallbackFromSecureTransactionPreferred(&resolve_context_)); EXPECT_TRUE(client_->CanUseInsecureDnsTransactions()); + EXPECT_TRUE(client_->CanQueryAdditionalTypesViaInsecureDns()); EXPECT_FALSE(client_->FallbackFromInsecureTransactionPreferred()); EXPECT_THAT(client_->GetEffectiveConfig(), @@ -128,7 +132,8 @@ } TEST_F(DnsClientTest, InsecureNotEnabled) { - client_->SetInsecureEnabled(false); + client_->SetInsecureEnabled(/*enabled=*/false, + /*additional_types_enabled=*/false); client_->SetSystemConfig(ValidConfigWithDoh(false /* doh_only */)); EXPECT_TRUE(client_->CanUseSecureDnsTransactions()); @@ -145,8 +150,22 @@ ValidConfigWithDoh(false /* doh_only */)); } +TEST_F(DnsClientTest, RespectsAdditionalTypesDisabled) { + client_->SetInsecureEnabled(/*enabled=*/true, + /*additional_types_enabled=*/false); + client_->SetSystemConfig(BasicValidConfig()); + + EXPECT_FALSE(client_->CanUseSecureDnsTransactions()); + EXPECT_TRUE( + client_->FallbackFromSecureTransactionPreferred(&resolve_context_)); + EXPECT_TRUE(client_->CanUseInsecureDnsTransactions()); + EXPECT_FALSE(client_->CanQueryAdditionalTypesViaInsecureDns()); + EXPECT_FALSE(client_->FallbackFromInsecureTransactionPreferred()); +} + TEST_F(DnsClientTest, UnhandledOptions) { - client_->SetInsecureEnabled(true); + client_->SetInsecureEnabled(/*enabled=*/true, + /*additional_types_enabled=*/true); DnsConfig config = ValidConfigWithDoh(false /* doh_only */); config.unhandled_options = true; client_->SetSystemConfig(config); @@ -183,7 +202,8 @@ } TEST_F(DnsClientTest, DnsOverTlsActive) { - client_->SetInsecureEnabled(true); + client_->SetInsecureEnabled(/*enabled=*/true, + /*additional_types_enabled=*/true); DnsConfig config = ValidConfigWithDoh(false /* doh_only */); config.dns_over_tls_active = true; client_->SetSystemConfig(config); @@ -201,7 +221,8 @@ } TEST_F(DnsClientTest, AllAllowed) { - client_->SetInsecureEnabled(true); + client_->SetInsecureEnabled(/*enabled=*/true, + /*additional_types_enabled=*/true); client_->SetSystemConfig(ValidConfigWithDoh(false /* doh_only */)); resolve_context_.InvalidateCachesAndPerSessionData( client_->GetCurrentSession(), false /* network_change */); @@ -213,6 +234,7 @@ EXPECT_FALSE( client_->FallbackFromSecureTransactionPreferred(&resolve_context_)); EXPECT_TRUE(client_->CanUseInsecureDnsTransactions()); + EXPECT_TRUE(client_->CanQueryAdditionalTypesViaInsecureDns()); EXPECT_FALSE(client_->FallbackFromInsecureTransactionPreferred()); EXPECT_THAT(client_->GetEffectiveConfig(), @@ -224,7 +246,8 @@ } TEST_F(DnsClientTest, FallbackFromInsecureTransactionPreferred_Failures) { - client_->SetInsecureEnabled(true); + client_->SetInsecureEnabled(/*enabled=*/true, + /*additional_types_enabled=*/true); client_->SetSystemConfig(ValidConfigWithDoh(false /* doh_only */)); for (int i = 0; i < DnsClient::kMaxInsecureFallbackFailures; ++i) { @@ -232,6 +255,7 @@ EXPECT_TRUE( client_->FallbackFromSecureTransactionPreferred(&resolve_context_)); EXPECT_TRUE(client_->CanUseInsecureDnsTransactions()); + EXPECT_TRUE(client_->CanQueryAdditionalTypesViaInsecureDns()); EXPECT_FALSE(client_->FallbackFromInsecureTransactionPreferred()); client_->IncrementInsecureFallbackFailures(); @@ -241,6 +265,7 @@ EXPECT_TRUE( client_->FallbackFromSecureTransactionPreferred(&resolve_context_)); EXPECT_TRUE(client_->CanUseInsecureDnsTransactions()); + EXPECT_TRUE(client_->CanQueryAdditionalTypesViaInsecureDns()); EXPECT_TRUE(client_->FallbackFromInsecureTransactionPreferred()); client_->ClearInsecureFallbackFailures(); @@ -249,6 +274,7 @@ EXPECT_TRUE( client_->FallbackFromSecureTransactionPreferred(&resolve_context_)); EXPECT_TRUE(client_->CanUseInsecureDnsTransactions()); + EXPECT_TRUE(client_->CanQueryAdditionalTypesViaInsecureDns()); EXPECT_FALSE(client_->FallbackFromInsecureTransactionPreferred()); }
diff --git a/net/dns/dns_test_util.cc b/net/dns/dns_test_util.cc index 7eeda50..1af39bd 100644 --- a/net/dns/dns_test_util.cc +++ b/net/dns/dns_test_util.cc
@@ -608,8 +608,15 @@ !config->dns_over_tls_active; } -void MockDnsClient::SetInsecureEnabled(bool enabled) { +bool MockDnsClient::CanQueryAdditionalTypesViaInsecureDns() const { + DCHECK(CanUseInsecureDnsTransactions()); + return additional_types_enabled_; +} + +void MockDnsClient::SetInsecureEnabled(bool enabled, + bool additional_types_enabled) { insecure_enabled_ = enabled; + additional_types_enabled_ = additional_types_enabled; } bool MockDnsClient::FallbackFromSecureTransactionPreferred(
diff --git a/net/dns/dns_test_util.h b/net/dns/dns_test_util.h index b69418ed..40a2cb44 100644 --- a/net/dns/dns_test_util.h +++ b/net/dns/dns_test_util.h
@@ -382,7 +382,8 @@ // DnsClient interface: bool CanUseSecureDnsTransactions() const override; bool CanUseInsecureDnsTransactions() const override; - void SetInsecureEnabled(bool enabled) override; + bool CanQueryAdditionalTypesViaInsecureDns() const override; + void SetInsecureEnabled(bool enabled, bool additional_types_enabled) override; bool FallbackFromSecureTransactionPreferred( ResolveContext* resolve_context) const override; bool FallbackFromInsecureTransactionPreferred() const override; @@ -425,6 +426,7 @@ scoped_refptr<DnsSession> BuildSession(); bool insecure_enabled_ = false; + bool additional_types_enabled_ = false; int fallback_failures_ = 0; int max_fallback_failures_ = DnsClient::kMaxInsecureFallbackFailures; bool ignore_system_config_changes_ = false;
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h index 4d7eab2..944fd64 100644 --- a/net/dns/host_resolver.h +++ b/net/dns/host_resolver.h
@@ -174,6 +174,10 @@ // SetInsecureDnsClientEnabled() for details. bool insecure_dns_client_enabled = false; + // Initial setting for whether additional DNS types (e.g. HTTPS) may be + // queried when using the built-in resolver for insecure DNS. + bool additional_types_via_insecure_dns_enabled = true; + // Initial configuration overrides for the built-in asynchronous DnsClient. // See HostResolverManager::SetDnsConfigOverrides() for details. DnsConfigOverrides dns_config_overrides;
diff --git a/net/dns/host_resolver_manager.cc b/net/dns/host_resolver_manager.cc index 45045af..e1eeb39 100644 --- a/net/dns/host_resolver_manager.cc +++ b/net/dns/host_resolver_manager.cc
@@ -86,6 +86,7 @@ #include "net/dns/httpssvc_metrics.h" #include "net/dns/mdns_client.h" #include "net/dns/public/dns_protocol.h" +#include "net/dns/public/dns_query_type.h" #include "net/dns/public/resolve_error_info.h" #include "net/dns/record_parsed.h" #include "net/dns/resolve_context.h" @@ -1150,13 +1151,16 @@ transactions_needed_.push(DnsQueryType::A); transactions_needed_.push(DnsQueryType::AAAA); - // Queue up an INTEGRITY query if we are allowed to. + // Queue up an INTEGRITY/HTTPS query if we are allowed to. const bool is_httpssvc_experiment_domain = httpssvc_domain_cache_.IsExperimental(hostname); const bool is_httpssvc_control_domain = httpssvc_domain_cache_.IsControl(hostname); + const bool can_query_via_insecure = + !secure_ && features::kDnsHttpssvcEnableQueryOverInsecure.Get() && + client_->CanQueryAdditionalTypesViaInsecureDns(); if (base::FeatureList::IsEnabled(features::kDnsHttpssvc) && - (secure_ || features::kDnsHttpssvcEnableQueryOverInsecure.Get()) && + (secure_ || can_query_via_insecure) && (is_httpssvc_experiment_domain || is_httpssvc_control_domain)) { httpssvc_metrics_.emplace( is_httpssvc_experiment_domain /* expect_intact */); @@ -1192,6 +1196,9 @@ DnsQueryType type = transactions_needed_.front(); transactions_needed_.pop(); + DCHECK(type != DnsQueryType::HTTPS || secure_ || + client_->CanQueryAdditionalTypesViaInsecureDns()); + // Record how long this transaction has been waiting to be created. base::TimeDelta time_queued = tick_clock_->NowTicks() - task_start_time_; UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.JobQueueTime.PerTransaction", @@ -2541,7 +2548,9 @@ #if defined(ENABLE_BUILT_IN_DNS) dns_client_ = DnsClient::CreateClient(net_log_); - dns_client_->SetInsecureEnabled(options.insecure_dns_client_enabled); + dns_client_->SetInsecureEnabled( + options.insecure_dns_client_enabled, + options.additional_types_via_insecure_dns_enabled); dns_client_->SetConfigOverrides(options.dns_config_overrides); #else DCHECK(options.dns_config_overrides == DnsConfigOverrides()); @@ -2614,17 +2623,30 @@ return listener; } -void HostResolverManager::SetInsecureDnsClientEnabled(bool enabled) { +void HostResolverManager::SetInsecureDnsClientEnabled( + bool enabled, + bool additional_dns_types_enabled) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (!dns_client_) return; bool enabled_before = dns_client_->CanUseInsecureDnsTransactions(); - dns_client_->SetInsecureEnabled(enabled); + bool additional_types_before = + enabled_before && dns_client_->CanQueryAdditionalTypesViaInsecureDns(); + dns_client_->SetInsecureEnabled(enabled, additional_dns_types_enabled); - if (dns_client_->CanUseInsecureDnsTransactions() != enabled_before) + // Abort current tasks if `CanUseInsecureDnsTransactions()` changes or if + // insecure transactions are enabled and + // `CanQueryAdditionalTypesViaInsecureDns()` changes. Changes to allowing + // additional types don't matter if insecure transactions are completely + // disabled. + if (dns_client_->CanUseInsecureDnsTransactions() != enabled_before || + (dns_client_->CanUseInsecureDnsTransactions() && + dns_client_->CanQueryAdditionalTypesViaInsecureDns() != + additional_types_before)) { AbortInsecureDnsTasks(ERR_NETWORK_CHANGED, false /* fallback_only */); + } } base::Value HostResolverManager::GetDnsConfigAsValue() const { @@ -3247,7 +3269,9 @@ if (dns_client_ && dns_client_->GetEffectiveConfig()) { bool insecure_allowed = dns_client_->CanUseInsecureDnsTransactions() && - !dns_client_->FallbackFromInsecureTransactionPreferred(); + !dns_client_->FallbackFromInsecureTransactionPreferred() && + (IsAddressType(dns_query_type) || + dns_client_->CanQueryAdditionalTypesViaInsecureDns()); PushDnsTasks(proc_task_allowed, *out_effective_secure_dns_mode, insecure_allowed, allow_cache, prioritize_local_lookups, resolve_context, out_tasks); @@ -3268,10 +3292,14 @@ break; case HostResolverSource::DNS: if (dns_client_ && dns_client_->GetEffectiveConfig()) { + bool insecure_allowed = + dns_client_->CanUseInsecureDnsTransactions() && + (IsAddressType(dns_query_type) || + dns_client_->CanQueryAdditionalTypesViaInsecureDns()); PushDnsTasks(false /* proc_task_allowed */, - *out_effective_secure_dns_mode, - dns_client_->CanUseInsecureDnsTransactions(), allow_cache, - prioritize_local_lookups, resolve_context, out_tasks); + *out_effective_secure_dns_mode, insecure_allowed, + allow_cache, prioritize_local_lookups, resolve_context, + out_tasks); } break; case HostResolverSource::MULTICAST_DNS:
diff --git a/net/dns/host_resolver_manager.h b/net/dns/host_resolver_manager.h index 573033e..4236235 100644 --- a/net/dns/host_resolver_manager.h +++ b/net/dns/host_resolver_manager.h
@@ -169,7 +169,8 @@ // DnsConfig, a new config is fetched from NetworkChangeNotifier. // // Setting to |true| has no effect if |ENABLE_BUILT_IN_DNS| not defined. - virtual void SetInsecureDnsClientEnabled(bool enabled); + virtual void SetInsecureDnsClientEnabled(bool enabled, + bool additional_dns_types_enabled); base::Value GetDnsConfigAsValue() const;
diff --git a/net/dns/host_resolver_manager_unittest.cc b/net/dns/host_resolver_manager_unittest.cc index 5e82854..7918bc3 100644 --- a/net/dns/host_resolver_manager_unittest.cc +++ b/net/dns/host_resolver_manager_unittest.cc
@@ -59,7 +59,9 @@ #include "net/dns/mock_host_resolver.h" #include "net/dns/mock_mdns_client.h" #include "net/dns/mock_mdns_socket_factory.h" +#include "net/dns/public/dns_config_overrides.h" #include "net/dns/public/dns_over_https_server_config.h" +#include "net/dns/public/dns_query_type.h" #include "net/dns/public/resolve_error_info.h" #include "net/dns/resolve_context.h" #include "net/dns/test_dns_config_service.h" @@ -3853,6 +3855,7 @@ HostResolver::ManagerOptions options = HostResolverManagerTest::DefaultOptions(); options.insecure_dns_client_enabled = true; + options.additional_types_via_insecure_dns_enabled = true; return options; } @@ -3867,7 +3870,9 @@ std::make_unique<MockDnsClient>(DnsConfig(), CreateDefaultDnsRules()); dns_client_ = dns_client.get(); resolver_->SetDnsClientForTesting(std::move(dns_client)); - resolver_->SetInsecureDnsClientEnabled(options.insecure_dns_client_enabled); + resolver_->SetInsecureDnsClientEnabled( + options.insecure_dns_client_enabled, + options.additional_types_via_insecure_dns_enabled); resolver_->set_proc_params_for_test(params); resolver_->RegisterResolveContext(resolve_context_.get()); @@ -3882,7 +3887,9 @@ std::make_unique<MockDnsClient>(DnsConfig(), std::move(rules)); dns_client_ = dns_client.get(); resolver_->SetDnsClientForTesting(std::move(dns_client)); - resolver_->SetInsecureDnsClientEnabled(true); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/true); if (!config.Equals(DnsConfig())) ChangeDnsConfig(config); } @@ -4117,7 +4124,9 @@ proc_->AddRuleForAllFamilies("nx_succeed", "192.168.2.47"); proc_->SignalMultiple(1u); - resolver_->SetInsecureDnsClientEnabled(false); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, + /*additional_dns_types_enabled*/ false); ResolveHostResponseHelper response_proc(resolver_->CreateRequest( HostPortPair("nx_succeed", 1212), NetworkIsolationKey(), NetLogWithSource(), base::nullopt, resolve_context_.get(), @@ -4126,7 +4135,8 @@ EXPECT_THAT(response_proc.request()->GetAddressResults().value().endpoints(), testing::ElementsAre(CreateExpected("192.168.2.47", 1212))); - resolver_->SetInsecureDnsClientEnabled(true); + resolver_->SetInsecureDnsClientEnabled(/*enabled*/ true, + /*additional_dns_types_enabled=*/true); ResolveHostResponseHelper response_dns_client(resolver_->CreateRequest( HostPortPair("ok_fail", 1212), NetworkIsolationKey(), NetLogWithSource(), base::nullopt, resolve_context_.get(), resolve_context_->host_cache())); @@ -4407,7 +4417,9 @@ // Simulate the case when the preference or policy has disabled the insecure // DNS client causing AbortInsecureDnsTasks. - resolver_->SetInsecureDnsClientEnabled(false); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, + /*additional_dns_types_enabled=*/false); // All requests should fallback to proc resolver. EXPECT_THAT(response0.result_error(), IsError(ERR_NAME_NOT_RESOLVED)); @@ -4440,7 +4452,9 @@ // Simulate the case when the preference or policy has disabled the insecure // DNS client causing AbortInsecureDnsTasks. - resolver_->SetInsecureDnsClientEnabled(false); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, + /*additional_dns_types_enabled=*/false); // No fallback expected. All requests should fail. EXPECT_THAT(response0.result_error(), IsError(ERR_NETWORK_CHANGED)); @@ -4468,7 +4482,9 @@ // Simulate the case when the preference or policy has disabled the insecure // DNS client causing AbortInsecureDnsTasks. - resolver_->SetInsecureDnsClientEnabled(false); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, + /*additional_dns_types_enabled*/ false); EXPECT_THAT(response_secure.result_error(), IsOk()); EXPECT_THAT( @@ -4635,7 +4651,9 @@ TEST_F(HostResolverManagerDnsTest, SkipHostsWithUpcomingProcTask) { // Disable the DnsClient. - resolver_->SetInsecureDnsClientEnabled(false); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, + /*additional_dns_types_enabled=*/false); proc_->AddRuleForAllFamilies(std::string(), std::string()); // Default to failures. @@ -4959,7 +4977,9 @@ proc_->AddRuleForAllFamilies(std::string(), std::string()); // Try without DnsClient. - resolver_->SetInsecureDnsClientEnabled(false); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, + /*additional_dns_types_enabled=*/false); ResolveHostResponseHelper system_response(resolver_->CreateRequest( HostPortPair("localhost", 80), NetworkIsolationKey(), NetLogWithSource(), base::nullopt, resolve_context_.get(), resolve_context_->host_cache())); @@ -5758,7 +5778,9 @@ SecureDnsMode_Automatic_InsecureAsyncDisabled) { proc_->AddRuleForAllFamilies("insecure_automatic", "192.168.1.100"); ChangeDnsConfig(CreateValidDnsConfig()); - resolver_->SetInsecureDnsClientEnabled(false); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, + /*additional_dns_types_enabled=*/false); DnsConfigOverrides overrides; overrides.secure_dns_mode = SecureDnsMode::kAutomatic; resolver_->SetDnsConfigOverrides(overrides); @@ -5940,7 +5962,9 @@ TEST_F(HostResolverManagerDnsTest, SecureDnsMode_Secure_InsecureAsyncDisabled) { proc_->AddRuleForAllFamilies("nx_succeed", "192.168.1.100"); set_allow_fallback_to_proctask(true); - resolver_->SetInsecureDnsClientEnabled(false); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, + /*additional_dns_types_enabled=*/false); ChangeDnsConfig(CreateValidDnsConfig()); DnsConfigOverrides overrides; @@ -6448,7 +6472,9 @@ // Clear DnsClient. The two in-progress jobs should fall back to a ProcTask, // and the next one should be started with a ProcTask. - resolver_->SetInsecureDnsClientEnabled(false); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, + /*additional_dns_types_enabled=*/false); // All three in-progress requests should now be running a ProcTask. EXPECT_EQ(3u, num_running_dispatcher_jobs()); @@ -6469,7 +6495,9 @@ // DnsClient disabled should result in an error. TEST_F(HostResolverManagerDnsTest, DnsCallsWithDisabledDnsClient) { ChangeDnsConfig(CreateValidDnsConfig()); - resolver_->SetInsecureDnsClientEnabled(false); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, + /*additional_dns_types_enabled=*/false); HostResolver::ResolveHostParameters params; params.source = HostResolverSource::DNS; @@ -8373,6 +8401,32 @@ EXPECT_EQ(resolve_context_->host_cache()->size(), 0u); } +TEST_F(HostResolverManagerDnsTest, + TxtInsecureQueryDisallowedWhenAdditionalTypesDisallowed) { + const std::string kName = "txt.test"; + + ChangeDnsConfig(CreateValidDnsConfig()); + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kOff; + resolver_->SetDnsConfigOverrides(overrides); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + HostResolver::ResolveHostParameters parameters; + parameters.dns_query_type = DnsQueryType::TXT; + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + parameters, resolve_context_.get(), resolve_context_->host_cache())); + // No non-local work is done, so ERR_DNS_CACHE_MISS is the result. + EXPECT_THAT(response.result_error(), IsError(ERR_DNS_CACHE_MISS)); + EXPECT_FALSE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); +} + // Same as TxtQuery except we specify DNS HostResolverSource instead of relying // on automatic determination. Expect same results since DNS should be what we // automatically determine, but some slightly different logic paths are @@ -8676,6 +8730,32 @@ EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); } +TEST_F(HostResolverManagerDnsTest, + PtrInsecureQueryDisallowedWhenAdditionalTypesDisallowed) { + const std::string kName = "ptr.test"; + + ChangeDnsConfig(CreateValidDnsConfig()); + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kOff; + resolver_->SetDnsConfigOverrides(overrides); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + HostResolver::ResolveHostParameters parameters; + parameters.dns_query_type = DnsQueryType::PTR; + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + parameters, resolve_context_.get(), resolve_context_->host_cache())); + // No non-local work is done, so ERR_DNS_CACHE_MISS is the result. + EXPECT_THAT(response.result_error(), IsError(ERR_DNS_CACHE_MISS)); + EXPECT_FALSE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); +} + // Same as PtrQuery except we specify DNS HostResolverSource instead of relying // on automatic determination. Expect same results since DNS should be what we // automatically determine, but some slightly different logic paths are @@ -8970,6 +9050,32 @@ EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); } +TEST_F(HostResolverManagerDnsTest, + SrvInsecureQueryDisallowedWhenAdditionalTypesDisallowed) { + const std::string kName = "srv.test"; + + ChangeDnsConfig(CreateValidDnsConfig()); + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kOff; + resolver_->SetDnsConfigOverrides(overrides); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + HostResolver::ResolveHostParameters parameters; + parameters.dns_query_type = DnsQueryType::SRV; + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + parameters, resolve_context_.get(), resolve_context_->host_cache())); + // No non-local work is done, so ERR_DNS_CACHE_MISS is the result. + EXPECT_THAT(response.result_error(), IsError(ERR_DNS_CACHE_MISS)); + EXPECT_FALSE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); +} + // Same as SrvQuery except we specify DNS HostResolverSource instead of relying // on automatic determination. Expect same results since DNS should be what we // automatically determine, but some slightly different logic paths are @@ -9049,6 +9155,101 @@ EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); } +TEST_F(HostResolverManagerDnsTest, + HttpsInsecureQueryDisallowedWhenAdditionalTypesDisallowed) { + const std::string kName = "https.test"; + + ChangeDnsConfig(CreateValidDnsConfig()); + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kOff; + resolver_->SetDnsConfigOverrides(overrides); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + HostResolver::ResolveHostParameters parameters; + parameters.dns_query_type = DnsQueryType::HTTPS; + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + parameters, resolve_context_.get(), resolve_context_->host_cache())); + // No non-local work is done, so ERR_DNS_CACHE_MISS is the result. + EXPECT_THAT(response.result_error(), IsError(ERR_DNS_CACHE_MISS)); + EXPECT_FALSE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); +} + +TEST_F(HostResolverManagerDnsTest, + HttpsSecureQueryAllowedWhenAdditionalTypesDisallowed) { + const std::string kName = "https.test"; + + MockDnsClientRuleList rules; + std::vector<DnsResourceRecord> records = { + BuildTestHttpsAliasRecord(kName, "alias.test")}; + rules.emplace_back(kName, dns_protocol::kTypeHttps, /*secure=*/true, + MockDnsClientRule::Result(BuildTestDnsResponse( + kName, dns_protocol::kTypeHttps, records)), + /*delay=*/false); + + CreateResolver(); + UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kSecure; + resolver_->SetDnsConfigOverrides(overrides); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + HostResolver::ResolveHostParameters parameters; + parameters.dns_query_type = DnsQueryType::HTTPS; + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + parameters, resolve_context_.get(), resolve_context_->host_cache())); + // Experimental type, so does not affect overall result. + EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED)); + EXPECT_FALSE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + // Results never saved when overall result not OK. + EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); +} + +TEST_F(HostResolverManagerDnsTest, + HttpsFallbackQueryDisallowedWhenAdditionalTypesDisallowed) { + const char kName[] = "https.test"; + + MockDnsClientRuleList rules; + rules.emplace_back(kName, dns_protocol::kTypeHttps, /*secure=*/true, + MockDnsClientRule::Result(MockDnsClientRule::FAIL), + /*delay=*/false); + // No expected HTTPS request in insecure mode. + + CreateResolver(); + UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kAutomatic; + resolver_->SetDnsConfigOverrides(overrides); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + HostResolver::ResolveHostParameters parameters; + parameters.dns_query_type = DnsQueryType::HTTPS; + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + parameters, resolve_context_.get(), resolve_context_->host_cache())); + + EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED)); + EXPECT_FALSE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); +} + // Test that HTTPS records can be extracted from a response that also contains // unrecognized record types. TEST_F(HostResolverManagerDnsTest, HttpsQuery_MixedWithUnrecognizedType) { @@ -9417,6 +9618,36 @@ EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); } +// Same as HttpsInsecureQueryDisallowedWhenAdditionalTypesDisallowed except we +// specify DNS HostResolverSource instead of relying on automatic determination. +// Expect same results since DNS should be what we automatically determine, but +// some slightly different logic paths are involved. +TEST_F(HostResolverManagerDnsTest, + HttpsDnsInsecureQueryDisallowedWhenAdditionalTypesDisallowed) { + const std::string kName = "https.test"; + + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kOff; + resolver_->SetDnsConfigOverrides(overrides); + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + HostResolver::ResolveHostParameters parameters; + parameters.source = HostResolverSource::DNS; + parameters.dns_query_type = DnsQueryType::HTTPS; + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + parameters, resolve_context_.get(), resolve_context_->host_cache())); + // No non-local work is done, so ERR_DNS_CACHE_MISS is the result. + EXPECT_THAT(response.result_error(), IsError(ERR_DNS_CACHE_MISS)); + EXPECT_FALSE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); +} + TEST_F(HostResolverManagerDnsTest, HttpsInAddressQuery) { const char kName[] = "combined.test"; @@ -9779,22 +10010,25 @@ testing::Optional(testing::ElementsAre(true))); } -TEST_F(HostResolverManagerDnsTest, HttpsInAddressQuery_Insecure) { +TEST_F(HostResolverManagerDnsTest, + HttpsInInsecureAddressQueryDisallowedWhenInsecureFeatureDisabled) { const char kName[] = "combined.test"; base::test::ScopedFeatureList features; features.InitAndEnableFeatureWithParameters( - features::kDnsHttpssvc, {{"DnsHttpssvcUseHttpssvc", "true"}, - {"DnsHttpssvcExperimentDomains", kName}}); + features::kDnsHttpssvc, + {{"DnsHttpssvcUseHttpssvc", "true"}, + {"DnsHttpssvcExperimentDomains", kName}, + {"DnsHttpssvcEnableQueryOverInsecure", "false"}}); MockDnsClientRuleList rules; // No expected HTTPS request in insecure mode. - rules.emplace_back(kName, dns_protocol::kTypeA, false /* secure */, + rules.emplace_back(kName, dns_protocol::kTypeA, /*secure=*/false, MockDnsClientRule::Result(MockDnsClientRule::OK), - false /* delay */); - rules.emplace_back(kName, dns_protocol::kTypeAAAA, false /* secure */, + /*delay=*/false); + rules.emplace_back(kName, dns_protocol::kTypeAAAA, /*secure=*/false, MockDnsClientRule::Result(MockDnsClientRule::OK), - false /* delay */); + /*delay=*/false); CreateResolver(); UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); @@ -9813,6 +10047,197 @@ EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); } +TEST_F(HostResolverManagerDnsTest, + HttpsInInsecureAddressQueryAllowedWhenInsecureFeatureEnabled) { + const char kName[] = "combined.test"; + + base::test::ScopedFeatureList features; + features.InitAndEnableFeatureWithParameters( + features::kDnsHttpssvc, {{"DnsHttpssvcUseHttpssvc", "true"}, + {"DnsHttpssvcExperimentDomains", kName}, + {"DnsHttpssvcEnableQueryOverInsecure", "true"}}); + + MockDnsClientRuleList rules; + std::vector<DnsResourceRecord> records = { + BuildTestHttpsAliasRecord(kName, "alias.test")}; + rules.emplace_back(kName, dns_protocol::kTypeHttps, /*secure=*/false, + MockDnsClientRule::Result(BuildTestDnsResponse( + kName, dns_protocol::kTypeHttps, records)), + /*delay=*/false); + rules.emplace_back(kName, dns_protocol::kTypeA, /*secure=*/false, + MockDnsClientRule::Result(MockDnsClientRule::OK), + /*delay=*/false); + rules.emplace_back(kName, dns_protocol::kTypeAAAA, /*secure=*/false, + MockDnsClientRule::Result(MockDnsClientRule::OK), + /*delay=*/false); + + CreateResolver(); + UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kOff; + resolver_->SetDnsConfigOverrides(overrides); + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + /*optional_parameters=*/base::nullopt, resolve_context_.get(), + resolve_context_->host_cache())); + + EXPECT_THAT(response.result_error(), IsOk()); + EXPECT_TRUE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_THAT(response.request()->GetExperimentalResultsForTesting(), + testing::Optional(testing::ElementsAre(true))); +} + +TEST_F(HostResolverManagerDnsTest, + HttpsInInsecureAddressQueryDisallowedWhenAdditionalTypesDisallowed) { + const char kName[] = "combined.test"; + + base::test::ScopedFeatureList features; + features.InitAndEnableFeatureWithParameters( + features::kDnsHttpssvc, {{"DnsHttpssvcUseHttpssvc", "true"}, + {"DnsHttpssvcExperimentDomains", kName}, + {"DnsHttpssvcEnableQueryOverInsecure", "true"}}); + + MockDnsClientRuleList rules; + // Use a delayed rule to hang if an unexpected HTTPS query is made. Allows the + // test to fail on unexpected query whether or not HTTPS query errors are + // ignored. + rules.emplace_back(kName, dns_protocol::kTypeHttps, /*secure=*/false, + MockDnsClientRule::Result(MockDnsClientRule::FAIL), + /*delay=*/true); + rules.emplace_back(kName, dns_protocol::kTypeA, /*secure=*/false, + MockDnsClientRule::Result(MockDnsClientRule::OK), + /*delay=*/false); + rules.emplace_back(kName, dns_protocol::kTypeAAAA, /*secure=*/false, + MockDnsClientRule::Result(MockDnsClientRule::OK), + /*delay=*/false); + + CreateResolver(); + UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kOff; + resolver_->SetDnsConfigOverrides(overrides); + + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + /*optional_parameters=*/base::nullopt, resolve_context_.get(), + resolve_context_->host_cache())); + + EXPECT_THAT(response.result_error(), IsOk()); + EXPECT_TRUE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); +} + +TEST_F(HostResolverManagerDnsTest, + HttpsInSecureAddressQueryAllowedWhenAdditionalQueriesDisallowed) { + const char kName[] = "combined.test"; + + base::test::ScopedFeatureList features; + features.InitAndEnableFeatureWithParameters( + features::kDnsHttpssvc, {{"DnsHttpssvcUseHttpssvc", "true"}, + {"DnsHttpssvcExperimentDomains", kName}, + {"DnsHttpssvcEnableQueryOverInsecure", "true"}}); + + MockDnsClientRuleList rules; + std::vector<DnsResourceRecord> records = { + BuildTestHttpsAliasRecord(kName, "alias.test")}; + rules.emplace_back(kName, dns_protocol::kTypeHttps, /*secure=*/true, + MockDnsClientRule::Result(BuildTestDnsResponse( + kName, dns_protocol::kTypeHttps, records)), + /*delay=*/false); + rules.emplace_back(kName, dns_protocol::kTypeA, /*secure=*/true, + MockDnsClientRule::Result(MockDnsClientRule::OK), + /*delay=*/false); + rules.emplace_back(kName, dns_protocol::kTypeAAAA, /*secure=*/true, + MockDnsClientRule::Result(MockDnsClientRule::OK), + /*delay=*/false); + + CreateResolver(); + UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kSecure; + resolver_->SetDnsConfigOverrides(overrides); + + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + /*optional_parameters=*/base::nullopt, resolve_context_.get(), + resolve_context_->host_cache())); + + EXPECT_THAT(response.result_error(), IsOk()); + EXPECT_TRUE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_THAT(response.request()->GetExperimentalResultsForTesting(), + testing::Optional(testing::ElementsAre(true))); +} + +TEST_F(HostResolverManagerDnsTest, + HttpsInAddressFallbackWhenAdditionalQueriesDisallowedIsDisallowed) { + const char kName[] = "combined.test"; + + base::test::ScopedFeatureList features; + features.InitAndEnableFeatureWithParameters( + features::kDnsHttpssvc, {{"DnsHttpssvcUseHttpssvc", "true"}, + {"DnsHttpssvcExperimentDomains", kName}, + {"DnsHttpssvcEnableQueryOverInsecure", "true"}}); + + MockDnsClientRuleList rules; + rules.emplace_back(kName, dns_protocol::kTypeHttps, /*secure=*/true, + MockDnsClientRule::Result(MockDnsClientRule::FAIL), + /*delay=*/false); + rules.emplace_back(kName, dns_protocol::kTypeA, /*secure=*/true, + MockDnsClientRule::Result(MockDnsClientRule::FAIL), + /*delay=*/false); + rules.emplace_back(kName, dns_protocol::kTypeAAAA, /*secure=*/true, + MockDnsClientRule::Result(MockDnsClientRule::FAIL), + /*delay=*/false); + // Use a delayed rule to hang if an unexpected HTTPS query is made. Allows the + // test to fail on unexpected query whether or not HTTPS query errors are + // ignored. + rules.emplace_back(kName, dns_protocol::kTypeHttps, /*secure=*/false, + MockDnsClientRule::Result(MockDnsClientRule::FAIL), + /*delay=*/true); + rules.emplace_back(kName, dns_protocol::kTypeA, /*secure=*/false, + MockDnsClientRule::Result(MockDnsClientRule::OK), + /*delay=*/false); + rules.emplace_back(kName, dns_protocol::kTypeAAAA, /*secure=*/false, + MockDnsClientRule::Result(MockDnsClientRule::OK), + /*delay=*/false); + + CreateResolver(); + UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); + DnsConfigOverrides overrides; + overrides.secure_dns_mode = SecureDnsMode::kAutomatic; + resolver_->SetDnsConfigOverrides(overrides); + + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + ResolveHostResponseHelper response(resolver_->CreateRequest( + HostPortPair(kName, 108), NetworkIsolationKey(), NetLogWithSource(), + /*optional_parameters=*/base::nullopt, resolve_context_.get(), + resolve_context_->host_cache())); + + EXPECT_THAT(response.result_error(), IsOk()); + EXPECT_TRUE(response.request()->GetAddressResults()); + EXPECT_FALSE(response.request()->GetTextResults()); + EXPECT_FALSE(response.request()->GetHostnameResults()); + EXPECT_FALSE(response.request()->GetExperimentalResultsForTesting()); +} + TEST_F(HostResolverManagerDnsTest, HttpsInAddressQuery_ExperimentalTimeout) { const char kName[] = "combined.test"; const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(2);
diff --git a/remoting/host/installer/linux/BUILD.gn b/remoting/host/installer/linux/BUILD.gn index 397b4d4..22ab53a 100644 --- a/remoting/host/installer/linux/BUILD.gn +++ b/remoting/host/installer/linux/BUILD.gn
@@ -67,6 +67,7 @@ ] deps = [ + "//remoting/host:remote_open_url", "//remoting/host:remoting_me2me_host", "//remoting/host:remoting_native_messaging_host", "//remoting/host:remoting_native_messaging_manifests",
diff --git a/remoting/host/installer/linux/Makefile b/remoting/host/installer/linux/Makefile index bbdfa7f..e0468d4 100644 --- a/remoting/host/installer/linux/Makefile +++ b/remoting/host/installer/linux/Makefile
@@ -27,6 +27,8 @@ ME2ME_NM_DEBUGFILE = $(ME2ME_NM_PROGNAME).debug REMOTE_ASSISTANCE_PROGNAME = $(BUILD_DIR)/remote_assistance_host REMOTE_ASSISTANCE_DEBUGFILE = $(REMOTE_ASSISTANCE_PROGNAME).debug +REMOTE_OPEN_URL_PROGNAME = $(BUILD_DIR)/remote_open_url +REMOTE_OPEN_URL_DEBUGFILE = $(REMOTE_OPEN_URL_PROGNAME).debug all: @@ -81,6 +83,11 @@ eu-strip -f "$(REMOTE_ASSISTANCE_DEBUGFILE)" \ "$(INSTALL_DIR)/remote-assistance-host" + install "$(REMOTE_OPEN_URL_PROGNAME)" \ + "$(INSTALL_DIR)/remote-open-url" + eu-strip -f "$(REMOTE_OPEN_URL_DEBUGFILE)" \ + "$(INSTALL_DIR)/remote-open-url" + install -m 0644 \ "$(BUILD_DIR)/icudtl.dat" "$(INSTALL_DIR)/icudtl.dat"
diff --git a/remoting/host/linux/BUILD.gn b/remoting/host/linux/BUILD.gn index fd97518..10ae674 100644 --- a/remoting/host/linux/BUILD.gn +++ b/remoting/host/linux/BUILD.gn
@@ -58,6 +58,7 @@ ":remoting_me2me_host_copy_user_session", ":remoting_me2me_host_copy_user_session_wrapper", ":remoting_native_messaging_host", + "//remoting/host:remote_open_url", "//remoting/host:remoting_me2me_host", ] }
diff --git a/services/network/host_resolver.cc b/services/network/host_resolver.cc index 1711176..0168bde 100644 --- a/services/network/host_resolver.cc +++ b/services/network/host_resolver.cc
@@ -9,15 +9,20 @@ #include "base/bind.h" #include "base/lazy_instance.h" #include "base/optional.h" +#include "mojo/public/cpp/bindings/enum_traits.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" #include "net/dns/host_resolver.h" #include "net/dns/host_resolver_source.h" +#include "net/dns/public/secure_dns_mode.h" +#include "net/dns/public/secure_dns_policy.h" #include "net/log/net_log.h" #include "net/net_buildflags.h" #include "services/network/host_resolver_mdns_listener.h" #include "services/network/public/cpp/host_resolver_mojom_traits.h" +#include "services/network/public/mojom/host_resolver.mojom-shared.h" +#include "services/network/public/mojom/host_resolver.mojom.h" #include "services/network/resolve_host_request.h" namespace network { @@ -54,8 +59,15 @@ parameters.include_canonical_name = mojo_parameters->include_canonical_name; parameters.loopback_only = mojo_parameters->loopback_only; parameters.is_speculative = mojo_parameters->is_speculative; - parameters.secure_dns_mode_override = mojo::FromOptionalSecureDnsMode( - mojo_parameters->secure_dns_mode_override); + + // TODO(crbug.com/1200908): Pass the SecureDnsPolicy through unmodified. + net::SecureDnsPolicy secure_dns_policy; + mojo::EnumTraits<mojom::SecureDnsPolicy, net::SecureDnsPolicy>::FromMojom( + mojo_parameters->secure_dns_policy, &secure_dns_policy); + + if (secure_dns_policy == net::SecureDnsPolicy::kDisable) { + parameters.secure_dns_mode_override = net::SecureDnsMode::kOff; + } return parameters; } } // namespace
diff --git a/services/network/host_resolver_unittest.cc b/services/network/host_resolver_unittest.cc index 370e39c0..4f592c68 100644 --- a/services/network/host_resolver_unittest.cc +++ b/services/network/host_resolver_unittest.cc
@@ -33,6 +33,7 @@ #include "net/dns/public/secure_dns_mode.h" #include "net/log/net_log.h" #include "net/net_buildflags.h" +#include "net/test/gtest_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -715,8 +716,8 @@ mojom::ResolveHostParametersPtr optional_parameters = mojom::ResolveHostParameters::New(); - optional_parameters->secure_dns_mode_override = - network::mojom::OptionalSecureDnsMode::SECURE; + optional_parameters->secure_dns_policy = + network::mojom::SecureDnsPolicy::DISABLE; base::RunLoop run_loop; mojo::PendingRemote<mojom::ResolveHostClient> pending_response_client; @@ -730,7 +731,7 @@ EXPECT_EQ(net::OK, response_client.result_error()); EXPECT_THAT(response_client.result_addresses().value().endpoints(), testing::ElementsAre(CreateExpectedEndPoint("127.0.0.1", 80))); - EXPECT_EQ(net::SecureDnsMode::kSecure, + EXPECT_EQ(net::SecureDnsMode::kOff, inner_resolver->last_secure_dns_mode_override().value()); } @@ -1292,7 +1293,9 @@ net::HostResolver::CreateStandaloneContextResolver(net::NetLog::Get()); inner_resolver->GetManagerForTesting()->SetDnsClientForTesting( std::move(dns_client)); - inner_resolver->GetManagerForTesting()->SetInsecureDnsClientEnabled(true); + inner_resolver->GetManagerForTesting()->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/true); HostResolver resolver(inner_resolver.get(), net::NetLog::Get()); @@ -1331,7 +1334,9 @@ net::HostResolver::CreateStandaloneContextResolver(net::NetLog::Get()); inner_resolver->GetManagerForTesting()->SetDnsClientForTesting( std::move(dns_client)); - inner_resolver->GetManagerForTesting()->SetInsecureDnsClientEnabled(true); + inner_resolver->GetManagerForTesting()->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/true); HostResolver resolver(inner_resolver.get(), net::NetLog::Get()); @@ -1357,6 +1362,40 @@ EXPECT_EQ(0u, resolver.GetNumOutstandingRequestsForTesting()); } +TEST_F(HostResolverTest, RespectsDisablingAdditionalQueryTypes) { + net::MockDnsClientRuleList rules; + auto dns_client = std::make_unique<net::MockDnsClient>(CreateValidDnsConfig(), + std::move(rules)); + dns_client->set_ignore_system_config_changes(true); + + std::unique_ptr<net::ContextHostResolver> inner_resolver = + net::HostResolver::CreateStandaloneContextResolver(net::NetLog::Get()); + inner_resolver->GetManagerForTesting()->SetDnsClientForTesting( + std::move(dns_client)); + inner_resolver->GetManagerForTesting()->SetInsecureDnsClientEnabled( + /*enabled=*/true, + /*additional_dns_types_enabled=*/false); + + HostResolver resolver(inner_resolver.get(), net::NetLog::Get()); + + base::RunLoop run_loop; + mojom::ResolveHostParametersPtr optional_parameters = + mojom::ResolveHostParameters::New(); + optional_parameters->dns_query_type = net::DnsQueryType::PTR; + mojo::PendingRemote<mojom::ResolveHostClient> pending_response_client; + TestResolveHostClient response_client(&pending_response_client, &run_loop); + + resolver.ResolveHost( + net::HostPortPair("example.com", 160), net::NetworkIsolationKey(), + std::move(optional_parameters), std::move(pending_response_client)); + run_loop.Run(); + + // No queries made, so result is `ERR_DNS_CACHE_MISS`. + EXPECT_THAT(response_client.result_error(), + net::test::IsError(net::ERR_DNS_CACHE_MISS)); + EXPECT_EQ(0u, resolver.GetNumOutstandingRequestsForTesting()); +} + #if BUILDFLAG(ENABLE_MDNS) TEST_F(HostResolverTest, MdnsListener_AddressResult) { auto inner_resolver = std::make_unique<net::MockHostResolver>();
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index eeadeb1..482d6022 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -1397,6 +1397,8 @@ // now, much easier to create entirely separate net::HostResolver instances. net::HostResolver::ManagerOptions options; options.insecure_dns_client_enabled = true; + // Assume additional types are unnecessary for these special cases. + options.additional_types_via_insecure_dns_enabled = false; options.dns_config_overrides = config_overrides.value(); private_internal_resolver = network_service_->host_resolver_factory()->CreateStandaloneResolver(
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc index 9684d3d..e64e7ec 100644 --- a/services/network/network_context_unittest.cc +++ b/services/network/network_context_unittest.cc
@@ -3812,7 +3812,8 @@ false /* delay */); auto mock_dns_client = std::make_unique<net::MockDnsClient>( base_configuration, std::move(rules)); - mock_dns_client->SetInsecureEnabled(true); + mock_dns_client->SetInsecureEnabled(/*enabled=*/true, + /*additional_types_enabled=*/false); mock_dns_client->set_ignore_system_config_changes(true); auto* mock_dns_client_ptr = mock_dns_client.get(); internal_resolver->GetManagerForTesting()->SetDnsClientForTesting(
diff --git a/services/network/network_service.cc b/services/network/network_service.cc index 92d2597..28cf047 100644 --- a/services/network/network_service.cc +++ b/services/network/network_service.cc
@@ -481,8 +481,10 @@ // Enable or disable the insecure part of DnsClient. "DnsClient" is the class // that implements the stub resolver. + // TODO(crbug.com/1203427): Pass the additional query types param through Mojo + // from the browser code. host_resolver_manager_->SetInsecureDnsClientEnabled( - insecure_dns_client_enabled); + insecure_dns_client_enabled, true); // Configure DNS over HTTPS. net::DnsConfigOverrides overrides;
diff --git a/services/network/public/cpp/host_resolver_mojom_traits.cc b/services/network/public/cpp/host_resolver_mojom_traits.cc index 37b8a86b..cec8c59 100644 --- a/services/network/public/cpp/host_resolver_mojom_traits.cc +++ b/services/network/public/cpp/host_resolver_mojom_traits.cc
@@ -6,6 +6,8 @@ #include "mojo/public/cpp/base/time_mojom_traits.h" #include "net/dns/public/dns_over_https_server_config.h" +#include "net/dns/public/secure_dns_mode.h" +#include "net/dns/public/secure_dns_policy.h" #include "services/network/public/cpp/ip_address_mojom_traits.h" #include "services/network/public/cpp/ip_endpoint_mojom_traits.h" #include "services/network/public/mojom/host_resolver.mojom.h" @@ -337,8 +339,6 @@ case net::SecureDnsMode::kSecure: return network::mojom::SecureDnsMode::SECURE; } - NOTREACHED(); - return network::mojom::SecureDnsMode::OFF; } // static @@ -356,7 +356,31 @@ *out = net::SecureDnsMode::kSecure; return true; } - return false; +} + +// static +network::mojom::SecureDnsPolicy +EnumTraits<network::mojom::SecureDnsPolicy, net::SecureDnsPolicy>::ToMojom( + net::SecureDnsPolicy secure_dns_mode) { + switch (secure_dns_mode) { + case net::SecureDnsPolicy::kAllow: + return network::mojom::SecureDnsPolicy::ALLOW; + case net::SecureDnsPolicy::kDisable: + return network::mojom::SecureDnsPolicy::DISABLE; + } +} + +// static +bool EnumTraits<network::mojom::SecureDnsPolicy, net::SecureDnsPolicy>:: + FromMojom(network::mojom::SecureDnsPolicy in, net::SecureDnsPolicy* out) { + switch (in) { + case network::mojom::SecureDnsPolicy::ALLOW: + *out = net::SecureDnsPolicy::kAllow; + return true; + case network::mojom::SecureDnsPolicy::DISABLE: + *out = net::SecureDnsPolicy::kDisable; + return true; + } } // static
diff --git a/services/network/public/cpp/host_resolver_mojom_traits.h b/services/network/public/cpp/host_resolver_mojom_traits.h index 4b3a9d9..4aed6e74 100644 --- a/services/network/public/cpp/host_resolver_mojom_traits.h +++ b/services/network/public/cpp/host_resolver_mojom_traits.h
@@ -22,6 +22,7 @@ #include "net/dns/public/dns_config_overrides.h" #include "net/dns/public/dns_query_type.h" #include "net/dns/public/secure_dns_mode.h" +#include "net/dns/public/secure_dns_policy.h" #include "services/network/public/mojom/host_resolver.mojom-forward.h" #include "services/network/public/mojom/host_resolver.mojom-shared.h" @@ -123,6 +124,14 @@ }; template <> +struct EnumTraits<network::mojom::SecureDnsPolicy, net::SecureDnsPolicy> { + static network::mojom::SecureDnsPolicy ToMojom( + net::SecureDnsPolicy secure_dns_mode); + static bool FromMojom(network::mojom::SecureDnsPolicy in, + net::SecureDnsPolicy* out); +}; + +template <> class StructTraits<network::mojom::ResolveErrorInfoDataView, net::ResolveErrorInfo> { public:
diff --git a/services/network/public/mojom/host_resolver.mojom b/services/network/public/mojom/host_resolver.mojom index 19da4d5..f5231d8 100644 --- a/services/network/public/mojom/host_resolver.mojom +++ b/services/network/public/mojom/host_resolver.mojom
@@ -40,6 +40,12 @@ SECURE, }; +// This enum corresponds to net::SecureDnsPolicy +enum SecureDnsPolicy { + ALLOW, + DISABLE, +}; + // Overridable DNS configuration values for host resolution. All fields default // to a non-overriding state where the relevant value will be used from system // DNS configuration. @@ -83,8 +89,9 @@ // (https://tools.ietf.org/id/draft-ietf-doh-dns-over-https-12.txt). array<DnsOverHttpsServer>? dns_over_https_servers; - // The default SecureDnsMode to use when resolving queries. It can be - // for individual requests such as requests to resolve a DoH server hostname. + // The SecureDnsMode to use when resolving queries. If set, it overrides + // the resolver's current configured mode, and can in turn be overridden by + // ResolveHostParameters.secure_dns_policy. OptionalSecureDnsMode secure_dns_mode = OptionalSecureDnsMode.NO_OVERRIDE; // Whether automatic upgrade to DNS over HTTPS servers is permitted. @@ -244,9 +251,8 @@ // ResolveHostClient::OnComplete will not receive any addresses. bool is_speculative = false; - // Set to override the resolver's default secure dns mode for this request. - OptionalSecureDnsMode secure_dns_mode_override = - OptionalSecureDnsMode.NO_OVERRIDE; + // Controls the resolver's Secure DNS behavior for this request. + SecureDnsPolicy secure_dns_policy = SecureDnsPolicy.ALLOW; }; // Response interface used to receive notifications from
diff --git a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter index 52b2c6f..e83cb35 100644 --- a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter +++ b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter
@@ -25,6 +25,7 @@ -All/WizardControllerDeviceStateExplicitRequirementTest.* -All/WizardControllerUpdateAfterCompletedOobeTest.* -AppDownloadingScreenTest.* +-AutoLaunchedKioskEphemeralUsersTest.* -ArcTermsOfServiceScreenTest.* -AssistantOptInFlowTest.* -AutoEnrollmentLocalPolicyServer.*
diff --git a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter index af6f465..8d3dc99e4 100644 --- a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter +++ b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter
@@ -25,6 +25,7 @@ All/WizardControllerDeviceStateExplicitRequirementTest.* All/WizardControllerUpdateAfterCompletedOobeTest.* AppDownloadingScreenTest.* +AutoLaunchedKioskEphemeralUsersTest.* ArcTermsOfServiceScreenTest.* AssistantOptInFlowTest.* AutoEnrollmentLocalPolicyServer.*
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index a2a3177..b73b2cdf 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -876,6 +876,21 @@ ] } ], + "AutofillDownstreamCvcPromptUseGooglePayLogo": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "AutofillDownstreamCvcPromptUseGooglePayLogo", + "enable_features": [ + "AutofillDownstreamCvcPromptUseGooglePayLogo" + ] + } + ] + } + ], "AutofillEnableAugmentedPhoneCountryCode": [ { "platforms": [ @@ -3919,6 +3934,21 @@ ] } ], + "IOSUMABackgroundSessions": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "IOSUMABackgroundSessions" + ] + } + ] + } + ], "IdentifiabilityStudy": [ { "platforms": [ @@ -6826,6 +6856,23 @@ ] } ], + "SignInProfileCreationEnterprise": [ + { + "platforms": [ + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "SignInProfileCreationEnterprise" + ] + } + ] + } + ], "SimplifiedUrlDisplay": [ { "platforms": [ @@ -8286,6 +8333,26 @@ ] } ], + "WebRTC-PreStreamDecoders": [ + { + "platforms": [ + "windows", + "mac", + "chromeos", + "chromeos_lacros", + "linux", + "ios", + "android", + "android_weblayer", + "android_webview" + ], + "experiments": [ + { + "name": "max:0,_V1" + } + ] + } + ], "WebRTC-TaskQueuePacer": [ { "platforms": [
diff --git a/third_party/abseil-cpp/CMake/AbseilHelpers.cmake b/third_party/abseil-cpp/CMake/AbseilHelpers.cmake index 1f75439..1a80b5b4 100644 --- a/third_party/abseil-cpp/CMake/AbseilHelpers.cmake +++ b/third_party/abseil-cpp/CMake/AbseilHelpers.cmake
@@ -141,7 +141,8 @@ endif() # Generate a pkg-config file for every library: - if(_build_type STREQUAL "static" OR _build_type STREQUAL "shared") + if((_build_type STREQUAL "static" OR _build_type STREQUAL "shared") + AND ABSL_ENABLE_INSTALL) if(NOT ABSL_CC_LIB_TESTONLY) if(absl_VERSION) set(PC_VERSION "${absl_VERSION}")
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium index 57d8d56b..2ec53aa 100644 --- a/third_party/abseil-cpp/README.chromium +++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@ License: Apache 2.0 License File: LICENSE Version: 0 -Revision: bcc11a8918f8cc9b43c9a0dc5da7b52d48452bd3 +Revision: a9831f1cbf93fb18dd951453635f488037454ce9 Security Critical: yes Description:
diff --git a/third_party/abseil-cpp/absl/base/attributes.h b/third_party/abseil-cpp/absl/base/attributes.h index d710f28..5213955 100644 --- a/third_party/abseil-cpp/absl/base/attributes.h +++ b/third_party/abseil-cpp/absl/base/attributes.h
@@ -599,31 +599,24 @@ // case 42: // ... // -// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED -// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed -// when performing switch labels fall-through diagnostic -// (`-Wimplicit-fallthrough`). See clang documentation on language extensions -// for details: +// Notes: When supported, GCC and Clang can issue a warning on switch labels +// with unannotated fallthrough using the warning `-Wimplicit-fallthrough`. See +// clang documentation on language extensions for details: // https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough // -// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro -// has no effect on diagnostics. In any case this macro has no effect on runtime +// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro has +// no effect on diagnostics. In any case this macro has no effect on runtime // behavior and performance of code. #ifdef ABSL_FALLTHROUGH_INTENDED #error "ABSL_FALLTHROUGH_INTENDED should not be defined." -#endif - -// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported. -#if defined(__clang__) && defined(__has_warning) -#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") +#elif ABSL_HAVE_CPP_ATTRIBUTE(fallthrough) +#define ABSL_FALLTHROUGH_INTENDED [[fallthrough]] +#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::fallthrough) #define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]] -#endif -#elif ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(7, 0) +#elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::fallthrough) #define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]] -#endif - -#ifndef ABSL_FALLTHROUGH_INTENDED +#else #define ABSL_FALLTHROUGH_INTENDED \ do { \ } while (0)
diff --git a/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc index e458a795..689e597 100644 --- a/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc +++ b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
@@ -136,7 +136,8 @@ #else const size_t page_mask = sysconf(_SC_PAGESIZE) - 1; #endif - size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask; + size_t stack_size = + (std::max<size_t>(SIGSTKSZ, 65536) + page_mask) & ~page_mask; #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) // Account for sanitizer instrumentation requiring additional stack space.
diff --git a/third_party/abseil-cpp/absl/memory/memory.h b/third_party/abseil-cpp/absl/memory/memory.h index 2b5ff623..d6332606 100644 --- a/third_party/abseil-cpp/absl/memory/memory.h +++ b/third_party/abseil-cpp/absl/memory/memory.h
@@ -420,7 +420,7 @@ // // A C++11 compatible implementation of C++17's std::allocator_traits. // -#if __cplusplus >= 201703L +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) using std::allocator_traits; #else // __cplusplus >= 201703L template <typename Alloc>
diff --git a/third_party/abseil-cpp/absl/meta/type_traits.h b/third_party/abseil-cpp/absl/meta/type_traits.h index b5427a4..e7c1239 100644 --- a/third_party/abseil-cpp/absl/meta/type_traits.h +++ b/third_party/abseil-cpp/absl/meta/type_traits.h
@@ -634,7 +634,7 @@ namespace type_traits_internal { -#if __cplusplus >= 201703L +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) // std::result_of is deprecated (C++17) or removed (C++20) template<typename> struct result_of; template<typename F, typename... Args>
diff --git a/third_party/abseil-cpp/absl/strings/BUILD.bazel b/third_party/abseil-cpp/absl/strings/BUILD.bazel index 68c71f0..15277de 100644 --- a/third_party/abseil-cpp/absl/strings/BUILD.bazel +++ b/third_party/abseil-cpp/absl/strings/BUILD.bazel
@@ -529,6 +529,7 @@ ":cord", ":cord_internal", ":strings", + "//absl/base:config", ], ) @@ -544,6 +545,7 @@ ":cordz_sample_token", ":cordz_statistics", ":cordz_update_tracker", + ":strings", "//absl/base:config", "//absl/base:core_headers", "@com_google_googletest//:gtest",
diff --git a/third_party/abseil-cpp/absl/strings/BUILD.gn b/third_party/abseil-cpp/absl/strings/BUILD.gn index 435f4a90..ff1a9046 100644 --- a/third_party/abseil-cpp/absl/strings/BUILD.gn +++ b/third_party/abseil-cpp/absl/strings/BUILD.gn
@@ -352,6 +352,7 @@ ":cord", ":cord_internal", ":strings", + "//third_party/abseil-cpp/absl/base:config", ] } @@ -365,6 +366,7 @@ ":cordz_sample_token", ":cordz_statistics", ":cordz_update_tracker", + ":strings", "//third_party/abseil-cpp/absl/base:config", "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/googletest:gtest",
diff --git a/third_party/abseil-cpp/absl/strings/CMakeLists.txt b/third_party/abseil-cpp/absl/strings/CMakeLists.txt index 80ae2a6..1750f7a 100644 --- a/third_party/abseil-cpp/absl/strings/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/strings/CMakeLists.txt
@@ -830,6 +830,7 @@ COPTS ${ABSL_TEST_COPTS} DEPS + absl::config absl::cord absl::cord_internal absl::strings @@ -852,6 +853,7 @@ absl::cordz_statistics absl::cordz_update_tracker absl::core_headers + absl::strings TESTONLY )
diff --git a/third_party/abseil-cpp/absl/strings/cord.cc b/third_party/abseil-cpp/absl/strings/cord.cc index 15d1733..1c2ff9f2 100644 --- a/third_party/abseil-cpp/absl/strings/cord.cc +++ b/third_party/abseil-cpp/absl/strings/cord.cc
@@ -56,6 +56,7 @@ using ::absl::cord_internal::CordRepFlat; using ::absl::cord_internal::CordRepRing; using ::absl::cord_internal::CordRepSubstring; +using ::absl::cord_internal::CordzUpdateTracker; using ::absl::cord_internal::InlineData; using ::absl::cord_internal::kMaxFlatLength; using ::absl::cord_internal::kMinFlatLength; @@ -281,6 +282,35 @@ } } +// Creates a CordRep from the provided string. If the string is large enough, +// and not wasteful, we move the string into an external cord rep, preserving +// the already allocated string contents. +// Requires the provided string length to be larger than `kMaxInline`. +static CordRep* CordRepFromString(std::string&& src) { + assert(src.length() > cord_internal::kMaxInline); + if ( + // String is short: copy data to avoid external block overhead. + src.size() <= kMaxBytesToCopy || + // String is wasteful: copy data to avoid pinning too much unused memory. + src.size() < src.capacity() / 2 + ) { + return NewTree(src.data(), src.size(), 0); + } + + struct StringReleaser { + void operator()(absl::string_view /* data */) {} + std::string data; + }; + const absl::string_view original_data = src; + auto* rep = + static_cast<::absl::cord_internal::CordRepExternalImpl<StringReleaser>*>( + absl::cord_internal::NewExternalRep(original_data, + StringReleaser{std::move(src)})); + // Moving src may have invalidated its data pointer, so adjust it. + rep->base = rep->template get<0>().data.data(); + return rep; +} + // -------------------------------------------------------------------- // Cord::InlineRep functions @@ -486,17 +516,17 @@ return true; } if (rep->tag == EXTERNAL) { - *total_mem_usage += sizeof(CordRepConcat) + rep->length; + // We don't know anything about the embedded / bound data, but we can safely + // assume it is 'at least' a word / pointer to data. In the future we may + // choose to use the 'data' byte as a tag to identify the types of some + // well-known externals, such as a std::string instance. + *total_mem_usage += + sizeof(cord_internal::CordRepExternalImpl<intptr_t>) + rep->length; return true; } return false; } -void Cord::InlineRep::UpdateCordzStatisticsSlow() { - CordRep* tree = as_tree(); - data_.cordz_info()->RecordMetrics(tree->length); -} - void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) { assert(&src != this); assert(is_tree() || src.is_tree()); @@ -525,42 +555,24 @@ // -------------------------------------------------------------------- // Constructors and destructors -Cord::Cord(absl::string_view src) : contents_(InlineData::kDefaultInit) { +Cord::Cord(absl::string_view src, MethodIdentifier method) + : contents_(InlineData::kDefaultInit) { const size_t n = src.size(); if (n <= InlineRep::kMaxInline) { contents_.set_data(src.data(), n, true); } else { CordRep* rep = NewTree(src.data(), n, 0); - contents_.EmplaceTree(rep, CordzUpdateTracker::kConstructorString); + contents_.EmplaceTree(rep, method); } } template <typename T, Cord::EnableIfString<T>> -Cord::Cord(T&& src) { - if ( - // String is short: copy data to avoid external block overhead. - src.size() <= kMaxBytesToCopy || - // String is wasteful: copy data to avoid pinning too much unused memory. - src.size() < src.capacity() / 2 - ) { - if (src.size() <= InlineRep::kMaxInline) { - contents_.set_data(src.data(), src.size(), false); - } else { - contents_.set_tree(NewTree(src.data(), src.size(), 0)); - } +Cord::Cord(T&& src) : contents_(InlineData::kDefaultInit) { + if (src.size() <= InlineRep::kMaxInline) { + contents_.set_data(src.data(), src.size(), true); } else { - struct StringReleaser { - void operator()(absl::string_view /* data */) {} - std::string data; - }; - const absl::string_view original_data = src; - auto* rep = static_cast< - ::absl::cord_internal::CordRepExternalImpl<StringReleaser>*>( - absl::cord_internal::NewExternalRep( - original_data, StringReleaser{std::forward<T>(src)})); - // Moving src may have invalidated its data pointer, so adjust it. - rep->base = rep->template get<0>().data.data(); - contents_.set_tree(rep); + CordRep* rep = CordRepFromString(std::forward<T>(src)); + contents_.EmplaceTree(rep, CordzUpdateTracker::kConstructorString); } } @@ -583,42 +595,53 @@ } } +Cord& Cord::AssignLargeString(std::string&& src) { + auto constexpr method = CordzUpdateTracker::kAssignString; + assert(src.size() > kMaxBytesToCopy); + CordRep* rep = CordRepFromString(std::move(src)); + if (CordRep* tree = contents_.tree()) { + CordzUpdateScope scope(contents_.cordz_info(), method); + contents_.SetTree(rep, scope); + CordRep::Unref(tree); + } else { + contents_.EmplaceTree(rep, method); + } + return *this; +} + Cord& Cord::operator=(absl::string_view src) { + auto constexpr method = CordzUpdateTracker::kAssignString; const char* data = src.data(); size_t length = src.size(); CordRep* tree = contents_.tree(); if (length <= InlineRep::kMaxInline) { - // Embed into this->contents_ - if (tree) CordzInfo::MaybeUntrackCord(contents_.cordz_info()); + // Embed into this->contents_, which is somewhat subtle: + // - MaybeUntrackCord must be called before Unref(tree). + // - MaybeUntrackCord must be called before set_data() clobbers cordz_info. + // - set_data() must be called before Unref(tree) as it may reference tree. + if (tree != nullptr) CordzInfo::MaybeUntrackCord(contents_.cordz_info()); contents_.set_data(data, length, true); - if (tree) CordRep::Unref(tree); + if (tree != nullptr) CordRep::Unref(tree); return *this; } - if (tree != nullptr && tree->tag >= FLAT && - tree->flat()->Capacity() >= length && tree->refcount.IsOne()) { - // Copy in place if the existing FLAT node is reusable. - memmove(tree->flat()->Data(), data, length); - tree->length = length; - VerifyTree(tree); - return *this; - } - contents_.set_tree(NewTree(data, length, 0)); - if (tree) CordRep::Unref(tree); - return *this; -} - -template <typename T, Cord::EnableIfString<T>> -Cord& Cord::operator=(T&& src) { - if (src.size() <= kMaxBytesToCopy) { - *this = absl::string_view(src); + if (tree != nullptr) { + CordzUpdateScope scope(contents_.cordz_info(), method); + if (tree->tag >= FLAT && tree->flat()->Capacity() >= length && + tree->refcount.IsOne()) { + // Copy in place if the existing FLAT node is reusable. + memmove(tree->flat()->Data(), data, length); + tree->length = length; + VerifyTree(tree); + return *this; + } + contents_.SetTree(NewTree(data, length, 0), scope); + CordRep::Unref(tree); } else { - *this = Cord(std::forward<T>(src)); + contents_.EmplaceTree(NewTree(data, length, 0), method); } return *this; } -template Cord& Cord::operator=(std::string&& src); - // TODO(sanjay): Move to Cord::InlineRep section of file. For now, // we keep it here to make diffs easier. void Cord::InlineRep::AppendArray(absl::string_view src, @@ -644,10 +667,8 @@ return; } - // It is possible that src.data() == data_, but when we transition from an - // InlineRep to a tree we need to assign data_ = root via set_tree. To - // avoid corrupting the source data before we copy it, delay calling - // set_tree until after we've copied data. + // Note: we don't concern ourselves if src aliases data stored in the + // inlined data of 'this', as we update the InlineData only at the end. // We are going from an inline size to beyond inline size. Make the new size // either double the inlined size, or the added size + 10%. const size_t size1 = inline_length * 2 + src.size(); @@ -753,7 +774,8 @@ if (src.size() <= kMaxBytesToCopy) { Append(absl::string_view(src)); } else { - Append(Cord(std::forward<T>(src))); + CordRep* rep = CordRepFromString(std::forward<T>(src)); + contents_.AppendTree(rep, CordzUpdateTracker::kAppendString); } } @@ -795,7 +817,8 @@ if (src.size() <= kMaxBytesToCopy) { Prepend(absl::string_view(src)); } else { - Prepend(Cord(std::forward<T>(src))); + CordRep* rep = CordRepFromString(std::forward<T>(src)); + contents_.PrependTree(rep, CordzUpdateTracker::kPrependString); } } @@ -893,12 +916,17 @@ CordRep* tree = contents_.tree(); if (tree == nullptr) { contents_.remove_prefix(n); - } else if (tree->tag == RING) { - contents_.replace_tree(CordRepRing::RemovePrefix(tree->ring(), n)); } else { - CordRep* newrep = RemovePrefixFrom(tree, n); - CordRep::Unref(tree); - contents_.replace_tree(VerifyTree(newrep)); + auto constexpr method = CordzUpdateTracker::kRemovePrefix; + CordzUpdateScope scope(contents_.cordz_info(), method); + if (tree->tag == RING) { + tree = CordRepRing::RemovePrefix(tree->ring(), n); + } else { + CordRep* newrep = RemovePrefixFrom(tree, n); + CordRep::Unref(tree); + tree = VerifyTree(newrep); + } + contents_.SetTreeOrEmpty(tree, scope); } } @@ -909,12 +937,17 @@ CordRep* tree = contents_.tree(); if (tree == nullptr) { contents_.reduce_size(n); - } else if (tree->tag == RING) { - contents_.replace_tree(CordRepRing::RemoveSuffix(tree->ring(), n)); } else { - CordRep* newrep = RemoveSuffixFrom(tree, n); - CordRep::Unref(tree); - contents_.replace_tree(VerifyTree(newrep)); + auto constexpr method = CordzUpdateTracker::kRemoveSuffix; + CordzUpdateScope scope(contents_.cordz_info(), method); + if (tree->tag == RING) { + tree = CordRepRing::RemoveSuffix(tree->ring(), n); + } else { + CordRep* newrep = RemoveSuffixFrom(tree, n); + CordRep::Unref(tree); + tree = VerifyTree(newrep); + } + contents_.SetTreeOrEmpty(tree, scope); } } @@ -974,17 +1007,20 @@ size_t length = size(); if (pos > length) pos = length; if (new_size > length - pos) new_size = length - pos; + if (new_size == 0) return sub_cord; + CordRep* tree = contents_.tree(); if (tree == nullptr) { // sub_cord is newly constructed, no need to re-zero-out the tail of // contents_ memory. sub_cord.contents_.set_data(contents_.data() + pos, new_size, false); - } else if (new_size == 0) { - // We want to return empty subcord, so nothing to do. - } else if (new_size <= InlineRep::kMaxInline) { + return sub_cord; + } + + if (new_size <= InlineRep::kMaxInline) { + char* dest = sub_cord.contents_.data_.as_chars(); Cord::ChunkIterator it = chunk_begin(); it.AdvanceBytes(pos); - char* dest = sub_cord.contents_.data_.as_chars(); size_t remaining_size = new_size; while (remaining_size > it->size()) { cord_internal::SmallMemmove(dest, it->data(), it->size()); @@ -994,12 +1030,17 @@ } cord_internal::SmallMemmove(dest, it->data(), remaining_size); sub_cord.contents_.set_inline_size(new_size); - } else if (tree->tag == RING) { - tree = CordRepRing::SubRing(CordRep::Ref(tree)->ring(), pos, new_size); - sub_cord.contents_.set_tree(tree); - } else { - sub_cord.contents_.set_tree(NewSubRange(tree, pos, new_size)); + return sub_cord; } + + if (tree->tag == RING) { + CordRepRing* ring = CordRep::Ref(tree)->ring(); + tree = CordRepRing::SubRing(ring, pos, new_size); + } else { + tree = NewSubRange(tree, pos, new_size); + } + sub_cord.contents_.EmplaceTree(tree, contents_.data_, + CordzUpdateTracker::kSubCord); return sub_cord; } @@ -1441,6 +1482,7 @@ ABSL_HARDENING_ASSERT(bytes_remaining_ >= n && "Attempted to iterate past `end()`"); Cord subcord; + auto constexpr method = CordzUpdateTracker::kCordReader; if (n <= InlineRep::kMaxInline) { // Range to read fits in inline data. Flatten it. @@ -1463,11 +1505,12 @@ if (ring_reader_) { size_t chunk_size = current_chunk_.size(); if (n <= chunk_size && n <= kMaxBytesToCopy) { - subcord = Cord(current_chunk_.substr(0, n)); + subcord = Cord(current_chunk_.substr(0, n), method); } else { auto* ring = CordRep::Ref(ring_reader_.ring())->ring(); size_t offset = ring_reader_.length() - bytes_remaining_; - subcord.contents_.set_tree(CordRepRing::SubRing(ring, offset, n)); + CordRep* rep = CordRepRing::SubRing(ring, offset, n); + subcord.contents_.EmplaceTree(rep, method); } if (n < chunk_size) { bytes_remaining_ -= n; @@ -1486,7 +1529,7 @@ const char* data = subnode->tag == EXTERNAL ? subnode->external()->base : subnode->flat()->Data(); subnode = NewSubstring(subnode, current_chunk_.data() - data, n); - subcord.contents_.set_tree(VerifyTree(subnode)); + subcord.contents_.EmplaceTree(VerifyTree(subnode), method); RemoveChunkPrefix(n); return subcord; } @@ -1529,7 +1572,7 @@ if (node == nullptr) { // We have reached the end of the Cord. assert(bytes_remaining_ == 0); - subcord.contents_.set_tree(VerifyTree(subnode)); + subcord.contents_.EmplaceTree(VerifyTree(subnode), method); return subcord; } @@ -1569,7 +1612,7 @@ current_chunk_ = absl::string_view(data + offset + n, length - n); current_leaf_ = node; bytes_remaining_ -= n; - subcord.contents_.set_tree(VerifyTree(subnode)); + subcord.contents_.EmplaceTree(VerifyTree(subnode), method); return subcord; } @@ -1676,6 +1719,7 @@ } absl::string_view Cord::FlattenSlowPath() { + assert(contents_.is_tree()); size_t total_size = size(); CordRep* new_rep; char* new_buffer; @@ -1696,10 +1740,9 @@ s.size()); }); } - if (CordRep* tree = contents_.tree()) { - CordRep::Unref(tree); - } - contents_.set_tree(new_rep); + CordzUpdateScope scope(contents_.cordz_info(), CordzUpdateTracker::kFlatten); + CordRep::Unref(contents_.as_tree()); + contents_.SetTree(new_rep, scope); return absl::string_view(new_buffer, total_size); }
diff --git a/third_party/abseil-cpp/absl/strings/cord.h b/third_party/abseil-cpp/absl/strings/cord.h index d5a13b34..8abc474 100644 --- a/third_party/abseil-cpp/absl/strings/cord.h +++ b/third_party/abseil-cpp/absl/strings/cord.h
@@ -678,6 +678,10 @@ using InlineData = cord_internal::InlineData; using MethodIdentifier = CordzUpdateTracker::MethodIdentifier; + // Creates a cord instance with `method` representing the originating + // public API call causing the cord to be created. + explicit Cord(absl::string_view src, MethodIdentifier method); + friend class CordTestPeer; friend bool operator==(const Cord& lhs, const Cord& rhs); friend bool operator==(const Cord& lhs, absl::string_view rhs); @@ -721,11 +725,6 @@ // Returns nullptr if holding bytes absl::cord_internal::CordRep* tree() const; absl::cord_internal::CordRep* as_tree() const; - // Discards old pointer, if any - void set_tree(absl::cord_internal::CordRep* rep); - // Replaces a tree with a new root. This is faster than set_tree, but it - // should only be used when it's clear that the old rep was a tree. - void replace_tree(absl::cord_internal::CordRep* rep); // Returns non-null iff was holding a pointer absl::cord_internal::CordRep* clear(); // Converts to pointer if necessary. @@ -745,12 +744,21 @@ // the CordzInfo instance is updated to reference the new `rep` value. void SetTree(CordRep* rep, const CordzUpdateScope& scope); + // Identical to SetTree(), except that `rep` is allowed to be null, in + // which case the current instance is reset to an empty value. + void SetTreeOrEmpty(CordRep* rep, const CordzUpdateScope& scope); + // Sets the tree value for this instance, and randomly samples this cord. // This function disregards existing contents in `data_`, and should be // called when a Cord is 'promoted' from an 'uninitialized' or 'inlined' // value to a non-inlined (tree / ring) value. void EmplaceTree(CordRep* rep, MethodIdentifier method); + // Identical to EmplaceTree, except that it copies the parent stack from + // the provided `parent` data if the parent is sampled. + void EmplaceTree(CordRep* rep, const InlineData& parent, + MethodIdentifier method); + // Commits the change of a newly created, or updated `rep` root value into // this cord. `old_rep` indicates the old (inlined or tree) value of the // cord, and determines if the commit invokes SetTree() or EmplaceTree(). @@ -818,11 +826,6 @@ // Resets the current cordz_info to null / empty. void clear_cordz_info() { data_.clear_cordz_info(); } - // Updates the cordz statistics. info may be nullptr if the CordzInfo object - // is unknown. - void UpdateCordzStatistics(); - void UpdateCordzStatisticsSlow(); - private: friend class Cord; @@ -879,6 +882,10 @@ template <typename C> void AppendImpl(C&& src); + // Assigns the value in 'src' to this instance, 'stealing' its contents. + // Requires src.length() > kMaxBytesToCopy. + Cord& AssignLargeString(std::string&& src); + // Helper for AbslHashValue(). template <typename H> H HashFragmented(H hash_state) const { @@ -981,8 +988,11 @@ template <typename Releaser> Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) { Cord cord; - cord.contents_.set_tree(::absl::cord_internal::NewExternalRep( - data, std::forward<Releaser>(releaser))); + if (auto* rep = ::absl::cord_internal::NewExternalRep( + data, std::forward<Releaser>(releaser))) { + cord.contents_.EmplaceTree(rep, + Cord::MethodIdentifier::kMakeCordFromExternal); + } return cord; } @@ -1071,6 +1081,12 @@ CordzInfo::MaybeTrackCord(data_, method); } +inline void Cord::InlineRep::EmplaceTree(CordRep* rep, const InlineData& parent, + MethodIdentifier method) { + data_.make_tree(rep); + CordzInfo::MaybeTrackCord(data_, parent, method); +} + inline void Cord::InlineRep::SetTree(CordRep* rep, const CordzUpdateScope& scope) { assert(rep); @@ -1079,6 +1095,17 @@ scope.SetCordRep(rep); } +inline void Cord::InlineRep::SetTreeOrEmpty(CordRep* rep, + const CordzUpdateScope& scope) { + assert(data_.is_tree()); + if (rep) { + data_.set_tree(rep); + } else { + data_ = {}; + } + scope.SetCordRep(rep); +} + inline void Cord::InlineRep::CommitTree(const CordRep* old_rep, CordRep* rep, const CordzUpdateScope& scope, MethodIdentifier method) { @@ -1089,36 +1116,6 @@ } } -inline void Cord::InlineRep::set_tree(absl::cord_internal::CordRep* rep) { - if (rep == nullptr) { - if (data_.is_tree()) { - CordzInfo::MaybeUntrackCord(data_.cordz_info()); - } - ResetToEmpty(); - } else { - if (data_.is_tree()) { - // `data_` already holds a 'tree' value and an optional cordz_info value. - // Replace the tree value only, leaving the cordz_info value unchanged. - data_.set_tree(rep); - } else { - // `data_` contains inlined data: initialize data_ to tree value `rep`. - data_.make_tree(rep); - CordzInfo::MaybeTrackCord(data_, CordzUpdateTracker::kUnknown); - } - UpdateCordzStatistics(); - } -} - -inline void Cord::InlineRep::replace_tree(absl::cord_internal::CordRep* rep) { - ABSL_ASSERT(is_tree()); - if (ABSL_PREDICT_FALSE(rep == nullptr)) { - set_tree(rep); - return; - } - data_.set_tree(rep); - UpdateCordzStatistics(); -} - inline absl::cord_internal::CordRep* Cord::InlineRep::clear() { if (is_tree()) { CordzInfo::MaybeUntrackCord(cordz_info()); @@ -1135,13 +1132,11 @@ cord_internal::SmallMemmove(dst, data_.as_chars(), n); } -inline void Cord::InlineRep::UpdateCordzStatistics() { - if (ABSL_PREDICT_TRUE(!is_profiled())) return; - UpdateCordzStatisticsSlow(); -} - constexpr inline Cord::Cord() noexcept {} +inline Cord::Cord(absl::string_view src) + : Cord(src, CordzUpdateTracker::kConstructorString) {} + template <typename T> constexpr Cord::Cord(strings_internal::StringConstant<T>) : contents_(strings_internal::StringConstant<T>::value.size() <= @@ -1157,6 +1152,15 @@ return *this; } +template <typename T, Cord::EnableIfString<T>> +Cord& Cord::operator=(T&& src) { + if (src.size() <= cord_internal::kMaxBytesToCopy) { + return operator=(absl::string_view(src)); + } else { + return AssignLargeString(std::forward<T>(src)); + } +} + inline Cord::Cord(const Cord& src) : contents_(src.contents_) {} inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {} @@ -1171,7 +1175,6 @@ } extern template Cord::Cord(std::string&& src); -extern template Cord& Cord::operator=(std::string&& src); inline size_t Cord::size() const { // Length is 1st field in str.rep_
diff --git a/third_party/abseil-cpp/absl/strings/cord_ring_test.cc b/third_party/abseil-cpp/absl/strings/cord_ring_test.cc index 2943cf3..cc8fbaf 100644 --- a/third_party/abseil-cpp/absl/strings/cord_ring_test.cc +++ b/third_party/abseil-cpp/absl/strings/cord_ring_test.cc
@@ -98,15 +98,22 @@ // Matcher validating when mutable copies are required / performed. MATCHER_P2(EqIfPrivate, param, rep, absl::StrCat("Equal 0x", absl::Hex(rep), " if private")) { - return param.refcount_is_one ? arg == rep : arg != rep; + return param.refcount_is_one ? arg == rep : true; } // Matcher validating when mutable copies are required / performed. MATCHER_P2(EqIfPrivateAndCapacity, param, rep, absl::StrCat("Equal 0x", absl::Hex(rep), " if private and capacity")) { - return (param.refcount_is_one && param.with_capacity) ? arg == rep - : arg != rep; + return (param.refcount_is_one && param.with_capacity) ? arg == rep : true; +} + +// Matcher validating a shared ring was re-allocated. Should only be used for +// tests doing exactly one update as subsequent updates could return the +// original (freed and re-used) pointer. +MATCHER_P2(NeIfShared, param, rep, + absl::StrCat("Not equal 0x", absl::Hex(rep), " if shared")) { + return param.refcount_is_one ? true : arg != rep; } MATCHER_P2(EqIfInputPrivate, param, rep, "Equal if input is private") { @@ -518,6 +525,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Create(ring)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats)); } @@ -655,6 +663,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, MakeFlat(str2))); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(result->length, Eq(str1.size() + str2.size())); EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2)); } @@ -666,6 +675,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, MakeFlat(str2))); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(result->length, Eq(str1.size() + str2.size())); EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1)); } @@ -677,6 +687,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(result->length, Eq(str1.size() + str2.size())); EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2)); } @@ -689,6 +700,7 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result->length, Eq(str1.size() + str2.size())); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); } TEST_P(CordRingBuildTest, AppendStringHavingPartialExtra) { @@ -710,6 +722,7 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result->length, Eq(str1.size() + str2.size())); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); if (GetParam().refcount_is_one) { EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str1, str1a), str2a)); } else { @@ -725,6 +738,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(result->length, Eq(4 + str2.size())); if (GetParam().refcount_is_one) { EXPECT_THAT(ToFlats(result), ElementsAre(StrCat("1234", str2))); @@ -758,6 +772,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(result->length, Eq(4 + str2.size())); EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2)); @@ -802,6 +817,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(result->length, Eq(4 + str2.size())); if (GetParam().refcount_is_one) { EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str2, "1234"))); @@ -833,6 +849,7 @@ ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result->length, Eq(str1a.size() + str2.size())); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1a)); CordRep::Unref(shared_type == 1 ? flat1 : flat); } @@ -920,6 +937,7 @@ result = NeedsUnref(CordRepRing::SubRing(ring, offset, len)); ASSERT_THAT(result, IsValidRingBuffer()); ASSERT_THAT(result, EqIfPrivate(GetParam(), ring)); + ASSERT_THAT(result, NeIfShared(GetParam(), ring)); ASSERT_THAT(ToString(result), Eq(all.substr(offset, len))); } } @@ -945,6 +963,7 @@ result = NeedsUnref(CordRepRing::SubRing(ring, offset, len)); ASSERT_THAT(result, IsValidRingBuffer()); ASSERT_THAT(result, EqIfPrivate(GetParam(), ring)); + ASSERT_THAT(result, NeIfShared(GetParam(), ring)); auto str = ToString(result); ASSERT_THAT(str, SizeIs(len)); ASSERT_THAT(str, Eq(all.substr(offset, len))); @@ -966,6 +985,7 @@ result = NeedsUnref(CordRepRing::RemovePrefix(ring, len)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); + ASSERT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToString(result), Eq(all.substr(len))); } } @@ -996,8 +1016,9 @@ ring = RefIfShared(FromFlats(flats, composition)); result = NeedsUnref(CordRepRing::RemoveSuffix(ring, len)); ASSERT_THAT(result, IsValidRingBuffer()); - EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); - EXPECT_THAT(ToString(result), Eq(all.substr(0, all.size() - len))); + ASSERT_THAT(result, EqIfPrivate(GetParam(), ring)); + ASSERT_THAT(result, NeIfShared(GetParam(), ring)); + ASSERT_THAT(ToString(result), Eq(all.substr(0, all.size() - len))); } } @@ -1010,6 +1031,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, child)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivate(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats)); } @@ -1023,6 +1045,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "brown ", "fox ", "jumps ", "over ", "the ", "lazy ", "dog")); } @@ -1037,6 +1060,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "umps ", "over ", "the ", "lazy ", "dog")); } @@ -1051,6 +1075,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ", "fox ", "jumps ", "over ", "the ")); } @@ -1065,6 +1090,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ", "fox ", "jumps ", "ov")); } @@ -1079,6 +1105,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "ck ", "brown ", "fox ", "jum")); } @@ -1093,6 +1120,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Head", "row")); } @@ -1110,6 +1138,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("Prepend", "Head", "row")); } @@ -1123,6 +1152,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, child)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats)); } @@ -1136,6 +1166,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("brown ", "fox ", "jumps ", "over ", "the ", "lazy ", "dog", "Tail")); } @@ -1149,6 +1180,7 @@ CordRep* stripped = RefIfInputSharedIndirect(RemovePrefix(21, child)); CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped)); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("umps ", "over ", "the ", "lazy ", "dog", "Tail")); } @@ -1163,6 +1195,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ", "jumps ", "over ", "the ", "Tail")); } @@ -1177,6 +1210,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ", "jumps ", "ov", "Tail")); } @@ -1192,6 +1226,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("ck ", "brown ", "fox ", "jum", "Tail")); } @@ -1206,6 +1241,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("row", "Tail")); } @@ -1222,6 +1258,7 @@ CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped)); ASSERT_THAT(result, IsValidRingBuffer()); EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring)); + EXPECT_THAT(result, NeIfShared(GetParam(), ring)); EXPECT_THAT(ToFlats(result), ElementsAre("row", "Prepend", "Tail")); }
diff --git a/third_party/abseil-cpp/absl/strings/cord_test.cc b/third_party/abseil-cpp/absl/strings/cord_test.cc index 74a9086..14eca15 100644 --- a/third_party/abseil-cpp/absl/strings/cord_test.cc +++ b/third_party/abseil-cpp/absl/strings/cord_test.cc
@@ -190,14 +190,15 @@ } static Cord MakeSubstring(Cord src, size_t offset, size_t length) { - Cord cord = src; - ABSL_RAW_CHECK(cord.contents_.is_tree(), "Can not be inlined"); + ABSL_RAW_CHECK(src.contents_.is_tree(), "Can not be inlined"); + Cord cord; auto* rep = new cord_internal::CordRepSubstring; rep->tag = cord_internal::SUBSTRING; - rep->child = cord.contents_.tree(); + rep->child = cord_internal::CordRep::Ref(src.contents_.tree()); rep->start = offset; rep->length = length; - cord.contents_.replace_tree(rep); + cord.contents_.EmplaceTree(rep, + cord_internal::CordzUpdateTracker::kSubCord); return cord; } };
diff --git a/third_party/abseil-cpp/absl/strings/cord_test_helpers.h b/third_party/abseil-cpp/absl/strings/cord_test_helpers.h index 6ccccc51..31a1dc8 100644 --- a/third_party/abseil-cpp/absl/strings/cord_test_helpers.h +++ b/third_party/abseil-cpp/absl/strings/cord_test_helpers.h
@@ -19,7 +19,9 @@ #include <cstdint> #include <iostream> +#include <string> +#include "absl/base/config.h" #include "absl/strings/cord.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/string_view.h" @@ -29,10 +31,27 @@ // Cord sizes relevant for testing enum class TestCordSize { + // An empty value kEmpty = 0, + + // An inlined string value kInlined = cord_internal::kMaxInline / 2 + 1, + + // 'Well known' SSO lengths (excluding terminating zero). + // libstdcxx has a maximum SSO of 15, libc++ has a maximum SSO of 22. + kStringSso1 = 15, + kStringSso2 = 22, + + // A string value which is too large to fit in inlined data, but small enough + // such that Cord prefers copying the value if possible, i.e.: not stealing + // std::string inputs, or referencing existing CordReps on Append, etc. kSmall = cord_internal::kMaxBytesToCopy / 2 + 1, + + // A string value large enough that Cord prefers to reference or steal from + // existing inputs rather than copying contents of the input. kMedium = cord_internal::kMaxFlatLength / 2 + 1, + + // A string value large enough to cause it to be stored in mutliple flats. kLarge = cord_internal::kMaxFlatLength * 4 }; @@ -45,6 +64,10 @@ return "Inlined"; case TestCordSize::kSmall: return "Small"; + case TestCordSize::kStringSso1: + return "StringSso1"; + case TestCordSize::kStringSso2: + return "StringSso2"; case TestCordSize::kMedium: return "Medium"; case TestCordSize::kLarge:
diff --git a/third_party/abseil-cpp/absl/strings/cordz_test.cc b/third_party/abseil-cpp/absl/strings/cordz_test.cc index b16e968..aeb3d13 100644 --- a/third_party/abseil-cpp/absl/strings/cordz_test.cc +++ b/third_party/abseil-cpp/absl/strings/cordz_test.cc
@@ -34,6 +34,7 @@ #ifdef ABSL_INTERNAL_CORDZ_ENABLED using testing::Eq; +using testing::AnyOf; namespace absl { ABSL_NAMESPACE_BEGIN @@ -52,6 +53,8 @@ namespace { +auto constexpr kMaxInline = cord_internal::kMaxInline; + // Returns a string_view value of the specified length // We do this to avoid 'consuming' large strings in Cord by default. absl::string_view MakeString(size_t size) { @@ -82,24 +85,50 @@ Cord cord_{MakeString(GetParam())}; }; +template <typename T> +std::string ParamToString(::testing::TestParamInfo<T> param) { + return std::string(ToString(param.param)); +} + INSTANTIATE_TEST_SUITE_P(WithParam, CordzUpdateTest, testing::Values(TestCordSize::kEmpty, TestCordSize::kInlined, TestCordSize::kLarge), TestParamToString); -TEST(CordzTest, ConstructSmallString) { +class CordzStringTest : public testing::TestWithParam<TestCordSize> { + private: + CordzSamplingIntervalHelper sample_every_{1}; +}; + +INSTANTIATE_TEST_SUITE_P(WithParam, CordzStringTest, + testing::Values(TestCordSize::kInlined, + TestCordSize::kStringSso1, + TestCordSize::kStringSso2, + TestCordSize::kSmall, + TestCordSize::kLarge), + ParamToString<TestCordSize>); + +TEST(CordzTest, ConstructSmallArray) { CordzSamplingIntervalHelper sample_every{1}; Cord cord(MakeString(TestCordSize::kSmall)); EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); } -TEST(CordzTest, ConstructLargeString) { +TEST(CordzTest, ConstructLargeArray) { CordzSamplingIntervalHelper sample_every{1}; Cord cord(MakeString(TestCordSize::kLarge)); EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); } +TEST_P(CordzStringTest, ConstructString) { + CordzSamplingIntervalHelper sample_every{1}; + Cord cord(std::string(Length(GetParam()), '.')); + if (Length(GetParam()) > kMaxInline) { + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); + } +} + TEST(CordzTest, CopyConstruct) { CordzSamplingIntervalHelper sample_every{1}; Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); @@ -139,6 +168,38 @@ EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); } +TEST_P(CordzUpdateTest, AssignSmallArray) { + cord() = MakeString(TestCordSize::kSmall); + EXPECT_THAT(cord(), HasValidCordzInfoOf(Method::kAssignString)); +} + +TEST_P(CordzUpdateTest, AssignInlinedArray) { + cord() = MakeString(TestCordSize::kInlined); + EXPECT_THAT(GetCordzInfoForTesting(cord()), Eq(nullptr)); +} + +TEST_P(CordzStringTest, AssignStringToInlined) { + Cord cord; + cord = std::string(Length(GetParam()), '.'); + if (Length(GetParam()) > kMaxInline) { + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kAssignString)); + } +} + +TEST_P(CordzStringTest, AssignStringToCord) { + Cord cord(MakeString(TestCordSize::kLarge)); + cord = std::string(Length(GetParam()), '.'); + if (Length(GetParam()) > kMaxInline) { + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); + EXPECT_THAT(cord, CordzMethodCountEq(Method::kAssignString, 1)); + } +} + +TEST_P(CordzUpdateTest, AssignInlinedString) { + cord() = std::string(Length(TestCordSize::kInlined), '.'); + EXPECT_THAT(GetCordzInfoForTesting(cord()), Eq(nullptr)); +} + TEST_P(CordzUpdateTest, AppendCord) { Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); cord().Append(src); @@ -150,12 +211,6 @@ EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kAppendCord))); } -TEST_P(CordzUpdateTest, PrependCord) { - Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); - cord().Prepend(src); - EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kPrependCord))); -} - TEST_P(CordzUpdateTest, AppendSmallArray) { cord().Append(MakeString(TestCordSize::kSmall)); EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kAppendString))); @@ -166,6 +221,130 @@ EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kAppendString))); } +TEST_P(CordzStringTest, AppendStringToEmpty) { + Cord cord; + cord.Append(std::string(Length(GetParam()), '.')); + if (Length(GetParam()) > kMaxInline) { + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kAppendString)); + } +} + +TEST_P(CordzStringTest, AppendStringToInlined) { + Cord cord(MakeString(TestCordSize::kInlined)); + cord.Append(std::string(Length(GetParam()), '.')); + if (Length(TestCordSize::kInlined) + Length(GetParam()) > kMaxInline) { + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kAppendString)); + } +} + +TEST_P(CordzStringTest, AppendStringToCord) { + Cord cord(MakeString(TestCordSize::kLarge)); + cord.Append(std::string(Length(GetParam()), '.')); + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); + EXPECT_THAT(cord, CordzMethodCountEq(Method::kAppendString, 1)); +} + +TEST(CordzTest, MakeCordFromExternal) { + CordzSamplingIntervalHelper sample_every{1}; + Cord cord = MakeCordFromExternal("Hello world", [](absl::string_view) {}); + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kMakeCordFromExternal)); +} + +TEST(CordzTest, MakeCordFromEmptyExternal) { + CordzSamplingIntervalHelper sample_every{1}; + Cord cord = MakeCordFromExternal({}, [](absl::string_view) {}); + EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); +} + +TEST_P(CordzUpdateTest, PrependCord) { + Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); + cord().Prepend(src); + EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kPrependCord))); +} + +TEST_P(CordzUpdateTest, PrependSmallArray) { + cord().Prepend(MakeString(TestCordSize::kSmall)); + EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kPrependString))); +} + +TEST_P(CordzUpdateTest, PrependLargeArray) { + cord().Prepend(MakeString(TestCordSize::kLarge)); + EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kPrependString))); +} + +TEST_P(CordzStringTest, PrependStringToEmpty) { + Cord cord; + cord.Prepend(std::string(Length(GetParam()), '.')); + if (Length(GetParam()) > kMaxInline) { + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kPrependString)); + } +} + +TEST_P(CordzStringTest, PrependStringToInlined) { + Cord cord(MakeString(TestCordSize::kInlined)); + cord.Prepend(std::string(Length(GetParam()), '.')); + if (Length(TestCordSize::kInlined) + Length(GetParam()) > kMaxInline) { + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kPrependString)); + } +} + +TEST_P(CordzStringTest, PrependStringToCord) { + Cord cord(MakeString(TestCordSize::kLarge)); + cord.Prepend(std::string(Length(GetParam()), '.')); + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); + EXPECT_THAT(cord, CordzMethodCountEq(Method::kPrependString, 1)); +} + +TEST(CordzTest, RemovePrefix) { + CordzSamplingIntervalHelper sample_every(1); + Cord cord(MakeString(TestCordSize::kLarge)); + + // Half the cord + cord.RemovePrefix(cord.size() / 2); + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); + EXPECT_THAT(cord, CordzMethodCountEq(Method::kRemovePrefix, 1)); + + // TODO(mvels): RemovePrefix does not reset to inlined, except if empty? + cord.RemovePrefix(cord.size() - kMaxInline); + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); + EXPECT_THAT(cord, CordzMethodCountEq(Method::kRemovePrefix, 2)); + + cord.RemovePrefix(cord.size()); + EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); +} + +TEST(CordzTest, RemoveSuffix) { + CordzSamplingIntervalHelper sample_every(1); + Cord cord(MakeString(TestCordSize::kLarge)); + + // Half the cord + cord.RemoveSuffix(cord.size() / 2); + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); + EXPECT_THAT(cord, CordzMethodCountEq(Method::kRemoveSuffix, 1)); + + // TODO(mvels): RemoveSuffix does not reset to inlined, except if empty? + cord.RemoveSuffix(cord.size() - kMaxInline); + EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); + EXPECT_THAT(cord, CordzMethodCountEq(Method::kRemoveSuffix, 2)); + + cord.RemoveSuffix(cord.size()); + EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); +} + +TEST(CordzTest, SubCord) { + CordzSamplingIntervalHelper sample_every{1}; + Cord src(MakeString(TestCordSize::kLarge)); + + Cord cord1 = src.Subcord(10, src.size() / 2); + EXPECT_THAT(cord1, HasValidCordzInfoOf(Method::kSubCord)); + + Cord cord2 = src.Subcord(10, kMaxInline + 1); + EXPECT_THAT(cord2, HasValidCordzInfoOf(Method::kSubCord)); + + Cord cord3 = src.Subcord(10, kMaxInline); + EXPECT_THAT(GetCordzInfoForTesting(cord3), Eq(nullptr)); +} + } // namespace ABSL_NAMESPACE_END
diff --git a/third_party/abseil-cpp/absl/strings/cordz_test_helpers.h b/third_party/abseil-cpp/absl/strings/cordz_test_helpers.h index d9573c9..e410eecf 100644 --- a/third_party/abseil-cpp/absl/strings/cordz_test_helpers.h +++ b/third_party/abseil-cpp/absl/strings/cordz_test_helpers.h
@@ -27,6 +27,7 @@ #include "absl/strings/internal/cordz_sample_token.h" #include "absl/strings/internal/cordz_statistics.h" #include "absl/strings/internal/cordz_update_tracker.h" +#include "absl/strings/str_cat.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -34,7 +35,7 @@ // Returns the CordzInfo for the cord, or nullptr if the cord is not sampled. inline const cord_internal::CordzInfo* GetCordzInfoForTesting( const Cord& cord) { - if (cord.size() <= cord_internal::kMaxInline) return nullptr; + if (!cord.contents_.is_tree()) return nullptr; return cord.contents_.cordz_info(); } @@ -47,13 +48,11 @@ return false; } -// Matcher on Cord* that verifies all of: +// Matcher on Cord that verifies all of: // - the cord is sampled // - the CordzInfo of the cord is listed / discoverable. // - the reported CordzStatistics match the cord's actual properties // - the cord has an (initial) UpdateTracker count of 1 for `method` -// This matcher accepts a const Cord* to avoid having the matcher dump -// copious amounts of cord data on failures. MATCHER_P(HasValidCordzInfoOf, method, "CordzInfo matches cord") { const cord_internal::CordzInfo* cord_info = GetCordzInfoForTesting(arg); if (cord_info == nullptr) { @@ -78,6 +77,24 @@ return true; } +// Matcher on Cord that verifies that the cord is sampled and that the CordzInfo +// update tracker has 'method' with a call count of 'n' +MATCHER_P2(CordzMethodCountEq, method, n, + absl::StrCat("CordzInfo method count equals ", n)) { + const cord_internal::CordzInfo* cord_info = GetCordzInfoForTesting(arg); + if (cord_info == nullptr) { + *result_listener << "cord is not sampled"; + return false; + } + cord_internal::CordzStatistics stat = cord_info->GetCordzStatistics(); + if (stat.update_tracker.Value(method) != n) { + *result_listener << "Expected method count " << n << " for " << method + << ", found " << stat.update_tracker.Value(method); + return false; + } + return true; +} + // Cordz will only update with a new rate once the previously scheduled event // has fired. When we disable Cordz, a long delay takes place where we won't // consider profiling new Cords. CordzSampleIntervalHelper will burn through
diff --git a/third_party/abseil-cpp/absl/strings/internal/cordz_handle.cc b/third_party/abseil-cpp/absl/strings/internal/cordz_handle.cc index 5297ec8..a73fefed 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cordz_handle.cc +++ b/third_party/abseil-cpp/absl/strings/internal/cordz_handle.cc
@@ -68,11 +68,16 @@ } } +bool CordzHandle::SafeToDelete() const { + return is_snapshot_ || queue_->IsEmpty(); +} + void CordzHandle::Delete(CordzHandle* handle) { + assert(handle); if (handle) { handle->ODRCheck(); Queue* const queue = handle->queue_; - if (!handle->is_snapshot_ && !queue->IsEmpty()) { + if (!handle->SafeToDelete()) { SpinLockHolder lock(&queue->mutex); CordzHandle* dq_tail = queue->dq_tail.load(std::memory_order_acquire); if (dq_tail != nullptr) {
diff --git a/third_party/abseil-cpp/absl/strings/internal/cordz_handle.h b/third_party/abseil-cpp/absl/strings/internal/cordz_handle.h index 93076cf..5df53c7 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cordz_handle.h +++ b/third_party/abseil-cpp/absl/strings/internal/cordz_handle.h
@@ -40,9 +40,20 @@ bool is_snapshot() const { return is_snapshot_; } + // Returns true if this instance is safe to be deleted because it is either a + // snapshot, which is always safe to delete, or not included in the global + // delete queue and thus not included in any snapshot. + // Callers are responsible for making sure this instance can not be newly + // discovered by other threads. For example, CordzInfo instances first de-list + // themselves from the global CordzInfo list before determining if they are + // safe to be deleted directly. + // If SafeToDelete returns false, callers MUST use the Delete() method to + // safely queue CordzHandle instances for deletion. + bool SafeToDelete() const; + // Deletes the provided instance, or puts it on the delete queue to be deleted // once there are no more sample tokens (snapshot) instances potentially - // referencing the instance. `handle` may be null. + // referencing the instance. `handle` should not be null. static void Delete(CordzHandle* handle); // Returns the current entries in the delete queue in LIFO order.
diff --git a/third_party/abseil-cpp/absl/strings/internal/cordz_handle_test.cc b/third_party/abseil-cpp/absl/strings/internal/cordz_handle_test.cc index c04240e..4eefd72 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cordz_handle_test.cc +++ b/third_party/abseil-cpp/absl/strings/internal/cordz_handle_test.cc
@@ -52,6 +52,7 @@ bool deleted = false; auto* handle = new CordzHandleDeleteTracker(&deleted); EXPECT_FALSE(handle->is_snapshot()); + EXPECT_TRUE(handle->SafeToDelete()); EXPECT_THAT(DeleteQueue(), SizeIs(0)); CordzHandle::Delete(handle); @@ -62,6 +63,7 @@ TEST(CordzHandleTest, CordzSnapshotCreateDelete) { auto* snapshot = new CordzSnapshot(); EXPECT_TRUE(snapshot->is_snapshot()); + EXPECT_TRUE(snapshot->SafeToDelete()); EXPECT_THAT(DeleteQueue(), ElementsAre(snapshot)); delete snapshot; EXPECT_THAT(DeleteQueue(), SizeIs(0)); @@ -71,10 +73,12 @@ bool deleted = false; auto* snapshot = new CordzSnapshot(); auto* handle = new CordzHandleDeleteTracker(&deleted); + EXPECT_FALSE(handle->SafeToDelete()); CordzHandle::Delete(handle); EXPECT_THAT(DeleteQueue(), ElementsAre(handle, snapshot)); EXPECT_FALSE(deleted); + EXPECT_FALSE(handle->SafeToDelete()); delete snapshot; EXPECT_THAT(DeleteQueue(), SizeIs(0)); @@ -219,8 +223,8 @@ if (safe_to_inspect.size() > max_safe_to_inspect) { max_safe_to_inspect = safe_to_inspect.size(); } + CordzHandle::Delete(old_handle); } - CordzHandle::Delete(old_handle); } // Confirm that the test did *something*. This check will be satisfied as @@ -234,9 +238,10 @@ // Have each thread attempt to clean up everything. Some thread will be // the last to reach this cleanup code, and it will be guaranteed to clean // up everything because nothing remains to create new handles. - for (size_t i = 0; i < handles.size(); i++) { - CordzHandle* handle = handles[i].exchange(nullptr); - CordzHandle::Delete(handle); + for (auto& h : handles) { + if (CordzHandle* handle = h.exchange(nullptr)) { + CordzHandle::Delete(handle); + } } }); }
diff --git a/third_party/abseil-cpp/absl/strings/internal/cordz_info.cc b/third_party/abseil-cpp/absl/strings/internal/cordz_info.cc index 0461ec4..0f657aaf 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cordz_info.cc +++ b/third_party/abseil-cpp/absl/strings/internal/cordz_info.cc
@@ -126,13 +126,6 @@ } void CordzInfo::Untrack() { - { - // TODO(b/117940323): change this to assuming ownership instead once all - // Cord logic is properly keeping `rep_` in sync with the Cord root rep. - absl::MutexLock lock(&mutex_); - rep_ = nullptr; - } - ODRCheck(); { SpinLockHolder l(&list_->mutex); @@ -154,6 +147,20 @@ list_->head.store(next, std::memory_order_release); } } + + // We can no longer be discovered: perform a fast path check if we are not + // listed on any delete queue, so we can directly delete this instance. + if (SafeToDelete()) { + UnsafeSetCordRep(nullptr); + delete this; + return; + } + + // We are likely part of a snapshot, extend the life of the CordRep + { + absl::MutexLock lock(&mutex_); + if (rep_) CordRep::Ref(rep_); + } CordzHandle::Delete(this); }
diff --git a/third_party/abseil-cpp/absl/strings/internal/cordz_info.h b/third_party/abseil-cpp/absl/strings/internal/cordz_info.h index f7682cb..1fe046e 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cordz_info.h +++ b/third_party/abseil-cpp/absl/strings/internal/cordz_info.h
@@ -110,7 +110,7 @@ // Asserts that this CordzInfo instance is locked. void AssertHeld() ABSL_ASSERT_EXCLUSIVE_LOCK(mutex_); - // Updates the `rep' property of this instance. This methods is invoked by + // Updates the `rep` property of this instance. This methods is invoked by // Cord logic each time the root node of a sampled Cord changes, and before // the old root reference count is deleted. This guarantees that collection // code can always safely take a reference on the tracked cord. @@ -119,6 +119,11 @@ // Cord code is in a state where this can be proven true by the compiler. void SetCordRep(CordRep* rep); + // Returns the current `rep` property of this instance with a reference + // added, or null if this instance represents a cord that has since been + // deleted or untracked. + CordRep* RefCordRep() const ABSL_LOCKS_EXCLUDED(mutex_); + // Returns the current value of `rep_` for testing purposes only. CordRep* GetCordRepForTesting() const ABSL_NO_THREAD_SAFETY_ANALYSIS { return rep_; @@ -148,6 +153,9 @@ } private: + using SpinLock = absl::base_internal::SpinLock; + using SpinLockHolder = ::absl::base_internal::SpinLockHolder; + // Global cordz info list. CordzInfo stores a pointer to the global list // instance to harden against ODR violations. struct List { @@ -155,7 +163,7 @@ : mutex(absl::kConstInit, absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL) {} - absl::base_internal::SpinLock mutex; + SpinLock mutex; std::atomic<CordzInfo*> head ABSL_GUARDED_BY(mutex){nullptr}; }; @@ -165,6 +173,9 @@ MethodIdentifier method); ~CordzInfo() override; + // Sets `rep_` without holding a lock. + void UnsafeSetCordRep(CordRep* rep) ABSL_NO_THREAD_SAFETY_ANALYSIS; + void Track(); // Returns the parent method from `src`, which is either `parent_method_` or @@ -244,6 +255,13 @@ } } +inline void CordzInfo::UnsafeSetCordRep(CordRep* rep) { rep_ = rep; } + +inline CordRep* CordzInfo::RefCordRep() const ABSL_LOCKS_EXCLUDED(mutex_) { + MutexLock lock(&mutex_); + return rep_ ? CordRep::Ref(rep_) : nullptr; +} + } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl
diff --git a/third_party/abseil-cpp/absl/strings/internal/cordz_info_test.cc b/third_party/abseil-cpp/absl/strings/internal/cordz_info_test.cc index 5eaf4b9..5bb23e4 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cordz_info_test.cc +++ b/third_party/abseil-cpp/absl/strings/internal/cordz_info_test.cc
@@ -38,6 +38,7 @@ using ::testing::Eq; using ::testing::HasSubstr; using ::testing::Ne; +using ::testing::SizeIs; // Used test values auto constexpr kUnknownMethod = CordzUpdateTracker::kUnknown; @@ -78,10 +79,19 @@ CordzInfo::TrackCord(data.data, kTrackCordMethod); CordzInfo* info = data.data.cordz_info(); + info->Untrack(); + EXPECT_THAT(DeleteQueue(), SizeIs(0)); +} + +TEST(CordzInfoTest, UntrackCordWithSnapshot) { + TestCordData data; + CordzInfo::TrackCord(data.data, kTrackCordMethod); + CordzInfo* info = data.data.cordz_info(); + CordzSnapshot snapshot; info->Untrack(); EXPECT_THAT(CordzInfo::Head(CordzSnapshot()), Eq(nullptr)); - EXPECT_THAT(info->GetCordRepForTesting(), Eq(nullptr)); + EXPECT_THAT(info->GetCordRepForTesting(), Eq(data.rep.rep)); EXPECT_THAT(DeleteQueue(), ElementsAre(info, &snapshot)); } @@ -113,6 +123,18 @@ EXPECT_THAT(CordzInfo::Head(CordzSnapshot()), Eq(nullptr)); } +TEST(CordzInfoTest, RefCordRep) { + TestCordData data; + CordzInfo::TrackCord(data.data, kTrackCordMethod); + CordzInfo* info = data.data.cordz_info(); + + size_t refcount = data.rep.rep->refcount.Get(); + EXPECT_THAT(info->RefCordRep(), Eq(data.rep.rep)); + EXPECT_THAT(data.rep.rep->refcount.Get(), Eq(refcount + 1)); + CordRep::Unref(data.rep.rep); + info->Untrack(); +} + #if GTEST_HAS_DEATH_TEST TEST(CordzInfoTest, SetCordRepRequiresMutex) {
diff --git a/third_party/abseil-cpp/absl/strings/internal/cordz_update_tracker.h b/third_party/abseil-cpp/absl/strings/internal/cordz_update_tracker.h index 741950b..d5b14067 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cordz_update_tracker.h +++ b/third_party/abseil-cpp/absl/strings/internal/cordz_update_tracker.h
@@ -47,8 +47,10 @@ kClear, kConstructorCord, kConstructorString, + kCordReader, kFlatten, kGetAppendRegion, + kMakeCordFromExternal, kMoveAppendCord, kMoveAssignCord, kMovePrependCord,
diff --git a/third_party/abseil-cpp/absl/strings/internal/cordz_update_tracker_test.cc b/third_party/abseil-cpp/absl/strings/internal/cordz_update_tracker_test.cc index eda662f..fcd17df7 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cordz_update_tracker_test.cc +++ b/third_party/abseil-cpp/absl/strings/internal/cordz_update_tracker_test.cc
@@ -45,8 +45,10 @@ Method::kClear, Method::kConstructorCord, Method::kConstructorString, + Method::kCordReader, Method::kFlatten, Method::kGetAppendRegion, + Method::kMakeCordFromExternal, Method::kMoveAppendCord, Method::kMoveAssignCord, Method::kMovePrependCord,
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h b/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h index 7040c86..3c91be70 100644 --- a/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h +++ b/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h
@@ -122,6 +122,14 @@ StringConvertResult FormatConvertImpl(string_view v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); +#if defined(ABSL_HAVE_STD_STRING_VIEW) && !defined(ABSL_USES_STD_STRING_VIEW) +inline StringConvertResult FormatConvertImpl(std::string_view v, + FormatConversionSpecImpl conv, + FormatSinkImpl* sink) { + return FormatConvertImpl(absl::string_view(v.data(), v.size()), conv, sink); +} +#endif // ABSL_HAVE_STD_STRING_VIEW && !ABSL_USES_STD_STRING_VIEW + ArgConvertResult<FormatConversionCharSetUnion( FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)> FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc index 926283c..91e0360 100644 --- a/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc +++ b/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
@@ -229,6 +229,9 @@ TestStringConvert(static_cast<const char*>("hello")); TestStringConvert(std::string("hello")); TestStringConvert(string_view("hello")); +#if defined(ABSL_HAVE_STD_STRING_VIEW) + TestStringConvert(std::string_view("hello")); +#endif // ABSL_HAVE_STD_STRING_VIEW } TEST_F(FormatConvertTest, NullString) {
diff --git a/third_party/abseil-cpp/symbols_arm64_dbg.def b/third_party/abseil-cpp/symbols_arm64_dbg.def index a05d35a0..09f0619 100644 --- a/third_party/abseil-cpp/symbols_arm64_dbg.def +++ b/third_party/abseil-cpp/symbols_arm64_dbg.def
@@ -118,10 +118,6 @@ ??$?0PEAVZoneInfoSource@cctz@time_internal@absl@@U__default_init_tag@__1@std@@@?$__compressed_pair@PEAVZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAA@$$QEAPEAVZoneInfoSource@cctz@time_internal@absl@@$$QEAU__default_init_tag@12@@Z ??$?0PEAVZoneInfoSource@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PEAVZoneInfoSource@cctz@time_internal@absl@@$0A@$0A@@__1@std@@QEAA@$$QEAPEAVZoneInfoSource@cctz@time_internal@absl@@@Z ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@X@?$__compressed_pair_elem@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@$00$00@__1@std@@QEAA@$$QEAU?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@12@@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$$V$00@?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@QEAA@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@?$CompressedTupleImpl@V?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@U?$integer_sequence@_K$0A@@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@3@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@3@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@QEAA@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@H@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@?$Storage@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$0A@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@3@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@3@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z ??$?0USynchEvent@absl@@@Condition@absl@@QEAA@P6A_NPEAUSynchEvent@1@@Z0@Z ??$?0Uday_tag@detail@cctz@time_internal@absl@@@?$civil_time@Umonth_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEAA@AEBV?$civil_time@Uday_tag@detail@cctz@time_internal@absl@@@1234@PEAX@Z ??$?0Uday_tag@detail@cctz@time_internal@absl@@@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEAA@AEBV?$civil_time@Uday_tag@detail@cctz@time_internal@absl@@@1234@PEAX@Z @@ -192,7 +188,6 @@ ??$?0V?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__1@std@@@__1@std@@XV012@@?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QEAA@AEBV?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__1@std@@@__1@std@@@Z ??$?0VBufferRawSink@str_format_internal@absl@@$0A@@FormatRawSinkImpl@str_format_internal@absl@@QEAA@PEAVBufferRawSink@12@@Z ??$?0VFILERawSink@str_format_internal@absl@@$0A@@FormatRawSinkImpl@str_format_internal@absl@@QEAA@PEAVFILERawSink@12@@Z - ??$?4V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAAAEAV01@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ??$?8PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV012@@__1@std@@YA_NAEBV?$__wrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@@01@0@Z ??$?8PEAUTransitionType@cctz@time_internal@absl@@PEAU0123@@__1@std@@YA_NAEBV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$?8PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEBU0123@@__1@std@@YA_NAEBV?$__wrap_iter@PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z @@ -358,12 +353,10 @@ ??$Init@H@FormatArgImpl@str_format_internal@absl@@AEAAXAEBH@Z ??$Initialize@V?$CopyValueAdapter@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAXV?$CopyValueAdapter@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@12@_K@Z ??$Invoke@A6AXXZ$$V@Callable@base_internal@absl@@SAXA6AXXZ@Z - ??$Invoke@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AEAVstring_view@3@@Callable@base_internal@absl@@SAX$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AEAVstring_view@2@@Z ??$InvokeFlush@V?$basic_ostream@DU?$char_traits@D@__1@std@@@__1@std@@@str_format_internal@absl@@YAXPEAV?$basic_ostream@DU?$char_traits@D@__1@std@@@__1@std@@Vstring_view@1@@Z ??$InvokeFlush@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@str_format_internal@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z ??$InvokeFlush@VBufferRawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVBufferRawSink@01@Vstring_view@1@@Z ??$InvokeFlush@VFILERawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVFILERawSink@01@Vstring_view@1@@Z - ??$InvokeReleaser@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@X@cord_internal@absl@@YAXURank0@01@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Vstring_view@1@@Z ??$LowLevelCallOnce@A6AXXZ$$V@base_internal@absl@@YAXPEAVonce_flag@1@A6AXXZ@Z ??$MakeConstSpan@$SQEAX@absl@@YA?AV?$Span@QEAX@0@PEBQEAX_K@Z ??$MakeSpan@$SI$0BAA@@absl@@YA?AV?$Span@I@0@AEAY0BAA@I@Z @@ -373,7 +366,6 @@ ??$MakeSpan@$SI$0IA@@absl@@YA?AV?$Span@I@0@AEAY0IA@I@Z ??$MakeSpan@$SVFormatArgImpl@str_format_internal@absl@@@absl@@YA?AV?$Span@VFormatArgImpl@str_format_internal@absl@@@0@PEAVFormatArgImpl@str_format_internal@0@_K@Z ??$Milliseconds@N$0A@@absl@@YA?AVDuration@0@N@Z - ??$NewExternalRep@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@YAPEAUCordRep@01@Vstring_view@1@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z ??$Offset@$00$0A@@?$LayoutImpl@V?$tuple@_KPEAUCordRep@cord_internal@absl@@I@__1@std@@U?$integer_sequence@_K$0A@$00$01@absl@@U45@@internal_layout@container_internal@absl@@QEBA_KXZ ??$Offset@$00$0A@@?$LayoutImpl@V?$tuple@_KPEAUCordRep@cord_internal@absl@@I@__1@std@@U?$integer_sequence@_K$0A@$00@absl@@U?$integer_sequence@_K$0A@$00$01@5@@internal_layout@container_internal@absl@@QEBA_KXZ ??$Offset@$00$0A@@?$LayoutImpl@V?$tuple@_KPEAUCordRep@cord_internal@absl@@I@__1@std@@U?$integer_sequence@_K$0A@@absl@@U?$integer_sequence@_K$0A@$00@5@@internal_layout@container_internal@absl@@QEBA_KXZ @@ -700,8 +692,6 @@ ??$forward@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@@__1@std@@YA$$QEAU?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@01@AEAU201@@Z ??$forward@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__1@std@@YA$$QEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@AEAU2345@@Z ??$forward@UPayload@status_internal@absl@@@__1@std@@YA$$QEAUPayload@status_internal@absl@@AEAU234@@Z - ??$forward@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@__1@std@@YA$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@01@@Z@AEAU2?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@34@QEAA@0@Z@@Z - ??$forward@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@absl@@YA$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@0@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AEAU1?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@20@QEAA@0@Z@@Z ??$forward@USubRange@absl@@@__1@std@@YA$$QEAUSubRange@absl@@AEAU23@@Z ??$forward@UTransition@cctz@time_internal@absl@@@__1@std@@YA$$QEAUTransition@cctz@time_internal@absl@@AEAU2345@@Z ??$forward@UTransitionType@cctz@time_internal@absl@@@__1@std@@YA$$QEAUTransitionType@cctz@time_internal@absl@@AEAU2345@@Z @@ -734,7 +724,6 @@ ??$get@$00@?$CompressedTuple@V?$allocator@USubRange@absl@@@__1@std@@_K@container_internal@absl@@QEGBAAEB_KXZ ??$get@$00@?$CompressedTuple@_KV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@XZ ??$get@$00Vstring_view@absl@@V12@@__1@std@@YAAEBVstring_view@absl@@AEBU?$pair@Vstring_view@absl@@V12@@01@@Z - ??$get@$0A@@?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@QEGAAAEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@H@__1@std@@PEAH@container_internal@absl@@QEGAAAEAV?$allocator@H@__1@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@H@__1@std@@_K@container_internal@absl@@QEGAAAEAV?$allocator@H@__1@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@PEAPEAUCordRep@cord_internal@absl@@@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@XZ @@ -751,7 +740,6 @@ ??$get@Vstring_view@absl@@V12@@?$__get_pair@$00@__1@std@@SAAEBVstring_view@absl@@AEBU?$pair@Vstring_view@absl@@V12@@12@@Z ??$get@Vstring_view@absl@@V12@@?$__get_pair@$0A@@__1@std@@SAAEBVstring_view@absl@@AEBU?$pair@Vstring_view@absl@@V12@@12@@Z ??$invoke@A6AXXZ$$V@base_internal@absl@@YAXA6AXXZ@Z - ??$invoke@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AEAVstring_view@3@@base_internal@absl@@YAX$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AEAVstring_view@1@@Z ??$lower_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@__1@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByUnixTime@2345@@Z ??$make_pair@AEAPEAUCordRep@cord_internal@absl@@AEAPEAU123@@__1@std@@YA?AU?$pair@PEAUCordRep@cord_internal@absl@@PEAU123@@01@AEAPEAUCordRep@cord_internal@absl@@0@Z ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@$$V@__1@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@@01@XZ @@ -786,7 +774,6 @@ ??$move@AEAPEBV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@YA$$QEAPEBV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@AEAPEBV23@@Z ??$move@AEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@__1@std@@YA$$QEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@AEAU2345@@Z ??$move@AEAUPayload@status_internal@absl@@@__1@std@@YA$$QEAUPayload@status_internal@absl@@AEAU234@@Z - ??$move@AEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@__1@std@@YA$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@01@@Z@AEAU2?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@34@QEAA@0@Z@@Z ??$move@AEAUSubRange@absl@@@__1@std@@YA$$QEAUSubRange@absl@@AEAU23@@Z ??$move@AEAUTransition@cctz@time_internal@absl@@@__1@std@@YA$$QEAUTransition@cctz@time_internal@absl@@AEAU2345@@Z ??$move@AEAUTransitionType@cctz@time_internal@absl@@@__1@std@@YA$$QEAUTransitionType@cctz@time_internal@absl@@AEAU2345@@Z @@ -1028,9 +1015,9 @@ ??0Condition@absl@@AEAA@XZ ??0Condition@absl@@QEAA@P6A_NPEAX@Z0@Z ??0Condition@absl@@QEAA@PEB_N@Z + ??0Cord@absl@@AEAA@Vstring_view@1@W4MethodIdentifier@CordzUpdateTracker@cord_internal@1@@Z ??0Cord@absl@@QEAA@$$QEAV01@@Z ??0Cord@absl@@QEAA@AEBV01@@Z - ??0Cord@absl@@QEAA@Vstring_view@1@@Z ??0Cord@absl@@QEAA@XZ ??0CordForest@absl@@QEAA@_K@Z ??0CordRep@cord_internal@absl@@QEAA@XZ @@ -1089,7 +1076,6 @@ ??0StatusRep@status_internal@absl@@QEAA@W4StatusCode@2@Vstring_view@2@V?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@@__1@std@@@Z ??0Storage@?$FixedArray@PEAUCordRep@cord_internal@absl@@$0?0V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAA@_KAEBV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@Z ??0Streamable@str_format_internal@absl@@QEAA@AEBVUntypedFormatSpecImpl@12@V?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@2@@Z - ??0StringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@QEAA@$$QEAU0?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@12@QEAA@0@Z@@Z ??0SubRange@absl@@QEAA@PEAUCordRep@cord_internal@1@_K1@Z ??0SynchWaitParams@absl@@QEAA@PEBUMuHowS@1@PEBVCondition@1@VKernelTimeout@synchronization_internal@1@PEAVMutex@1@PEAUPerThreadSynch@base_internal@1@PEAU?$atomic@_J@__1@std@@@Z ??0Time@absl@@AEAA@VDuration@1@@Z @@ -1147,9 +1133,6 @@ ??1?$AllocationTransaction@V?$allocator@PEBUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ ??1?$AllocationTransaction@V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ ??1?$AllocationTransaction@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ - ??1?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@QEAA@XZ - ??1?$CompressedTupleImpl@V?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@U?$integer_sequence@_K$0A@@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@XZ - ??1?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@QEAA@XZ ??1?$FixedArray@PEAUCordRep@cord_internal@absl@@$0?0V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAA@XZ ??1?$InlinedVector@H$0CP@V?$allocator@H@__1@std@@@absl@@QEAA@XZ ??1?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAA@XZ @@ -1162,7 +1145,6 @@ ??1?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ ??1?$Storage@PEBUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEBUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ ??1?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ - ??1?$Storage@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$0A@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@XZ ??1?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ ??1?$__policy_func@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__1@std@@@__1@std@@AEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@23@@Z@__function@__1@std@@QEAA@XZ ??1?$__policy_func@$$A6AXVstring_view@absl@@AEBVCord@2@@Z@__function@__1@std@@QEAA@XZ @@ -1234,7 +1216,6 @@ ??1StatusRep@status_internal@absl@@QEAA@XZ ??1Storage@?$FixedArray@PEAUCordRep@cord_internal@absl@@$0?0V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAA@XZ ??1Streamable@str_format_internal@absl@@QEAA@XZ - ??1StringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@QEAA@XZ ??1TimeZoneIf@cctz@time_internal@absl@@UEAA@XZ ??1TimeZoneInfo@cctz@time_internal@absl@@UEAA@XZ ??1TimeZoneLibC@cctz@time_internal@absl@@UEAA@XZ @@ -1452,7 +1433,6 @@ ??R<lambda_1>@?0??pop_back@?$InlinedVector@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@absl@@QEAAXXZ@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0??remove_prefix@string_view@absl@@QEAAX_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0??remove_suffix@string_view@absl@@QEAAX_K@Z@QEBA?A?<auto>@@XZ - ??R<lambda_1>@?0??replace_tree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@4@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0??set_inline_size@InlineData@cord_internal@absl@@QEAAX_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$AddRing@$00@CordRepRing@cord_internal@absl@@CAPEAV123@PEAV123@0_K1@Z@QEBA?A?<auto>@@I@Z ??R<lambda_2>@?0???$AddRing@$0A@@CordRepRing@cord_internal@absl@@CAPEAV123@PEAV123@0_K1@Z@QEBA?A?<auto>@@I@Z @@ -1480,7 +1460,6 @@ ??R?$function@$$A6AXVstring_view@absl@@AEBVCord@2@@Z@__1@std@@QEBAXVstring_view@absl@@AEBVCord@4@@Z ??RByCivilTime@Transition@cctz@time_internal@absl@@QEBA_NAEBU1234@0@Z ??RByUnixTime@Transition@cctz@time_internal@absl@@QEBA_NAEBU1234@0@Z - ??RStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@QEAAXVstring_view@2@@Z ??Sabsl@@YA?AVuint128@0@V10@@Z ??Tabsl@@YA?AVuint128@0@V10@0@Z ??Uabsl@@YA?AVuint128@0@V10@0@Z @@ -1582,6 +1561,7 @@ ?AssertHeld@Mutex@absl@@QEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ + ?AssignLargeString@Cord@absl@@AEAAAEAV12@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ?AssignNext@?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__1@std@@V?$move_iterator@PEAUPayload@status_internal@absl@@@23@@inlined_vector_internal@absl@@QEAAXPEAUPayload@status_internal@3@@Z ?AssignSlow@InlineRep@Cord@absl@@AEAAXAEBV123@@Z ?At@TimeZone@absl@@QEBA?AUCivilInfo@12@VTime@2@@Z @@ -1740,6 +1720,7 @@ ?DumpPCAndFrameSizesAndStackTrace@debugging_internal@absl@@YAXPEAXQEBQEAXQEAHHH_NP6AXPEBD0@Z0@Z ?DurationFromTimespec@absl@@YA?AVDuration@1@Utimespec@@@Z ?DurationFromTimeval@absl@@YA?AVDuration@1@Utimeval@@@Z + ?EmplaceTree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@AEBVInlineData@53@W4MethodIdentifier@CordzUpdateTracker@53@@Z ?EmplaceTree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@W4MethodIdentifier@CordzUpdateTracker@53@@Z ?EmptyString@Status@absl@@CAPEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@XZ ?EnableDebugLog@CondVar@absl@@QEAAXPEBD@Z @@ -2203,7 +2184,6 @@ ?ReaderUnlock@Mutex@absl@@QEAAXXZ ?ReclaimThreadIdentity@synchronization_internal@absl@@YAXPEAX@Z ?RecordInsertSlow@container_internal@absl@@YAXPEAUHashtablezInfo@12@_K1@Z - ?RecordMetrics@CordzInfo@cord_internal@absl@@QEAAX_J@Z ?Ref@CordRep@cord_internal@absl@@SAPEAU123@PEAU123@@Z ?Register@CycleClockSource@base_internal@absl@@CAXP6A_JXZ@Z ?Register@HashtablezSampler@container_internal@absl@@QEAAPEAUHashtablezInfo@23@XZ @@ -2215,7 +2195,6 @@ ?RegisterMutexTracer@absl@@YAXP6AXPEBDPEBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPEBX_J@Z@Z ?RegisterSymbolizer@absl@@YAXP6A_NPEBXPEADH@Z@Z - ?Release@?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@SAXPEAUCordRepExternal@23@@Z ?Release@ReleasableMutexLock@absl@@QEAAXXZ ?Remove@CondVar@absl@@AEAAXPEAUPerThreadSynch@base_internal@2@@Z ?RemoveChunkPrefix@ChunkIterator@Cord@absl@@AEAAX_K@Z @@ -2240,6 +2219,7 @@ ?Rethrow@variant_internal@absl@@YAXXZ ?RoundUp@cord_internal@absl@@YA_K_K0@Z ?RoundUpForTag@cord_internal@absl@@YA_K_K@Z + ?SafeToDelete@CordzHandle@cord_internal@absl@@QEBA_NXZ ?SafeWriteToStderr@raw_logging_internal@absl@@YAXPEBD_K@Z ?SampleSlow@container_internal@absl@@YAPEAUHashtablezInfo@12@PEA_J@Z ?Seconds@absl@@YA?AVDuration@1@_J@Z @@ -2275,6 +2255,7 @@ ?SetToZero@?$BigUnsigned@$03@strings_internal@absl@@QEAAXXZ ?SetToZero@?$BigUnsigned@$0FE@@strings_internal@absl@@QEAAXXZ ?SetTree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@AEBVCordzUpdateScope@53@@Z + ?SetTreeOrEmpty@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@AEBVCordzUpdateScope@53@@Z ?SetValue@?$Manager@H$01@FormatArgImpl@str_format_internal@absl@@SA?ATData@234@AEBH@Z ?SetWidth@FormatConversionSpecImplFriend@str_format_internal@absl@@SAXHPEAVFormatConversionSpecImpl@23@@Z ?ShiftLeft@?$BigUnsigned@$03@strings_internal@absl@@QEAAXH@Z @@ -2452,10 +2433,9 @@ ?UnrefNonInlined@Status@absl@@CAX_K@Z ?UnrefTree@InlineRep@Cord@absl@@AEAAXXZ ?Unregister@HashtablezSampler@container_internal@absl@@QEAAXPEAUHashtablezInfo@23@@Z + ?UnsafeSetCordRep@CordzInfo@cord_internal@absl@@AEAAXPEAUCordRep@23@@Z ?UnsampleSlow@container_internal@absl@@YAXPEAUHashtablezInfo@12@@Z ?Untrack@CordzInfo@cord_internal@absl@@QEAAXXZ - ?UpdateCordzStatistics@InlineRep@Cord@absl@@QEAAXXZ - ?UpdateCordzStatisticsSlow@InlineRep@Cord@absl@@QEAAXXZ ?UpdateStackTrace@GraphCycles@synchronization_internal@absl@@QEAAXUGraphId@23@HP6AHPEAPEAXH@Z@Z ?UsingInlinedStorage@Storage@?$FixedArray@PEAUCordRep@cord_internal@absl@@$0?0V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@CA_N_K@Z ?Utf8SafeCEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z @@ -3144,7 +3124,6 @@ ?get@?$Storage@PEAPEBUCordRep@cord_internal@absl@@$00$0A@@internal_compressed_tuple@container_internal@absl@@QEGAAAEAPEAPEBUCordRep@cord_internal@4@XZ ?get@?$Storage@PEAUPayload@status_internal@absl@@$00$0A@@internal_compressed_tuple@container_internal@absl@@QEGAAAEAPEAUPayload@status_internal@4@XZ ?get@?$Storage@PEAUSubRange@absl@@$00$0A@@internal_compressed_tuple@container_internal@absl@@QEGAAAEAPEAUSubRange@4@XZ - ?get@?$Storage@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$0A@$0A@@internal_compressed_tuple@container_internal@absl@@QEGAAAEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@4@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@XZ ?get@?$Storage@V?$allocator@H@__1@std@@$0A@$00@internal_compressed_tuple@container_internal@absl@@QEGAAAEAV?$allocator@H@__1@std@@XZ ?get@?$Storage@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@$00$00@internal_compressed_tuple@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@XZ ?get@?$Storage@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@$0A@$00@internal_compressed_tuple@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@XZ @@ -3192,7 +3171,6 @@ ?is_leap_year@impl@detail@cctz@time_internal@absl@@YA_N_J@Z ?is_length@ConvTag@str_format_internal@absl@@QEBA_NXZ ?is_profiled@InlineData@cord_internal@absl@@QEBA_NXZ - ?is_profiled@InlineRep@Cord@absl@@QEBA_NXZ ?is_snapshot@CordzHandle@cord_internal@absl@@QEBA_NXZ ?is_tree@InlineData@cord_internal@absl@@QEBA_NXZ ?is_tree@InlineRep@Cord@absl@@QEBA_NXZ @@ -3318,7 +3296,6 @@ ?remove_prefix@string_view@absl@@QEAAX_K@Z ?remove_suffix@string_view@absl@@QEAAX_K@Z ?rend@string_view@absl@@QEBA?AV?$reverse_iterator@PEBD@__1@std@@XZ - ?replace_tree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@@Z ?reserve@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAX_K@Z ?reserve@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAX_K@Z ?reserve@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__1@std@@@__1@std@@QEAAX_K@Z @@ -3398,7 +3375,6 @@ ?set_inline_size@InlineData@cord_internal@absl@@QEAAX_K@Z ?set_inline_size@InlineRep@Cord@absl@@AEAAX_K@Z ?set_tree@InlineData@cord_internal@absl@@QEAAXPEAUCordRep@23@@Z - ?set_tree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@@Z ?set_value@InputValue@UnboundConversion@str_format_internal@absl@@QEAAXH@Z ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAXXZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QEBAHXZ
diff --git a/third_party/abseil-cpp/symbols_arm64_rel.def b/third_party/abseil-cpp/symbols_arm64_rel.def index 73aea3a..011e403 100644 --- a/third_party/abseil-cpp/symbols_arm64_rel.def +++ b/third_party/abseil-cpp/symbols_arm64_rel.def
@@ -1,6 +1,5 @@ EXPORTS ??$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z - ??$?4V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAAAEAV01@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAPEBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAPEBD@Z ??$AddRing@$00@CordRepRing@cord_internal@absl@@CAPEAV012@PEAV012@0_K1@Z @@ -62,7 +61,6 @@ ??$GenericCompare@HVstring_view@absl@@@absl@@YAHAEBVCord@0@AEBVstring_view@0@_K@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NAEBVCord@0@0_K@Z ??$GenericCompare@_NVstring_view@absl@@@absl@@YA_NAEBVCord@0@AEBVstring_view@0@_K@Z - ??$NewExternalRep@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@YAPEAUCordRep@01@Vstring_view@1@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z ??$ParseFloat@$09@strings_internal@absl@@YA?AUParsedFloat@01@PEBD0W4chars_format@1@@Z ??$ParseFloat@$0BA@@strings_internal@absl@@YA?AUParsedFloat@01@PEBD0W4chars_format@1@@Z ??$ParseFormatString@UParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@@str_format_internal@absl@@YA_NVstring_view@1@UParsedFormatConsumer@ParsedFormatBase@01@@Z @@ -108,7 +106,7 @@ ??0Condition@absl@@AEAA@XZ ??0Condition@absl@@QEAA@P6A_NPEAX@Z0@Z ??0Condition@absl@@QEAA@PEB_N@Z - ??0Cord@absl@@QEAA@Vstring_view@1@@Z + ??0Cord@absl@@AEAA@Vstring_view@1@W4MethodIdentifier@CordzUpdateTracker@cord_internal@1@@Z ??0CordzHandle@cord_internal@absl@@IEAA@_N@Z ??0CordzInfo@cord_internal@absl@@AEAA@PEAUCordRep@12@PEBV012@W4MethodIdentifier@CordzUpdateTracker@12@@Z ??0GraphCycles@synchronization_internal@absl@@QEAA@XZ @@ -225,6 +223,7 @@ ?AssertHeld@Mutex@absl@@QEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ + ?AssignLargeString@Cord@absl@@AEAAAEAV12@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ?AssignSlow@InlineRep@Cord@absl@@AEAAXAEBV123@@Z ?At@TimeZone@absl@@QEBA?AUCivilInfo@12@VTime@2@@Z ?At@TimeZone@absl@@QEBA?AUTimeInfo@12@V?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@2@@Z @@ -600,7 +599,6 @@ ?RegisterMutexTracer@absl@@YAXP6AXPEBDPEBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPEBX_J@Z@Z ?RegisterSymbolizer@absl@@YAXP6A_NPEBXPEADH@Z@Z - ?Release@?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@SAXPEAUCordRepExternal@23@@Z ?Release@ReleasableMutexLock@absl@@QEAAXXZ ?Remove@CondVar@absl@@AEAAXPEAUPerThreadSynch@base_internal@2@@Z ?RemoveEdge@GraphCycles@synchronization_internal@absl@@QEAAXUGraphId@23@0@Z @@ -613,6 +611,7 @@ ?ResetToBuiltinUTC@TimeZoneInfo@cctz@time_internal@absl@@AEAA_NAEBV?$duration@_JV?$ratio@$00$00@__1@std@@@chrono@__1@std@@@Z ?ResourceExhaustedError@absl@@YA?AVStatus@1@Vstring_view@1@@Z ?Rethrow@variant_internal@absl@@YAXXZ + ?SafeToDelete@CordzHandle@cord_internal@absl@@QEBA_NXZ ?SafeWriteToStderr@raw_logging_internal@absl@@YAXPEBD_K@Z ?SampleSlow@container_internal@absl@@YAPEAUHashtablezInfo@12@PEA_J@Z ?Seek@CordRepRingReader@cord_internal@absl@@QEAA?AVstring_view@3@_K@Z @@ -750,7 +749,6 @@ ?Unregister@HashtablezSampler@container_internal@absl@@QEAAXPEAUHashtablezInfo@23@@Z ?UnsampleSlow@container_internal@absl@@YAXPEAUHashtablezInfo@12@@Z ?Untrack@CordzInfo@cord_internal@absl@@QEAAXXZ - ?UpdateCordzStatisticsSlow@InlineRep@Cord@absl@@QEAAXXZ ?UpdateStackTrace@GraphCycles@synchronization_internal@absl@@QEAAXUGraphId@23@HP6AHPEAPEAXH@Z@Z ?Utf8SafeCEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z ?Utf8SafeCHexEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z @@ -854,7 +852,6 @@ ?safe_strtou32_base@numbers_internal@absl@@YA_NVstring_view@2@PEAIH@Z ?safe_strtou64_base@numbers_internal@absl@@YA_NVstring_view@2@PEA_KH@Z ?set_cordz_mean_interval@cord_internal@absl@@YAXH@Z - ?set_tree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@@Z ?shallow_subcords_enabled@cord_internal@absl@@3U?$atomic@_N@__1@std@@A ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAXXZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QEBAHXZ
diff --git a/third_party/abseil-cpp/symbols_x64_dbg.def b/third_party/abseil-cpp/symbols_x64_dbg.def index fd92091..9f722fd 100644 --- a/third_party/abseil-cpp/symbols_x64_dbg.def +++ b/third_party/abseil-cpp/symbols_x64_dbg.def
@@ -118,10 +118,6 @@ ??$?0PEAVZoneInfoSource@cctz@time_internal@absl@@U__default_init_tag@__1@std@@@?$__compressed_pair@PEAVZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAA@$$QEAPEAVZoneInfoSource@cctz@time_internal@absl@@$$QEAU__default_init_tag@12@@Z ??$?0PEAVZoneInfoSource@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PEAVZoneInfoSource@cctz@time_internal@absl@@$0A@$0A@@__1@std@@QEAA@$$QEAPEAVZoneInfoSource@cctz@time_internal@absl@@@Z ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@X@?$__compressed_pair_elem@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@$00$00@__1@std@@QEAA@$$QEAU?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@12@@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$$V$00@?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@QEAA@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@?$CompressedTupleImpl@V?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@U?$integer_sequence@_K$0A@@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@3@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@3@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@QEAA@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@H@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@?$Storage@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$0A@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@3@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@3@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z ??$?0USynchEvent@absl@@@Condition@absl@@QEAA@P6A_NPEAUSynchEvent@1@@Z0@Z ??$?0Uday_tag@detail@cctz@time_internal@absl@@@?$civil_time@Umonth_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEAA@AEBV?$civil_time@Uday_tag@detail@cctz@time_internal@absl@@@1234@PEAX@Z ??$?0Uday_tag@detail@cctz@time_internal@absl@@@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEAA@AEBV?$civil_time@Uday_tag@detail@cctz@time_internal@absl@@@1234@PEAX@Z @@ -192,7 +188,6 @@ ??$?0V?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__1@std@@@__1@std@@XV012@@?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QEAA@AEBV?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__1@std@@@__1@std@@@Z ??$?0VBufferRawSink@str_format_internal@absl@@$0A@@FormatRawSinkImpl@str_format_internal@absl@@QEAA@PEAVBufferRawSink@12@@Z ??$?0VFILERawSink@str_format_internal@absl@@$0A@@FormatRawSinkImpl@str_format_internal@absl@@QEAA@PEAVFILERawSink@12@@Z - ??$?4V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAAAEAV01@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ??$?8PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV012@@__1@std@@YA_NAEBV?$__wrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@@01@0@Z ??$?8PEAUTransitionType@cctz@time_internal@absl@@PEAU0123@@__1@std@@YA_NAEBV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$?8PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEBU0123@@__1@std@@YA_NAEBV?$__wrap_iter@PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z @@ -358,12 +353,10 @@ ??$Init@H@FormatArgImpl@str_format_internal@absl@@AEAAXAEBH@Z ??$Initialize@V?$CopyValueAdapter@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAXV?$CopyValueAdapter@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@12@_K@Z ??$Invoke@A6AXXZ$$V@Callable@base_internal@absl@@SAXA6AXXZ@Z - ??$Invoke@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AEAVstring_view@3@@Callable@base_internal@absl@@SAX$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AEAVstring_view@2@@Z ??$InvokeFlush@V?$basic_ostream@DU?$char_traits@D@__1@std@@@__1@std@@@str_format_internal@absl@@YAXPEAV?$basic_ostream@DU?$char_traits@D@__1@std@@@__1@std@@Vstring_view@1@@Z ??$InvokeFlush@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@str_format_internal@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z ??$InvokeFlush@VBufferRawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVBufferRawSink@01@Vstring_view@1@@Z ??$InvokeFlush@VFILERawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVFILERawSink@01@Vstring_view@1@@Z - ??$InvokeReleaser@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@X@cord_internal@absl@@YAXURank0@01@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Vstring_view@1@@Z ??$LowLevelCallOnce@A6AXXZ$$V@base_internal@absl@@YAXPEAVonce_flag@1@A6AXXZ@Z ??$MakeConstSpan@$SQEAX@absl@@YA?AV?$Span@QEAX@0@PEBQEAX_K@Z ??$MakeSpan@$SI$0BAA@@absl@@YA?AV?$Span@I@0@AEAY0BAA@I@Z @@ -373,7 +366,6 @@ ??$MakeSpan@$SI$0IA@@absl@@YA?AV?$Span@I@0@AEAY0IA@I@Z ??$MakeSpan@$SVFormatArgImpl@str_format_internal@absl@@@absl@@YA?AV?$Span@VFormatArgImpl@str_format_internal@absl@@@0@PEAVFormatArgImpl@str_format_internal@0@_K@Z ??$Milliseconds@N$0A@@absl@@YA?AVDuration@0@N@Z - ??$NewExternalRep@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@YAPEAUCordRep@01@Vstring_view@1@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z ??$Offset@$00$0A@@?$LayoutImpl@V?$tuple@_KPEAUCordRep@cord_internal@absl@@I@__1@std@@U?$integer_sequence@_K$0A@$00$01@absl@@U45@@internal_layout@container_internal@absl@@QEBA_KXZ ??$Offset@$00$0A@@?$LayoutImpl@V?$tuple@_KPEAUCordRep@cord_internal@absl@@I@__1@std@@U?$integer_sequence@_K$0A@$00@absl@@U?$integer_sequence@_K$0A@$00$01@5@@internal_layout@container_internal@absl@@QEBA_KXZ ??$Offset@$00$0A@@?$LayoutImpl@V?$tuple@_KPEAUCordRep@cord_internal@absl@@I@__1@std@@U?$integer_sequence@_K$0A@@absl@@U?$integer_sequence@_K$0A@$00@5@@internal_layout@container_internal@absl@@QEBA_KXZ @@ -702,8 +694,6 @@ ??$forward@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@@__1@std@@YA$$QEAU?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@01@AEAU201@@Z ??$forward@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__1@std@@YA$$QEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@AEAU2345@@Z ??$forward@UPayload@status_internal@absl@@@__1@std@@YA$$QEAUPayload@status_internal@absl@@AEAU234@@Z - ??$forward@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@__1@std@@YA$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@01@@Z@AEAU2?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@34@QEAA@0@Z@@Z - ??$forward@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@absl@@YA$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@0@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AEAU1?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@20@QEAA@0@Z@@Z ??$forward@USubRange@absl@@@__1@std@@YA$$QEAUSubRange@absl@@AEAU23@@Z ??$forward@UTransition@cctz@time_internal@absl@@@__1@std@@YA$$QEAUTransition@cctz@time_internal@absl@@AEAU2345@@Z ??$forward@UTransitionType@cctz@time_internal@absl@@@__1@std@@YA$$QEAUTransitionType@cctz@time_internal@absl@@AEAU2345@@Z @@ -736,7 +726,6 @@ ??$get@$00@?$CompressedTuple@V?$allocator@USubRange@absl@@@__1@std@@_K@container_internal@absl@@QEGBAAEB_KXZ ??$get@$00@?$CompressedTuple@_KV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@XZ ??$get@$00Vstring_view@absl@@V12@@__1@std@@YAAEBVstring_view@absl@@AEBU?$pair@Vstring_view@absl@@V12@@01@@Z - ??$get@$0A@@?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@QEGAAAEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@H@__1@std@@PEAH@container_internal@absl@@QEGAAAEAV?$allocator@H@__1@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@H@__1@std@@_K@container_internal@absl@@QEGAAAEAV?$allocator@H@__1@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@PEAPEAUCordRep@cord_internal@absl@@@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@XZ @@ -753,7 +742,6 @@ ??$get@Vstring_view@absl@@V12@@?$__get_pair@$00@__1@std@@SAAEBVstring_view@absl@@AEBU?$pair@Vstring_view@absl@@V12@@12@@Z ??$get@Vstring_view@absl@@V12@@?$__get_pair@$0A@@__1@std@@SAAEBVstring_view@absl@@AEBU?$pair@Vstring_view@absl@@V12@@12@@Z ??$invoke@A6AXXZ$$V@base_internal@absl@@YAXA6AXXZ@Z - ??$invoke@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AEAVstring_view@3@@base_internal@absl@@YAX$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AEAVstring_view@1@@Z ??$lower_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@__1@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByUnixTime@2345@@Z ??$make_pair@AEAPEAUCordRep@cord_internal@absl@@AEAPEAU123@@__1@std@@YA?AU?$pair@PEAUCordRep@cord_internal@absl@@PEAU123@@01@AEAPEAUCordRep@cord_internal@absl@@0@Z ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@$$V@__1@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@@01@XZ @@ -788,7 +776,6 @@ ??$move@AEAPEBV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@YA$$QEAPEBV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@AEAPEBV23@@Z ??$move@AEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@__1@std@@YA$$QEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@AEAU2345@@Z ??$move@AEAUPayload@status_internal@absl@@@__1@std@@YA$$QEAUPayload@status_internal@absl@@AEAU234@@Z - ??$move@AEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@__1@std@@YA$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@01@@Z@AEAU2?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@34@QEAA@0@Z@@Z ??$move@AEAUSubRange@absl@@@__1@std@@YA$$QEAUSubRange@absl@@AEAU23@@Z ??$move@AEAUTransition@cctz@time_internal@absl@@@__1@std@@YA$$QEAUTransition@cctz@time_internal@absl@@AEAU2345@@Z ??$move@AEAUTransitionType@cctz@time_internal@absl@@@__1@std@@YA$$QEAUTransitionType@cctz@time_internal@absl@@AEAU2345@@Z @@ -1030,9 +1017,9 @@ ??0Condition@absl@@AEAA@XZ ??0Condition@absl@@QEAA@P6A_NPEAX@Z0@Z ??0Condition@absl@@QEAA@PEB_N@Z + ??0Cord@absl@@AEAA@Vstring_view@1@W4MethodIdentifier@CordzUpdateTracker@cord_internal@1@@Z ??0Cord@absl@@QEAA@$$QEAV01@@Z ??0Cord@absl@@QEAA@AEBV01@@Z - ??0Cord@absl@@QEAA@Vstring_view@1@@Z ??0Cord@absl@@QEAA@XZ ??0CordForest@absl@@QEAA@_K@Z ??0CordRep@cord_internal@absl@@QEAA@XZ @@ -1091,7 +1078,6 @@ ??0StatusRep@status_internal@absl@@QEAA@W4StatusCode@2@Vstring_view@2@V?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@@__1@std@@@Z ??0Storage@?$FixedArray@PEAUCordRep@cord_internal@absl@@$0?0V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAA@_KAEBV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@Z ??0Streamable@str_format_internal@absl@@QEAA@AEBVUntypedFormatSpecImpl@12@V?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@2@@Z - ??0StringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@QEAA@$$QEAU0?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@12@QEAA@0@Z@@Z ??0SubRange@absl@@QEAA@PEAUCordRep@cord_internal@1@_K1@Z ??0SynchWaitParams@absl@@QEAA@PEBUMuHowS@1@PEBVCondition@1@VKernelTimeout@synchronization_internal@1@PEAVMutex@1@PEAUPerThreadSynch@base_internal@1@PEAU?$atomic@_J@__1@std@@@Z ??0Time@absl@@AEAA@VDuration@1@@Z @@ -1149,9 +1135,6 @@ ??1?$AllocationTransaction@V?$allocator@PEBUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ ??1?$AllocationTransaction@V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ ??1?$AllocationTransaction@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ - ??1?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@QEAA@XZ - ??1?$CompressedTupleImpl@V?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@U?$integer_sequence@_K$0A@@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@XZ - ??1?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@QEAA@XZ ??1?$FixedArray@PEAUCordRep@cord_internal@absl@@$0?0V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAA@XZ ??1?$InlinedVector@H$0CP@V?$allocator@H@__1@std@@@absl@@QEAA@XZ ??1?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAA@XZ @@ -1164,7 +1147,6 @@ ??1?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ ??1?$Storage@PEBUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEBUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ ??1?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ - ??1?$Storage@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$0A@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@XZ ??1?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAA@XZ ??1?$__policy_func@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__1@std@@@__1@std@@AEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@23@@Z@__function@__1@std@@QEAA@XZ ??1?$__policy_func@$$A6AXVstring_view@absl@@AEBVCord@2@@Z@__function@__1@std@@QEAA@XZ @@ -1236,7 +1218,6 @@ ??1StatusRep@status_internal@absl@@QEAA@XZ ??1Storage@?$FixedArray@PEAUCordRep@cord_internal@absl@@$0?0V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAA@XZ ??1Streamable@str_format_internal@absl@@QEAA@XZ - ??1StringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@QEAA@XZ ??1TimeZoneIf@cctz@time_internal@absl@@UEAA@XZ ??1TimeZoneInfo@cctz@time_internal@absl@@UEAA@XZ ??1TimeZoneLibC@cctz@time_internal@absl@@UEAA@XZ @@ -1454,7 +1435,6 @@ ??R<lambda_1>@?0??pop_back@?$InlinedVector@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@absl@@QEAAXXZ@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0??remove_prefix@string_view@absl@@QEAAX_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0??remove_suffix@string_view@absl@@QEAAX_K@Z@QEBA?A?<auto>@@XZ - ??R<lambda_1>@?0??replace_tree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@4@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0??set_inline_size@InlineData@cord_internal@absl@@QEAAX_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$AddRing@$00@CordRepRing@cord_internal@absl@@CAPEAV123@PEAV123@0_K1@Z@QEBA?A?<auto>@@I@Z ??R<lambda_2>@?0???$AddRing@$0A@@CordRepRing@cord_internal@absl@@CAPEAV123@PEAV123@0_K1@Z@QEBA?A?<auto>@@I@Z @@ -1482,7 +1462,6 @@ ??R?$function@$$A6AXVstring_view@absl@@AEBVCord@2@@Z@__1@std@@QEBAXVstring_view@absl@@AEBVCord@4@@Z ??RByCivilTime@Transition@cctz@time_internal@absl@@QEBA_NAEBU1234@0@Z ??RByUnixTime@Transition@cctz@time_internal@absl@@QEBA_NAEBU1234@0@Z - ??RStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@QEAAXVstring_view@2@@Z ??Sabsl@@YA?AVuint128@0@V10@@Z ??Tabsl@@YA?AVuint128@0@V10@0@Z ??XDuration@absl@@QEAAAEAV01@N@Z @@ -1583,6 +1562,7 @@ ?AssertHeld@Mutex@absl@@QEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ + ?AssignLargeString@Cord@absl@@AEAAAEAV12@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ?AssignNext@?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__1@std@@V?$move_iterator@PEAUPayload@status_internal@absl@@@23@@inlined_vector_internal@absl@@QEAAXPEAUPayload@status_internal@3@@Z ?AssignSlow@InlineRep@Cord@absl@@AEAAXAEBV123@@Z ?At@TimeZone@absl@@QEBA?AUCivilInfo@12@VTime@2@@Z @@ -1741,6 +1721,7 @@ ?DumpPCAndFrameSizesAndStackTrace@debugging_internal@absl@@YAXPEAXQEBQEAXQEAHHH_NP6AXPEBD0@Z0@Z ?DurationFromTimespec@absl@@YA?AVDuration@1@Utimespec@@@Z ?DurationFromTimeval@absl@@YA?AVDuration@1@Utimeval@@@Z + ?EmplaceTree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@AEBVInlineData@53@W4MethodIdentifier@CordzUpdateTracker@53@@Z ?EmplaceTree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@W4MethodIdentifier@CordzUpdateTracker@53@@Z ?EmptyString@Status@absl@@CAPEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@XZ ?EnableDebugLog@CondVar@absl@@QEAAXPEBD@Z @@ -2202,7 +2183,6 @@ ?ReaderUnlock@Mutex@absl@@QEAAXXZ ?ReclaimThreadIdentity@synchronization_internal@absl@@YAXPEAX@Z ?RecordInsertSlow@container_internal@absl@@YAXPEAUHashtablezInfo@12@_K1@Z - ?RecordMetrics@CordzInfo@cord_internal@absl@@QEAAX_J@Z ?Ref@CordRep@cord_internal@absl@@SAPEAU123@PEAU123@@Z ?Register@CycleClockSource@base_internal@absl@@CAXP6A_JXZ@Z ?Register@HashtablezSampler@container_internal@absl@@QEAAPEAUHashtablezInfo@23@XZ @@ -2214,7 +2194,6 @@ ?RegisterMutexTracer@absl@@YAXP6AXPEBDPEBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPEBX_J@Z@Z ?RegisterSymbolizer@absl@@YAXP6A_NPEBXPEADH@Z@Z - ?Release@?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@SAXPEAUCordRepExternal@23@@Z ?Release@ReleasableMutexLock@absl@@QEAAXXZ ?Remove@CondVar@absl@@AEAAXPEAUPerThreadSynch@base_internal@2@@Z ?RemoveChunkPrefix@ChunkIterator@Cord@absl@@AEAAX_K@Z @@ -2239,6 +2218,7 @@ ?Rethrow@variant_internal@absl@@YAXXZ ?RoundUp@cord_internal@absl@@YA_K_K0@Z ?RoundUpForTag@cord_internal@absl@@YA_K_K@Z + ?SafeToDelete@CordzHandle@cord_internal@absl@@QEBA_NXZ ?SafeWriteToStderr@raw_logging_internal@absl@@YAXPEBD_K@Z ?SampleSlow@container_internal@absl@@YAPEAUHashtablezInfo@12@PEA_J@Z ?Seconds@absl@@YA?AVDuration@1@_J@Z @@ -2274,6 +2254,7 @@ ?SetToZero@?$BigUnsigned@$03@strings_internal@absl@@QEAAXXZ ?SetToZero@?$BigUnsigned@$0FE@@strings_internal@absl@@QEAAXXZ ?SetTree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@AEBVCordzUpdateScope@53@@Z + ?SetTreeOrEmpty@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@AEBVCordzUpdateScope@53@@Z ?SetValue@?$Manager@H$01@FormatArgImpl@str_format_internal@absl@@SA?ATData@234@AEBH@Z ?SetWidth@FormatConversionSpecImplFriend@str_format_internal@absl@@SAXHPEAVFormatConversionSpecImpl@23@@Z ?ShiftLeft@?$BigUnsigned@$03@strings_internal@absl@@QEAAXH@Z @@ -2448,10 +2429,9 @@ ?UnrefNonInlined@Status@absl@@CAX_K@Z ?UnrefTree@InlineRep@Cord@absl@@AEAAXXZ ?Unregister@HashtablezSampler@container_internal@absl@@QEAAXPEAUHashtablezInfo@23@@Z + ?UnsafeSetCordRep@CordzInfo@cord_internal@absl@@AEAAXPEAUCordRep@23@@Z ?UnsampleSlow@container_internal@absl@@YAXPEAUHashtablezInfo@12@@Z ?Untrack@CordzInfo@cord_internal@absl@@QEAAXXZ - ?UpdateCordzStatistics@InlineRep@Cord@absl@@QEAAXXZ - ?UpdateCordzStatisticsSlow@InlineRep@Cord@absl@@QEAAXXZ ?UpdateStackTrace@GraphCycles@synchronization_internal@absl@@QEAAXUGraphId@23@HP6AHPEAPEAXH@Z@Z ?UsingInlinedStorage@Storage@?$FixedArray@PEAUCordRep@cord_internal@absl@@$0?0V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@CA_N_K@Z ?Utf8SafeCEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z @@ -3141,7 +3121,6 @@ ?get@?$Storage@PEAPEBUCordRep@cord_internal@absl@@$00$0A@@internal_compressed_tuple@container_internal@absl@@QEGAAAEAPEAPEBUCordRep@cord_internal@4@XZ ?get@?$Storage@PEAUPayload@status_internal@absl@@$00$0A@@internal_compressed_tuple@container_internal@absl@@QEGAAAEAPEAUPayload@status_internal@4@XZ ?get@?$Storage@PEAUSubRange@absl@@$00$0A@@internal_compressed_tuple@container_internal@absl@@QEGAAAEAPEAUSubRange@4@XZ - ?get@?$Storage@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$0A@$0A@@internal_compressed_tuple@container_internal@absl@@QEGAAAEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@4@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@XZ ?get@?$Storage@V?$allocator@H@__1@std@@$0A@$00@internal_compressed_tuple@container_internal@absl@@QEGAAAEAV?$allocator@H@__1@std@@XZ ?get@?$Storage@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@$00$00@internal_compressed_tuple@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@XZ ?get@?$Storage@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@$0A@$00@internal_compressed_tuple@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@XZ @@ -3189,7 +3168,6 @@ ?is_leap_year@impl@detail@cctz@time_internal@absl@@YA_N_J@Z ?is_length@ConvTag@str_format_internal@absl@@QEBA_NXZ ?is_profiled@InlineData@cord_internal@absl@@QEBA_NXZ - ?is_profiled@InlineRep@Cord@absl@@QEBA_NXZ ?is_snapshot@CordzHandle@cord_internal@absl@@QEBA_NXZ ?is_tree@InlineData@cord_internal@absl@@QEBA_NXZ ?is_tree@InlineRep@Cord@absl@@QEBA_NXZ @@ -3315,7 +3293,6 @@ ?remove_prefix@string_view@absl@@QEAAX_K@Z ?remove_suffix@string_view@absl@@QEAAX_K@Z ?rend@string_view@absl@@QEBA?AV?$reverse_iterator@PEBD@__1@std@@XZ - ?replace_tree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@@Z ?reserve@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAX_K@Z ?reserve@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAX_K@Z ?reserve@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__1@std@@@__1@std@@QEAAX_K@Z @@ -3395,7 +3372,6 @@ ?set_inline_size@InlineData@cord_internal@absl@@QEAAX_K@Z ?set_inline_size@InlineRep@Cord@absl@@AEAAX_K@Z ?set_tree@InlineData@cord_internal@absl@@QEAAXPEAUCordRep@23@@Z - ?set_tree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@@Z ?set_value@InputValue@UnboundConversion@str_format_internal@absl@@QEAAXH@Z ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAXXZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QEBAHXZ
diff --git a/third_party/abseil-cpp/symbols_x64_rel.def b/third_party/abseil-cpp/symbols_x64_rel.def index a36e6a12..d2820ce 100644 --- a/third_party/abseil-cpp/symbols_x64_rel.def +++ b/third_party/abseil-cpp/symbols_x64_rel.def
@@ -1,6 +1,5 @@ EXPORTS ??$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z - ??$?4V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAAAEAV01@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAPEBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAPEBD@Z ??$AddRing@$00@CordRepRing@cord_internal@absl@@CAPEAV012@PEAV012@0_K1@Z @@ -62,7 +61,6 @@ ??$GenericCompare@HVstring_view@absl@@@absl@@YAHAEBVCord@0@AEBVstring_view@0@_K@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NAEBVCord@0@0_K@Z ??$GenericCompare@_NVstring_view@absl@@@absl@@YA_NAEBVCord@0@AEBVstring_view@0@_K@Z - ??$NewExternalRep@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@YAPEAUCordRep@01@Vstring_view@1@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z ??$ParseFloat@$09@strings_internal@absl@@YA?AUParsedFloat@01@PEBD0W4chars_format@1@@Z ??$ParseFloat@$0BA@@strings_internal@absl@@YA?AUParsedFloat@01@PEBD0W4chars_format@1@@Z ??$ParseFormatString@UParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@@str_format_internal@absl@@YA_NVstring_view@1@UParsedFormatConsumer@ParsedFormatBase@01@@Z @@ -110,7 +108,7 @@ ??0Condition@absl@@AEAA@XZ ??0Condition@absl@@QEAA@P6A_NPEAX@Z0@Z ??0Condition@absl@@QEAA@PEB_N@Z - ??0Cord@absl@@QEAA@Vstring_view@1@@Z + ??0Cord@absl@@AEAA@Vstring_view@1@W4MethodIdentifier@CordzUpdateTracker@cord_internal@1@@Z ??0CordzHandle@cord_internal@absl@@IEAA@_N@Z ??0CordzInfo@cord_internal@absl@@AEAA@PEAUCordRep@12@PEBV012@W4MethodIdentifier@CordzUpdateTracker@12@@Z ??0GraphCycles@synchronization_internal@absl@@QEAA@XZ @@ -227,6 +225,7 @@ ?AssertHeld@Mutex@absl@@QEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ + ?AssignLargeString@Cord@absl@@AEAAAEAV12@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ?AssignSlow@InlineRep@Cord@absl@@AEAAXAEBV123@@Z ?At@TimeZone@absl@@QEBA?AUCivilInfo@12@VTime@2@@Z ?At@TimeZone@absl@@QEBA?AUTimeInfo@12@V?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@2@@Z @@ -600,7 +599,6 @@ ?RegisterMutexTracer@absl@@YAXP6AXPEBDPEBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPEBX_J@Z@Z ?RegisterSymbolizer@absl@@YAXP6A_NPEBXPEADH@Z@Z - ?Release@?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@SAXPEAUCordRepExternal@23@@Z ?Release@ReleasableMutexLock@absl@@QEAAXXZ ?Remove@CondVar@absl@@AEAAXPEAUPerThreadSynch@base_internal@2@@Z ?RemoveEdge@GraphCycles@synchronization_internal@absl@@QEAAXUGraphId@23@0@Z @@ -613,6 +611,7 @@ ?ResetToBuiltinUTC@TimeZoneInfo@cctz@time_internal@absl@@AEAA_NAEBV?$duration@_JV?$ratio@$00$00@__1@std@@@chrono@__1@std@@@Z ?ResourceExhaustedError@absl@@YA?AVStatus@1@Vstring_view@1@@Z ?Rethrow@variant_internal@absl@@YAXXZ + ?SafeToDelete@CordzHandle@cord_internal@absl@@QEBA_NXZ ?SafeWriteToStderr@raw_logging_internal@absl@@YAXPEBD_K@Z ?SampleSlow@container_internal@absl@@YAPEAUHashtablezInfo@12@PEA_J@Z ?Seek@CordRepRingReader@cord_internal@absl@@QEAA?AVstring_view@3@_K@Z @@ -750,7 +749,6 @@ ?Unregister@HashtablezSampler@container_internal@absl@@QEAAXPEAUHashtablezInfo@23@@Z ?UnsampleSlow@container_internal@absl@@YAXPEAUHashtablezInfo@12@@Z ?Untrack@CordzInfo@cord_internal@absl@@QEAAXXZ - ?UpdateCordzStatisticsSlow@InlineRep@Cord@absl@@QEAAXXZ ?UpdateStackTrace@GraphCycles@synchronization_internal@absl@@QEAAXUGraphId@23@HP6AHPEAPEAXH@Z@Z ?Utf8SafeCEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z ?Utf8SafeCHexEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z @@ -854,7 +852,6 @@ ?safe_strtou32_base@numbers_internal@absl@@YA_NVstring_view@2@PEAIH@Z ?safe_strtou64_base@numbers_internal@absl@@YA_NVstring_view@2@PEA_KH@Z ?set_cordz_mean_interval@cord_internal@absl@@YAXH@Z - ?set_tree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@@Z ?shallow_subcords_enabled@cord_internal@absl@@3U?$atomic@_N@__1@std@@A ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAXXZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QEBAHXZ
diff --git a/third_party/abseil-cpp/symbols_x64_rel_asan.def b/third_party/abseil-cpp/symbols_x64_rel_asan.def index e6f752d3..5c25343 100644 --- a/third_party/abseil-cpp/symbols_x64_rel_asan.def +++ b/third_party/abseil-cpp/symbols_x64_rel_asan.def
@@ -1,6 +1,5 @@ EXPORTS ??$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z - ??$?4V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAAAEAV01@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAPEBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAPEBD@Z ??$AddRing@$00@CordRepRing@cord_internal@absl@@CAPEAV012@PEAV012@0_K1@Z @@ -62,7 +61,6 @@ ??$GenericCompare@HVstring_view@absl@@@absl@@YAHAEBVCord@0@AEBVstring_view@0@_K@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NAEBVCord@0@0_K@Z ??$GenericCompare@_NVstring_view@absl@@@absl@@YA_NAEBVCord@0@AEBVstring_view@0@_K@Z - ??$NewExternalRep@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@YAPEAUCordRep@01@Vstring_view@1@$$QEAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z ??$ParseFloat@$09@strings_internal@absl@@YA?AUParsedFloat@01@PEBD0W4chars_format@1@@Z ??$ParseFloat@$0BA@@strings_internal@absl@@YA?AUParsedFloat@01@PEBD0W4chars_format@1@@Z ??$ParseFormatString@UParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@@str_format_internal@absl@@YA_NVstring_view@1@UParsedFormatConsumer@ParsedFormatBase@01@@Z @@ -114,7 +112,7 @@ ??0Condition@absl@@AEAA@XZ ??0Condition@absl@@QEAA@P6A_NPEAX@Z0@Z ??0Condition@absl@@QEAA@PEB_N@Z - ??0Cord@absl@@QEAA@Vstring_view@1@@Z + ??0Cord@absl@@AEAA@Vstring_view@1@W4MethodIdentifier@CordzUpdateTracker@cord_internal@1@@Z ??0CordzHandle@cord_internal@absl@@IEAA@_N@Z ??0CordzInfo@cord_internal@absl@@AEAA@PEAUCordRep@12@PEBV012@W4MethodIdentifier@CordzUpdateTracker@12@@Z ??0GraphCycles@synchronization_internal@absl@@QEAA@XZ @@ -240,6 +238,7 @@ ?AssertHeld@Mutex@absl@@QEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ + ?AssignLargeString@Cord@absl@@AEAAAEAV12@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ?AssignSlow@InlineRep@Cord@absl@@AEAAXAEBV123@@Z ?At@TimeZone@absl@@QEBA?AUCivilInfo@12@VTime@2@@Z ?At@TimeZone@absl@@QEBA?AUTimeInfo@12@V?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@2@@Z @@ -614,7 +613,6 @@ ?RegisterMutexTracer@absl@@YAXP6AXPEBDPEBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPEBX_J@Z@Z ?RegisterSymbolizer@absl@@YAXP6A_NPEBXPEADH@Z@Z - ?Release@?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@SAXPEAUCordRepExternal@23@@Z ?Release@ReleasableMutexLock@absl@@QEAAXXZ ?Remove@CondVar@absl@@AEAAXPEAUPerThreadSynch@base_internal@2@@Z ?RemoveEdge@GraphCycles@synchronization_internal@absl@@QEAAXUGraphId@23@0@Z @@ -627,6 +625,7 @@ ?ResetToBuiltinUTC@TimeZoneInfo@cctz@time_internal@absl@@AEAA_NAEBV?$duration@_JV?$ratio@$00$00@__1@std@@@chrono@__1@std@@@Z ?ResourceExhaustedError@absl@@YA?AVStatus@1@Vstring_view@1@@Z ?Rethrow@variant_internal@absl@@YAXXZ + ?SafeToDelete@CordzHandle@cord_internal@absl@@QEBA_NXZ ?SafeWriteToStderr@raw_logging_internal@absl@@YAXPEBD_K@Z ?SampleSlow@container_internal@absl@@YAPEAUHashtablezInfo@12@PEA_J@Z ?Seek@CordRepRingReader@cord_internal@absl@@QEAA?AVstring_view@3@_K@Z @@ -764,7 +763,6 @@ ?Unregister@HashtablezSampler@container_internal@absl@@QEAAXPEAUHashtablezInfo@23@@Z ?UnsampleSlow@container_internal@absl@@YAXPEAUHashtablezInfo@12@@Z ?Untrack@CordzInfo@cord_internal@absl@@QEAAXXZ - ?UpdateCordzStatisticsSlow@InlineRep@Cord@absl@@QEAAXXZ ?UpdateStackTrace@GraphCycles@synchronization_internal@absl@@QEAAXUGraphId@23@HP6AHPEAPEAXH@Z@Z ?Utf8SafeCEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z ?Utf8SafeCHexEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z @@ -904,7 +902,6 @@ ?safe_strtou32_base@numbers_internal@absl@@YA_NVstring_view@2@PEAIH@Z ?safe_strtou64_base@numbers_internal@absl@@YA_NVstring_view@2@PEA_KH@Z ?set_cordz_mean_interval@cord_internal@absl@@YAXH@Z - ?set_tree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@@Z ?shallow_subcords_enabled@cord_internal@absl@@3U?$atomic@_N@__1@std@@A ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAXXZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QEBAHXZ
diff --git a/third_party/abseil-cpp/symbols_x86_dbg.def b/third_party/abseil-cpp/symbols_x86_dbg.def index 75334b42..e1c26cc 100644 --- a/third_party/abseil-cpp/symbols_x86_dbg.def +++ b/third_party/abseil-cpp/symbols_x86_dbg.def
@@ -118,10 +118,6 @@ ??$?0PAVZoneInfoSource@cctz@time_internal@absl@@U__default_init_tag@__1@std@@@?$__compressed_pair@PAVZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__1@std@@@__1@std@@QAE@$$QAPAVZoneInfoSource@cctz@time_internal@absl@@$$QAU__default_init_tag@12@@Z ??$?0PAVZoneInfoSource@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PAVZoneInfoSource@cctz@time_internal@absl@@$0A@$0A@@__1@std@@QAE@$$QAPAVZoneInfoSource@cctz@time_internal@absl@@@Z ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@X@?$__compressed_pair_elem@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@$00$00@__1@std@@QAE@$$QAU?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@12@@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$$V$00@?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@QAE@$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@?$CompressedTupleImpl@V?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@U?$integer_sequence@I$0A@@3@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@3@$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@3@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@QAE@$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@H@Z - ??$?0UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@?$Storage@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$0A@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@3@$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@3@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z ??$?0USynchEvent@absl@@@Condition@absl@@QAE@P6A_NPAUSynchEvent@1@@Z0@Z ??$?0Uday_tag@detail@cctz@time_internal@absl@@@?$civil_time@Umonth_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QAE@ABV?$civil_time@Uday_tag@detail@cctz@time_internal@absl@@@1234@PAX@Z ??$?0Uday_tag@detail@cctz@time_internal@absl@@@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QAE@ABV?$civil_time@Uday_tag@detail@cctz@time_internal@absl@@@1234@PAX@Z @@ -192,7 +188,6 @@ ??$?0V?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__1@std@@@__1@std@@XV012@@?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QAE@ABV?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__1@std@@@__1@std@@@Z ??$?0VBufferRawSink@str_format_internal@absl@@$0A@@FormatRawSinkImpl@str_format_internal@absl@@QAE@PAVBufferRawSink@12@@Z ??$?0VFILERawSink@str_format_internal@absl@@$0A@@FormatRawSinkImpl@str_format_internal@absl@@QAE@PAVFILERawSink@12@@Z - ??$?4V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAEAAV01@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ??$?8PAPAVCordzHandle@cord_internal@absl@@PAPAV012@@__1@std@@YA_NABV?$__wrap_iter@PAPAVCordzHandle@cord_internal@absl@@@01@0@Z ??$?8PAUTransitionType@cctz@time_internal@absl@@PAU0123@@__1@std@@YA_NABV?$__wrap_iter@PAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$?8PBUConversionItem@ParsedFormatBase@str_format_internal@absl@@PBU0123@@__1@std@@YA_NABV?$__wrap_iter@PBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z @@ -358,12 +353,10 @@ ??$Init@H@FormatArgImpl@str_format_internal@absl@@AAEXABH@Z ??$Initialize@V?$CopyValueAdapter@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAEXV?$CopyValueAdapter@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@12@I@Z ??$Invoke@A6AXXZ$$V@Callable@base_internal@absl@@SAXA6AXXZ@Z - ??$Invoke@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AAVstring_view@3@@Callable@base_internal@absl@@SAX$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AAVstring_view@2@@Z ??$InvokeFlush@V?$basic_ostream@DU?$char_traits@D@__1@std@@@__1@std@@@str_format_internal@absl@@YAXPAV?$basic_ostream@DU?$char_traits@D@__1@std@@@__1@std@@Vstring_view@1@@Z ??$InvokeFlush@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@str_format_internal@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z ??$InvokeFlush@VBufferRawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPAVBufferRawSink@01@Vstring_view@1@@Z ??$InvokeFlush@VFILERawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPAVFILERawSink@01@Vstring_view@1@@Z - ??$InvokeReleaser@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@X@cord_internal@absl@@YAXURank0@01@$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Vstring_view@1@@Z ??$LowLevelCallOnce@A6AXXZ$$V@base_internal@absl@@YAXPAVonce_flag@1@A6AXXZ@Z ??$MakeConstSpan@$SQAX@absl@@YA?AV?$Span@QAX@0@PBQAXI@Z ??$MakeSpan@$SI$0BAA@@absl@@YA?AV?$Span@I@0@AAY0BAA@I@Z @@ -373,7 +366,6 @@ ??$MakeSpan@$SI$0IA@@absl@@YA?AV?$Span@I@0@AAY0IA@I@Z ??$MakeSpan@$SVFormatArgImpl@str_format_internal@absl@@@absl@@YA?AV?$Span@VFormatArgImpl@str_format_internal@absl@@@0@PAVFormatArgImpl@str_format_internal@0@I@Z ??$Milliseconds@N$0A@@absl@@YA?AVDuration@0@N@Z - ??$NewExternalRep@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@YAPAUCordRep@01@Vstring_view@1@$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z ??$Offset@$00$0A@@?$LayoutImpl@V?$tuple@IPAUCordRep@cord_internal@absl@@I@__1@std@@U?$integer_sequence@I$0A@$00$01@absl@@U45@@internal_layout@container_internal@absl@@QBEIXZ ??$Offset@$00$0A@@?$LayoutImpl@V?$tuple@IPAUCordRep@cord_internal@absl@@I@__1@std@@U?$integer_sequence@I$0A@$00@absl@@U?$integer_sequence@I$0A@$00$01@5@@internal_layout@container_internal@absl@@QBEIXZ ??$Offset@$00$0A@@?$LayoutImpl@V?$tuple@IPAUCordRep@cord_internal@absl@@I@__1@std@@U?$integer_sequence@I$0A@@absl@@U?$integer_sequence@I$0A@$00@5@@internal_layout@container_internal@absl@@QBEIXZ @@ -697,8 +689,6 @@ ??$forward@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@@__1@std@@YA$$QAU?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@01@AAU201@@Z ??$forward@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__1@std@@YA$$QAUConversionItem@ParsedFormatBase@str_format_internal@absl@@AAU2345@@Z ??$forward@UPayload@status_internal@absl@@@__1@std@@YA$$QAUPayload@status_internal@absl@@AAU234@@Z - ??$forward@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@__1@std@@YA$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@01@@Z@AAU2?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@34@QAE@0@Z@@Z - ??$forward@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@absl@@YA$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@0@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AAU1?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@20@QAE@0@Z@@Z ??$forward@USubRange@absl@@@__1@std@@YA$$QAUSubRange@absl@@AAU23@@Z ??$forward@UTransition@cctz@time_internal@absl@@@__1@std@@YA$$QAUTransition@cctz@time_internal@absl@@AAU2345@@Z ??$forward@UTransitionType@cctz@time_internal@absl@@@__1@std@@YA$$QAUTransitionType@cctz@time_internal@absl@@AAU2345@@Z @@ -732,7 +722,6 @@ ??$get@$00@?$CompressedTuple@V?$allocator@USubRange@absl@@@__1@std@@PAUSubRange@absl@@@container_internal@absl@@QGAEAAPAUSubRange@2@XZ ??$get@$00Vstring_view@absl@@V12@@__1@std@@YAABVstring_view@absl@@ABU?$pair@Vstring_view@absl@@V12@@01@@Z ??$get@$0A@@?$CompressedTuple@IV?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@container_internal@absl@@QGBEABIXZ - ??$get@$0A@@?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@QGAEAAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@2@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@H@__1@std@@I@container_internal@absl@@QGAEAAV?$allocator@H@__1@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@H@__1@std@@PAH@container_internal@absl@@QGAEAAV?$allocator@H@__1@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@I@container_internal@absl@@QGAEAAV?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@XZ @@ -748,7 +737,6 @@ ??$get@Vstring_view@absl@@V12@@?$__get_pair@$00@__1@std@@SAABVstring_view@absl@@ABU?$pair@Vstring_view@absl@@V12@@12@@Z ??$get@Vstring_view@absl@@V12@@?$__get_pair@$0A@@__1@std@@SAABVstring_view@absl@@ABU?$pair@Vstring_view@absl@@V12@@12@@Z ??$invoke@A6AXXZ$$V@base_internal@absl@@YAXA6AXXZ@Z - ??$invoke@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AAVstring_view@3@@base_internal@absl@@YAX$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@AAVstring_view@1@@Z ??$lower_bound@PBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@__1@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@0ABU2345@UByUnixTime@2345@@Z ??$make_pair@AAPAUCordRep@cord_internal@absl@@AAPAU123@@__1@std@@YA?AU?$pair@PAUCordRep@cord_internal@absl@@PAU123@@01@AAPAUCordRep@cord_internal@absl@@0@Z ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@$$V@__1@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@@01@XZ @@ -783,7 +771,6 @@ ??$move@AAPBV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@YA$$QAPBV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@AAPBV23@@Z ??$move@AAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@__1@std@@YA$$QAUConversionItem@ParsedFormatBase@str_format_internal@absl@@AAU2345@@Z ??$move@AAUPayload@status_internal@absl@@@__1@std@@YA$$QAUPayload@status_internal@absl@@AAU234@@Z - ??$move@AAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@__1@std@@YA$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@01@@Z@AAU2?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@34@QAE@0@Z@@Z ??$move@AAUSubRange@absl@@@__1@std@@YA$$QAUSubRange@absl@@AAU23@@Z ??$move@AAUTransition@cctz@time_internal@absl@@@__1@std@@YA$$QAUTransition@cctz@time_internal@absl@@AAU2345@@Z ??$move@AAUTransitionType@cctz@time_internal@absl@@@__1@std@@YA$$QAUTransitionType@cctz@time_internal@absl@@AAU2345@@Z @@ -1025,9 +1012,9 @@ ??0Condition@absl@@AAE@XZ ??0Condition@absl@@QAE@P6A_NPAX@Z0@Z ??0Condition@absl@@QAE@PB_N@Z + ??0Cord@absl@@AAE@Vstring_view@1@W4MethodIdentifier@CordzUpdateTracker@cord_internal@1@@Z ??0Cord@absl@@QAE@$$QAV01@@Z ??0Cord@absl@@QAE@ABV01@@Z - ??0Cord@absl@@QAE@Vstring_view@1@@Z ??0Cord@absl@@QAE@XZ ??0CordForest@absl@@QAE@I@Z ??0CordRep@cord_internal@absl@@QAE@XZ @@ -1086,7 +1073,6 @@ ??0StatusRep@status_internal@absl@@QAE@W4StatusCode@2@Vstring_view@2@V?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@@__1@std@@@__1@std@@@Z ??0Storage@?$FixedArray@PAUCordRep@cord_internal@absl@@$0PPPPPPPP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QAE@IABV?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@Z ??0Streamable@str_format_internal@absl@@QAE@ABVUntypedFormatSpecImpl@12@V?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@2@@Z - ??0StringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@QAE@$$QAU0?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@12@QAE@0@Z@@Z ??0SubRange@absl@@QAE@PAUCordRep@cord_internal@1@II@Z ??0SynchWaitParams@absl@@QAE@PBUMuHowS@1@PBVCondition@1@VKernelTimeout@synchronization_internal@1@PAVMutex@1@PAUPerThreadSynch@base_internal@1@PAU?$atomic@H@__1@std@@@Z ??0Time@absl@@AAE@VDuration@1@@Z @@ -1144,9 +1130,6 @@ ??1?$AllocationTransaction@V?$allocator@PBUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAE@XZ ??1?$AllocationTransaction@V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAE@XZ ??1?$AllocationTransaction@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QAE@XZ - ??1?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@QAE@XZ - ??1?$CompressedTupleImpl@V?$CompressedTuple@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@container_internal@absl@@U?$integer_sequence@I$0A@@3@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@XZ - ??1?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@QAE@XZ ??1?$FixedArray@PAUCordRep@cord_internal@absl@@$0PPPPPPPP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QAE@XZ ??1?$InlinedVector@H$0CP@V?$allocator@H@__1@std@@@absl@@QAE@XZ ??1?$InlinedVector@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QAE@XZ @@ -1159,7 +1142,6 @@ ??1?$Storage@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAE@XZ ??1?$Storage@PBUCordRep@cord_internal@absl@@$0CP@V?$allocator@PBUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAE@XZ ??1?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAE@XZ - ??1?$Storage@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$0A@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@XZ ??1?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QAE@XZ ??1?$__policy_func@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__1@std@@@__1@std@@ABV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@23@@Z@__function@__1@std@@QAE@XZ ??1?$__policy_func@$$A6AXVstring_view@absl@@ABVCord@2@@Z@__function@__1@std@@QAE@XZ @@ -1231,7 +1213,6 @@ ??1StatusRep@status_internal@absl@@QAE@XZ ??1Storage@?$FixedArray@PAUCordRep@cord_internal@absl@@$0PPPPPPPP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QAE@XZ ??1Streamable@str_format_internal@absl@@QAE@XZ - ??1StringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@QAE@XZ ??1TimeZoneIf@cctz@time_internal@absl@@UAE@XZ ??1TimeZoneInfo@cctz@time_internal@absl@@UAE@XZ ??1TimeZoneLibC@cctz@time_internal@absl@@UAE@XZ @@ -1449,7 +1430,6 @@ ??R<lambda_1>@?0??pop_back@?$InlinedVector@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@absl@@QAEXXZ@QBE?A?<auto>@@XZ ??R<lambda_1>@?0??remove_prefix@string_view@absl@@QAEXI@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0??remove_suffix@string_view@absl@@QAEXI@Z@QBE?A?<auto>@@XZ - ??R<lambda_1>@?0??replace_tree@InlineRep@Cord@absl@@QAEXPAUCordRep@cord_internal@4@@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0??set_inline_size@InlineData@cord_internal@absl@@QAEXI@Z@QBE?A?<auto>@@XZ ??R<lambda_2>@?0???$AddRing@$00@CordRepRing@cord_internal@absl@@CAPAV123@PAV123@0II@Z@QBE?A?<auto>@@I@Z ??R<lambda_2>@?0???$AddRing@$0A@@CordRepRing@cord_internal@absl@@CAPAV123@PAV123@0II@Z@QBE?A?<auto>@@I@Z @@ -1477,7 +1457,6 @@ ??R?$function@$$A6AXVstring_view@absl@@ABVCord@2@@Z@__1@std@@QBEXVstring_view@absl@@ABVCord@4@@Z ??RByCivilTime@Transition@cctz@time_internal@absl@@QBE_NABU1234@0@Z ??RByUnixTime@Transition@cctz@time_internal@absl@@QBE_NABU1234@0@Z - ??RStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@QAEXVstring_view@2@@Z ??Sabsl@@YA?AVuint128@0@V10@@Z ??XDuration@absl@@QAEAAV01@N@Z ??XDuration@absl@@QAEAAV01@_J@Z @@ -1577,6 +1556,7 @@ ?AssertHeld@Mutex@absl@@QBEXXZ ?AssertNotHeld@Mutex@absl@@QBEXXZ ?AssertReaderHeld@Mutex@absl@@QBEXXZ + ?AssignLargeString@Cord@absl@@AAEAAV12@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ?AssignNext@?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__1@std@@V?$move_iterator@PAUPayload@status_internal@absl@@@23@@inlined_vector_internal@absl@@QAEXPAUPayload@status_internal@3@@Z ?AssignSlow@InlineRep@Cord@absl@@AAEXABV123@@Z ?At@TimeZone@absl@@QBE?AUCivilInfo@12@VTime@2@@Z @@ -1735,6 +1715,7 @@ ?DumpPCAndFrameSizesAndStackTrace@debugging_internal@absl@@YAXPAXQBQAXQAHHH_NP6AXPBD0@Z0@Z ?DurationFromTimespec@absl@@YA?AVDuration@1@Utimespec@@@Z ?DurationFromTimeval@absl@@YA?AVDuration@1@Utimeval@@@Z + ?EmplaceTree@InlineRep@Cord@absl@@QAEXPAUCordRep@cord_internal@3@ABVInlineData@53@W4MethodIdentifier@CordzUpdateTracker@53@@Z ?EmplaceTree@InlineRep@Cord@absl@@QAEXPAUCordRep@cord_internal@3@W4MethodIdentifier@CordzUpdateTracker@53@@Z ?EmptyString@Status@absl@@CAPBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@XZ ?EnableDebugLog@CondVar@absl@@QAEXPBD@Z @@ -2196,7 +2177,6 @@ ?ReaderUnlock@Mutex@absl@@QAEXXZ ?ReclaimThreadIdentity@synchronization_internal@absl@@YAXPAX@Z ?RecordInsertSlow@container_internal@absl@@YAXPAUHashtablezInfo@12@II@Z - ?RecordMetrics@CordzInfo@cord_internal@absl@@QAEX_J@Z ?Ref@CordRep@cord_internal@absl@@SAPAU123@PAU123@@Z ?Register@CycleClockSource@base_internal@absl@@CAXP6A_JXZ@Z ?Register@HashtablezSampler@container_internal@absl@@QAEPAUHashtablezInfo@23@XZ @@ -2208,7 +2188,6 @@ ?RegisterMutexTracer@absl@@YAXP6AXPBDPBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPBX_J@Z@Z ?RegisterSymbolizer@absl@@YAXP6A_NPBXPADH@Z@Z - ?Release@?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@SAXPAUCordRepExternal@23@@Z ?Release@ReleasableMutexLock@absl@@QAEXXZ ?Remove@CondVar@absl@@AAEXPAUPerThreadSynch@base_internal@2@@Z ?RemoveChunkPrefix@ChunkIterator@Cord@absl@@AAEXI@Z @@ -2233,6 +2212,7 @@ ?Rethrow@variant_internal@absl@@YAXXZ ?RoundUp@cord_internal@absl@@YAIII@Z ?RoundUpForTag@cord_internal@absl@@YAII@Z + ?SafeToDelete@CordzHandle@cord_internal@absl@@QBE_NXZ ?SafeWriteToStderr@raw_logging_internal@absl@@YAXPBDI@Z ?SampleSlow@container_internal@absl@@YAPAUHashtablezInfo@12@PA_J@Z ?Seconds@absl@@YA?AVDuration@1@_J@Z @@ -2268,6 +2248,7 @@ ?SetToZero@?$BigUnsigned@$03@strings_internal@absl@@QAEXXZ ?SetToZero@?$BigUnsigned@$0FE@@strings_internal@absl@@QAEXXZ ?SetTree@InlineRep@Cord@absl@@QAEXPAUCordRep@cord_internal@3@ABVCordzUpdateScope@53@@Z + ?SetTreeOrEmpty@InlineRep@Cord@absl@@QAEXPAUCordRep@cord_internal@3@ABVCordzUpdateScope@53@@Z ?SetValue@?$Manager@H$01@FormatArgImpl@str_format_internal@absl@@SA?ATData@234@ABH@Z ?SetWidth@FormatConversionSpecImplFriend@str_format_internal@absl@@SAXHPAVFormatConversionSpecImpl@23@@Z ?ShiftLeft@?$BigUnsigned@$03@strings_internal@absl@@QAEXH@Z @@ -2442,10 +2423,9 @@ ?UnrefNonInlined@Status@absl@@CAXI@Z ?UnrefTree@InlineRep@Cord@absl@@AAEXXZ ?Unregister@HashtablezSampler@container_internal@absl@@QAEXPAUHashtablezInfo@23@@Z + ?UnsafeSetCordRep@CordzInfo@cord_internal@absl@@AAEXPAUCordRep@23@@Z ?UnsampleSlow@container_internal@absl@@YAXPAUHashtablezInfo@12@@Z ?Untrack@CordzInfo@cord_internal@absl@@QAEXXZ - ?UpdateCordzStatistics@InlineRep@Cord@absl@@QAEXXZ - ?UpdateCordzStatisticsSlow@InlineRep@Cord@absl@@QAEXXZ ?UpdateStackTrace@GraphCycles@synchronization_internal@absl@@QAEXUGraphId@23@HP6AHPAPAXH@Z@Z ?UsingInlinedStorage@Storage@?$FixedArray@PAUCordRep@cord_internal@absl@@$0PPPPPPPP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@CA_NI@Z ?Utf8SafeCEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z @@ -3138,7 +3118,6 @@ ?get@?$Storage@PAPBUCordRep@cord_internal@absl@@$00$0A@@internal_compressed_tuple@container_internal@absl@@QGAEAAPAPBUCordRep@cord_internal@4@XZ ?get@?$Storage@PAUPayload@status_internal@absl@@$00$0A@@internal_compressed_tuple@container_internal@absl@@QGAEAAPAUPayload@status_internal@4@XZ ?get@?$Storage@PAUSubRange@absl@@$00$0A@@internal_compressed_tuple@container_internal@absl@@QGAEAAPAUSubRange@4@XZ - ?get@?$Storage@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@$0A@$0A@@internal_compressed_tuple@container_internal@absl@@QGAEAAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@4@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@XZ ?get@?$Storage@V?$allocator@H@__1@std@@$0A@$00@internal_compressed_tuple@container_internal@absl@@QGAEAAV?$allocator@H@__1@std@@XZ ?get@?$Storage@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@$00$00@internal_compressed_tuple@container_internal@absl@@QGAEAAV?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@XZ ?get@?$Storage@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@$0A@$00@internal_compressed_tuple@container_internal@absl@@QGAEAAV?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@XZ @@ -3183,7 +3162,6 @@ ?is_leap_year@impl@detail@cctz@time_internal@absl@@YA_N_J@Z ?is_length@ConvTag@str_format_internal@absl@@QBE_NXZ ?is_profiled@InlineData@cord_internal@absl@@QBE_NXZ - ?is_profiled@InlineRep@Cord@absl@@QBE_NXZ ?is_snapshot@CordzHandle@cord_internal@absl@@QBE_NXZ ?is_tree@InlineData@cord_internal@absl@@QBE_NXZ ?is_tree@InlineRep@Cord@absl@@QBE_NXZ @@ -3309,7 +3287,6 @@ ?remove_prefix@string_view@absl@@QAEXI@Z ?remove_suffix@string_view@absl@@QAEXI@Z ?rend@string_view@absl@@QBE?AV?$reverse_iterator@PBD@__1@std@@XZ - ?replace_tree@InlineRep@Cord@absl@@QAEXPAUCordRep@cord_internal@3@@Z ?reserve@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__1@std@@@__1@std@@QAEXI@Z ?reserve@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__1@std@@@__1@std@@QAEXI@Z ?reserve@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__1@std@@@__1@std@@QAEXI@Z @@ -3389,7 +3366,6 @@ ?set_inline_size@InlineData@cord_internal@absl@@QAEXI@Z ?set_inline_size@InlineRep@Cord@absl@@AAEXI@Z ?set_tree@InlineData@cord_internal@absl@@QAEXPAUCordRep@23@@Z - ?set_tree@InlineRep@Cord@absl@@QAEXPAUCordRep@cord_internal@3@@Z ?set_value@InputValue@UnboundConversion@str_format_internal@absl@@QAEXH@Z ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__1@std@@@__1@std@@QAEXXZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QBEHXZ
diff --git a/third_party/abseil-cpp/symbols_x86_rel.def b/third_party/abseil-cpp/symbols_x86_rel.def index e816caa..1c763535 100644 --- a/third_party/abseil-cpp/symbols_x86_rel.def +++ b/third_party/abseil-cpp/symbols_x86_rel.def
@@ -1,6 +1,5 @@ EXPORTS ??$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z - ??$?4V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAEAAV01@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?RW4LogSeverity@absl@@ABQBDHAAPBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAPBD@Z ??$AddRing@$00@CordRepRing@cord_internal@absl@@CAPAV012@PAV012@0II@Z @@ -62,7 +61,6 @@ ??$GenericCompare@HVstring_view@absl@@@absl@@YAHABVCord@0@ABVstring_view@0@I@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NABVCord@0@0I@Z ??$GenericCompare@_NVstring_view@absl@@@absl@@YA_NABVCord@0@ABVstring_view@0@I@Z - ??$NewExternalRep@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@YAPAUCordRep@01@Vstring_view@1@$$QAUStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@1@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@Z ??$ParseFloat@$09@strings_internal@absl@@YA?AUParsedFloat@01@PBD0W4chars_format@1@@Z ??$ParseFloat@$0BA@@strings_internal@absl@@YA?AUParsedFloat@01@PBD0W4chars_format@1@@Z ??$ParseFormatString@UParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@@str_format_internal@absl@@YA_NVstring_view@1@UParsedFormatConsumer@ParsedFormatBase@01@@Z @@ -108,7 +106,7 @@ ??0Condition@absl@@AAE@XZ ??0Condition@absl@@QAE@P6A_NPAX@Z0@Z ??0Condition@absl@@QAE@PB_N@Z - ??0Cord@absl@@QAE@Vstring_view@1@@Z + ??0Cord@absl@@AAE@Vstring_view@1@W4MethodIdentifier@CordzUpdateTracker@cord_internal@1@@Z ??0CordzHandle@cord_internal@absl@@IAE@_N@Z ??0CordzInfo@cord_internal@absl@@AAE@PAUCordRep@12@PBV012@W4MethodIdentifier@CordzUpdateTracker@12@@Z ??0GraphCycles@synchronization_internal@absl@@QAE@XZ @@ -223,6 +221,7 @@ ?AssertHeld@Mutex@absl@@QBEXXZ ?AssertNotHeld@Mutex@absl@@QBEXXZ ?AssertReaderHeld@Mutex@absl@@QBEXXZ + ?AssignLargeString@Cord@absl@@AAEAAV12@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z ?AssignSlow@InlineRep@Cord@absl@@AAEXABV123@@Z ?At@TimeZone@absl@@QBE?AUCivilInfo@12@VTime@2@@Z ?At@TimeZone@absl@@QBE?AUTimeInfo@12@V?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@2@@Z @@ -596,7 +595,6 @@ ?RegisterMutexTracer@absl@@YAXP6AXPBDPBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPBX_J@Z@Z ?RegisterSymbolizer@absl@@YAXP6A_NPBXPADH@Z@Z - ?Release@?$CordRepExternalImpl@UStringReleaser@?M@???$?0V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@@cord_internal@absl@@SAXPAUCordRepExternal@23@@Z ?Release@ReleasableMutexLock@absl@@QAEXXZ ?Remove@CondVar@absl@@AAEXPAUPerThreadSynch@base_internal@2@@Z ?RemoveEdge@GraphCycles@synchronization_internal@absl@@QAEXUGraphId@23@0@Z @@ -609,6 +607,7 @@ ?ResetToBuiltinUTC@TimeZoneInfo@cctz@time_internal@absl@@AAE_NABV?$duration@_JV?$ratio@$00$00@__1@std@@@chrono@__1@std@@@Z ?ResourceExhaustedError@absl@@YA?AVStatus@1@Vstring_view@1@@Z ?Rethrow@variant_internal@absl@@YAXXZ + ?SafeToDelete@CordzHandle@cord_internal@absl@@QBE_NXZ ?SafeWriteToStderr@raw_logging_internal@absl@@YAXPBDI@Z ?SampleSlow@container_internal@absl@@YAPAUHashtablezInfo@12@PA_J@Z ?Seek@CordRepRingReader@cord_internal@absl@@QAE?AVstring_view@3@I@Z @@ -746,7 +745,6 @@ ?Unregister@HashtablezSampler@container_internal@absl@@QAEXPAUHashtablezInfo@23@@Z ?UnsampleSlow@container_internal@absl@@YAXPAUHashtablezInfo@12@@Z ?Untrack@CordzInfo@cord_internal@absl@@QAEXXZ - ?UpdateCordzStatisticsSlow@InlineRep@Cord@absl@@QAEXXZ ?UpdateStackTrace@GraphCycles@synchronization_internal@absl@@QAEXUGraphId@23@HP6AHPAPAXH@Z@Z ?Utf8SafeCEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z ?Utf8SafeCHexEscape@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@Vstring_view@1@@Z @@ -848,7 +846,6 @@ ?safe_strtou32_base@numbers_internal@absl@@YA_NVstring_view@2@PAIH@Z ?safe_strtou64_base@numbers_internal@absl@@YA_NVstring_view@2@PA_KH@Z ?set_cordz_mean_interval@cord_internal@absl@@YAXH@Z - ?set_tree@InlineRep@Cord@absl@@QAEXPAUCordRep@cord_internal@3@@Z ?shallow_subcords_enabled@cord_internal@absl@@3U?$atomic@_N@__1@std@@A ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__1@std@@@__1@std@@QAEXXZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QBEHXZ
diff --git a/third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom b/third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom index ee8e9dcc..ca007008 100644 --- a/third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom +++ b/third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom
@@ -101,10 +101,34 @@ SCANNING_BLOCKED, }; +// To match a filter, a Bluetooth device must: +// - support all the UUIDs in the services list if that member is present, +// - have a name equal to name if that member is present, +// - have a name starting with name_prefix if that member is present, +// - advertise manufacturer data matching all of the values in +// manufacturer_data if that member is present. struct WebBluetoothLeScanFilter { array<bluetooth.mojom.UUID>? services; string? name; string? name_prefix; + map<WebBluetoothCompany, array<WebBluetoothDataFilter>>? manufacturer_data; +}; + +// A Bluetooth company identifier is a unique number assigned by the Bluetooth +// SIG to member companies. This struct is currently required in +// WebBluetoothLeScanFilter because WTF::HashMap doesn't allow integer keys of 0 +// and -1, 0xffff being -1 in a uint16t. See crbug.com/1204960 +struct WebBluetoothCompany { + uint16 id; +}; + +// This struct is used as elements of an array to filter Bluetooth device data +// such as manufacturer data and service data. Bluetooth device data matches +// if for each bit in mask, the corresponding bit in Bluetooth device data is +// equal to the corresponding bit in |data|. +struct WebBluetoothDataFilter { + uint8 data; + uint8 mask; }; struct WebBluetoothRequestDeviceOptions {
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 71e78535..6a1be66 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -3204,6 +3204,11 @@ kCSSFilterColorMatrix = 3889, kHTMLFencedFrameElement = 3890, kCSSFilterLuminanceToAlpha = 3891, + kHandwritingRecognitionCreateRecognizer = 3892, + kHandwritingRecognitionQuerySupport = 3893, + kHandwritingRecognitionStartDrawing = 3894, + kHandwritingRecognitionGetPrediction = 3895, + kWebBluetoothManufacturerDataFilter = 3896, // 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/renderer/bindings/core/v8/native_value_traits_impl.h b/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h index 2971361..0fc6904 100644 --- a/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h +++ b/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
@@ -827,6 +827,85 @@ struct NativeValueTraits<IDLNullable<IDLPromise>>; // Sequence types + +namespace bindings { + +// Fast case: we're iterating over an Array that adheres to +// %ArrayIteratorPrototype%'s protocol. +template <typename T> +typename NativeValueTraits<IDLSequence<T>>::ImplType +CreateIDLSequenceFromV8Array(v8::Isolate* isolate, + v8::Local<v8::Array> v8_array, + ExceptionState& exception_state) { + // https://heycam.github.io/webidl/#create-sequence-from-iterable + const uint32_t length = v8_array->Length(); + if (length > NativeValueTraits<IDLSequence<T>>::ImplType::MaxCapacity()) { + exception_state.ThrowRangeError("Array length exceeds supported limit."); + return {}; + } + + typename NativeValueTraits<IDLSequence<T>>::ImplType result; + result.ReserveInitialCapacity(length); + v8::Local<v8::Context> current_context = isolate->GetCurrentContext(); + v8::TryCatch try_block(isolate); + // Array length may change if array is mutated during iteration. + for (uint32_t i = 0; i < v8_array->Length(); ++i) { + v8::Local<v8::Value> v8_element; + if (!v8_array->Get(current_context, i).ToLocal(&v8_element)) { + exception_state.RethrowV8Exception(try_block.Exception()); + return {}; + } + // 3.4. Initialize Si to the result of converting nextItem to an IDL value + // of type T. + auto&& element = + NativeValueTraits<T>::NativeValue(isolate, v8_element, exception_state); + if (exception_state.HadException()) + return {}; + result.push_back(std::move(element)); + } + // 3.2. If next is false, then return an IDL sequence value of type + // sequence<T> of length i, where the value of the element at index j is Sj. + return result; +} + +// Slow case: follow WebIDL's "Creating a sequence from an iterable" steps to +// iterate through each element. +template <typename T> +typename NativeValueTraits<IDLSequence<T>>::ImplType +CreateIDLSequenceFromIterator(v8::Isolate* isolate, + ScriptIterator script_iterator, + ExceptionState& exception_state) { + // https://heycam.github.io/webidl/#create-sequence-from-iterable + ExecutionContext* execution_context = + ToExecutionContext(isolate->GetCurrentContext()); + typename NativeValueTraits<IDLSequence<T>>::ImplType result; + // 3. Repeat: + while (script_iterator.Next(execution_context, exception_state)) { + // 3.1. Let next be ? IteratorStep(iter). + DCHECK(!exception_state.HadException()); + // 3.3. Let nextItem be ? IteratorValue(next). + // + // The value should already be non-empty, as guaranteed by the call to + // Next() and the |exception_state| check above. + v8::Local<v8::Value> v8_element = + script_iterator.GetValue().ToLocalChecked(); + // 3.4. Initialize Si to the result of converting nextItem to an IDL value + // of type T. + auto&& element = + NativeValueTraits<T>::NativeValue(isolate, v8_element, exception_state); + if (exception_state.HadException()) + return {}; + result.push_back(std::move(element)); + } + if (exception_state.HadException()) + return {}; + // 3.2. If next is false, then return an IDL sequence value of type + // sequence<T> of length i, where the value of the element at index j is Sj. + return result; +} + +} // namespace bindings + template <typename T> struct NativeValueTraits<IDLSequence<T>> : public NativeValueTraitsBase<IDLSequence<T>> { @@ -837,6 +916,15 @@ static ImplType NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exception_state) { + // TODO(https://crbug.com/715122): Checking for IsArray() may not be + // enough. Other engines also prefer regular array iteration over a custom + // @@iterator when the latter is defined, but it is not clear if this is a + // valid optimization. + if (value->IsArray()) { + return bindings::CreateIDLSequenceFromV8Array<T>( + isolate, value.As<v8::Array>(), exception_state); + } + // 1. If Type(V) is not Object, throw a TypeError. if (!value->IsObject()) { exception_state.ThrowTypeError( @@ -844,36 +932,22 @@ return ImplType(); } - ImplType result; - // TODO(https://crbug.com/715122): Checking for IsArray() may not be - // enough. Other engines also prefer regular array iteration over a custom - // @@iterator when the latter is defined, but it is not clear if this is a - // valid optimization. - if (value->IsArray()) { - ConvertSequenceFast(isolate, value.As<v8::Array>(), exception_state, - result); - } else { - // 2. Let method be ? GetMethod(V, @@iterator). - // 3. If method is undefined, throw a TypeError. - // 4. Return the result of creating a sequence from V and method. - auto script_iterator = ScriptIterator::FromIterable( - isolate, value.As<v8::Object>(), exception_state); - if (exception_state.HadException()) - return ImplType(); - if (script_iterator.IsNull()) { - // A null ScriptIterator with an empty |exception_state| means the - // object is lacking a callable @@iterator property. - exception_state.ThrowTypeError( - "The object must have a callable @@iterator property."); - return ImplType(); - } - ConvertSequenceSlow(isolate, std::move(script_iterator), exception_state, - result); - } - + // 2. Let method be ? GetMethod(V, @@iterator). + // 3. If method is undefined, throw a TypeError. + // 4. Return the result of creating a sequence from V and method. + auto script_iterator = ScriptIterator::FromIterable( + isolate, value.As<v8::Object>(), exception_state); if (exception_state.HadException()) return ImplType(); - return result; + if (script_iterator.IsNull()) { + // A null ScriptIterator with an empty |exception_state| means the + // object is lacking a callable @@iterator property. + exception_state.ThrowTypeError( + "The object must have a callable @@iterator property."); + return ImplType(); + } + return bindings::CreateIDLSequenceFromIterator<T>( + isolate, std::move(script_iterator), exception_state); } // https://heycam.github.io/webidl/#es-sequence @@ -883,74 +957,8 @@ ScriptIterator script_iterator, ExceptionState& exception_state) { DCHECK(!script_iterator.IsNull()); - ImplType result; - ConvertSequenceSlow(isolate, std::move(script_iterator), exception_state, - result); - return result; - } - - private: - // Fast case: we're interating over an Array that adheres to - // %ArrayIteratorPrototype%'s protocol. - static void ConvertSequenceFast(v8::Isolate* isolate, - v8::Local<v8::Array> v8_array, - ExceptionState& exception_state, - ImplType& result) { - const uint32_t length = v8_array->Length(); - if (length > ImplType::MaxCapacity()) { - exception_state.ThrowRangeError("Array length exceeds supported limit."); - return; - } - result.ReserveInitialCapacity(length); - v8::TryCatch block(isolate); - // Array length may change if array is mutated during iteration. - for (uint32_t i = 0; i < v8_array->Length(); ++i) { - v8::Local<v8::Value> element; - if (!v8_array->Get(isolate->GetCurrentContext(), i).ToLocal(&element)) { - exception_state.RethrowV8Exception(block.Exception()); - return; - } - result.push_back( - NativeValueTraits<T>::NativeValue(isolate, element, exception_state)); - if (exception_state.HadException()) - return; - } - } - - // Slow case: follow WebIDL's "Creating a sequence from an iterable" steps to - // iterate through each element. - static void ConvertSequenceSlow(v8::Isolate* isolate, - ScriptIterator script_iterator, - ExceptionState& exception_state, - ImplType& result) { - // https://heycam.github.io/webidl/#create-sequence-from-iterable - // 2. Initialize i to be 0. - // 3. Repeat: - ExecutionContext* execution_context = - ToExecutionContext(isolate->GetCurrentContext()); - while (script_iterator.Next(execution_context, exception_state)) { - // 3.1. Let next be ? IteratorStep(iter). - // 3.2. If next is false, then return an IDL sequence value of type - // sequence<T> of length i, where the value of the element at index - // j is Sj. - // 3.3. Let nextItem be ? IteratorValue(next). - if (exception_state.HadException()) - return; - - // The value should already be non-empty, as guaranteed by the call to - // Next() and the |exception_state| check above. - v8::Local<v8::Value> element = - script_iterator.GetValue().ToLocalChecked(); - DCHECK(!element.IsEmpty()); - - // 3.4. Initialize Si to the result of converting nextItem to an IDL - // value of type T. - // 3.5. Set i to i + 1. - result.push_back( - NativeValueTraits<T>::NativeValue(isolate, element, exception_state)); - if (exception_state.HadException()) - return; - } + return bindings::CreateIDLSequenceFromIterator<T>( + isolate, std::move(script_iterator), exception_state); } };
diff --git a/third_party/blink/renderer/bindings/core/v8/script_iterator.cc b/third_party/blink/renderer/bindings/core/v8/script_iterator.cc index 6520efd4..18648cb9 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_iterator.cc +++ b/third_party/blink/renderer/bindings/core/v8/script_iterator.cc
@@ -13,68 +13,89 @@ // static ScriptIterator ScriptIterator::FromIterable(v8::Isolate* isolate, - v8::Local<v8::Object> value, + v8::Local<v8::Object> iterable, ExceptionState& exception_state) { - // First, call the GetMethod(V, @@iterator) abstract ES operation. - const v8::Local<v8::Function> iterator_method = - GetEsIteratorMethod(isolate, value, exception_state); - if (exception_state.HadException()) - return ScriptIterator(); - if (iterator_method.IsEmpty()) - return ScriptIterator(); + // 7.4.1 GetIterator ( obj [ , hint [ , method ] ] ) + // https://tc39.es/ecma262/#sec-getiterator + v8::TryCatch try_catch(isolate); + v8::Local<v8::Context> current_context = isolate->GetCurrentContext(); - // Use the method returned above to invoke the GetIterator(V, sync, method) - // abstract ES operation. - const v8::Local<v8::Object> iterator = - GetEsIteratorWithMethod(isolate, iterator_method, value, exception_state); - if (exception_state.HadException()) + // 3.b. Otherwise, set method to ? GetMethod(obj, @@iterator). + v8::Local<v8::Value> method; + if (!iterable->Get(current_context, v8::Symbol::GetIterator(isolate)) + .ToLocal(&method)) { + exception_state.RethrowV8Exception(try_catch.Exception()); return ScriptIterator(); + } + if (method->IsNullOrUndefined()) { + // Some algorithms in Web IDL want to change their behavior when `method` is + // undefined, so give them a choice. + return ScriptIterator(); // Return without an exception. + } + if (!method->IsFunction()) { + exception_state.ThrowTypeError("@@iterator must be a callable."); + return ScriptIterator(); + } - return ScriptIterator(isolate, iterator); + // 4. Let iterator be ? Call(method, obj). + v8::Local<v8::Value> iterator; + if (!V8ScriptRunner::CallFunction(method.As<v8::Function>(), + ToExecutionContext(current_context), + iterable, 0, nullptr, isolate) + .ToLocal(&iterator)) { + exception_state.RethrowV8Exception(try_catch.Exception()); + return ScriptIterator(); + } + // 5. If Type(iterator) is not Object, throw a TypeError exception. + if (!iterator->IsObject()) { + exception_state.ThrowTypeError("Iterator object must be an object."); + return ScriptIterator(); + } + + // 6. Let nextMethod be ? GetV(iterator, "next"). + v8::Local<v8::Value> next_method; + if (!iterator.As<v8::Object>() + ->Get(current_context, V8AtomicString(isolate, "next")) + .ToLocal(&next_method)) { + exception_state.RethrowV8Exception(try_catch.Exception()); + return ScriptIterator(); + } + + // 7. Let iteratorRecord be the Record { [[Iterator]]: iterator, + // [[NextMethod]]: nextMethod, [[Done]]: false }. + // 8. Return iteratorRecord. + return ScriptIterator(isolate, iterator.As<v8::Object>(), next_method); } ScriptIterator::ScriptIterator(v8::Isolate* isolate, - v8::Local<v8::Object> iterator) + v8::Local<v8::Object> iterator, + v8::Local<v8::Value> next_method) : isolate_(isolate), iterator_(iterator), - next_key_(V8AtomicString(isolate, "next")), + next_method_(next_method), done_key_(V8AtomicString(isolate, "done")), value_key_(V8AtomicString(isolate, "value")), done_(false) { - DCHECK(!iterator.IsEmpty()); + DCHECK(!IsNull()); } bool ScriptIterator::Next(ExecutionContext* execution_context, ExceptionState& exception_state, - v8::Local<v8::Value> next_value) { + v8::Local<v8::Value> value) { DCHECK(!IsNull()); - v8::TryCatch try_catch(isolate_); - v8::Local<v8::Context> context = isolate_->GetCurrentContext(); - - v8::Local<v8::Value> next; - if (!iterator_->Get(context, next_key_).ToLocal(&next)) { - CHECK(!try_catch.Exception().IsEmpty()); - exception_state.RethrowV8Exception(try_catch.Exception()); - done_ = true; - return false; - } - if (!next->IsFunction()) { + if (!next_method_->IsFunction()) { exception_state.ThrowTypeError("Expected next() function on iterator."); done_ = true; return false; } - Vector<v8::Local<v8::Value>, 1> argv; - if (!next_value.IsEmpty()) - argv = {next_value}; - + v8::TryCatch try_catch(isolate_); v8::Local<v8::Value> result; - if (!V8ScriptRunner::CallFunction(v8::Local<v8::Function>::Cast(next), - execution_context, iterator_, argv.size(), - argv.data(), isolate_) + if (!V8ScriptRunner::CallFunction(next_method_.As<v8::Function>(), + execution_context, iterator_, + value.IsEmpty() ? 0 : 1, &value, isolate_) .ToLocal(&result)) { - CHECK(!try_catch.Exception().IsEmpty()); exception_state.RethrowV8Exception(try_catch.Exception()); done_ = true; return false; @@ -85,22 +106,22 @@ done_ = true; return false; } - v8::Local<v8::Object> result_object = v8::Local<v8::Object>::Cast(result); + v8::Local<v8::Object> result_object = result.As<v8::Object>(); + v8::Local<v8::Context> context = isolate_->GetCurrentContext(); value_ = result_object->Get(context, value_key_); if (value_.IsEmpty()) { - CHECK(!try_catch.Exception().IsEmpty()); - exception_state.RethrowV8Exception(try_catch.Exception()); - } - - v8::Local<v8::Value> done; - if (!result_object->Get(context, done_key_).ToLocal(&done)) { - CHECK(!try_catch.Exception().IsEmpty()); exception_state.RethrowV8Exception(try_catch.Exception()); done_ = true; return false; } + v8::Local<v8::Value> done; + if (!result_object->Get(context, done_key_).ToLocal(&done)) { + exception_state.RethrowV8Exception(try_catch.Exception()); + done_ = true; + return false; + } done_ = done->BooleanValue(isolate_); return !done_; }
diff --git a/third_party/blink/renderer/bindings/core/v8/script_iterator.h b/third_party/blink/renderer/bindings/core/v8/script_iterator.h index 0d5e3be..7bbfb65 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_iterator.h +++ b/third_party/blink/renderer/bindings/core/v8/script_iterator.h
@@ -61,16 +61,9 @@ // - ScriptIterator can be null even if there is no exception. In this case, // it indicates that the given ES object does not have an @@iterator // property. - static ScriptIterator FromIterable(v8::Isolate*, - v8::Local<v8::Object>, - ExceptionState&); - - // Constructs a ScriptIterator from an ES object that implements the iterator - // protocol: |iterator| is supposed to have a next() method that returns an - // object with two properties, "done" and "value". - ScriptIterator(v8::Isolate*, v8::Local<v8::Object> iterator); - - ScriptIterator() = default; + static ScriptIterator FromIterable(v8::Isolate* isolate, + v8::Local<v8::Object> iterable, + ExceptionState& exception_state); ScriptIterator(ScriptIterator&&) noexcept = default; ScriptIterator& operator=(ScriptIterator&&) noexcept = default; @@ -81,16 +74,25 @@ bool IsNull() const { return iterator_.IsEmpty(); } // Returns true if the iterator is still not done. - bool Next(ExecutionContext*, - ExceptionState&, - v8::Local<v8::Value> next_value = v8::Local<v8::Value>()); + bool Next(ExecutionContext* execution_context, + ExceptionState& exception_state, + v8::Local<v8::Value> value = v8::Local<v8::Value>()); v8::MaybeLocal<v8::Value> GetValue() { return value_; } private: + // Constructs a ScriptIterator from an ES object that implements the iterator + // protocol: |iterator| is supposed to have a next() method that returns an + // object with two properties, "done" and "value". + ScriptIterator(v8::Isolate*, + v8::Local<v8::Object> iterator, + v8::Local<v8::Value> next_method); + + ScriptIterator() = default; + v8::Isolate* isolate_ = nullptr; v8::Local<v8::Object> iterator_; - v8::Local<v8::String> next_key_; + v8::Local<v8::Value> next_method_; v8::Local<v8::String> done_key_; v8::Local<v8::String> value_key_; bool done_ = true;
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc index f96f4e0..03ab4d2 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
@@ -651,7 +651,7 @@ ExecutionContext* context, v8::Local<v8::Value> receiver, int argc, - v8::Local<v8::Value> args[], + v8::Local<v8::Value> argv[], v8::Isolate* isolate) { LocalDOMWindow* window = DynamicTo<LocalDOMWindow>(context); LocalFrame* frame = window ? window->GetFrame() : nullptr; @@ -688,7 +688,7 @@ probe::CallFunction probe(context, function, depth); v8::MaybeLocal<v8::Value> result = - function->Call(isolate->GetCurrentContext(), receiver, argc, args); + function->Call(isolate->GetCurrentContext(), receiver, argc, argv); CHECK(!isolate->IsDead()); if (!depth)
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h index 1bf869a..110ad7ad 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h +++ b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h
@@ -140,7 +140,7 @@ ExecutionContext*, v8::Local<v8::Value> receiver, int argc, - v8::Local<v8::Value> info[], + v8::Local<v8::Value> argv[], v8::Isolate*); // https://html.spec.whatwg.org/C/#run-a-module-script
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni index acfe110..ce85dab 100644 --- a/third_party/blink/renderer/bindings/generated_in_modules.gni +++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -175,10 +175,14 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_blob_event_init.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_advertising_event_init.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_advertising_event_init.h", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_data_filter_init.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_data_filter_init.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_le_scan_filter_init.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_le_scan_filter_init.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_le_scan_options.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_le_scan_options.h", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_manufacturer_data_filter_init.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_manufacturer_data_filter_init.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_cable_authentication_data.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_cable_authentication_data.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_cable_registration_data.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni index 8c28c97..0acd6f72 100644 --- a/third_party/blink/renderer/bindings/idl_in_modules.gni +++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -55,10 +55,12 @@ "//third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event_init.idl", "//third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.idl", "//third_party/blink/renderer/modules/bluetooth/bluetooth_device.idl", + "//third_party/blink/renderer/modules/bluetooth/bluetooth_data_filter_init.idl", "//third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.idl", "//third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_filter_init.idl", "//third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_options.idl", "//third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.idl", + "//third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_filter_init.idl", "//third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.idl", "//third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.idl", "//third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_server.idl",
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/union.py b/third_party/blink/renderer/bindings/scripts/bind_gen/union.py index fe36cd3..3e8825d 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/union.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/union.py
@@ -12,6 +12,8 @@ from .blink_v8_bridge import v8_bridge_class_name from .code_node import EmptyNode from .code_node import ListNode +from .code_node import SequenceNode +from .code_node import SymbolDefinitionNode from .code_node import SymbolNode from .code_node import SymbolScopeNode from .code_node import TextNode @@ -193,6 +195,7 @@ S = SymbolNode T = TextNode + F = lambda *args, **kwargs: T(_format(*args, **kwargs)) func_decl = CxxFuncDeclNode(name="Create", arg_decls=[ @@ -220,9 +223,10 @@ "exception_state": "exception_state", }) - # Create an instance from v8::Value based on the overload resolution - # algorithm. - # https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm + # Create an instance from v8::Value based on the conversion algorithm. + # + # 3.2.24. Union types + # https://heycam.github.io/webidl/#es-union union_members = cg_context.union_members member = None # Will be a found member in union_members. @@ -239,7 +243,10 @@ return member return None - def dispatch_if(cond_text, value_symbol=None): + def dispatch_if(cond_text, value_symbol=None, target_node=body): + assert isinstance(cond_text, str) or cond_text is True + assert value_symbol is None or isinstance(value_symbol, SymbolNode) + assert isinstance(target_node, SequenceNode) scope_node = SymbolScopeNode( [T("return MakeGarbageCollected<${class_name}>(${blink_value});")]) if not value_symbol: @@ -250,17 +257,26 @@ error_exit_return_statement="return nullptr;") scope_node.register_code_symbol(value_symbol) if cond_text is True: - body.append(CxxBlockNode(body=scope_node)) + target_node.append(CxxBlockNode(body=scope_node)) else: - body.append(CxxUnlikelyIfNode(cond=cond_text, body=scope_node)) + target_node.append( + CxxUnlikelyIfNode(cond=cond_text, body=scope_node)) - # 12.3. if V is null or undefined, ... + # 2. If the union type includes a nullable type and V is null or undefined, + # ... member = find_by_member(lambda m: m.is_null) if member: dispatch_if("${v8_value}->IsNullOrUndefined()", S("blink_value", "auto&& ${blink_value} = nullptr;")) - # 12.4. if V is a platform object, ... + # 4. If V is null or undefined, then: + # 4.1. If types includes a dictionary type, ... + member = find_by_type(lambda t: t.is_dictionary) + if member: + dispatch_if("${v8_value}->IsNullOrUndefined()") + + # 5. If V is a platform object, then: + # 5.1. If types includes an interface type that V implements, ... interface_members = filter( lambda member: member.idl_type and member.idl_type.is_interface, union_members) @@ -278,8 +294,9 @@ _format("{}::HasInstance(${isolate}, ${v8_value})", v8_bridge_name)) - # 12.5. if Type(V) is Object, V has an [[ArrayBufferData]] internal - # slot, ... + # 6. If Type(V) is Object and V has an [[ArrayBufferData]] internal slot, + # then: + # 6.1. If types includes ArrayBuffer, ... member = find_by_type(lambda t: t.is_array_buffer) if member: dispatch_if("${v8_value}->IsArrayBuffer() || " @@ -290,12 +307,16 @@ if member: dispatch_if("${v8_value}->IsArrayBufferView()") - # 12.6. if Type(V) is Object, V has a [[DataView]] internal slot, ... + # 7. If Type(V) is Object and V has a [[DataView]] internal slot, then: + # 7.1. If types includes DataView, ... member = find_by_type(lambda t: t.is_data_view) if member: dispatch_if("${v8_value}->IsDataView()") - # 12.7. if Type(V) is Object, V has a [[TypedArrayName]] internal slot, ... + # 8. If Type(V) is Object and V has a [[TypedArrayName]] internal slot, + # then: + # 8.1. If types includes a typed array type whose name is the value of V's + # [[TypedArrayName]] internal slot, ... typed_array_types = ("Int8Array", "Int16Array", "Int32Array", "Uint8Array", "Uint16Array", "Uint32Array", "Uint8ClampedArray", "Float32Array", "Float64Array") @@ -304,46 +325,88 @@ if member: dispatch_if(_format("${v8_value}->Is{}()", typed_array_type)) - # 12.8. if IsCallable(V) is true, ... + # 9. If IsCallable(V) is true, then: + # 9.1. If types includes a callback function type, ... member = find_by_type(lambda t: t.is_callback_function) if member: dispatch_if("${v8_value}->IsFunction()") - # 12.9. if Type(V) is Object and ... @@iterator ... + # 10. If Type(V) is Object, then: + # 10.1. If types includes a sequence type, ... + # 10.2. If types includes a frozen array type, ... member = find_by_type(lambda t: t.is_sequence or t.is_frozen_array) if member: - dispatch_if("${v8_value}->IsArray() || " # Excessive optimization - "bindings::IsEsIterableObject" - "(${isolate}, ${v8_value}, ${exception_state})") - body.append( - CxxUnlikelyIfNode(cond="${exception_state}.HadException()", - body=T("return nullptr;"))) + # TODO(crbug.com/715122): Excessive optimization + dispatch_if("${v8_value}->IsArray()") - # 12.10. if Type(V) is Object and ... - member = find_by_type(lambda t: t.is_callback_interface or t.is_dictionary - or t.is_record or t.is_object) + # Create an IDL sequence from an iterable object. + scope_node = SymbolScopeNode() + body.append( + CxxUnlikelyIfNode(cond="${v8_value}->IsObject()", body=scope_node)) + scope_node.extend([ + T("ScriptIterator script_iterator = ScriptIterator::FromIterable(" + "${isolate}, ${v8_value}.As<v8::Object>(), " + "${exception_state});"), + CxxUnlikelyIfNode(cond="${exception_state}.HadException()", + body=T("return nullptr;")), + ]) + + def blink_value_from_iterator(union_member): + def symbol_definition_constructor(symbol_node): + node = SymbolDefinitionNode(symbol_node) + node.extend([ + F( + "auto&& ${blink_value} = " + "bindings::CreateIDLSequenceFromIterator<{}>(" + "${isolate}, std::move(script_iterator), " + "${exception_state});", + native_value_tag( + union_member.idl_type.unwrap().element_type)), + CxxUnlikelyIfNode(cond="${exception_state}.HadException()", + body=T("return nullptr;")), + ]) + return node + + return symbol_definition_constructor + + dispatch_if( + "!script_iterator.IsNull()", + S("blink_value", + definition_constructor=blink_value_from_iterator(member)), + target_node=scope_node) + + # 10. If Type(V) is Object, then: + # 10.3. If types includes a dictionary type, ... + # 10.4. If types includes a record type, ... + # 10.5. If types includes a callback interface type, ... + # 10.6. If types includes object, ... + member = find_by_type(lambda t: t.is_dictionary or t.is_record or t. + is_callback_interface or t.is_object) if member: dispatch_if("${v8_value}->IsObject()") - # 12.11. if Type(V) is Boolean and ... + # 11. If Type(V) is Boolean, then: + # 11.1. If types includes boolean, ... member = find_by_type(lambda t: t.is_boolean) if member: dispatch_if("${v8_value}->IsBoolean()") - # 12.12. if Type(V) is Number and ... + # 12. If Type(V) is Number, then: + # 12.1. If types includes a numeric type, ... member = find_by_type(lambda t: t.is_numeric) if member: dispatch_if("${v8_value}->IsNumber()") - # 12.13. if there is an entry in S that has ... a string type ... - # 12.14. if there is an entry in S that has ... a numeric type ... - # 12.15. if there is an entry in S that has ... boolean ... + # 14. If types includes a string type, ... + # 16. If types includes a numeric type, ... + # 17. If types includes boolean, ... member = (find_by_type(lambda t: t.is_enumeration or t.is_string) or find_by_type(lambda t: t.is_numeric) or find_by_type(lambda t: t.is_boolean)) if member: dispatch_if(True) else: + # 19. Throw a TypeError. body.append( T("${exception_state}.ThrowTypeError(" "ExceptionMessages::ValueNotOfType("
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc index 6852eb9..2caa48e64 100644 --- a/third_party/blink/renderer/core/animation/css/css_animations.cc +++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -433,12 +433,12 @@ } CSSScrollTimeline* CreateCSSScrollTimeline( - Element* element, + Document& document, CSSScrollTimeline::Options&& options) { if (!options.IsValid()) return nullptr; - auto* scroll_timeline = MakeGarbageCollected<CSSScrollTimeline>( - &element->GetDocument(), std::move(options)); + auto* scroll_timeline = + MakeGarbageCollected<CSSScrollTimeline>(&document, std::move(options)); // It's is not allowed for a style resolve to create timelines that // needs timing updates (i.e. AnimationTimeline::NeedsAnimationTimingUpdate() // must return false). Servicing animations after creation preserves this @@ -471,7 +471,7 @@ return nullptr; } if (rule) { - CSSScrollTimeline::Options options(element, *rule); + CSSScrollTimeline::Options options(document, *rule); const AtomicString& name = timeline_name.GetName().GetValue(); // When multiple animations refer to the same @scroll-timeline, the same @@ -486,8 +486,11 @@ if (timeline->Matches(options)) return existing_timeline; } - if (auto* timeline = CreateCSSScrollTimeline(element, std::move(options))) + if (auto* timeline = + CreateCSSScrollTimeline(document, std::move(options))) { + document.GetDocumentAnimations().CacheCSSScrollTimeline(*timeline); return timeline; + } } return nullptr; }
diff --git a/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc b/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc index 0ea72a8..5a42582d 100644 --- a/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc +++ b/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc
@@ -204,13 +204,11 @@ } // anonymous namespace -CSSScrollTimeline::Options::Options(Element* element, +CSSScrollTimeline::Options::Options(Document& document, StyleRuleScrollTimeline& rule) - : source_(ComputeScrollSource(element->GetDocument(), rule.GetSource())), + : source_(ComputeScrollSource(document, rule.GetSource())), direction_(ComputeScrollDirection(rule.GetOrientation())), - offsets_(ComputeScrollOffsets(element->GetDocument(), - rule.GetStart(), - rule.GetEnd())), + offsets_(ComputeScrollOffsets(document, rule.GetStart(), rule.GetEnd())), time_range_(ComputeTimeRange(rule.GetTimeRange())), rule_(&rule) {} @@ -223,7 +221,6 @@ rule_(options.rule_) { DCHECK(options.IsValid()); DCHECK(rule_); - document->GetDocumentAnimations().CacheCSSScrollTimeline(*this); } const AtomicString& CSSScrollTimeline::Name() const {
diff --git a/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h b/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h index ef6811a5..9bc5333 100644 --- a/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h +++ b/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h
@@ -23,7 +23,7 @@ STACK_ALLOCATED(); public: - Options(Element*, StyleRuleScrollTimeline&); + Options(Document&, StyleRuleScrollTimeline&); // TODO(crbug.com/1097041): Support 'auto' value. bool IsValid() const { return time_range_.has_value(); }
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc index fc321b9..42cdbdf 100644 --- a/third_party/blink/renderer/core/css/style_engine.cc +++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -1999,7 +1999,8 @@ // styles. GetStyleResolver().PropagateStyleToViewport(); } - GetDocument().GetLayoutView()->UpdateMarkersAndCountersAfterStyleChange(); + GetDocument().GetLayoutView()->UpdateMarkersAndCountersAfterStyleChange( + container.GetLayoutObject()); } void StyleEngine::RecalcStyle(StyleRecalcChange change,
diff --git a/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/third_party/blink/renderer/core/fullscreen/fullscreen.cc index 7360bbee..bd3ca9b 100644 --- a/third_party/blink/renderer/core/fullscreen/fullscreen.cc +++ b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
@@ -283,25 +283,16 @@ // // The current implementation of WebXR's "dom-overlay" mode internally uses // the Fullscreen API to show a single DOM element based on configuration at - // XR session start. In addition, for WebXR sessions without "dom-overlay" - // the renderer may need to force the page to fullscreen to ensure that - // browser UI hides/responds accordingly. In either case, requesting a WebXR - // Session does require a user gesture, but it has likely expired by the time - // the renderer actually gets the XR session from the device and attempts - // to fullscreen the page. + // XR session start. The WebXR API doesn't support changing elements during + // the session, so to avoid inconsistencies between implementations we need + // to block changes via Fullscreen API while the XR session is active, while + // still allowing the XR code to set up fullscreen mode on session start. if (ScopedAllowFullscreen::FullscreenAllowedReason() == - ScopedAllowFullscreen::kXrOverlay || - ScopedAllowFullscreen::FullscreenAllowedReason() == - ScopedAllowFullscreen::kXrSession) { - DVLOG(1) << __func__ << ": allowing fullscreen element setup for XR"; + ScopedAllowFullscreen::kXrOverlay) { + DVLOG(1) << __func__ + << ": allowing fullscreen element setup for XR DOM overlay"; return true; } - - // The WebXR API doesn't support changing elements during the session if the - // dom-overlay feature is in use (indicated by the IsXrOverlay property). To - // avoid inconsistencies between implementations we need to block changes via - // Fullscreen API while the XR session is active, while still allowing the XR - // code to set up fullscreen mode on session start. if (document.IsXrOverlay()) { DVLOG(1) << __func__ << ": rejecting change of fullscreen element for XR DOM overlay";
diff --git a/third_party/blink/renderer/core/fullscreen/scoped_allow_fullscreen.h b/third_party/blink/renderer/core/fullscreen/scoped_allow_fullscreen.h index caf1056..fb2b80f 100644 --- a/third_party/blink/renderer/core/fullscreen/scoped_allow_fullscreen.h +++ b/third_party/blink/renderer/core/fullscreen/scoped_allow_fullscreen.h
@@ -16,7 +16,7 @@ STACK_ALLOCATED(); public: - enum Reason { kOrientationChange, kXrOverlay, kXrSession }; + enum Reason { kOrientationChange, kXrOverlay }; static base::Optional<Reason> FullscreenAllowedReason(); explicit ScopedAllowFullscreen(Reason);
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index db3e0872..85eda5a1 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -3461,8 +3461,9 @@ // If the display-lock blocked child layout, then we don't clear child needs // layout bits. However, we can still use the cached result, since we will // re-layout when unlocking. + bool is_blocked_by_display_lock = ChildLayoutBlockedByDisplayLock(); bool child_needs_layout_unless_locked = - !ChildLayoutBlockedByDisplayLock() && + !is_blocked_by_display_lock && (PosChildNeedsLayout() || NormalChildNeedsLayout()); const NGPhysicalBoxFragment& physical_fragment = @@ -3636,9 +3637,9 @@ // For example, for elements with a transform change we can re-use the cached // result but we still need to recalculate the layout overflow. - if (RuntimeEnabledFeatures::LayoutNGLayoutOverflowRecalcEnabled() && - use_layout_cache_slot && NeedsLayoutOverflowRecalc() && - !ChildLayoutBlockedByDisplayLock()) { + if (use_layout_cache_slot && !is_blocked_by_display_lock && + NeedsLayoutOverflowRecalc() && + RuntimeEnabledFeatures::LayoutNGLayoutOverflowRecalcEnabled()) { #if DCHECK_IS_ON() const NGLayoutResult* cloned_cached_layout_result = NGLayoutResult::CloneWithPostLayoutFragments(*cached_layout_result);
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc index 140b919..63dc0522 100644 --- a/third_party/blink/renderer/core/layout/layout_view.cc +++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -925,17 +925,35 @@ return CompositingReason::kNone; } -void LayoutView::UpdateMarkersAndCountersAfterStyleChange() { +void LayoutView::UpdateMarkersAndCountersAfterStyleChange( + LayoutObject* container) { NOT_DESTROYED(); if (!needs_marker_counter_update_) return; + DCHECK(!container || + (container->View() == this && container->IsDescendantOf(this) && + GetDocument().GetStyleEngine().InContainerQueryStyleRecalc())) + << "The container parameter is currently only for scoping updates for " + "container query style recalcs"; + needs_marker_counter_update_ = false; if (!HasLayoutCounters() && !HasLayoutListItems()) return; - for (LayoutObject* layout_object = this; layout_object; - layout_object = layout_object->NextInPreOrder()) { + // For container queries style recalc, we know the counter styles didn't + // change outside the container. Hence, we can start the update traversal from + // the container. + LayoutObject* start = container ? container : this; + // Additionally, if the container contains style, we know counters inside the + // container cannot affect counters outside the container, which means we can + // limit the traversal to the container subtree. + LayoutObject* stay_within = + container && container->ShouldApplyStyleContainment() ? container + : nullptr; + + for (LayoutObject* layout_object = start; layout_object; + layout_object = layout_object->NextInPreOrder(stay_within)) { if (auto* list_item = DynamicTo<LayoutListItem>(layout_object)) { list_item->UpdateCounterStyle(); } else if (auto* ng_list_item =
diff --git a/third_party/blink/renderer/core/layout/layout_view.h b/third_party/blink/renderer/core/layout/layout_view.h index 66beab5..c1f912d 100644 --- a/third_party/blink/renderer/core/layout/layout_view.h +++ b/third_party/blink/renderer/core/layout/layout_view.h
@@ -284,7 +284,11 @@ NOT_DESTROYED(); needs_marker_counter_update_ = true; } - void UpdateMarkersAndCountersAfterStyleChange(); + + // Update generated markers and counters after style and layout tree update. + // container - The container for container queries, otherwise nullptr. + void UpdateMarkersAndCountersAfterStyleChange( + LayoutObject* container = nullptr); bool BackgroundIsKnownToBeOpaqueInRect( const PhysicalRect& local_rect) const override;
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc index 5589a3d..3322656 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
@@ -100,9 +100,7 @@ } } break; case kPercentageGuess: { - // Percent columns grow in proportion to difference between their - // percentage size and minimum size. - // Auto/Fixed columns get min inline size. + // Percent columns grow, auto/fixed get min inline size. LayoutUnit percent_inline_size_increases = guess_size_total_increases[kPercentageGuess]; LayoutUnit distributable_inline_size = @@ -296,10 +294,8 @@ *last_computed_size += rounding_error_inline_size; } } else if (percent_columns_count > 0) { - // All remaining columns are percent. - // They grow to max(col minimum, %ge size) + additional size - // proportional to column percent. - LayoutUnit rounding_error_inline_size = distributable_inline_size; + // All remaining columns are percent. Grow them. + LayoutUnit rounding_error_inline_size = target_inline_size; LayoutUnit* last_computed_size = nullptr; LayoutUnit* computed_size = computed_sizes.begin(); for (const NGTableTypes::Column* column = start_column; @@ -308,18 +304,13 @@ continue; DCHECK(column->percent); last_computed_size = computed_size; - LayoutUnit percent_inline_size = - column->ResolvePercentInlineSize(target_inline_size); - LayoutUnit delta; - if (total_percent != 0.0f) { - delta = LayoutUnit(distributable_inline_size * *column->percent / - total_percent); + if (total_percent > 0.0f) { + *computed_size = LayoutUnit(*column->percent / total_percent * + target_inline_size); } else { - delta = LayoutUnit(distributable_inline_size.ToFloat() / - percent_columns_count); + *computed_size = distributable_inline_size / percent_columns_count; } - rounding_error_inline_size -= delta; - *computed_size = percent_inline_size + delta; + rounding_error_inline_size -= *computed_size; } if (rounding_error_inline_size != LayoutUnit()) { DCHECK(last_computed_size);
diff --git a/third_party/blink/renderer/core/paint/paint_timing.cc b/third_party/blink/renderer/core/paint/paint_timing.cc index b5541a0..5b92ab25 100644 --- a/third_party/blink/renderer/core/paint/paint_timing.cc +++ b/third_party/blink/renderer/core/paint/paint_timing.cc
@@ -252,7 +252,7 @@ frame->GetDocument()->Fetcher()->MarkFirstContentfulPaint(); if (frame->GetFrameScheduler()) - frame->GetFrameScheduler()->OnFirstContentfulPaint(); + frame->GetFrameScheduler()->OnFirstContentfulPaintInMainFrame(); if (auto* mf_checker = frame->View()->GetMobileFriendlinessChecker()) mf_checker->NotifyFirstContentfulPaint();
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc b/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc index 1f87e85..ec68b5b 100644 --- a/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc +++ b/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc
@@ -30,8 +30,12 @@ return v8::Local<v8::Object>(); DCHECK(v8_buffer->IsArrayBuffer()); - v8::Local<v8::Object> wrapper = v8::DataView::New( - v8_buffer.As<v8::ArrayBuffer>(), byteOffset(), byteLength()); + v8::Local<v8::Object> wrapper; + { + v8::Context::Scope context_scope(creation_context->CreationContext()); + wrapper = v8::DataView::New(v8_buffer.As<v8::ArrayBuffer>(), byteOffset(), + byteLength()); + } return AssociateWithWrapper(isolate, wrapper_type_info, wrapper); } @@ -47,8 +51,12 @@ } DCHECK(v8_buffer->IsArrayBuffer()); - v8::Local<v8::Object> wrapper = v8::DataView::New( - v8_buffer.As<v8::ArrayBuffer>(), byteOffset(), byteLength()); + v8::Local<v8::Object> wrapper; + { + v8::Context::Scope context_scope(script_state->GetContext()); + wrapper = v8::DataView::New(v8_buffer.As<v8::ArrayBuffer>(), byteOffset(), + byteLength()); + } return AssociateWithWrapper(script_state->GetIsolate(), wrapper_type_info, wrapper);
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc b/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc index 66a99d97..a8b3c61 100644 --- a/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc +++ b/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
@@ -64,12 +64,15 @@ DCHECK_EQ(IsShared(), v8_buffer->IsSharedArrayBuffer()); v8::Local<v8::Object> wrapper; - if (IsShared()) { - wrapper = V8TypedArray::New(v8_buffer.As<v8::SharedArrayBuffer>(), - byteOffset(), length()); - } else { - wrapper = V8TypedArray::New(v8_buffer.As<v8::ArrayBuffer>(), byteOffset(), - length()); + { + v8::Context::Scope context_scope(script_state->GetContext()); + if (IsShared()) { + wrapper = V8TypedArray::New(v8_buffer.As<v8::SharedArrayBuffer>(), + byteOffset(), length()); + } else { + wrapper = V8TypedArray::New(v8_buffer.As<v8::ArrayBuffer>(), byteOffset(), + length()); + } } return AssociateWithWrapper(script_state->GetIsolate(), wrapper_type_info,
diff --git a/third_party/blink/renderer/modules/bluetooth/bluetooth.cc b/third_party/blink/renderer/modules/bluetooth/bluetooth.cc index 7670c51..c31eab74 100644 --- a/third_party/blink/renderer/modules/bluetooth/bluetooth.cc +++ b/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
@@ -17,7 +17,9 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_advertising_event_init.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_data_filter_init.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_le_scan_options.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_bluetooth_manufacturer_data_filter_init.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_request_device_options.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/dom/events/event.h" @@ -36,7 +38,9 @@ #include "third_party/blink/renderer/modules/bluetooth/bluetooth_uuid.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/wtf/functional.h" +#include "third_party/blink/renderer/platform/wtf/hash_map.h" namespace blink { @@ -71,8 +75,8 @@ const BluetoothLEScanFilterInit* filter, mojom::blink::WebBluetoothLeScanFilterPtr& canonicalized_filter, ExceptionState& exception_state) { - if (!(filter->hasServices() || filter->hasName() || - filter->hasNamePrefix())) { + if (!(filter->hasServices() || filter->hasName() || filter->hasNamePrefix() || + filter->hasManufacturerData())) { exception_state.ThrowTypeError( "A filter must restrict the devices in some way."); return; @@ -111,16 +115,78 @@ } if (filter->namePrefix().length() == 0) { exception_state.ThrowTypeError( - "'namePrefix', if present, must me non-empty."); + "'namePrefix', if present, must be non-empty."); return; } canonicalized_filter->name_prefix = filter->namePrefix(); } + + if (filter->hasManufacturerData()) { + if (filter->manufacturerData().size() == 0) { + exception_state.ThrowTypeError( + "'manufacturerData', if present, must be non-empty."); + return; + } + canonicalized_filter->manufacturer_data.emplace(); + for (const auto& manufacturer_data : filter->manufacturerData()) { + DOMArrayPiece mask_buffer = manufacturer_data->mask(); + DOMArrayPiece data_prefix_buffer = manufacturer_data->dataPrefix(); + if (manufacturer_data->hasMask()) { + if (mask_buffer.IsDetached()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "'mask' value buffer has been detached."); + return; + } + + if (!manufacturer_data->hasDataPrefix()) { + exception_state.ThrowTypeError( + "'dataPrefix' must be non-empty when 'mask' is present."); + return; + } + + if (data_prefix_buffer.ByteLength() != mask_buffer.ByteLength()) { + exception_state.ThrowTypeError( + "'mask' size must be equal to 'dataPrefix' size."); + return; + } + } + + Vector<mojom::blink::WebBluetoothDataFilterPtr> data_filters_vector; + if (manufacturer_data->hasDataPrefix()) { + if (data_prefix_buffer.IsDetached()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "'dataPrefix' value buffer has been detached."); + return; + } + + // Iterate by index here since we're iterating through two arrays. + for (wtf_size_t i = 0; i < data_prefix_buffer.ByteLength(); ++i) { + uint8_t data = data_prefix_buffer.Bytes()[i]; + uint8_t mask = + manufacturer_data->hasMask() ? mask_buffer.Bytes()[i] : 0xff; + data_filters_vector.push_back( + mojom::blink::WebBluetoothDataFilter::New(data, mask)); + } + } + + auto company = mojom::blink::WebBluetoothCompany::New(); + company->id = manufacturer_data->companyIdentifier(); + auto result = canonicalized_filter->manufacturer_data->insert( + std::move(company), std::move(data_filters_vector)); + if (!result.is_new_entry) { + exception_state.ThrowTypeError("'companyIdentifier' must be unique."); + return; + } + } + } } static void ConvertRequestDeviceOptions( const RequestDeviceOptions* options, mojom::blink::WebBluetoothRequestDeviceOptionsPtr& result, + ExecutionContext* execution_context, ExceptionState& exception_state) { if (!(options->hasFilters() ^ options->acceptAllDevices())) { exception_state.ThrowTypeError( @@ -148,6 +214,11 @@ if (exception_state.HadException()) return; + if (canonicalized_filter->manufacturer_data) { + UseCounter::Count(execution_context, + WebFeature::kWebBluetoothManufacturerDataFilter); + } + result->filters->push_back(std::move(canonicalized_filter)); } } @@ -275,7 +346,8 @@ // In order to convert the arguments from service names and aliases to just // UUIDs, do the following substeps: auto device_options = mojom::blink::WebBluetoothRequestDeviceOptions::New(); - ConvertRequestDeviceOptions(options, device_options, exception_state); + ConvertRequestDeviceOptions(options, device_options, GetExecutionContext(), + exception_state); if (exception_state.HadException()) return ScriptPromise();
diff --git a/third_party/blink/renderer/modules/bluetooth/bluetooth_data_filter_init.idl b/third_party/blink/renderer/modules/bluetooth/bluetooth_data_filter_init.idl new file mode 100644 index 0000000..87c30336 --- /dev/null +++ b/third_party/blink/renderer/modules/bluetooth/bluetooth_data_filter_init.idl
@@ -0,0 +1,10 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://webbluetoothcg.github.io/web-bluetooth/#dictdef-bluetoothdatafilterinit + +dictionary BluetoothDataFilterInit { + BufferSource dataPrefix; + BufferSource mask; +}; \ No newline at end of file
diff --git a/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_filter_init.idl b/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_filter_init.idl index ea372ec0..dbd8734 100644 --- a/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_filter_init.idl +++ b/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_filter_init.idl
@@ -8,5 +8,6 @@ sequence<BluetoothServiceUUID> services; DOMString name; DOMString namePrefix; - // TODO(crbug.com/707635): Support manufacturerData and serviceData filters. + [RuntimeEnabled=WebBluetoothManufacturerDataFilter] sequence<BluetoothManufacturerDataFilterInit> manufacturerData; + // TODO(crbug.com/707635): Support serviceData filter. };
diff --git a/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_filter_init.idl b/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_filter_init.idl new file mode 100644 index 0000000..606c40b --- /dev/null +++ b/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_filter_init.idl
@@ -0,0 +1,9 @@ +// 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. + +// https://webbluetoothcg.github.io/web-bluetooth/#dictdef-bluetoothmanufacturerdatafilterinit + +dictionary BluetoothManufacturerDataFilterInit : BluetoothDataFilterInit { + required [EnforceRange] unsigned short companyIdentifier; +}; \ No newline at end of file
diff --git a/third_party/blink/renderer/modules/bluetooth/idls.gni b/third_party/blink/renderer/modules/bluetooth/idls.gni index e784aae1..30ee000 100644 --- a/third_party/blink/renderer/modules/bluetooth/idls.gni +++ b/third_party/blink/renderer/modules/bluetooth/idls.gni
@@ -19,8 +19,10 @@ modules_dictionary_idl_files = [ "bluetooth_advertising_event_init.idl", + "bluetooth_data_filter_init.idl", "bluetooth_le_scan_filter_init.idl", "bluetooth_le_scan_options.idl", + "bluetooth_manufacturer_data_filter_init.idl", "request_device_options.idl", "watch_advertisements_options.idl", ]
diff --git a/third_party/blink/renderer/modules/handwriting/handwriting_drawing.idl b/third_party/blink/renderer/modules/handwriting/handwriting_drawing.idl index a4a0e3e..1a4f505 100644 --- a/third_party/blink/renderer/modules/handwriting/handwriting_drawing.idl +++ b/third_party/blink/renderer/modules/handwriting/handwriting_drawing.idl
@@ -13,6 +13,6 @@ void clear(); sequence<HandwritingStroke> getStrokes(); - [CallWith=ScriptState] + [CallWith=ScriptState, MeasureAs=HandwritingRecognitionGetPrediction] Promise<sequence<HandwritingPrediction>> getPrediction(); };
diff --git a/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.idl b/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.idl index 09bc3d8..12b5ccb 100644 --- a/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.idl +++ b/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.idl
@@ -9,7 +9,7 @@ RuntimeEnabled=HandwritingRecognition ] interface HandwritingRecognizer { - [CallWith=ScriptState, RaisesException] + [CallWith=ScriptState, RaisesException, MeasureAs=HandwritingRecognitionStartDrawing] HandwritingDrawing startDrawing(optional HandwritingHints hints = {}); [RaisesException] void finish();
diff --git a/third_party/blink/renderer/modules/handwriting/navigator_handwriting_recognition_service.idl b/third_party/blink/renderer/modules/handwriting/navigator_handwriting_recognition_service.idl index a5e0fc4..ff4e433 100644 --- a/third_party/blink/renderer/modules/handwriting/navigator_handwriting_recognition_service.idl +++ b/third_party/blink/renderer/modules/handwriting/navigator_handwriting_recognition_service.idl
@@ -9,11 +9,11 @@ ImplementedAs=HandwritingRecognitionService, RuntimeEnabled=HandwritingRecognition ] partial interface Navigator { - [CallWith=ScriptState, RaisesException] + [CallWith=ScriptState, RaisesException, MeasureAs=HandwritingRecognitionCreateRecognizer] Promise<HandwritingRecognizer> createHandwritingRecognizer(HandwritingModelConstraint constraint); - [CallWith=ScriptState, RaisesException] + [CallWith=ScriptState, RaisesException, MeasureAs=HandwritingRecognitionQuerySupport] Promise<HandwritingFeatureQueryResult> queryHandwritingRecognizerSupport(HandwritingFeatureQuery query); };
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc index 1abb606..7612cd53 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
@@ -353,6 +353,7 @@ } else if (encoding->scalabilityMode() == "L1T3") { webrtc_encoding.num_temporal_layers = 3; } + webrtc_encoding.scalability_mode = encoding->scalabilityMode().Utf8(); } webrtc_encoding.adaptive_ptime = encoding->adaptivePtime(); return webrtc_encoding; @@ -757,12 +758,36 @@ } codec->setSdpFmtpLine(sdp_fmtp_line.c_str()); } - if (rtc_codec.mime_type() == "video/VP8" || - rtc_codec.mime_type() == "video/VP9") { + if (rtc_codec.mime_type() == "video/VP8") { Vector<String> modes; modes.push_back("L1T2"); modes.push_back("L1T3"); codec->setScalabilityModes(modes); + } else if (rtc_codec.mime_type() == "video/VP9") { + auto profile_id = rtc_codec.parameters.find("profile-id"); + if (profile_id == rtc_codec.parameters.end() || + profile_id->second != "2") { + Vector<String> modes; + modes.push_back("L1T2"); + modes.push_back("L1T3"); + codec->setScalabilityModes(modes); + } + } else if (rtc_codec.mime_type() == "video/AV1" || + rtc_codec.mime_type() == "video/AV1X") { + Vector<String> modes; + modes.push_back("L1T2"); + modes.push_back("L1T3"); + modes.push_back("L2T1"); + modes.push_back("L2T1h"); + modes.push_back("L2T1_KEY"); + modes.push_back("L2T2"); + modes.push_back("L2T2_KEY"); + modes.push_back("L2T2_KEY_SHIFT"); + modes.push_back("L3T1"); + modes.push_back("L3T3"); + modes.push_back("L3T3_KEY"); + modes.push_back("S2T1"); + codec->setScalabilityModes(modes); } codecs.push_back(codec); }
diff --git a/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.cc b/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.cc index ef582af6..4c05e96 100644 --- a/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.cc +++ b/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.cc
@@ -28,6 +28,8 @@ ScriptState* script_state = ToScriptStateForMainWorld(GetSupplementable()); ScriptState::Scope scope(script_state); v8::Isolate* isolate = script_state->GetIsolate(); + v8::MicrotasksScope microtasks_scope( + isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::Local<v8::Context> context = script_state->GetContext(); if (context.IsEmpty()) return;
diff --git a/third_party/blink/renderer/modules/xr/xr_enter_fullscreen_observer.cc b/third_party/blink/renderer/modules/xr/xr_enter_fullscreen_observer.cc index fde4fa7..08022833 100644 --- a/third_party/blink/renderer/modules/xr/xr_enter_fullscreen_observer.cc +++ b/third_party/blink/renderer/modules/xr/xr_enter_fullscreen_observer.cc
@@ -44,7 +44,6 @@ void XrEnterFullscreenObserver::RequestFullscreen( Element* fullscreen_element, - bool setup_for_dom_overlay, base::OnceCallback<void(bool)> on_completed) { DCHECK(!on_completed_); DCHECK(fullscreen_element); @@ -85,16 +84,11 @@ // immersive session had required a user activation state, but that may have // expired by now due to the user taking time to respond to the consent // prompt. - ScopedAllowFullscreen scope(setup_for_dom_overlay - ? ScopedAllowFullscreen::kXrOverlay - : ScopedAllowFullscreen::kXrSession); + ScopedAllowFullscreen scope(ScopedAllowFullscreen::kXrOverlay); - FullscreenRequestType request_type = FullscreenRequestType::kUnprefixed; - if (setup_for_dom_overlay) { - request_type = request_type | FullscreenRequestType::kForXrOverlay; - } - - Fullscreen::RequestFullscreen(*fullscreen_element_, options, request_type); + Fullscreen::RequestFullscreen(*fullscreen_element_, options, + FullscreenRequestType::kUnprefixed | + FullscreenRequestType::kForXrOverlay); if (!wait_for_fullscreen_change) { // Element was already fullscreen, proceed with session creation.
diff --git a/third_party/blink/renderer/modules/xr/xr_enter_fullscreen_observer.h b/third_party/blink/renderer/modules/xr/xr_enter_fullscreen_observer.h index d687dc6..8b8756c0 100644 --- a/third_party/blink/renderer/modules/xr/xr_enter_fullscreen_observer.h +++ b/third_party/blink/renderer/modules/xr/xr_enter_fullscreen_observer.h
@@ -26,7 +26,6 @@ // Attempt to enter fullscreen with |element| as the root. |on_completed| will // be notified with whether or not fullscreen was successfully entered. void RequestFullscreen(Element* element, - bool setup_for_dom_overlay, base::OnceCallback<void(bool)> on_completed); void Trace(Visitor*) const override;
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc index eec8382..cf78b72 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.cc +++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -2018,8 +2018,7 @@ // cross-origin content. If that's the case, the input source is set as // invisible, and must not return poses or hit test results. bool hide_input_source = false; - if (IsFeatureEnabled(device::mojom::XRSessionFeature::DOM_OVERLAY) && - overlay_element_ && input_state->overlay_pointer_position) { + if (overlay_element_ && input_state->overlay_pointer_position) { input_source->ProcessOverlayHitTest(overlay_element_, input_state); if (!stored_input_source && !input_source->IsVisible()) { DVLOG(2) << __func__ << ": (new) hidden_input_source";
diff --git a/third_party/blink/renderer/modules/xr/xr_system.cc b/third_party/blink/renderer/modules/xr/xr_system.cc index 143424a14..7dc5b990 100644 --- a/third_party/blink/renderer/modules/xr/xr_system.cc +++ b/third_party/blink/renderer/modules/xr/xr_system.cc
@@ -6,7 +6,6 @@ #include <utility> -#include "build/build_config.h" #include "device/vr/public/mojom/vr_service.mojom-blink.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "third_party/blink/public/common/browser_interface_broker_proxy.h" @@ -1117,10 +1116,17 @@ void XRSystem::DoRequestSession( PendingRequestSessionQuery* query, device::mojom::blink::XRSessionOptionsPtr session_options) { - service_->RequestSession( - std::move(session_options), - WTF::Bind(&XRSystem::OnRequestSessionReturned, WrapWeakPersistent(this), - WrapPersistent(query))); + // In DOM overlay mode, there's an additional step before an immersive-ar + // session can start, we need to enter fullscreen mode by setting the + // appropriate element as fullscreen from the Renderer, then waiting for the + // browser side to send an event indicating success or failure. + auto callback = + query->DOMOverlayElement() + ? WTF::Bind(&XRSystem::OnRequestSessionSetupForDomOverlay, + WrapWeakPersistent(this), WrapPersistent(query)) + : WTF::Bind(&XRSystem::OnRequestSessionReturned, + WrapWeakPersistent(this), WrapPersistent(query)); + service_->RequestSession(std::move(session_options), std::move(callback)); } void XRSystem::RequestInlineSession(PendingRequestSessionQuery* query, @@ -1449,72 +1455,39 @@ query->Resolve(supports_session); } -void XRSystem::OnRequestSessionReturned( +void XRSystem::OnRequestSessionSetupForDomOverlay( PendingRequestSessionQuery* query, device::mojom::blink::RequestSessionResultPtr result) { - // If session creation failed, move straight on to processing that. - if (!result->is_success()) { - FinishSessionCreation(query, std::move(result)); - return; + DCHECK(query->DOMOverlayElement()); + if (result->is_success()) { + // Success. Now request fullscreen mode and continue with + // OnRequestSessionReturned once that completes. + fullscreen_enter_observer_ = + MakeGarbageCollected<XrEnterFullscreenObserver>(); + fullscreen_enter_observer_->RequestFullscreen( + query->DOMOverlayElement(), + WTF::Bind(&XRSystem::OnFullscreenConfigured, WrapPersistent(this), + WrapPersistent(query), std::move(result))); + } else { + // Session request failed, continue processing that normally. + OnRequestSessionReturned(query, std::move(result)); } - - Element* fullscreen_element = nullptr; - const auto& enabled_features = - result->get_success()->session->enabled_features; - if (base::Contains(enabled_features, - device::mojom::XRSessionFeature::DOM_OVERLAY)) { - fullscreen_element = query->DOMOverlayElement(); - } - - // Only setup for dom_overlay if the query actually had a DOMOverlayElement - // and the session enabled dom_overlay. (Note that fullscreen_element will be - // null if the feature was not enabled). - bool setup_for_dom_overlay = !!fullscreen_element; - -// On Android, due to the way the device renderer is configured, we always need -// to enter fullscreen if we're starting an AR session, so if we aren't supposed -// to enter DOMOverlay, we simply fullscreen the document body. -#if defined(OS_ANDROID) - if (!fullscreen_element && - query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr) { - fullscreen_element = DomWindow()->document()->body(); - } -#endif - - // If we don't need to enter fullscreen continue with session setup. - if (!fullscreen_element) { - FinishSessionCreation(query, std::move(result)); - return; - } - - // At this point, we know that we have an element that we need to make - // fullscreen, so we do that before we continue setting up the session. - fullscreen_enter_observer_ = - MakeGarbageCollected<XrEnterFullscreenObserver>(); - fullscreen_enter_observer_->RequestFullscreen( - fullscreen_element, setup_for_dom_overlay, - WTF::Bind(&XRSystem::OnFullscreenConfigured, WrapPersistent(this), - WrapPersistent(query), std::move(result))); } void XRSystem::OnFullscreenConfigured( PendingRequestSessionQuery* query, device::mojom::blink::RequestSessionResultPtr result, bool fullscreen_succeeded) { - // At this point we no longer need the enter observer, so go ahead and destroy - // it. - fullscreen_enter_observer_ = nullptr; - if (fullscreen_succeeded) { - FinishSessionCreation(query, std::move(result)); + OnRequestSessionReturned(query, std::move(result)); } else { - FinishSessionCreation( + OnRequestSessionReturned( query, device::mojom::blink::RequestSessionResult::NewFailureReason( device::mojom::RequestSessionError::FULLSCREEN_ERROR)); } } -void XRSystem::FinishSessionCreation( +void XRSystem::OnRequestSessionReturned( PendingRequestSessionQuery* query, device::mojom::blink::RequestSessionResultPtr result) { DVLOG(2) << __func__; @@ -1528,6 +1501,10 @@ has_outstanding_immersive_request_ = false; } + // Clean up the fullscreen event manager which may have been added for + // DOM overlay setup. + fullscreen_enter_observer_ = nullptr; + if (!result->is_success()) { // |service_| does not support the requested mode. Attempt to create a // sensorless session. @@ -1590,14 +1567,15 @@ session->OnEnvironmentProviderCreated(); } - auto dom_overlay_feature = device::mojom::XRSessionFeature::DOM_OVERLAY; - if (query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr && - query->HasFeature(dom_overlay_feature) && - base::Contains(enabled_features, dom_overlay_feature)) { - DCHECK(query->DOMOverlayElement()); - // The session is using DOM overlay mode. At this point the overlay - // element is already in fullscreen mode, and the session can proceed. - session->SetDOMOverlayElement(query->DOMOverlayElement()); + if (query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr) { + DCHECK(DomWindow()); + if (query->HasFeature(device::mojom::XRSessionFeature::DOM_OVERLAY)) { + DCHECK(query->DOMOverlayElement()); + // The session is using DOM overlay mode. At this point the overlay + // element is already in fullscreen mode, and the session can + // proceed. + session->SetDOMOverlayElement(query->DOMOverlayElement()); + } } if (query->mode() == device::mojom::blink::XRSessionMode::kImmersiveVr &&
diff --git a/third_party/blink/renderer/modules/xr/xr_system.h b/third_party/blink/renderer/modules/xr/xr_system.h index d4af864..6f52a7d 100644 --- a/third_party/blink/renderer/modules/xr/xr_system.h +++ b/third_party/blink/renderer/modules/xr/xr_system.h
@@ -359,14 +359,14 @@ void DoRequestSession( PendingRequestSessionQuery* query, device::mojom::blink::XRSessionOptionsPtr session_options); - void OnRequestSessionReturned( + void OnRequestSessionSetupForDomOverlay( PendingRequestSessionQuery*, device::mojom::blink::RequestSessionResultPtr result); void OnFullscreenConfigured( PendingRequestSessionQuery* query, device::mojom::blink::RequestSessionResultPtr result, bool fullscreen_succeeded); - void FinishSessionCreation( + void OnRequestSessionReturned( PendingRequestSessionQuery*, device::mojom::blink::RequestSessionResultPtr result); void OnSupportsSessionReturned(PendingSupportsSessionQuery*,
diff --git a/third_party/blink/renderer/platform/heap/BUILD.gn b/third_party/blink/renderer/platform/heap/BUILD.gn index 233fda4..601e1692 100644 --- a/third_party/blink/renderer/platform/heap/BUILD.gn +++ b/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -111,8 +111,6 @@ "v8_wrapper/garbage_collected.h", "v8_wrapper/heap.h", "v8_wrapper/heap_allocator_impl.h", - "v8_wrapper/heap_stats_collector.h", - "v8_wrapper/heap_traits.h", "v8_wrapper/member.h", "v8_wrapper/persistent.h", "v8_wrapper/process_heap.h", @@ -120,7 +118,6 @@ "v8_wrapper/thread_state.h", "v8_wrapper/thread_state_scopes.h", "v8_wrapper/trace_traits.h", - "v8_wrapper/unified_heap_controller.h", "v8_wrapper/unified_heap_marking_visitor.h", "v8_wrapper/visitor.h", "v8_wrapper/write_barrier.h",
diff --git a/third_party/blink/renderer/platform/heap/heap_stats_collector.h b/third_party/blink/renderer/platform/heap/heap_stats_collector.h index 0939d5e..4b7f0657 100644 --- a/third_party/blink/renderer/platform/heap/heap_stats_collector.h +++ b/third_party/blink/renderer/platform/heap/heap_stats_collector.h
@@ -7,10 +7,8 @@ #include "third_party/blink/renderer/platform/wtf/buildflags.h" -#if BUILDFLAG(USE_V8_OILPAN) -#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h" -#else // !USE_V8_OILPAN +#if !BUILDFLAG(USE_V8_OILPAN) #include "third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h" -#endif // !USE_V8_OILPAN +#endif // !BUILDFLAG(USE_V8_OILPAN) #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_traits.h b/third_party/blink/renderer/platform/heap/heap_traits.h index f72489d..cb1f430 100644 --- a/third_party/blink/renderer/platform/heap/heap_traits.h +++ b/third_party/blink/renderer/platform/heap/heap_traits.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TRAITS_H_ #include <type_traits> + #include "third_party/blink/renderer/platform/heap/heap_allocator.h" #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/wtf/type_traits.h"
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_controller.h b/third_party/blink/renderer/platform/heap/unified_heap_controller.h index 636651e..c1fd663 100644 --- a/third_party/blink/renderer/platform/heap/unified_heap_controller.h +++ b/third_party/blink/renderer/platform/heap/unified_heap_controller.h
@@ -7,10 +7,8 @@ #include "third_party/blink/renderer/platform/wtf/buildflags.h" -#if BUILDFLAG(USE_V8_OILPAN) -#include "third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h" -#else // !USE_V8_OILPAN +#if !BUILDFLAG(USE_V8_OILPAN) #include "third_party/blink/renderer/platform/heap/impl/unified_heap_controller.h" -#endif // !USE_V8_OILPAN +#endif // !BUILDFLAG(USE_V8_OILPAN) #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h b/third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h deleted file mode 100644 index 042d806..0000000 --- a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h +++ /dev/null
@@ -1,10 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_STATS_COLLECTOR_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_STATS_COLLECTOR_H_ - -// TODO(chromium:1056170): Implement wrapper. - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_STATS_COLLECTOR_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h b/third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h deleted file mode 100644 index 59d9b9e2..0000000 --- a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h +++ /dev/null
@@ -1,10 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TRAITS_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TRAITS_H_ - -// TODO(chromium:1056170): Implement wrapper. - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h b/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h deleted file mode 100644 index 36fe078..0000000 --- a/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h +++ /dev/null
@@ -1,10 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_CONTROLLER_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_CONTROLLER_H_ - -// TODO(chromium:1056170): Implement wrapper. - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_CONTROLLER_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/write_barrier.h b/third_party/blink/renderer/platform/heap/v8_wrapper/write_barrier.h index 06bf198..4bfa2a3 100644 --- a/third_party/blink/renderer/platform/heap/v8_wrapper/write_barrier.h +++ b/third_party/blink/renderer/platform/heap/v8_wrapper/write_barrier.h
@@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_WRITE_BARRIER_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_WRITE_BARRIER_H_ +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "v8/include/cppgc/heap-consistency.h" namespace blink {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index f579035b..8432695 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2261,6 +2261,10 @@ status: "experimental", }, { + name: "WebBluetoothManufacturerDataFilter", + status: "experimental", + }, + { name: "WebBluetoothRemoteCharacteristicNewWriteValue", status: { "Android": "stable",
diff --git a/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc b/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc index 0d8f272..67982ca 100644 --- a/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc +++ b/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc
@@ -61,7 +61,7 @@ void DidStartProvisionalLoad(bool is_main_frame) override {} void DidCommitProvisionalLoad(bool, FrameScheduler::NavigationType) override { } - void OnFirstContentfulPaint() override {} + void OnFirstContentfulPaintInMainFrame() override {} void OnFirstMeaningfulPaint() override {} void OnLoad() override {} bool IsExemptFromBudgetBasedThrottling() const override { return false; }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc index 8b83129f..0559e51 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -937,10 +937,10 @@ return SchedulingLifecycleState::kNotThrottled; } -void FrameSchedulerImpl::OnFirstContentfulPaint() { +void FrameSchedulerImpl::OnFirstContentfulPaintInMainFrame() { waiting_for_contentful_paint_ = false; - if (GetFrameType() == FrameScheduler::FrameType::kMainFrame) - main_thread_scheduler_->OnMainFramePaint(); + DCHECK_EQ(GetFrameType(), FrameScheduler::FrameType::kMainFrame); + main_thread_scheduler_->OnMainFramePaint(); } void FrameSchedulerImpl::OnFirstMeaningfulPaint() {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h index 6c831164..17a5369f 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
@@ -122,7 +122,7 @@ const WTF::String& name, WebScopedVirtualTimePauser::VirtualTaskDuration duration) override; - void OnFirstContentfulPaint() override; + void OnFirstContentfulPaintInMainFrame() override; void OnFirstMeaningfulPaint() override; void OnLoad() override; bool IsWaitingForContentfulPaint() const;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc index 04f47bd..12c39c5 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -1605,7 +1605,7 @@ CreateFrameScheduler(page_scheduler_.get(), frame_scheduler_delegate_.get(), nullptr, FrameScheduler::FrameType::kMainFrame); - main_frame_scheduler->OnFirstContentfulPaint(); + main_frame_scheduler->OnFirstContentfulPaintInMainFrame(); ASSERT_EQ(scheduler_->current_use_case(), UseCase::kLoading); // Hidden Frame Task Queues. @@ -1698,7 +1698,7 @@ CreateFrameScheduler(page_scheduler_.get(), frame_scheduler_delegate_.get(), nullptr, FrameScheduler::FrameType::kMainFrame); - main_frame_scheduler->OnFirstContentfulPaint(); + main_frame_scheduler->OnFirstContentfulPaintInMainFrame(); ASSERT_EQ(scheduler_->current_use_case(), UseCase::kLoading); // Sub-Frame Task Queues. @@ -1794,7 +1794,7 @@ CreateFrameScheduler(page_scheduler_.get(), frame_scheduler_delegate_.get(), nullptr, FrameScheduler::FrameType::kMainFrame); - main_frame_scheduler->OnFirstContentfulPaint(); + main_frame_scheduler->OnFirstContentfulPaintInMainFrame(); ASSERT_EQ(scheduler_->current_use_case(), UseCase::kLoading); // Sub-Frame Task Queues. @@ -1889,7 +1889,7 @@ CreateFrameScheduler(page_scheduler_.get(), frame_scheduler_delegate_.get(), nullptr, FrameScheduler::FrameType::kMainFrame); - main_frame_scheduler->OnFirstContentfulPaint(); + main_frame_scheduler->OnFirstContentfulPaintInMainFrame(); ASSERT_EQ(scheduler_->current_use_case(), UseCase::kLoading); EXPECT_EQ(LoadingTaskQueue()->GetTaskQueue()->GetQueuePriority(), @@ -1927,7 +1927,6 @@ TEST_F(LowPriorityThrottleableTaskDuringLoadingExperimentTest, MainFrameQueuesPriorities) { - frame_scheduler_->OnFirstContentfulPaint(); frame_scheduler_->OnFirstMeaningfulPaint(); frame_scheduler_ = @@ -1935,7 +1934,7 @@ FrameScheduler::FrameType::kMainFrame); // Main thread is in the loading use case. - frame_scheduler_->OnFirstContentfulPaint(); + frame_scheduler_->OnFirstContentfulPaintInMainFrame(); // Main Frame Task Queues. EXPECT_EQ(LoadingTaskQueue()->GetTaskQueue()->GetQueuePriority(), @@ -2047,7 +2046,7 @@ CreateFrameScheduler(page_scheduler_.get(), frame_scheduler_delegate_.get(), nullptr, FrameScheduler::FrameType::kMainFrame); - main_frame_scheduler->OnFirstContentfulPaint(); + main_frame_scheduler->OnFirstContentfulPaintInMainFrame(); ASSERT_EQ(scheduler_->current_use_case(), UseCase::kLoading); EXPECT_EQ(LoadingTaskQueue()->GetTaskQueue()->GetQueuePriority(), @@ -2160,7 +2159,7 @@ CreateFrameScheduler(page_scheduler_.get(), frame_scheduler_delegate_.get(), nullptr, FrameScheduler::FrameType::kMainFrame); - main_frame_scheduler->OnFirstContentfulPaint(); + main_frame_scheduler->OnFirstContentfulPaintInMainFrame(); ASSERT_EQ(scheduler_->current_use_case(), UseCase::kLoading); EXPECT_EQ(LoadingTaskQueue()->GetTaskQueue()->GetQueuePriority(), @@ -2266,7 +2265,7 @@ TaskQueue::QueuePriority::kNormalPriority); // Main thread scheduler is in the loading use case. - main_frame_scheduler->OnFirstContentfulPaint(); + main_frame_scheduler->OnFirstContentfulPaintInMainFrame(); ASSERT_EQ(scheduler_->current_use_case(), UseCase::kLoading); handle = GetResourceLoadingTaskRunnerHandleImpl(); @@ -2357,7 +2356,7 @@ frame_scheduler_delegate_.get(), nullptr, FrameScheduler::FrameType::kMainFrame); - main_frame_scheduler->OnFirstContentfulPaint(); + main_frame_scheduler->OnFirstContentfulPaintInMainFrame(); ASSERT_EQ(scheduler_->current_use_case(), UseCase::kLoading); EXPECT_EQ(LoadingTaskQueue()->GetTaskQueue()->GetQueuePriority(), @@ -2913,7 +2912,7 @@ EXPECT_CALL(mock_main_thread_scheduler, OnMainFramePaint).Times(2); main_frame_scheduler->OnFirstMeaningfulPaint(); - main_frame_scheduler->OnFirstContentfulPaint(); + main_frame_scheduler->OnFirstContentfulPaintInMainFrame(); main_frame_scheduler = nullptr; page_scheduler = nullptr; @@ -2935,7 +2934,6 @@ EXPECT_CALL(mock_main_thread_scheduler, OnMainFramePaint).Times(0); subframe_scheduler->OnFirstMeaningfulPaint(); - subframe_scheduler->OnFirstContentfulPaint(); subframe_scheduler = nullptr; page_scheduler = nullptr;
diff --git a/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h index dcfe768..ffba694 100644 --- a/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h +++ b/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h
@@ -161,8 +161,8 @@ NavigationType navigation_type) = 0; // Tells the scheduler that the first contentful paint has occurred for this - // frame. - virtual void OnFirstContentfulPaint() = 0; + // frame. Only for main frames. + virtual void OnFirstContentfulPaintInMainFrame() = 0; // Tells the scheduler that the first meaningful paint has occurred for this // frame.
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index d8da3f5..58fa590 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -917,7 +917,6 @@ crbug.com/958381 external/wpt/css/css-tables/tentative/baseline-td.html [ Failure ] crbug.com/958381 external/wpt/css/css-tables/tentative/caption.html [ Failure ] crbug.com/958381 external/wpt/css/css-tables/tentative/colgroup-col.html [ Failure ] -crbug.com/958381 external/wpt/css/css-tables/tentative/colspan-redistribution.html [ Failure ] crbug.com/174167 external/wpt/css/css-tables/tentative/element-sizing.html [ Failure ] crbug.com/958381 external/wpt/css/css-tables/tentative/paint/background-image-column.html [ Failure ] crbug.com/958381 external/wpt/css/css-tables/tentative/paint/collapsed-border-large-cell.html [ Failure ]
diff --git a/third_party/blink/web_tests/LeakExpectations b/third_party/blink/web_tests/LeakExpectations index 4b659a72..c72f459 100644 --- a/third_party/blink/web_tests/LeakExpectations +++ b/third_party/blink/web_tests/LeakExpectations
@@ -203,6 +203,9 @@ # Sheriff 2021-05-03 crbug.com/1197465 [ Linux ] virtual/scroll-unification/fast/events/mouse-cursor-no-mousemove.html [ Pass Failure ] +# Sheriff 2021-05-05 +crbug.com/1205815 [ Linux ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/sources/snippet-module.js [ Pass Failure ] + ########################################################################### # WARNING: Memory leaks must be fixed asap. Sheriff is expected to revert # # culprit CLs instead of suppressing the leaks. If you have any question, #
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 669cc2f..c74ed46 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -6039,8 +6039,10 @@ crbug.com/1048149 [ Mac ] fast/forms/color/color-picker-zoom150-bottom-edge-no-nan.html [ Pass Crash ] crbug.com/1048149 crbug.com/1050121 [ Mac ] fast/forms/month/month-picker-appearance-zoom150.html [ Pass Crash ] -# SwANGLE issue +# SwANGLE issues crbug.com/1204234 [ Linux ] css3/blending/background-blend-mode-single-accelerated-element.html [ Failure ] +crbug.com/1204234 [ Linux ] external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https.html [ Failure ] +crbug.com/1204234 [ Linux ] external/wpt/webxr/xrWebGLLayer_opaque_framebuffer_stencil.https.html [ Failure ] # Upcoming DevTools change crbug.com/1006759 http/tests/devtools/profiler/cpu-profiler-save-load.js [ Pass Failure Timeout ] @@ -7088,3 +7090,12 @@ # Browser Infra 2021-05-04 # Re-enable once all Linux CI/CQ builders migrated to Bionic crbug.com/1200134 [ Linux ] fast/gradients/unprefixed-repeating-gradient-color-hint.html [ Pass Failure ] + +# Sheriff 2021-05-05 +crbug.com/1205779 [ Win7 ] external/wpt/url/a-element.html [ Failure ] +crbug.com/1205780 [ Win7 ] external/wpt/css/mediaqueries/test_media_queries.html [ Failure ] +crbug.com/1205780 [ Mac10.14 ] external/wpt/css/mediaqueries/test_media_queries.html [ Failure ] +crbug.com/1205780 [ Mac10.15 ] external/wpt/css/mediaqueries/test_media_queries.html [ Failure Pass ] +crbug.com/1205796 [ Mac10.12 ] external/wpt/html/dom/idlharness.https.html?include=HTML.* [ Failure ] +crbug.com/1205796 [ Mac10.14 ] external/wpt/html/dom/idlharness.https.html?include=HTML.* [ Failure ] +crbug.com/1205801 [ Mac10.14 ] external/wpt/css/css-will-change/will-change-fixpos-cb-position-1.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index e5cadba..b24a0ba3 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -1443,7 +1443,7 @@ ] ], "imperative-slot-api-crash.html": [ - "ca444778e313aaab73d2ba5925b35e201ce110a1", + "b029689211f57f355974130fba51d1ea0cebbbcf", [ null, {} @@ -45899,6 +45899,19 @@ {} ] ], + "mix-blend-mode-rotated-clip.html": [ + "9e915ac3cca49d127104e43a7fc50fa734eb9da1", + [ + null, + [ + [ + "/css/compositing/mix-blend-mode/reference/mix-blend-mode-rotated-clip-ref.html", + "==" + ] + ], + {} + ] + ], "mix-blend-mode-script.html": [ "1268a8dc3f8242f03007dfc5a5afbd321ee57b7b", [ @@ -133108,32 +133121,6 @@ {} ] ], - "3d-rendering-context-and-abspos.html": [ - "c5eef46b5e800bcb411b2aed9c65534b8e3e1bc8", - [ - null, - [ - [ - "/css/css-transforms/reference/green.html", - "==" - ] - ], - {} - ] - ], - "3d-rendering-context-and-fixpos.html": [ - "e763e8b703ca7582fb8756f00c5faff47c7db408", - [ - null, - [ - [ - "/css/css-transforms/reference/green.html", - "==" - ] - ], - {} - ] - ], "3d-rendering-context-and-z-ordering-001.html": [ "d07c59a5db229cd1ed1ee9a429ea7656cd18d3e5", [ @@ -148764,6 +148751,19 @@ {} ] ], + "will-change-transform-huge-offset-scrolled.html": [ + "506ac67f0c876740ce8b4529de4abe18a194db05", + [ + null, + [ + [ + "/css/css-will-change/will-change-transform-huge-offset-scrolled-ref.html", + "==" + ] + ], + {} + ] + ], "will-change-transform-image.html": [ "edce6c1f9bfa840004d8e82e6720be9c18bd23b6", [ @@ -193256,6 +193256,10 @@ "275105c5dbb03cf1b82eb058e856d53b129ecbe9", [] ], + "mix-blend-mode-rotated-clip-ref.html": [ + "377ed7c879fd8ec15ff660da617294bc119206e0", + [] + ], "mix-blend-mode-script-ref.html": [ "b18ed6cd3c83d98495ab7c46ccb90fc593c3ad49", [] @@ -223210,6 +223214,10 @@ "edbeaa7b69290ea2514dc85e0e3f47bd8247735e", [] ], + "will-change-transform-huge-offset-scrolled-ref.html": [ + "c2af258e11161654a109d030596cfcca1f96a4d9", + [] + ], "will-change-transform-image-ref.html": [ "d42d5b7fea22d3d2bc2abf782b1efc78f261f69e", [] @@ -314513,7 +314521,7 @@ ] ], "colspan-redistribution.html": [ - "e440728e1004bc952a5725bc50206b316a8e7450", + "2797a1e6894ed28387af24669e238c743d53787a", [ null, {} @@ -431472,14 +431480,14 @@ ] ], "imperative-slot-api-slotchange.html": [ - "dd9ebbd3f849b3262a01139d6acfbbfc6ade87a6", + "1aa6a786760f81fdd37628fe6863717a4cfa7cb8", [ null, {} ] ], "imperative-slot-api.html": [ - "54b22632d11547f33b4d08ef9f51c8ef52380baf", + "8133d7e8ebe5e2c90ddd893ffd0b60552ba9c5f1", [ null, {} @@ -450824,7 +450832,7 @@ ] ], "audioparam-setValueCurve-exceptions.html": [ - "37062993f9dc8d90e2d418c842b30e20517bd21d", + "ed0c15fb9b3bdf5a9c79e48f97949b21ac05a952", [ null, {} @@ -451921,6 +451929,13 @@ {} ] ], + "pannernode-setposition-throws.html": [ + "2053411943719d647ac0f17ac71d0beb742102c9", + [ + null, + {} + ] + ], "test-pannernode-automation.html": [ "ce474b10b5122eaf40b8b6d1af874ad7ec9bff70", [ @@ -452458,7 +452473,7 @@ ] ], "image-decoder.any.js": [ - "2bbc6238d0a6bf8454cf693ae3369ee657f0fb48", + "1912e63f8c7c06786eb8b368796d65243de02f36", [ "webcodecs/image-decoder.any.html", {
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/data-prefix-and-mask-size.https.window.js b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/data-prefix-and-mask-size.https.window.js new file mode 100644 index 0000000..49cf41c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/data-prefix-and-mask-size.https.window.js
@@ -0,0 +1,24 @@ +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = + 'Manufacturer data mask size must be equal to dataPrefix size.'; + +bluetooth_test(async (t) => { + const companyIdentifier = 0x0001; + const dataPrefix = new Uint8Array([0x01, 0x02, 0x03, 0x04]); + const mask = new Uint8Array([0xff]); + + await promise_rejects_js( + t, TypeError, + requestDeviceWithTrustedClick( + {filters: [{manufacturerData: [{companyIdentifier, mask}]}]})); + await promise_rejects_js( + t, TypeError, requestDeviceWithTrustedClick({ + filters: [{manufacturerData: [{companyIdentifier, dataPrefix, mask}]}] + })); +}, test_desc);
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/dataPrefix-buffer-is-detached.https.window.js b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/dataPrefix-buffer-is-detached.https.window.js new file mode 100644 index 0000000..936ca473 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/dataPrefix-buffer-is-detached.https.window.js
@@ -0,0 +1,33 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'dataPrefix value buffer must not be detached'; + +function detachBuffer(buffer) { + window.postMessage('', '*', [buffer]); +} + +bluetooth_test(async (t) => { + const companyIdentifier = 0x0001; + + const typed_array = Uint8Array.of(1, 2); + detachBuffer(typed_array.buffer); + + await promise_rejects_dom( + t, 'InvalidStateError', requestDeviceWithTrustedClick({ + filters: + [{manufacturerData: [{companyIdentifier, dataPrefix: typed_array}]}] + })); + + const array_buffer = Uint8Array.of(3, 4).buffer; + detachBuffer(array_buffer); + + await promise_rejects_dom( + t, 'InvalidStateError', requestDeviceWithTrustedClick({ + filters: [ + {manufacturerData: [{companyIdentifier, dataPrefix: array_buffer}]} + ] + })); +}, test_desc); \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/empty-manufacturerData-member.https.window.js b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/empty-manufacturerData-member.https.window.js new file mode 100644 index 0000000..af3118a4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/empty-manufacturerData-member.https.window.js
@@ -0,0 +1,37 @@ +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'requestDevice with empty manufacturerData. ' + + 'Should reject with TypeError.'; +const test_specs = [ + {filters: [{manufacturerData: []}]}, + {filters: [{manufacturerData: [], name: 'Name'}]}, + {filters: [{manufacturerData: [], services: ['heart_rate']}]}, + {filters: [{manufacturerData: [], name: 'Name', services: ['heart_rate']}]}, + {filters: [{manufacturerData: []}], optionalServices: ['heart_rate']}, { + filters: [{manufacturerData: [], name: 'Name'}], + optionalServices: ['heart_rate'] + }, + { + filters: [{manufacturerData: [], services: ['heart_rate']}], + optionalServices: ['heart_rate'] + }, + { + filters: [{manufacturerData: [], name: 'Name', services: ['heart_rate']}], + optionalServices: ['heart_rate'] + } +]; + +bluetooth_test((t) => { + let test_promises = Promise.resolve(); + test_specs.forEach(args => { + test_promises = test_promises.then( + () => promise_rejects_js( + t, TypeError, requestDeviceWithTrustedClick(args))); + }); + return test_promises; +}, test_desc); \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/invalid-companyIdentifier.https.window.js b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/invalid-companyIdentifier.https.window.js new file mode 100644 index 0000000..18cdbb4b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/invalid-companyIdentifier.https.window.js
@@ -0,0 +1,17 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'companyIdentifier must be in the [0, 65535] range'; + +bluetooth_test(async (t) => { + await promise_rejects_js( + t, TypeError, + requestDeviceWithTrustedClick( + {filters: [{manufacturerData: [{companyIdentifier: -1}]}]})); + await promise_rejects_js( + t, TypeError, + requestDeviceWithTrustedClick( + {filters: [{manufacturerData: [{companyIdentifier: 65536}]}]})); +}, test_desc); \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/mask-buffer-is-detached.https.window.js b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/mask-buffer-is-detached.https.window.js new file mode 100644 index 0000000..502e2e4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/mask-buffer-is-detached.https.window.js
@@ -0,0 +1,36 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'mask value buffer must not be detached'; + +function detachBuffer(buffer) { + window.postMessage('', '*', [buffer]); +} + +bluetooth_test(async (t) => { + const companyIdentifier = 0x0001; + const dataPrefix = Uint8Array.of(1, 2); + + const typed_array = Uint8Array.of(1, 2); + detachBuffer(typed_array.buffer); + + await promise_rejects_dom( + t, 'InvalidStateError', requestDeviceWithTrustedClick({ + filters: [{ + manufacturerData: [{companyIdentifier, dataPrefix, mask: typed_array}] + }] + })); + + const array_buffer = Uint8Array.of(3, 4).buffer; + detachBuffer(array_buffer); + + await promise_rejects_dom( + t, 'InvalidStateError', requestDeviceWithTrustedClick({ + filters: [{ + manufacturerData: + [{companyIdentifier, dataPrefix, mask: array_buffer}] + }] + })); +}, test_desc); \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/same-company-identifier.https.window.js b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/same-company-identifier.https.window.js new file mode 100644 index 0000000..7416202d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/canonicalizeFilter/same-company-identifier.https.window.js
@@ -0,0 +1,25 @@ +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Manufacturer data company identifier must be unique.'; +const expected = new TypeError(); + +let filters = [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + }, + { + companyIdentifier: 0x0001, + } + ] +}]; + +bluetooth_test( + (t) => promise_rejects_js( + t, TypeError, requestDeviceWithTrustedClick({filters})), + test_desc);
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/filter-matches.https.html b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/filter-matches.https.html index 1c42d77..7815a1a 100644 --- a/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/filter-matches.https.html +++ b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/filter-matches.https.html
@@ -11,6 +11,7 @@ let matching_services = [health_thermometer.uuid]; let matching_name = 'Health Thermometer'; let matching_namePrefix = 'Health'; +let matching_manufacturerData = [{ companyIdentifier: 0x0001 }]; let test_specs = [ { @@ -24,25 +25,50 @@ name: matching_name, }] }, - {filters: [{services: matching_services, namePrefix: matching_namePrefix}]}, { + { + filters: [{ + services: matching_services, + namePrefix: matching_namePrefix + }] + }, + { + filters: [{ + services: matching_services, + manufacturerData: matching_manufacturerData + }] + }, + { filters: [{ name: matching_name, }], optionalServices: matching_services }, { - filters: [{name: matching_name, namePrefix: matching_namePrefix}], + filters: [{ + namePrefix: matching_namePrefix + }], optionalServices: matching_services }, { - filters: [{namePrefix: matching_namePrefix}], + filters: [{ + manufacturerData: matching_manufacturerData + }], + optionalServices: matching_services + }, + { + filters: [{ + name: matching_name, + namePrefix: matching_namePrefix, + manufacturerData: matching_manufacturerData + }], optionalServices: matching_services }, { filters: [{ services: matching_services, name: matching_name, - namePrefix: matching_namePrefix + namePrefix: matching_namePrefix, + manufacturerData: matching_manufacturerData }] } ];
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/manufacturer-data-filter-matches.https.window.js b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/manufacturer-data-filter-matches.https.window.js new file mode 100644 index 0000000..548b5d0b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/bluetooth/requestDevice/manufacturer-data-filter-matches.https.window.js
@@ -0,0 +1,141 @@ +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Matches a filter when manufacturer data match.'; + +let test_specs = [ + { + filters: [{ + manufacturerData: [{ + companyIdentifier: 0x0001, + }], + }], + }, + { + filters: [{ + manufacturerData: [{ + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01]), + }], + }], + }, + { + filters: [{ + manufacturerData: [{ + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01]), + mask: new Uint8Array([0xff]), + }], + }], + }, + { + filters: [{ + manufacturerData: [{ + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + }], + }], + }, + { + filters: [{ + manufacturerData: [{ + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }], + }], + }, + { + filters: [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }, + { + companyIdentifier: 0x0002, + } + ], + }], + }, + { + filters: [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }, + { + companyIdentifier: 0x0002, + dataPrefix: new Uint8Array([0x03]), + } + ], + }], + }, + { + filters: [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }, + { + companyIdentifier: 0x0002, + dataPrefix: new Uint8Array([0x03]), + mask: new Uint8Array([0xff]), + } + ], + }], + }, + { + filters: [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }, + { + companyIdentifier: 0x0002, + dataPrefix: new Uint8Array([0x03, 0x04]), + } + ], + }], + }, + { + filters: [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }, + { + companyIdentifier: 0x0002, + dataPrefix: new Uint8Array([0x03, 0x04]), + mask: new Uint8Array([0xff, 0xff]) + } + ], + }], + }, +]; + +bluetooth_test( + () => setUpHealthThermometerDevice().then(() => { + let test_promises = Promise.resolve(); + test_specs.forEach(args => { + test_promises = test_promises.then(async () => { + const device = await requestDeviceWithTrustedClick(args); + assert_equals(device.name, 'Health Thermometer'); + }); + }); + return test_promises; + }), + test_desc);
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/resources/bluetooth-fake-devices.js b/third_party/blink/web_tests/external/wpt/bluetooth/resources/bluetooth-fake-devices.js index c4d699a..bc142aa4 100644 --- a/third_party/blink/web_tests/external/wpt/bluetooth/resources/bluetooth-fake-devices.js +++ b/third_party/blink/web_tests/external/wpt/bluetooth/resources/bluetooth-fake-devices.js
@@ -196,8 +196,19 @@ return [ {filters: [{services: services}]}, {filters: [{services: services, name: 'Name'}]}, - {filters: [{services: services, namePrefix: 'Pre'}]}, - {filters: [{services: services, name: 'Name', namePrefix: 'Pre'}]}, + {filters: [{services: services, namePrefix: 'Pre'}]}, { + filters: [ + {services: services, manufacturerData: [{companyIdentifier: 0x0001}]} + ] + }, + { + filters: [{ + services: services, + name: 'Name', + namePrefix: 'Pre', + manufacturerData: [{companyIdentifier: 0x0001}] + }] + }, {filters: [{services: services}], optionalServices: ['heart_rate']}, { filters: [{services: services, name: 'Name'}], optionalServices: ['heart_rate'] @@ -207,7 +218,18 @@ optionalServices: ['heart_rate'] }, { - filters: [{services: services, name: 'Name', namePrefix: 'Pre'}], + filters: [ + {services: services, manufacturerData: [{companyIdentifier: 0x0001}]} + ], + optionalServices: ['heart_rate'] + }, + { + filters: [{ + services: services, + name: 'Name', + namePrefix: 'Pre', + manufacturerData: [{companyIdentifier: 0x0001}] + }], optionalServices: ['heart_rate'] } ]; @@ -242,6 +264,7 @@ /** * A dictionary for specifying fake Bluetooth device setup options. * @typedef {{address: !string, name: !string, + * manufacturerData: !Object<uint16,Array<uint8>>, * knownServiceUUIDs: !Array<string>, connectable: !boolean, * serviceDiscoveryComplete: !boolean}} */ @@ -260,6 +283,7 @@ const fakeDeviceOptionsDefault = { address: '00:00:00:00:00:00', name: 'LE Device', + manufacturerData: {}, knownServiceUUIDs: [], connectable: false, serviceDiscoveryComplete: false, @@ -327,6 +351,7 @@ await fake_central.simulatePreconnectedPeripheral({ address: setupOptions.fakeDeviceOptions.address, name: setupOptions.fakeDeviceOptions.name, + manufacturerData: setupOptions.fakeDeviceOptions.manufacturerData, knownServiceUUIDs: setupOptions.fakeDeviceOptions.knownServiceUUIDs, }); @@ -360,14 +385,16 @@ /** * Deprecated: Use setUpPreconnectedFakeDevice() instead. - * Simulates a preconnected device with |address|, |name| and - * |knownServiceUUIDs|. A preconnected device is a device that has been paired - * with the system previously. This can be done if, for example, the user pairs - * the device using the OS'es settings. + * Simulates a preconnected device with |address|, |name|, |manufacturerData| + * and |knownServiceUUIDs|. A preconnected device is a device that has been + * paired with the system previously. This can be done if, for example, the user + * pairs the device using the OS'es settings. * TODO(https://crbug.com/1070816): Remove this method when all uses have been * converted to using setUpPreconnectedFakeDevice(); * @param {string} address The device MAC address. * @param {string} name The device name. + * @param {Object<uint16,Array<uint8>>} manufacturerData A map of company + * identifier and manufacturer data to set up the fake with. * @param {Array<string>} knownServiceUUIDs An array of GATT service UUIDs to * set up the fake with. * @returns {Promise<FakePeripheral>} The fake devices are initialized with the @@ -376,12 +403,14 @@ async function setUpPreconnectedDevice({ address = '00:00:00:00:00:00', name = 'LE Device', + manufacturerData = {}, knownServiceUUIDs = [] }) { await initializeFakeCentral({state: 'powered-on'}); return await fake_central.simulatePreconnectedPeripheral({ address: address, name: name, + manufacturerData: manufacturerData, knownServiceUUIDs: knownServiceUUIDs, }); } @@ -705,7 +734,7 @@ /** * Returns a FakePeripheral that corresponds to a simulated pre-connected device * called 'Health Thermometer'. The device has two known serviceUUIDs: - * 'generic_access' and 'health_thermometer'. + * 'generic_access' and 'health_thermometer' and some fake manufacturer data. * @returns {Promise<FakePeripheral>} The device fake initialized as a Health * Thermometer device. */ @@ -713,6 +742,7 @@ return setUpPreconnectedDevice({ address: '09:09:09:09:09:09', name: 'Health Thermometer', + manufacturerData: {0x0001: manufacturer1Data, 0x0002: manufacturer2Data}, knownServiceUUIDs: ['generic_access', 'health_thermometer'], }); } @@ -1122,11 +1152,13 @@ fake_central.simulatePreconnectedPeripheral({ address: '09:09:09:09:09:09', name: 'Health Thermometer', + manufacturerData: {}, knownServiceUUIDs: ['generic_access', 'health_thermometer'], }), fake_central.simulatePreconnectedPeripheral({ address: '08:08:08:08:08:08', name: 'Heart Rate', + manufacturerData: {}, knownServiceUUIDs: ['generic_access', 'heart_rate'], }) ]);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/colspan-redistribution.html b/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/colspan-redistribution.html index 2797a1e..e440728 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/colspan-redistribution.html +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/colspan-redistribution.html
@@ -216,31 +216,29 @@ </table> </div> -<p 12 class="testdesc">Colspan>1:Auto/468 C0:50%/150 C1:30%/150 C2:20/Auto +<p 12 class="testdesc">Colspan>1:Auto/400 C0:50%/150 C1:30%/150 C2:20/Auto This tests conflict resolution where min-width > redistributed min width. -Colspanned redistribution: distributed 468-8 = 460 over C0/C1 -Colspanned 468px needs to distribute 460px over C0/C1. -C0 percent size is 50% * 460 = 230 -C1 percent size is 30% * 460 = 138, defaults to min size of 150 -Column 1 size is 230 + 50%/80% * 80 = 280px -Column 2 size is 150 + 30%/80% * 80 = 180px -Column 3 remains 20px -Assignable table inline size -C1 dominates estimate: 180/30% + 4*8 = 632 -Compute final column widths from assignable table size: -C0 = 50% of 600 = 300 C1 = 30% of 600 = 180 , C2 gets the remaining 120</p> -<table data-expected-width="632"> +400-8px distributed max width tries to redistribute as 245|147, but gets constrained to 245|150 in Chrome. +table width from C0 245/0.5 + 4*8 = 522 +table width from C1 150/0.3 + 4*8 = 532 +C0 = 50% of 500 = 250, C1 = 30% of 500 = 150 , C2 gets the remaining 100</p> +<p class="error">Chrome/FF/Edge end up with tables of different widths: 532/590/685. Chrome's 2nd span cell seems 'most correct' at its original max width of 150. In FF, extra min-width seems to cause more width to be redistributed. If you hover over 30%/150 cell, its min width will change to 100px, and all browsers will agree.</p> +<style> + .test12:hover { + width:100px !important; + } +</style> +<table data-expected-width="532"> <tr> - <td style="width:50%" data-expected-width="300"><div style="width:150px">50%/150px</div></td> - <td style="width:30%" data-expected-width="180"><div style="width:150px">30%/150px</div></td> - <td style="width:20px" data-expected-width="120">x</td> + <td style="width:50%" data-expected-width="250"><div style="width:150px">50%/150px</div></td> + <td style="width:30%" data-expected-width="150"><div class="test12" style="width:150px">30%/150px</div></td> + <td style="width:20px" data-expected-width="100">x</td> </tr> <tr> - <td colspan=2 style=""><div style="width:468px">408px min</div></td> + <td colspan=2 style=""><div style="width:400px">400px min</div></td> </tr> </table> - <p 13 class="testdesc"> Colspan>1:Auto/400px C0:50%/75px/125px, C1:30%/75px/125px C2:20px/Auto Colspan>1 cell distribution over different percentages. 400-8px min width gets redistributed as 245/147 (no min width limits)
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/full-credentialless/cookie.tentative.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/full-credentialless/cookie.tentative.https-expected.txt index f698df7..377c729 100644 --- a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/full-credentialless/cookie.tentative.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/full-credentialless/cookie.tentative.https-expected.txt
@@ -1,8 +1,14 @@ This is a testharness.js-based test. PASS Setup +FAIL Anonymous same-origin iframe is loaded without credentials assert_equals: expected (undefined) undefined but got (string) "same_origin" +FAIL Anonymous cross-origin iframe is loaded without credentials assert_equals: expected (undefined) undefined but got (string) "cross_origin" FAIL same_origin anonymous iframe can't send same_origin credentials assert_equals: expected (undefined) undefined but got (string) "same_origin" FAIL same_origin anonymous iframe can't send cross_origin credentials assert_equals: expected (undefined) undefined but got (string) "cross_origin" FAIL cross_origin anonymous iframe can't send cross_origin credentials assert_equals: expected (undefined) undefined but got (string) "cross_origin" FAIL cross_origin anonymous iframe can't send same_origin credentials assert_equals: expected (undefined) undefined but got (string) "same_origin" +FAIL same_origin anonymous iframe can't send same_origin credentials on child iframe assert_equals: expected (undefined) undefined but got (string) "same_origin" +FAIL same_origin anonymous iframe can't send cross_origin credentials on child iframe assert_equals: expected (undefined) undefined but got (string) "cross_origin" +FAIL cross_origin anonymous iframe can't send cross_origin credentials on child iframe assert_equals: expected (undefined) undefined but got (string) "cross_origin" +FAIL cross_origin anonymous iframe can't send same_origin credentials on child iframe assert_equals: expected (undefined) undefined but got (string) "same_origin" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/full-credentialless/cookie.tentative.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/full-credentialless/cookie.tentative.https.html index aa2a383..acd60c5 100644 --- a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/full-credentialless/cookie.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/full-credentialless/cookie.tentative.https.html
@@ -13,55 +13,120 @@ const cookie_same_origin = "same_origin"; const cookie_cross_origin = "cross_origin"; -// Fetch a resource, returns the HTTP request cookies. -const cookieFromResource = async (document_token, resource_origin) => { - const resource_token = token(); - send(document_token, ` - let img = document.createElement("img"); - img.src = "${showRequestHeaders(resource_origin, resource_token)}"; - document.body.appendChild(img); - `); +const cookieFromResource = async resource_token => { let headers = JSON.parse(await receive(resource_token)); return parseCookies(headers)[cookie_key]; }; +// Load an iframe, return the HTTP request cookies. +const cookieFromIframeNavigationRequest = async (iframe_origin) => { + const resource_token = token(); + let iframe = document.createElement("iframe"); + iframe.src = `${showRequestHeaders(iframe_origin, resource_token)}`; + document.body.appendChild(iframe); + return await cookieFromResource(resource_token); +}; + +// Load a resource `type` from the iframe with `document_token`, +// return the HTTP request cookies. +const cookieFromResourceInIframe = + async (document_token, resource_origin, type = "img") => { + const resource_token = token(); + send(document_token, ` + let el = document.createElement("${type}"); + el.src = "${showRequestHeaders(resource_origin, resource_token)}"; + document.body.appendChild(el); + `); + return await cookieFromResource(resource_token); +}; + promise_test_parallel(async test => { await Promise.all([ setCookie(same_origin, cookie_key, cookie_same_origin), setCookie(cross_origin, cookie_key, cookie_cross_origin), ]); + promise_test_parallel(async test => { + assert_equals( + await cookieFromIframeNavigationRequest(same_origin), + undefined + ); + }, "Anonymous same-origin iframe is loaded without credentials"); + + promise_test_parallel(async test => { + assert_equals( + await cookieFromIframeNavigationRequest(cross_origin), + undefined + ); + }, "Anonymous cross-origin iframe is loaded without credentials"); + let iframe_same_origin = newAnonymousIframe(same_origin); let iframe_cross_origin = newAnonymousIframe(cross_origin); promise_test_parallel(async test => { assert_equals( - await cookieFromResource(iframe_same_origin, same_origin), + await cookieFromResourceInIframe(iframe_same_origin, same_origin), undefined ); }, "same_origin anonymous iframe can't send same_origin credentials"); promise_test_parallel(async test => { assert_equals( - await cookieFromResource(iframe_same_origin, cross_origin), + await cookieFromResourceInIframe(iframe_same_origin, cross_origin), undefined ); }, "same_origin anonymous iframe can't send cross_origin credentials"); promise_test_parallel(async test => { assert_equals( - await cookieFromResource(iframe_cross_origin, cross_origin), + await cookieFromResourceInIframe(iframe_cross_origin, cross_origin), undefined ); }, "cross_origin anonymous iframe can't send cross_origin credentials"); promise_test_parallel(async test => { assert_equals( - await cookieFromResource(iframe_cross_origin, same_origin), + await cookieFromResourceInIframe(iframe_cross_origin, same_origin), undefined ); }, "cross_origin anonymous iframe can't send same_origin credentials"); + promise_test_parallel(async test => { + assert_equals( + await cookieFromResourceInIframe(iframe_same_origin, same_origin, + "iframe"), + undefined + ); + }, "same_origin anonymous iframe can't send same_origin credentials " + + "on child iframe"); + + promise_test_parallel(async test => { + assert_equals( + await cookieFromResourceInIframe(iframe_same_origin, cross_origin, + "iframe"), + undefined + ); + }, "same_origin anonymous iframe can't send cross_origin credentials " + + "on child iframe"); + + promise_test_parallel(async test => { + assert_equals( + await cookieFromResourceInIframe(iframe_cross_origin, cross_origin, + "iframe"), + undefined + ); + }, "cross_origin anonymous iframe can't send cross_origin credentials " + + "on child iframe"); + + promise_test_parallel(async test => { + assert_equals( + await cookieFromResourceInIframe(iframe_cross_origin, same_origin, + "iframe"), + undefined + ); + }, "cross_origin anonymous iframe can't send same_origin credentials " + + "on child iframe"); + }, "Setup") </script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/fetch-cross-origin-redirect.https.html b/third_party/blink/web_tests/external/wpt/resource-timing/fetch-cross-origin-redirect.https.html index eab615b..4193422 100644 --- a/third_party/blink/web_tests/external/wpt/resource-timing/fetch-cross-origin-redirect.https.html +++ b/third_party/blink/web_tests/external/wpt/resource-timing/fetch-cross-origin-redirect.https.html
@@ -1,65 +1,33 @@ <!DOCTYPE html> <meta charset="utf-8"> <title>Test cross-origin fetch redirects have the right values.</title> +<link rel="author" title="Google" href="http://www.google.com/" /> +<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#sec-performanceresourcetiming"/> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/common/get-host-info.sub.js"></script> +<script src="resources/entry-invariants.js"></script> +<script src="resources/resource-loaders.js"></script> <script> -const run_test = async (t, url, cross_origin) => { - // Set up PerformanceObserver - const href = new URL(url).href; - const setPerformanceObserver = new Promise(resolve => { - const po = new PerformanceObserver(resolve); - po.observe({type: "resource"}); - }); - - // Fetch the resource - await fetch(href, {mode: "no-cors", credentials: "include" }); - - // Wait for an entry - const timeout = new Promise(resolve => t.step_timeout(resolve, 1000)); - const list = await Promise.race([setPerformanceObserver, timeout]); - assert_equals(typeof(list), "object", "No iframe entry was fired"); - const entries = list.getEntriesByName(url); - assert_equals(entries.length, 1); - - // Test entry values - const entry = entries[0]; - if (cross_origin) { - assert_equals(entry.redirectStart, 0, "redirectStart should be 0 in cross-origin redirect."); - assert_equals(entry.redirectEnd, 0, "redirectEnd should be 0 in cross-origin redirect."); - assert_equals(entry.domainLookupStart, 0, "domainLookupStart should be 0 in cross-origin redirect."); - assert_equals(entry.domainLookupEnd, 0, "domainLookupEnd should be 0 in cross-origin redirect."); - assert_equals(entry.connectStart, 0, "connectStart should be 0 in cross-origin redirect."); - assert_equals(entry.connectEnd, 0, "connectEnd should be 0 in cross-origin redirect."); - assert_equals(entry.requestStart, 0, "requestStart should be 0 in cross-origin redirect."); - assert_equals(entry.responseStart, 0, "responseStart should be 0 in cross-origin redirect."); - assert_equals(entry.secureConnectionStart, 0, "secureConnectionStart should be 0 in cross-origin redirect."); - } else { - assert_greater_than(entry.redirectStart, 0, "redirectStart should be more than 0 in same-origin redirect."); - assert_greater_than(entry.redirectEnd, 0, "redirectEnd should be more than 0 in same-origin redirect."); - assert_greater_than(entry.domainLookupStart, 0, "domainLookupStart should be more than 0 in same-origin redirect."); - assert_greater_than(entry.domainLookupEnd, 0, "domainLookupEnd should be more than 0 in same-origin redirect."); - assert_greater_than(entry.connectStart, 0, "connectStart should be more than 0 in same-origin redirect."); - assert_greater_than(entry.connectEnd, 0, "connectEnd should be more than 0 in same-origin redirect."); - assert_greater_than(entry.requestStart, 0, "requestStart should be more than 0 in same-origin redirect."); - assert_greater_than(entry.responseStart, 0, "responseStart should be more than 0 in same-origin redirect."); - assert_greater_than(entry.secureConnectionStart, 0, "secureConnectionStart should be more than 0 in same-origin redirect."); - } - assert_greater_than(entry.fetchStart, 0, "fetchStart should be greater than 0 in redirects."); - assert_greater_than(entry.responseEnd, 0, "responseEnd should be greater than 0 in redirects."); - assert_greater_than(entry.duration, 0, "duration should be greater than 0 in redirects."); - assert_greater_than(entry.responseEnd, entry.fetchStart, "responseEnd should be greater than fetchStart in redirects."); -} const {REMOTE_ORIGIN, ORIGIN} = get_host_info(); -const redirect = "/common/redirect.py?location=" + "/resource-timing/resources/green.html"; +const redirect = "/common/redirect.py?" + + "location=/resource-timing/resources/green.html"; const cross_origin_redirect = REMOTE_ORIGIN + redirect; const same_origin_redirect = ORIGIN + redirect; -promise_test(t => { - return run_test(t, cross_origin_redirect, true); -}, "Test fetch for a cross-origin redirect URL"); -promise_test(t => { - return run_test(t, same_origin_redirect, false); -}, "Test fetch for a same-origin redirect URL"); + +attribute_test( + url => fetch(url, {mode: "no-cors", credentials: "include"}), + new URL(cross_origin_redirect).href, + invariants.assert_cross_origin_redirected_resource, + "Test fetching through a cross-origin redirect URL" +); + +attribute_test( + url => fetch(url, {mode: "no-cors", credentials: "include"}), + new URL(same_origin_redirect).href, + invariants.assert_same_origin_redirected_resource, + "Test fetching through a same-origin redirect URL" +); + </script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/nextHopProtocol-is-tao-protected.https.html b/third_party/blink/web_tests/external/wpt/resource-timing/nextHopProtocol-is-tao-protected.https.html new file mode 100644 index 0000000..e0e96af --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/resource-timing/nextHopProtocol-is-tao-protected.https.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8" /> +<title>Resource Timing - Check that nextHopProtocol is TAO protected</title> +<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#sec-performanceresourcetiming"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/entry-invariants.js"></script> +<script src="resources/resource-loaders.js"></script> +</head> +<body> +<script> + +const {HTTPS_REMOTE_ORIGIN} = get_host_info(); +const remote_resources = `${HTTPS_REMOTE_ORIGIN}/resource-timing/resources`; + +// Add iframe to remote origin - page without TAO +attribute_test( + load.iframe, `${remote_resources}/green.htm`, + entry => assert_equals(entry.nextHopProtocol, "", + "nextHopProtocol should be the empty string"), + "Add TAO-less iframe from remote origin. Make sure nextHopProtocol is the " + + "empty string" +); + +// Add iframe to remote origin - page with TAO +attribute_test( + load.iframe, `${remote_resources}/blank-with-tao.html`, + entry => assert_not_equals(entry.nextHopProtocol, "", + "nextHopProtocol should not be the empty string"), + "Add TAO'd iframe from remote origin. Make sure nextHopProtocol is not " + + "the empty string" +); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/nextHopProtocol-tao-protected.https.html b/third_party/blink/web_tests/external/wpt/resource-timing/nextHopProtocol-tao-protected.https.html deleted file mode 100644 index 6011ec2a..0000000 --- a/third_party/blink/web_tests/external/wpt/resource-timing/nextHopProtocol-tao-protected.https.html +++ /dev/null
@@ -1,65 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<meta charset="utf-8" /> -<meta name=timeout content=long> -<title>Resource Timing - Check that nextHopProtocol is TAO protected</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/common/get-host-info.sub.js"></script> -</head> -<body> -<script> - -const addFrame = url => { - const iframe = document.createElement("iframe"); - iframe.src = url; - document.body.appendChild(iframe); -}; - -const host_info = get_host_info(); - -// Add iframe to remote origin - page without TAO -promise_test(t => { - return new Promise((resolve, reject) => { - const observer = new PerformanceObserver(list => { - const entries = list.getEntries(); - for (entry of entries) { - if (entry.name.includes("green.html")) { - observer.disconnect(); - // Observe its performance entry to make sure nextHopProtocol is empty - if (entry.nextHopProtocol != "") { - reject("nextHopProtocol should be the empty string"); - } - resolve(); - } - } - }); - observer.observe({entryTypes: ["resource"]}); - addFrame(host_info.HTTPS_REMOTE_ORIGIN + "/resource-timing/resources/green.html"); - }); -}, "Add TAO-less iframe to remote origin. Make sure nextHopProtocol is the empty string"); - -// Add iframe to remote origin - page with TAO -promise_test(t => { - return new Promise((resolve, reject) => { - const observer = new PerformanceObserver(list => { - const entries = list.getEntries(); - for (entry of entries) { - if (entry.name.includes("blank-with-tao.html")) { - observer.disconnect(); - // Observe its performance entry to make sure nextHopProtocol is empty - if (entry.nextHopProtocol == "") { - reject("nextHopProtocol should not be the empty string"); - } - resolve(); - } - } - }); - observer.observe({entryTypes: ["resource"]}); - addFrame(host_info.HTTPS_REMOTE_ORIGIN + "/resource-timing/resources/blank-with-tao.html"); - }); -}, "Add TAO iframe to remote origin. Make sure nextHopProtocol is not the empty string"); -</script> -</body> -</html>
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/web-bluetooth-test.js b/third_party/blink/web_tests/external/wpt/resources/chromium/web-bluetooth-test.js index ee835c2..ecea5e7 100644 --- a/third_party/blink/web_tests/external/wpt/resources/chromium/web-bluetooth-test.js +++ b/third_party/blink/web_tests/external/wpt/resources/chromium/web-bluetooth-test.js
@@ -129,21 +129,23 @@ this.peripherals_ = new Map(); } - // Simulates a peripheral with |address|, |name| and |known_service_uuids| - // that has already been connected to the system. If the peripheral existed - // already it updates its name and known UUIDs. |known_service_uuids| should - // be an array of BluetoothServiceUUIDs + // Simulates a peripheral with |address|, |name|, |manufacturerData| and + // |known_service_uuids| that has already been connected to the system. If the + // peripheral existed already it updates its name, manufacturer data, and + // known UUIDs. |known_service_uuids| should be an array of + // BluetoothServiceUUIDs // https://webbluetoothcg.github.io/web-bluetooth/#typedefdef-bluetoothserviceuuid // // Platforms offer methods to retrieve devices that have already been // connected to the system or weren't connected through the UA e.g. a user // connected a peripheral through the system's settings. This method is // intended to simulate peripherals that those methods would return. - async simulatePreconnectedPeripheral({ - address, name, knownServiceUUIDs = []}) { - + async simulatePreconnectedPeripheral( + {address, name, manufacturerData = {}, knownServiceUUIDs = []}) { await this.fake_central_ptr_.simulatePreconnectedPeripheral( - address, name, canonicalizeAndConvertToMojoUUID(knownServiceUUIDs)); + address, name, + convertToMojoMap(manufacturerData, Number, true /* isNumberKey */), + canonicalizeAndConvertToMojoUUID(knownServiceUUIDs)); return this.fetchOrCreatePeripheral_(address); }
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html index 3706299..ed0c15f 100644 --- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html
@@ -20,7 +20,6 @@ let audit = Audit.createTaskRunner(); audit.define('setValueCurve', (task, should) => { - let success = true; let context = new OfflineAudioContext(1, testDurationFrames, sampleRate); let g = context.createGain(); @@ -79,6 +78,37 @@ task.done(); }); + audit.define('value setter', (task, should) => { + let context = + new OfflineAudioContext(1, testDurationFrames, sampleRate); + let g = context.createGain(); + let curve = new Float32Array(2); + + // Start time and duration for setValueCurveAtTime + let curveStartTime = 0.; + let duration = 0.2 * testDurationSec; + + // Some time that is known to be during the setValueCurveTime interval. + let automationTime = 0.; + + should( + () => { + g.gain.setValueCurveAtTime(curve, curveStartTime, duration); + }, + 'setValueCurveAtTime(curve, ' + curveStartTime + ', ' + duration + + ')') + .notThrow(); + + should( + function() { + g.gain.value = 0.; + }, + 'value setter') + .throw(DOMException, 'NotSupportedError'); + + task.done(); + }); + audit.define('automations', (task, should) => { let context = new OfflineAudioContext(1, testDurationFrames, sampleRate); @@ -175,7 +205,6 @@ audit.define('catch-exception', (task, should) => { // Verify that the curve isn't inserted into the time line even if we // catch the exception. - let success = true; let context = new OfflineAudioContext(1, testDurationFrames, sampleRate); let gain = context.createGain();
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/pannernode-setposition-throws.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/pannernode-setposition-throws.html new file mode 100644 index 0000000..20534119 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/pannernode-setposition-throws.html
@@ -0,0 +1,37 @@ +<!doctype html> +<meta charset=utf-8> +<title>Test PannerNode.setPosition() throws with parameter out of range of float</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +// https://webaudio.github.io/web-audio-api/#dom-pannernode-setposition +// setPosition(x, y, z) "is equivalent to setting positionX.value, +// positionY.value, and positionZ.value directly with the given x, y, and z +// values, respectively." setPosition() parameters are double, but the +// AudioParam value setter has a float parameter, so out of range values +// throw. +const FLT_MAX = 3.40282e+38; +let panner; +setup(() => { + const ctx = new OfflineAudioContext({length: 1, sampleRate: 24000}); + panner = ctx.createPanner(); +}); +test(() => { + assert_throws_js(TypeError, () => panner.setPosition(2 * FLT_MAX, 0, 0)); +}, "setPosition x"); +test(() => { + assert_throws_js(TypeError, () => panner.setPosition(0, -2 * FLT_MAX, 0)); +}, "setPosition y"); +test(() => { + assert_throws_js(TypeError, () => panner.setPosition(0, 0, 2 * FLT_MAX)); +}, "setPosition z"); +test(() => { + assert_throws_js(TypeError, () => panner.setOrientation(-2 * FLT_MAX, 0, 0)); +}, "setOrientation x"); +test(() => { + assert_throws_js(TypeError, () => panner.setOrientation(0, 2 * FLT_MAX, 0)); +}, "setOrientation y"); +test(() => { + assert_throws_js(TypeError, () => panner.setOrientation(0, 0, -2 * FLT_MAX)); +}, "setOrientation z"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability.html b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability.html index 98a8b3d..3a732f0 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability.html +++ b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability.html
@@ -5,6 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="/webrtc/dictionary-helper.js"></script> <script src="/webrtc/RTCRtpParameters-helper.js"></script> +<script src="/webrtc/RTCPeerConnection-helper.js"></script> <script> 'use strict'; @@ -19,6 +20,36 @@ return encodings[0]; } + const capabilities = RTCRtpSender.getCapabilities('video'); + let index = 0; + for (const codec of capabilities.codecs) { + if ('scalabilityModes' in codec && codec.scalabilityModes.length > 0) { + for (const scalabilityMode of codec.scalabilityModes) { + promise_test(async t => { + const v = document.createElement('video'); + v.autoplay = true; + const pc1 = new RTCPeerConnection(); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + const stream1 = await getNoiseStream({ video: { signal: 100 , width: 60, height: 60} }); + const [track1] = stream1.getTracks(); + t.add_cleanup(() => track1.stop()); + const transceiver = pc1.addTransceiver(track1, { + sendEncodings: [{ scalabilityMode: scalabilityMode }], + }); + transceiver.setCodecPreferences([codec]); + const haveTrackEvent = new Promise(r => pc2.ontrack = r); + exchangeIceCandidates(pc1, pc2); + await exchangeOfferAnswer(pc1, pc2); + v.srcObject = new MediaStream([(await haveTrackEvent).track]); + await new Promise(r => v.onloadedmetadata = r); + await detectSignal(t, v, 100); + }, `[${index++}] ${codec.mimeType} - ${scalabilityMode} should produce valid video content`); + } + } + } + promise_test(async t => { const pc = new RTCPeerConnection(); t.add_cleanup(() => pc.close());
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https-expected.txt deleted file mode 100644 index 845f5cf..0000000 --- a/third_party/blink/web_tests/platform/linux/external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Failed to execute 'end' on 'XRSession': XRSession has already ended. -FAIL Test that getReflectionCubeMap returns or throws appropriately without a reflection map. - webgl Failed to execute 'getReflectionCubeMap' on 'XRWebGLBinding': WebGL contexts must have the OES_texture_half_float extension enabled prior to calling getReflectionCubeMap with a format of "rgba16f". This restriction does not apply to WebGL 2.0 contexts. -PASS Test that getReflectionCubeMap returns or throws appropriately without a reflection map. - webgl2 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer_stencil.https-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer_stencil.https-expected.txt deleted file mode 100644 index 5c38daf1..0000000 --- a/third_party/blink/web_tests/platform/linux/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer_stencil.https-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -FAIL Ensure that the framebuffer given by the WebGL layer works with stencil for non-immersive - webgl promise_test: Unhandled rejection with value: "Failed, readPixels (1) didn't work, gl error = 1282, pixel = 30 30 30" -FAIL Ensure that the framebuffer given by the WebGL layer works with stencil for non-immersive - webgl2 promise_test: Unhandled rejection with value: "Failed, readPixels (1) didn't work, gl error = 1282, pixel = 30 30 30" -FAIL Ensure that the framebuffer given by the WebGL layer works with stencil for immersive - webgl promise_test: Unhandled rejection with value: "Failed, readPixels (1) didn't work, gl error = 1282, pixel = 30 30 30" -FAIL Ensure that the framebuffer given by the WebGL layer works with stencil for immersive - webgl2 promise_test: Unhandled rejection with value: "Failed, readPixels (1) didn't work, gl error = 1282, pixel = 30 30 30" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/linux/tables/mozilla/core/col_widths_auto_per-expected.png b/third_party/blink/web_tests/platform/linux/tables/mozilla/core/col_widths_auto_per-expected.png index ce66397..088a44b9 100644 --- a/third_party/blink/web_tests/platform/linux/tables/mozilla/core/col_widths_auto_per-expected.png +++ b/third_party/blink/web_tests/platform/linux/tables/mozilla/core/col_widths_auto_per-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/tables/mozilla/core/col_widths_fix_per-expected.png b/third_party/blink/web_tests/platform/linux/tables/mozilla/core/col_widths_fix_per-expected.png index e164a92..e4d4e6e 100644 --- a/third_party/blink/web_tests/platform/linux/tables/mozilla/core/col_widths_fix_per-expected.png +++ b/third_party/blink/web_tests/platform/linux/tables/mozilla/core/col_widths_fix_per-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug17826-expected.png b/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug17826-expected.png index 08611ed8..a47cc3cd 100644 --- a/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug17826-expected.png +++ b/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug17826-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/plz-service-worker/external/wpt/service-workers/service-worker/getregistrations.https-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/plz-service-worker/external/wpt/service-workers/service-worker/getregistrations.https-expected.txt deleted file mode 100644 index e34401fc..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/plz-service-worker/external/wpt/service-workers/service-worker/getregistrations.https-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -This is a testharness.js-based test. -PASS registrations are not returned following unregister -PASS Register then getRegistrations -PASS Register multiple times then getRegistrations -PASS Register then Unregister then getRegistrations -PASS Register then Unregister with controlled frame then getRegistrations -PASS getRegistrations promise resolves only with same origin registrations. -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/fetch/api/idlharness.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/fetch/api/idlharness.any.sharedworker-expected.txt deleted file mode 100644 index 3a6843f..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/fetch/api/idlharness.any.sharedworker-expected.txt +++ /dev/null
@@ -1,142 +0,0 @@ -This is a testharness.js-based test. -Found 138 tests; 136 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS idl_test setup -PASS idl_test validation -PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined -PASS Partial interface mixin WindowOrWorkerGlobalScope: member names are unique -PASS Partial interface Window: member names are unique -PASS Request includes Body: member names are unique -PASS Response includes Body: member names are unique -PASS Window includes GlobalEventHandlers: member names are unique -PASS Window includes WindowEventHandlers: member names are unique -PASS Window includes WindowOrWorkerGlobalScope: member names are unique -PASS WorkerGlobalScope includes WindowOrWorkerGlobalScope: member names are unique -PASS Window includes AnimationFrameProvider: member names are unique -PASS Window includes WindowSessionStorage: member names are unique -PASS Window includes WindowLocalStorage: member names are unique -PASS Headers interface: existence and properties of interface object -PASS Headers interface object length -PASS Headers interface object name -PASS Headers interface: existence and properties of interface prototype object -PASS Headers interface: existence and properties of interface prototype object's "constructor" property -PASS Headers interface: existence and properties of interface prototype object's @@unscopables property -PASS Headers interface: operation append(ByteString, ByteString) -PASS Headers interface: operation delete(ByteString) -PASS Headers interface: operation get(ByteString) -PASS Headers interface: operation has(ByteString) -PASS Headers interface: operation set(ByteString, ByteString) -PASS Headers interface: iterable<ByteString, ByteString> -PASS Headers must be primary interface of new Headers() -PASS Stringification of new Headers() -PASS Headers interface: new Headers() must inherit property "append(ByteString, ByteString)" with the proper type -PASS Headers interface: calling append(ByteString, ByteString) on new Headers() with too few arguments must throw TypeError -PASS Headers interface: new Headers() must inherit property "delete(ByteString)" with the proper type -PASS Headers interface: calling delete(ByteString) on new Headers() with too few arguments must throw TypeError -PASS Headers interface: new Headers() must inherit property "get(ByteString)" with the proper type -PASS Headers interface: calling get(ByteString) on new Headers() with too few arguments must throw TypeError -PASS Headers interface: new Headers() must inherit property "has(ByteString)" with the proper type -PASS Headers interface: calling has(ByteString) on new Headers() with too few arguments must throw TypeError -PASS Headers interface: new Headers() must inherit property "set(ByteString, ByteString)" with the proper type -PASS Headers interface: calling set(ByteString, ByteString) on new Headers() with too few arguments must throw TypeError -PASS Request interface: existence and properties of interface object -PASS Request interface object length -PASS Request interface object name -PASS Request interface: existence and properties of interface prototype object -PASS Request interface: existence and properties of interface prototype object's "constructor" property -PASS Request interface: existence and properties of interface prototype object's @@unscopables property -PASS Request interface: attribute method -PASS Request interface: attribute url -PASS Request interface: attribute headers -PASS Request interface: attribute destination -PASS Request interface: attribute referrer -PASS Request interface: attribute referrerPolicy -PASS Request interface: attribute mode -PASS Request interface: attribute credentials -PASS Request interface: attribute cache -PASS Request interface: attribute redirect -PASS Request interface: attribute integrity -PASS Request interface: attribute keepalive -FAIL Request interface: attribute isReloadNavigation assert_true: The prototype object must have a property "isReloadNavigation" expected true got false -PASS Request interface: attribute isHistoryNavigation -PASS Request interface: attribute signal -PASS Request interface: operation clone() -PASS Request interface: attribute body -PASS Request interface: attribute bodyUsed -PASS Request interface: operation arrayBuffer() -PASS Request interface: operation blob() -PASS Request interface: operation formData() -PASS Request interface: operation json() -PASS Request interface: operation text() -PASS Request must be primary interface of new Request('about:blank') -PASS Stringification of new Request('about:blank') -PASS Request interface: new Request('about:blank') must inherit property "method" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "url" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "headers" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "destination" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "referrer" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "referrerPolicy" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "mode" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "credentials" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "cache" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "redirect" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "integrity" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "keepalive" with the proper type -FAIL Request interface: new Request('about:blank') must inherit property "isReloadNavigation" with the proper type assert_inherits: property "isReloadNavigation" not found in prototype chain -PASS Request interface: new Request('about:blank') must inherit property "isHistoryNavigation" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "signal" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "clone()" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "body" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "bodyUsed" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "arrayBuffer()" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "blob()" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "formData()" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "json()" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "text()" with the proper type -PASS Response interface: existence and properties of interface object -PASS Response interface object length -PASS Response interface object name -PASS Response interface: existence and properties of interface prototype object -PASS Response interface: existence and properties of interface prototype object's "constructor" property -PASS Response interface: existence and properties of interface prototype object's @@unscopables property -PASS Response interface: operation error() -PASS Response interface: operation redirect(USVString, optional unsigned short) -PASS Response interface: attribute type -PASS Response interface: attribute url -PASS Response interface: attribute redirected -PASS Response interface: attribute status -PASS Response interface: attribute ok -PASS Response interface: attribute statusText -PASS Response interface: attribute headers -PASS Response interface: operation clone() -PASS Response interface: attribute body -PASS Response interface: attribute bodyUsed -PASS Response interface: operation arrayBuffer() -PASS Response interface: operation blob() -PASS Response interface: operation formData() -PASS Response interface: operation json() -PASS Response interface: operation text() -PASS Response must be primary interface of new Response() -PASS Stringification of new Response() -PASS Response interface: new Response() must inherit property "error()" with the proper type -PASS Response interface: new Response() must inherit property "redirect(USVString, optional unsigned short)" with the proper type -PASS Response interface: calling redirect(USVString, optional unsigned short) on new Response() with too few arguments must throw TypeError -PASS Response interface: new Response() must inherit property "type" with the proper type -PASS Response interface: new Response() must inherit property "url" with the proper type -PASS Response interface: new Response() must inherit property "redirected" with the proper type -PASS Response interface: new Response() must inherit property "status" with the proper type -PASS Response interface: new Response() must inherit property "ok" with the proper type -PASS Response interface: new Response() must inherit property "statusText" with the proper type -PASS Response interface: new Response() must inherit property "headers" with the proper type -PASS Response interface: new Response() must inherit property "clone()" with the proper type -PASS Response interface: new Response() must inherit property "body" with the proper type -PASS Response interface: new Response() must inherit property "bodyUsed" with the proper type -PASS Response interface: new Response() must inherit property "arrayBuffer()" with the proper type -PASS Response interface: new Response() must inherit property "blob()" with the proper type -PASS Response interface: new Response() must inherit property "formData()" with the proper type -PASS Response interface: new Response() must inherit property "json()" with the proper type -PASS Response interface: new Response() must inherit property "text()" with the proper type -PASS WorkerGlobalScope interface: operation fetch(RequestInfo, optional RequestInit) -PASS WorkerGlobalScope interface: self must inherit property "fetch(RequestInfo, optional RequestInit)" with the proper type -PASS WorkerGlobalScope interface: calling fetch(RequestInfo, optional RequestInit) on self with too few arguments must throw TypeError -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/gamepad/idlharness.https.window-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/gamepad/idlharness.https.window-expected.txt deleted file mode 100644 index 1d8a0ea4..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/gamepad/idlharness.https.window-expected.txt +++ /dev/null
@@ -1,77 +0,0 @@ -This is a testharness.js-based test. -Found 73 tests; 66 PASS, 7 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS idl_test setup -PASS idl_test validation -PASS Partial interface Navigator: original interface defined -PASS Partial interface Navigator: valid exposure set -PASS Partial interface Navigator: member names are unique -PASS Partial interface mixin WindowEventHandlers: original interface mixin defined -PASS Partial interface mixin WindowEventHandlers: member names are unique -PASS Partial interface mixin NavigatorID: member names are unique -PASS Partial interface HTMLBodyElement: member names are unique -PASS Partial interface Window: member names are unique -PASS HTMLElement includes GlobalEventHandlers: member names are unique -PASS HTMLElement includes DocumentAndElementEventHandlers: member names are unique -PASS HTMLElement includes ElementContentEditable: member names are unique -PASS HTMLElement includes HTMLOrSVGElement: member names are unique -PASS HTMLBodyElement includes WindowEventHandlers: member names are unique -PASS Window includes GlobalEventHandlers: member names are unique -PASS Window includes WindowEventHandlers: member names are unique -PASS Window includes WindowOrWorkerGlobalScope: member names are unique -PASS Navigator includes NavigatorID: member names are unique -PASS Navigator includes NavigatorLanguage: member names are unique -PASS Navigator includes NavigatorOnLine: member names are unique -PASS Navigator includes NavigatorContentUtils: member names are unique -PASS Navigator includes NavigatorCookies: member names are unique -PASS Navigator includes NavigatorPlugins: member names are unique -PASS Navigator includes NavigatorConcurrentHardware: member names are unique -PASS Window includes AnimationFrameProvider: member names are unique -PASS Window includes WindowSessionStorage: member names are unique -PASS Window includes WindowLocalStorage: member names are unique -PASS HTMLFrameSetElement includes WindowEventHandlers: member names are unique -PASS Element includes ParentNode: member names are unique -PASS Element includes NonDocumentTypeChildNode: member names are unique -PASS Element includes ChildNode: member names are unique -PASS Element includes Slottable: member names are unique -PASS Gamepad interface: existence and properties of interface object -PASS Gamepad interface object length -PASS Gamepad interface object name -PASS Gamepad interface: existence and properties of interface prototype object -PASS Gamepad interface: existence and properties of interface prototype object's "constructor" property -PASS Gamepad interface: existence and properties of interface prototype object's @@unscopables property -PASS Gamepad interface: attribute id -PASS Gamepad interface: attribute index -PASS Gamepad interface: attribute connected -PASS Gamepad interface: attribute timestamp -PASS Gamepad interface: attribute mapping -PASS Gamepad interface: attribute axes -PASS Gamepad interface: attribute buttons -PASS GamepadButton interface: existence and properties of interface object -PASS GamepadButton interface object length -PASS GamepadButton interface object name -PASS GamepadButton interface: existence and properties of interface prototype object -PASS GamepadButton interface: existence and properties of interface prototype object's "constructor" property -PASS GamepadButton interface: existence and properties of interface prototype object's @@unscopables property -PASS GamepadButton interface: attribute pressed -PASS GamepadButton interface: attribute touched -PASS GamepadButton interface: attribute value -PASS GamepadEvent interface: existence and properties of interface object -FAIL GamepadEvent interface object length assert_equals: wrong value for GamepadEvent.length expected 2 but got 1 -PASS GamepadEvent interface object name -PASS GamepadEvent interface: existence and properties of interface prototype object -PASS GamepadEvent interface: existence and properties of interface prototype object's "constructor" property -PASS GamepadEvent interface: existence and properties of interface prototype object's @@unscopables property -PASS GamepadEvent interface: attribute gamepad -PASS GamepadEvent must be primary interface of new GamepadEvent("gamepad") -PASS Stringification of new GamepadEvent("gamepad") -PASS GamepadEvent interface: new GamepadEvent("gamepad") must inherit property "gamepad" with the proper type -FAIL HTMLBodyElement interface: attribute ongamepadconnected assert_true: The prototype object must have a property "ongamepadconnected" expected true got false -FAIL HTMLBodyElement interface: attribute ongamepaddisconnected assert_true: The prototype object must have a property "ongamepaddisconnected" expected true got false -FAIL Window interface: attribute ongamepadconnected assert_own_property: The global object must have a property "ongamepadconnected" expected property "ongamepadconnected" missing -FAIL Window interface: attribute ongamepaddisconnected assert_own_property: The global object must have a property "ongamepaddisconnected" expected property "ongamepaddisconnected" missing -PASS Navigator interface: operation getGamepads() -PASS Navigator interface: navigator must inherit property "getGamepads()" with the proper type -FAIL HTMLFrameSetElement interface: attribute ongamepadconnected assert_true: The prototype object must have a property "ongamepadconnected" expected true got false -FAIL HTMLFrameSetElement interface: attribute ongamepaddisconnected assert_true: The prototype object must have a property "ongamepaddisconnected" expected true got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/storage/idlharness.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/storage/idlharness.https.any.worker-expected.txt deleted file mode 100644 index ea67f14d..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/storage/idlharness.https.any.worker-expected.txt +++ /dev/null
@@ -1,35 +0,0 @@ -This is a testharness.js-based test. -PASS idl_test setup -PASS idl_test validation -PASS Partial interface mixin NavigatorID: member names are unique -PASS Navigator includes NavigatorStorage: member names are unique -PASS WorkerNavigator includes NavigatorStorage: member names are unique -PASS Navigator includes NavigatorID: member names are unique -PASS Navigator includes NavigatorLanguage: member names are unique -PASS Navigator includes NavigatorOnLine: member names are unique -PASS Navigator includes NavigatorContentUtils: member names are unique -PASS Navigator includes NavigatorCookies: member names are unique -PASS Navigator includes NavigatorPlugins: member names are unique -PASS Navigator includes NavigatorConcurrentHardware: member names are unique -PASS WorkerNavigator includes NavigatorID: member names are unique -PASS WorkerNavigator includes NavigatorLanguage: member names are unique -PASS WorkerNavigator includes NavigatorOnLine: member names are unique -PASS WorkerNavigator includes NavigatorConcurrentHardware: member names are unique -FAIL StorageManager interface: existence and properties of interface object assert_equals: prototype of self's property "StorageManager" is not Function.prototype expected function "function () { [native code] }" but got function "function EventTarget() { [native code] }" -PASS StorageManager interface object length -PASS StorageManager interface object name -FAIL StorageManager interface: existence and properties of interface prototype object assert_equals: prototype of StorageManager.prototype is not Object.prototype expected object "[object Object]" but got object "[object EventTarget]" -PASS StorageManager interface: existence and properties of interface prototype object's "constructor" property -PASS StorageManager interface: existence and properties of interface prototype object's @@unscopables property -PASS StorageManager interface: operation persisted() -PASS StorageManager interface: member persist -PASS StorageManager interface: operation estimate() -PASS StorageManager must be primary interface of navigator.storage -PASS Stringification of navigator.storage -PASS StorageManager interface: navigator.storage must inherit property "persisted()" with the proper type -PASS StorageManager interface: navigator.storage must not have property "persist" -PASS StorageManager interface: navigator.storage must inherit property "estimate()" with the proper type -PASS WorkerNavigator interface: attribute storage -PASS WorkerNavigator interface: navigator must inherit property "storage" with the proper type -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/fetch/api/idlharness.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/fetch/api/idlharness.any.sharedworker-expected.txt deleted file mode 100644 index 3a6843f..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/fetch/api/idlharness.any.sharedworker-expected.txt +++ /dev/null
@@ -1,142 +0,0 @@ -This is a testharness.js-based test. -Found 138 tests; 136 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS idl_test setup -PASS idl_test validation -PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined -PASS Partial interface mixin WindowOrWorkerGlobalScope: member names are unique -PASS Partial interface Window: member names are unique -PASS Request includes Body: member names are unique -PASS Response includes Body: member names are unique -PASS Window includes GlobalEventHandlers: member names are unique -PASS Window includes WindowEventHandlers: member names are unique -PASS Window includes WindowOrWorkerGlobalScope: member names are unique -PASS WorkerGlobalScope includes WindowOrWorkerGlobalScope: member names are unique -PASS Window includes AnimationFrameProvider: member names are unique -PASS Window includes WindowSessionStorage: member names are unique -PASS Window includes WindowLocalStorage: member names are unique -PASS Headers interface: existence and properties of interface object -PASS Headers interface object length -PASS Headers interface object name -PASS Headers interface: existence and properties of interface prototype object -PASS Headers interface: existence and properties of interface prototype object's "constructor" property -PASS Headers interface: existence and properties of interface prototype object's @@unscopables property -PASS Headers interface: operation append(ByteString, ByteString) -PASS Headers interface: operation delete(ByteString) -PASS Headers interface: operation get(ByteString) -PASS Headers interface: operation has(ByteString) -PASS Headers interface: operation set(ByteString, ByteString) -PASS Headers interface: iterable<ByteString, ByteString> -PASS Headers must be primary interface of new Headers() -PASS Stringification of new Headers() -PASS Headers interface: new Headers() must inherit property "append(ByteString, ByteString)" with the proper type -PASS Headers interface: calling append(ByteString, ByteString) on new Headers() with too few arguments must throw TypeError -PASS Headers interface: new Headers() must inherit property "delete(ByteString)" with the proper type -PASS Headers interface: calling delete(ByteString) on new Headers() with too few arguments must throw TypeError -PASS Headers interface: new Headers() must inherit property "get(ByteString)" with the proper type -PASS Headers interface: calling get(ByteString) on new Headers() with too few arguments must throw TypeError -PASS Headers interface: new Headers() must inherit property "has(ByteString)" with the proper type -PASS Headers interface: calling has(ByteString) on new Headers() with too few arguments must throw TypeError -PASS Headers interface: new Headers() must inherit property "set(ByteString, ByteString)" with the proper type -PASS Headers interface: calling set(ByteString, ByteString) on new Headers() with too few arguments must throw TypeError -PASS Request interface: existence and properties of interface object -PASS Request interface object length -PASS Request interface object name -PASS Request interface: existence and properties of interface prototype object -PASS Request interface: existence and properties of interface prototype object's "constructor" property -PASS Request interface: existence and properties of interface prototype object's @@unscopables property -PASS Request interface: attribute method -PASS Request interface: attribute url -PASS Request interface: attribute headers -PASS Request interface: attribute destination -PASS Request interface: attribute referrer -PASS Request interface: attribute referrerPolicy -PASS Request interface: attribute mode -PASS Request interface: attribute credentials -PASS Request interface: attribute cache -PASS Request interface: attribute redirect -PASS Request interface: attribute integrity -PASS Request interface: attribute keepalive -FAIL Request interface: attribute isReloadNavigation assert_true: The prototype object must have a property "isReloadNavigation" expected true got false -PASS Request interface: attribute isHistoryNavigation -PASS Request interface: attribute signal -PASS Request interface: operation clone() -PASS Request interface: attribute body -PASS Request interface: attribute bodyUsed -PASS Request interface: operation arrayBuffer() -PASS Request interface: operation blob() -PASS Request interface: operation formData() -PASS Request interface: operation json() -PASS Request interface: operation text() -PASS Request must be primary interface of new Request('about:blank') -PASS Stringification of new Request('about:blank') -PASS Request interface: new Request('about:blank') must inherit property "method" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "url" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "headers" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "destination" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "referrer" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "referrerPolicy" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "mode" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "credentials" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "cache" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "redirect" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "integrity" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "keepalive" with the proper type -FAIL Request interface: new Request('about:blank') must inherit property "isReloadNavigation" with the proper type assert_inherits: property "isReloadNavigation" not found in prototype chain -PASS Request interface: new Request('about:blank') must inherit property "isHistoryNavigation" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "signal" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "clone()" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "body" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "bodyUsed" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "arrayBuffer()" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "blob()" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "formData()" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "json()" with the proper type -PASS Request interface: new Request('about:blank') must inherit property "text()" with the proper type -PASS Response interface: existence and properties of interface object -PASS Response interface object length -PASS Response interface object name -PASS Response interface: existence and properties of interface prototype object -PASS Response interface: existence and properties of interface prototype object's "constructor" property -PASS Response interface: existence and properties of interface prototype object's @@unscopables property -PASS Response interface: operation error() -PASS Response interface: operation redirect(USVString, optional unsigned short) -PASS Response interface: attribute type -PASS Response interface: attribute url -PASS Response interface: attribute redirected -PASS Response interface: attribute status -PASS Response interface: attribute ok -PASS Response interface: attribute statusText -PASS Response interface: attribute headers -PASS Response interface: operation clone() -PASS Response interface: attribute body -PASS Response interface: attribute bodyUsed -PASS Response interface: operation arrayBuffer() -PASS Response interface: operation blob() -PASS Response interface: operation formData() -PASS Response interface: operation json() -PASS Response interface: operation text() -PASS Response must be primary interface of new Response() -PASS Stringification of new Response() -PASS Response interface: new Response() must inherit property "error()" with the proper type -PASS Response interface: new Response() must inherit property "redirect(USVString, optional unsigned short)" with the proper type -PASS Response interface: calling redirect(USVString, optional unsigned short) on new Response() with too few arguments must throw TypeError -PASS Response interface: new Response() must inherit property "type" with the proper type -PASS Response interface: new Response() must inherit property "url" with the proper type -PASS Response interface: new Response() must inherit property "redirected" with the proper type -PASS Response interface: new Response() must inherit property "status" with the proper type -PASS Response interface: new Response() must inherit property "ok" with the proper type -PASS Response interface: new Response() must inherit property "statusText" with the proper type -PASS Response interface: new Response() must inherit property "headers" with the proper type -PASS Response interface: new Response() must inherit property "clone()" with the proper type -PASS Response interface: new Response() must inherit property "body" with the proper type -PASS Response interface: new Response() must inherit property "bodyUsed" with the proper type -PASS Response interface: new Response() must inherit property "arrayBuffer()" with the proper type -PASS Response interface: new Response() must inherit property "blob()" with the proper type -PASS Response interface: new Response() must inherit property "formData()" with the proper type -PASS Response interface: new Response() must inherit property "json()" with the proper type -PASS Response interface: new Response() must inherit property "text()" with the proper type -PASS WorkerGlobalScope interface: operation fetch(RequestInfo, optional RequestInit) -PASS WorkerGlobalScope interface: self must inherit property "fetch(RequestInfo, optional RequestInit)" with the proper type -PASS WorkerGlobalScope interface: calling fetch(RequestInfo, optional RequestInit) on self with too few arguments must throw TypeError -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/gamepad/idlharness.https.window-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/gamepad/idlharness.https.window-expected.txt deleted file mode 100644 index 1d8a0ea4..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/gamepad/idlharness.https.window-expected.txt +++ /dev/null
@@ -1,77 +0,0 @@ -This is a testharness.js-based test. -Found 73 tests; 66 PASS, 7 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS idl_test setup -PASS idl_test validation -PASS Partial interface Navigator: original interface defined -PASS Partial interface Navigator: valid exposure set -PASS Partial interface Navigator: member names are unique -PASS Partial interface mixin WindowEventHandlers: original interface mixin defined -PASS Partial interface mixin WindowEventHandlers: member names are unique -PASS Partial interface mixin NavigatorID: member names are unique -PASS Partial interface HTMLBodyElement: member names are unique -PASS Partial interface Window: member names are unique -PASS HTMLElement includes GlobalEventHandlers: member names are unique -PASS HTMLElement includes DocumentAndElementEventHandlers: member names are unique -PASS HTMLElement includes ElementContentEditable: member names are unique -PASS HTMLElement includes HTMLOrSVGElement: member names are unique -PASS HTMLBodyElement includes WindowEventHandlers: member names are unique -PASS Window includes GlobalEventHandlers: member names are unique -PASS Window includes WindowEventHandlers: member names are unique -PASS Window includes WindowOrWorkerGlobalScope: member names are unique -PASS Navigator includes NavigatorID: member names are unique -PASS Navigator includes NavigatorLanguage: member names are unique -PASS Navigator includes NavigatorOnLine: member names are unique -PASS Navigator includes NavigatorContentUtils: member names are unique -PASS Navigator includes NavigatorCookies: member names are unique -PASS Navigator includes NavigatorPlugins: member names are unique -PASS Navigator includes NavigatorConcurrentHardware: member names are unique -PASS Window includes AnimationFrameProvider: member names are unique -PASS Window includes WindowSessionStorage: member names are unique -PASS Window includes WindowLocalStorage: member names are unique -PASS HTMLFrameSetElement includes WindowEventHandlers: member names are unique -PASS Element includes ParentNode: member names are unique -PASS Element includes NonDocumentTypeChildNode: member names are unique -PASS Element includes ChildNode: member names are unique -PASS Element includes Slottable: member names are unique -PASS Gamepad interface: existence and properties of interface object -PASS Gamepad interface object length -PASS Gamepad interface object name -PASS Gamepad interface: existence and properties of interface prototype object -PASS Gamepad interface: existence and properties of interface prototype object's "constructor" property -PASS Gamepad interface: existence and properties of interface prototype object's @@unscopables property -PASS Gamepad interface: attribute id -PASS Gamepad interface: attribute index -PASS Gamepad interface: attribute connected -PASS Gamepad interface: attribute timestamp -PASS Gamepad interface: attribute mapping -PASS Gamepad interface: attribute axes -PASS Gamepad interface: attribute buttons -PASS GamepadButton interface: existence and properties of interface object -PASS GamepadButton interface object length -PASS GamepadButton interface object name -PASS GamepadButton interface: existence and properties of interface prototype object -PASS GamepadButton interface: existence and properties of interface prototype object's "constructor" property -PASS GamepadButton interface: existence and properties of interface prototype object's @@unscopables property -PASS GamepadButton interface: attribute pressed -PASS GamepadButton interface: attribute touched -PASS GamepadButton interface: attribute value -PASS GamepadEvent interface: existence and properties of interface object -FAIL GamepadEvent interface object length assert_equals: wrong value for GamepadEvent.length expected 2 but got 1 -PASS GamepadEvent interface object name -PASS GamepadEvent interface: existence and properties of interface prototype object -PASS GamepadEvent interface: existence and properties of interface prototype object's "constructor" property -PASS GamepadEvent interface: existence and properties of interface prototype object's @@unscopables property -PASS GamepadEvent interface: attribute gamepad -PASS GamepadEvent must be primary interface of new GamepadEvent("gamepad") -PASS Stringification of new GamepadEvent("gamepad") -PASS GamepadEvent interface: new GamepadEvent("gamepad") must inherit property "gamepad" with the proper type -FAIL HTMLBodyElement interface: attribute ongamepadconnected assert_true: The prototype object must have a property "ongamepadconnected" expected true got false -FAIL HTMLBodyElement interface: attribute ongamepaddisconnected assert_true: The prototype object must have a property "ongamepaddisconnected" expected true got false -FAIL Window interface: attribute ongamepadconnected assert_own_property: The global object must have a property "ongamepadconnected" expected property "ongamepadconnected" missing -FAIL Window interface: attribute ongamepaddisconnected assert_own_property: The global object must have a property "ongamepaddisconnected" expected property "ongamepaddisconnected" missing -PASS Navigator interface: operation getGamepads() -PASS Navigator interface: navigator must inherit property "getGamepads()" with the proper type -FAIL HTMLFrameSetElement interface: attribute ongamepadconnected assert_true: The prototype object must have a property "ongamepadconnected" expected true got false -FAIL HTMLFrameSetElement interface: attribute ongamepaddisconnected assert_true: The prototype object must have a property "ongamepaddisconnected" expected true got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/input-device-capabilities/idlharness.window-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/input-device-capabilities/idlharness.window-expected.txt deleted file mode 100644 index a164b00..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/input-device-capabilities/idlharness.window-expected.txt +++ /dev/null
@@ -1,25 +0,0 @@ -This is a testharness.js-based test. -PASS idl_test setup -PASS idl_test validation -PASS Partial interface UIEvent: original interface defined -PASS Partial interface UIEvent: member names are unique -PASS Partial dictionary UIEventInit: original dictionary defined -PASS Partial dictionary UIEventInit: member names are unique -PASS Partial interface UIEvent[2]: member names are unique -PASS Partial interface UIEvent[3]: member names are unique -PASS Partial dictionary UIEventInit[2]: member names are unique -PASS InputDeviceCapabilities interface: existence and properties of interface object -PASS InputDeviceCapabilities interface object length -PASS InputDeviceCapabilities interface object name -PASS InputDeviceCapabilities interface: existence and properties of interface prototype object -PASS InputDeviceCapabilities interface: existence and properties of interface prototype object's "constructor" property -PASS InputDeviceCapabilities interface: existence and properties of interface prototype object's @@unscopables property -PASS InputDeviceCapabilities interface: attribute firesTouchEvents -FAIL InputDeviceCapabilities interface: attribute pointerMovementScrolls assert_true: The prototype object must have a property "pointerMovementScrolls" expected true got false -PASS InputDeviceCapabilities must be primary interface of new InputDeviceCapabilities -PASS Stringification of new InputDeviceCapabilities -PASS InputDeviceCapabilities interface: new InputDeviceCapabilities must inherit property "firesTouchEvents" with the proper type -FAIL InputDeviceCapabilities interface: new InputDeviceCapabilities must inherit property "pointerMovementScrolls" with the proper type assert_inherits: property "pointerMovementScrolls" not found in prototype chain -PASS UIEvent interface: attribute sourceCapabilities -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/periodic-background-sync/idlharness.https.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/periodic-background-sync/idlharness.https.any-expected.txt deleted file mode 100644 index edc336c..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/periodic-background-sync/idlharness.https.any-expected.txt +++ /dev/null
@@ -1,36 +0,0 @@ -This is a testharness.js-based test. -PASS idl_test setup -PASS idl_test validation -PASS Partial interface ServiceWorkerGlobalScope: original interface defined -PASS Partial interface ServiceWorkerGlobalScope: member names are unique -PASS Partial interface ServiceWorkerRegistration: original interface defined -PASS Partial interface ServiceWorkerRegistration: valid exposure set -PASS Partial interface ServiceWorkerRegistration: member names are unique -PASS WorkerGlobalScope includes WindowOrWorkerGlobalScope: member names are unique -PASS PeriodicSyncManager interface: existence and properties of interface object -PASS PeriodicSyncManager interface object length -PASS PeriodicSyncManager interface object name -PASS PeriodicSyncManager interface: existence and properties of interface prototype object -PASS PeriodicSyncManager interface: existence and properties of interface prototype object's "constructor" property -PASS PeriodicSyncManager interface: existence and properties of interface prototype object's @@unscopables property -PASS PeriodicSyncManager interface: operation register(DOMString, optional BackgroundSyncOptions) -PASS PeriodicSyncManager interface: operation getTags() -PASS PeriodicSyncManager interface: operation unregister(DOMString) -FAIL PeriodicSyncManager must be primary interface of registration.periodicSync assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: registration is not defined" -FAIL Stringification of registration.periodicSync assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: registration is not defined" -FAIL PeriodicSyncManager interface: registration.periodicSync must inherit property "register(DOMString, optional BackgroundSyncOptions)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: registration is not defined" -FAIL PeriodicSyncManager interface: calling register(DOMString, optional BackgroundSyncOptions) on registration.periodicSync with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: registration is not defined" -FAIL PeriodicSyncManager interface: registration.periodicSync must inherit property "getTags()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: registration is not defined" -FAIL PeriodicSyncManager interface: registration.periodicSync must inherit property "unregister(DOMString)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: registration is not defined" -FAIL PeriodicSyncManager interface: calling unregister(DOMString) on registration.periodicSync with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: registration is not defined" -PASS PeriodicSyncEvent interface: existence and properties of interface object -FAIL PeriodicSyncEvent must be primary interface of new PeriodicSyncEvent("tag") assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: PeriodicSyncEvent is not defined" -FAIL Stringification of new PeriodicSyncEvent("tag") assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: PeriodicSyncEvent is not defined" -FAIL PeriodicSyncEvent interface: new PeriodicSyncEvent("tag") must not have property "undefined" assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: PeriodicSyncEvent is not defined" -FAIL PeriodicSyncEvent interface: new PeriodicSyncEvent("tag") must not have property "tag" assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: PeriodicSyncEvent is not defined" -PASS ServiceWorkerRegistration interface: attribute periodicSync -FAIL ServiceWorkerRegistration interface: registration must inherit property "periodicSync" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: registration is not defined" -PASS ServiceWorkerGlobalScope interface: self must not have property "onperiodicsync" -FAIL ServiceWorkerGlobalScope interface: onperiodicsync must not have property "onperiodicsync" assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: onperiodicsync is not defined" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/storage/idlharness.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/storage/idlharness.https.any.worker-expected.txt deleted file mode 100644 index ea67f14d..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/storage/idlharness.https.any.worker-expected.txt +++ /dev/null
@@ -1,35 +0,0 @@ -This is a testharness.js-based test. -PASS idl_test setup -PASS idl_test validation -PASS Partial interface mixin NavigatorID: member names are unique -PASS Navigator includes NavigatorStorage: member names are unique -PASS WorkerNavigator includes NavigatorStorage: member names are unique -PASS Navigator includes NavigatorID: member names are unique -PASS Navigator includes NavigatorLanguage: member names are unique -PASS Navigator includes NavigatorOnLine: member names are unique -PASS Navigator includes NavigatorContentUtils: member names are unique -PASS Navigator includes NavigatorCookies: member names are unique -PASS Navigator includes NavigatorPlugins: member names are unique -PASS Navigator includes NavigatorConcurrentHardware: member names are unique -PASS WorkerNavigator includes NavigatorID: member names are unique -PASS WorkerNavigator includes NavigatorLanguage: member names are unique -PASS WorkerNavigator includes NavigatorOnLine: member names are unique -PASS WorkerNavigator includes NavigatorConcurrentHardware: member names are unique -FAIL StorageManager interface: existence and properties of interface object assert_equals: prototype of self's property "StorageManager" is not Function.prototype expected function "function () { [native code] }" but got function "function EventTarget() { [native code] }" -PASS StorageManager interface object length -PASS StorageManager interface object name -FAIL StorageManager interface: existence and properties of interface prototype object assert_equals: prototype of StorageManager.prototype is not Object.prototype expected object "[object Object]" but got object "[object EventTarget]" -PASS StorageManager interface: existence and properties of interface prototype object's "constructor" property -PASS StorageManager interface: existence and properties of interface prototype object's @@unscopables property -PASS StorageManager interface: operation persisted() -PASS StorageManager interface: member persist -PASS StorageManager interface: operation estimate() -PASS StorageManager must be primary interface of navigator.storage -PASS Stringification of navigator.storage -PASS StorageManager interface: navigator.storage must inherit property "persisted()" with the proper type -PASS StorageManager interface: navigator.storage must not have property "persist" -PASS StorageManager interface: navigator.storage must inherit property "estimate()" with the proper type -PASS WorkerNavigator interface: attribute storage -PASS WorkerNavigator interface: navigator must inherit property "storage" with the proper type -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/plz-dedicated-worker/external/wpt/service-workers/service-worker/fetch-event.https-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/plz-dedicated-worker/external/wpt/service-workers/service-worker/fetch-event.https-expected.txt deleted file mode 100644 index 3fe3911..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/plz-dedicated-worker/external/wpt/service-workers/service-worker/fetch-event.https-expected.txt +++ /dev/null
@@ -1,49 +0,0 @@ -This is a testharness.js-based test. -PASS global setup -PASS Service Worker headers in the request of a fetch event -PASS Service Worker responds to fetch event with string -PASS Service Worker responds to fetch event using request fragment with string -PASS Service Worker responds to fetch event with blob body -PASS Service Worker responds to fetch event with the referrer URL -PASS Service Worker responds to fetch event with an existing client id -PASS Service Worker responds to fetch event with the correct resulting client id -PASS Service Worker does not respond to fetch event -PASS Service Worker responds to fetch event with null response body -PASS Service Worker fetches other file in fetch event -PASS Service Worker responds to fetch event with POST form -PASS Service Worker falls back to network in fetch event with POST form -PASS Multiple calls of respondWith must throw InvalidStateErrors -PASS Service Worker event.respondWith must set the used flag -PASS Service Worker should expose FetchEvent URL fragments. -PASS Service Worker responds to fetch event with the correct cache types -PASS Service Worker should intercept EventSource -FAIL Service Worker responds to fetch event with the correct integrity_metadata assert_equals: integrity expected "gs0nqru8KbsrIt5YToQqS9fYao4GQJXtcId610g7cCU=" but got "" -PASS FetchEvent#body is a string -FAIL FetchEvent#body is a ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch" -PASS FetchEvent#body is a string and is passed to network fallback -FAIL FetchEvent#body is a ReadableStream and is passed to network fallback promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch" -PASS FetchEvent#body is a none Uint8Array ReadableStream and is passed to a service worker -PASS FetchEvent#body is a string, used and passed to network fallback -PASS FetchEvent#body is a ReadableStream, used and passed to network fallback -PASS FetchEvent#body is a string, cloned and passed to network fallback -PASS FetchEvent#body is a ReadableStream, cloned and passed to network fallback -PASS FetchEvent#body is a blob -PASS FetchEvent#body is a blob and is passed to network fallback -PASS Service Worker responds to fetch event with the correct keepalive value -FAIL FetchEvent#request.isReloadNavigation is true (location.reload()) assert_equals: expected "method = GET, isReloadNavigation = false" but got "method = GET, isReloadNavigation = undefined" -FAIL FetchEvent#request.isReloadNavigation is true (history.go(0)) assert_equals: expected "method = GET, isReloadNavigation = false" but got "method = GET, isReloadNavigation = undefined" -FAIL FetchEvent#request.isReloadNavigation is true (POST + location.reload()) assert_equals: expected "method = GET, isReloadNavigation = false" but got "method = GET, isReloadNavigation = undefined" -FAIL FetchEvent#request.isReloadNavigation is true (with history traversal) assert_equals: expected "method = GET, isReloadNavigation = false" but got "method = GET, isReloadNavigation = undefined" -PASS FetchEvent#request.isHistoryNavigation is true (with history.go(-1)) -PASS FetchEvent#request.isHistoryNavigation is true (with history.go(1)) -PASS FetchEvent#request.isHistoryNavigation is false (with history.go(0)) -PASS FetchEvent#request.isHistoryNavigation is false (with location.reload) -PASS FetchEvent#request.isHistoryNavigation is true (with history.go(-2)) -PASS FetchEvent#request.isHistoryNavigation is true (with history.go(2)) -PASS FetchEvent#request.isHistoryNavigation is true (POST + history.go(-1)) -PASS XHR upload progress events for response coming from SW -PASS XHR upload progress events for network fallback -PASS Fetch with POST with text on sw 421 response should not be retried. -PASS restore global state -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/threaded/external/wpt/animation-worklet/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/threaded/external/wpt/animation-worklet/idlharness.any.worker-expected.txt deleted file mode 100644 index 0a15a780..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/threaded/external/wpt/animation-worklet/idlharness.any.worker-expected.txt +++ /dev/null
@@ -1,18 +0,0 @@ -This is a testharness.js-based test. -PASS idl_test setup -PASS idl_test validation -PASS Partial namespace CSS: original namespace defined -PASS Partial namespace CSS: valid exposure set -PASS Partial namespace CSS: member names are unique -PASS AnimationWorkletGlobalScope interface: existence and properties of interface object -PASS WorkletAnimationEffect interface: existence and properties of interface object -PASS WorkletAnimation interface: existence and properties of interface object -FAIL WorkletAnimation must be primary interface of new WorkletAnimation("name") assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: WorkletAnimation is not defined" -FAIL Stringification of new WorkletAnimation("name") assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: WorkletAnimation is not defined" -FAIL WorkletAnimation interface: new WorkletAnimation("name") must not have property "undefined" assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: WorkletAnimation is not defined" -FAIL WorkletAnimation interface: new WorkletAnimation("name") must not have property "animatorName" assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: WorkletAnimation is not defined" -PASS WorkletGroupEffect interface: existence and properties of interface object -FAIL CSS namespace: operation escape(CSSOMString) Cannot read property 'hasOwnProperty' of undefined -FAIL CSS namespace: attribute animationWorklet Cannot read property 'hasOwnProperty' of undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/tables/mozilla/core/col_widths_auto_per-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/tables/mozilla/core/col_widths_auto_per-expected.png deleted file mode 100644 index a27738cb9..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.15/tables/mozilla/core/col_widths_auto_per-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/tables/mozilla/core/col_widths_fix_per-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/tables/mozilla/core/col_widths_fix_per-expected.png deleted file mode 100644 index 0630f43c..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.15/tables/mozilla/core/col_widths_fix_per-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/tables/mozilla_expected_failures/bugs/bug17826-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/tables/mozilla_expected_failures/bugs/bug17826-expected.png deleted file mode 100644 index 33317a1..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.15/tables/mozilla_expected_failures/bugs/bug17826-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/tables/mozilla/core/col_widths_auto_per-expected.png b/third_party/blink/web_tests/platform/win/tables/mozilla/core/col_widths_auto_per-expected.png index 9a6749d..17dd5db 100644 --- a/third_party/blink/web_tests/platform/win/tables/mozilla/core/col_widths_auto_per-expected.png +++ b/third_party/blink/web_tests/platform/win/tables/mozilla/core/col_widths_auto_per-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/tables/mozilla/core/col_widths_fix_per-expected.png b/third_party/blink/web_tests/platform/win/tables/mozilla/core/col_widths_fix_per-expected.png index b89fe1c..bc69e128 100644 --- a/third_party/blink/web_tests/platform/win/tables/mozilla/core/col_widths_fix_per-expected.png +++ b/third_party/blink/web_tests/platform/win/tables/mozilla/core/col_widths_fix_per-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug17826-expected.png b/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug17826-expected.png index 30b31bd..7e7b317 100644 --- a/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug17826-expected.png +++ b/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug17826-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/jxl-enabled/images/jxl/jxl-images-expected.png b/third_party/blink/web_tests/virtual/jxl-enabled/images/jxl/jxl-images-expected.png index d46fdd23..5fb151c 100644 --- a/third_party/blink/web_tests/virtual/jxl-enabled/images/jxl/jxl-images-expected.png +++ b/third_party/blink/web_tests/virtual/jxl-enabled/images/jxl/jxl-images-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/wpt_internal/bluetooth/requestDevice/filter-does-not-match.https.html b/third_party/blink/web_tests/wpt_internal/bluetooth/requestDevice/filter-does-not-match.https.html index fc3ae3e..44f12e8 100644 --- a/third_party/blink/web_tests/wpt_internal/bluetooth/requestDevice/filter-does-not-match.https.html +++ b/third_party/blink/web_tests/wpt_internal/bluetooth/requestDevice/filter-does-not-match.https.html
@@ -9,59 +9,124 @@ let matching_services = [heart_rate.uuid]; let matching_name = 'Heart Rate Device'; let matching_namePrefix = 'Heart'; +let matching_manufacturerData = [{ companyIdentifier: 0x0001 }]; let non_matching_services = ['battery_service']; let non_matching_name = 'Some Device'; let non_matching_namePrefix = 'Some'; +let non_matching_manufacturerData = [{ companyIdentifier: 0x000f }]; let test_specs = [ { filters: [{ services: non_matching_services, name: non_matching_name, - namePrefix: non_matching_namePrefix + namePrefix: non_matching_namePrefix, + manufacturerData: non_matching_manufacturerData }] }, { filters: [{ services: matching_services, name: non_matching_name, - namePrefix: non_matching_namePrefix + namePrefix: non_matching_namePrefix, + manufacturerData: non_matching_manufacturerData }] }, { filters: [{ services: non_matching_services, name: matching_name, - namePrefix: non_matching_namePrefix + namePrefix: non_matching_namePrefix, + manufacturerData: non_matching_manufacturerData }] }, { filters: [{ services: matching_services, name: matching_name, - namePrefix: non_matching_namePrefix + namePrefix: non_matching_namePrefix, + manufacturerData: non_matching_manufacturerData }] }, { filters: [{ services: non_matching_services, name: non_matching_name, - namePrefix: matching_namePrefix + namePrefix: matching_namePrefix, + manufacturerData: non_matching_manufacturerData }] }, { filters: [{ services: matching_services, name: non_matching_name, - namePrefix: matching_namePrefix + namePrefix: matching_namePrefix, + manufacturerData: non_matching_manufacturerData }] }, { filters: [{ services: non_matching_services, name: matching_name, - namePrefix: matching_namePrefix + namePrefix: matching_namePrefix, + manufacturerData: non_matching_manufacturerData + }] + }, + { + filters: [{ + services: non_matching_services, + name: non_matching_name, + namePrefix: non_matching_namePrefix, + manufacturerData: matching_manufacturerData + }] + }, + { + filters: [{ + services: matching_services, + name: non_matching_name, + namePrefix: non_matching_namePrefix, + manufacturerData: matching_manufacturerData + }] + }, + { + filters: [{ + services: non_matching_services, + name: matching_name, + namePrefix: non_matching_namePrefix, + manufacturerData: matching_manufacturerData + }] + }, + { + filters: [{ + services: non_matching_services, + name: non_matching_name, + namePrefix: matching_namePrefix, + manufacturerData: matching_manufacturerData + }] + }, + { + filters: [{ + services: matching_services, + name: matching_name, + namePrefix: non_matching_namePrefix, + manufacturerData: matching_manufacturerData + }] + }, + { + filters: [{ + services: matching_services, + name: non_matching_name, + namePrefix: matching_namePrefix, + manufacturerData: matching_manufacturerData + }] + }, + { + filters: [{ + services: non_matching_services, + name: matching_name, + namePrefix: matching_namePrefix, + manufacturerData: matching_manufacturerData }] }, { @@ -76,6 +141,29 @@ }] }, { + filters: [{ + manufacturerData: non_matching_manufacturerData, + }] + }, + { + filters: [{ + services: non_matching_services, + manufacturerData: non_matching_manufacturerData, + }] + }, + { + filters: [{ + name: non_matching_name, + manufacturerData: non_matching_manufacturerData, + }] + }, + { + filters: [{ + namePrefix: non_matching_namePrefix, + manufacturerData: non_matching_manufacturerData, + }] + }, + { filters: [{services: non_matching_services, namePrefix: non_matching_namePrefix}] },
diff --git a/third_party/blink/web_tests/wpt_internal/bluetooth/requestLEScan/attempt-to-connect-after-scan.https.https.html b/third_party/blink/web_tests/wpt_internal/bluetooth/requestLEScan/attempt-to-connect-after-scan.https.https.html index e3d1eeb..ca2d7c1b 100644 --- a/third_party/blink/web_tests/wpt_internal/bluetooth/requestLEScan/attempt-to-connect-after-scan.https.https.html +++ b/third_party/blink/web_tests/wpt_internal/bluetooth/requestLEScan/attempt-to-connect-after-scan.https.https.html
@@ -19,6 +19,7 @@ const fake_device = await fake_central.simulatePreconnectedPeripheral({ address: fake_device_address, name: 'Some Device', + manufacturerData: {}, knownServiceUUIDs: [], });
diff --git a/third_party/libjxl/README.chromium b/third_party/libjxl/README.chromium index f2dcfd3..fb382bd 100644 --- a/third_party/libjxl/README.chromium +++ b/third_party/libjxl/README.chromium
@@ -2,8 +2,8 @@ Short Name: libjxl URL: https://gitlab.com/wg1/jpeg-xl Version: 0 -Date: 2021-04-29 -Revision: e5ce94456581d43f8a52c8100c726a0d079f65e7 +Date: 2021-05-04 +Revision: 9a8f5195e4d1c45112fd65f184ebe115f4163ba2 License: Apache 2.0 Security Critical: yes CPEPrefix: unknown
diff --git a/tools/autotest.py b/tools/autotest.py index 6372616..90294ffd 100755 --- a/tools/autotest.py +++ b/tools/autotest.py
@@ -347,13 +347,18 @@ return (test_targets, used_cache) -def RunTestTargets(out_dir, targets, gtest_filter, extra_args, dry_run): +def RunTestTargets(out_dir, targets, gtest_filter, extra_args, dry_run, + no_try_android_wrappers): + for target in targets: + # Look for the Android wrapper script first. path = os.path.join(out_dir, 'bin', f'run_{target}') - if not os.path.isfile(path): - # Otherwise, use the Desktop target which is an executable. + if no_try_android_wrappers or not os.path.isfile(path): + # If the wrapper is not found or disabled use the Desktop target + # which is an executable. path = os.path.join(out_dir, target) + cmd = [path, f'--gtest_filter={gtest_filter}'] + extra_args print('Running test: ' + ' '.join(cmd)) if not dry_run: @@ -411,6 +416,10 @@ '-n', action='store_true', help='Print ninja and test run commands without executing them.') + parser.add_argument( + '--no-try-android-wrappers', + action='store_true', + help='Do not try to use Android test wrappers to run tests.') parser.add_argument('file', metavar='FILE_NAME', help='test suite file (eg. FooTest.java)') @@ -461,7 +470,8 @@ else: # cache still valid, quit if the build failed if not build_ok: sys.exit(1) - RunTestTargets(out_dir, targets, gtest_filter, _extras, args.dry_run) + RunTestTargets(out_dir, targets, gtest_filter, _extras, args.dry_run, + args.no_try_android_wrappers) if __name__ == '__main__':
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 4ddc2202..404e888 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -5048,6 +5048,8 @@ <int value="23" label="Disabled proactive help setting"/> <int value="24" label="Base64 decoding error"/> <int value="25" label="The user rejected the bottom sheet onboarding"/> + <int value="26" label="CCT -> tab not supported"/> + <int value="27" label="Canceled"/> </enum> <enum name="AutofillAssistantLiteScriptOnboarding"> @@ -32374,6 +32376,11 @@ <int value="3889" label="CSSFilterColorMatrix"/> <int value="3890" label="HTMLFencedFrameElement"/> <int value="3891" label="CSSFilterLuminanceToAlpha"/> + <int value="3892" label="HandwritingRecognitionCreateRecognizer"/> + <int value="3893" label="HandwritingRecognitionQuerySupport"/> + <int value="3894" label="HandwritingRecognitionStartDrawing"/> + <int value="3895" label="HandwritingRecognitionGetPrediction"/> + <int value="3896" label="WebBluetoothManufacturerDataFilter"/> </enum> <enum name="FeaturePolicyAllowlistType"> @@ -70476,9 +70483,17 @@ </enum> <enum name="SendTabToSelfClickResult"> - <int value="0" label="SendTabToSelf entry point is shown. (Obsolete)"/> + <int value="0" label="SendTabToSelf entry point is shown."> + <obsolete> + Removed on 06/2020. + </obsolete> + </int> <int value="1" label="SendTabToSelf target device is clicked."/> - <int value="2" label="SendTabToSelf device list is shown. (Obsolete)"/> + <int value="2" label="SendTabToSelf device list is shown."> + <obsolete> + Removed on 06/2020. + </obsolete> + </int> </enum> <enum name="SendTabToSelfNotification">
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml index dd25941..7413c97 100644 --- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -17070,6 +17070,8 @@ <owner>jeffreycohen@chromium.org</owner> <owner>tgupta@chromium.org</owner> <owner>chrome-sharing-core@google.com</owner> + <suffix name="AndroidShareSheet" + label="Option to show in the android share sheet"/> <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"/>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index 2f5ce77c..79cce27f 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -5185,6 +5185,9 @@ <histogram name="EphemeralTab.BottomSheet.CloseReason" enum="BottomSheet.StateChangeReason" expires_after="M92"> + <obsolete> + Deprecated as of 05/2021 + </obsolete> <owner>donnd@chromium.org</owner> <owner>jinsukkim@chromium.org</owner> <summary> @@ -5195,6 +5198,9 @@ <histogram name="EphemeralTab.CloseReason" enum="OverlayPanel.StateChangeReason" expires_after="M92"> + <obsolete> + Deprecated as of 05/2021 + </obsolete> <owner>donnd@chromium.org</owner> <owner>jinsukkim@chromium.org</owner> <summary> @@ -13828,21 +13834,22 @@ <summary>The time spent before the screen locker is ready.</summary> </histogram> -<histogram name="SendTabToSelf.AndroidShareSheet.ClickResult" - 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="M97"> <owner>jeffreycohen@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. + Records user flow for SendTabToSelf feature. + + Only the "SendTabToSelf target device is clicked" bucket is + recorded today, causing sharing of a tab with the tapped device. Until M84 + other buckets were recorded. Because each bucket represents a different + aspect of the flow, it's important to look at "bucket count", not + "bucket proportion". + + On iOS this was not recorded between M85 and M90, inclusive (see + crbug.com/1204944). </summary> </histogram>
diff --git a/tools/metrics/histograms/histograms_xml/password/histograms.xml b/tools/metrics/histograms/histograms_xml/password/histograms.xml index 10daab22..f412591 100644 --- a/tools/metrics/histograms/histograms_xml/password/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/password/histograms.xml
@@ -520,54 +520,65 @@ </histogram> <histogram name="PasswordManager.AffiliationBackend.FetchSize" units="facets" - expires_after="M90"> - <owner>engedy@chromium.org</owner> + expires_after="M96"> + <owner>vsemeniuk@google.com</owner> + <owner>vasilii@chromium.org</owner> <summary> The number of facets for which affiliation information was requested in a - network fetch. Recorded for each network fetch. + network fetch. Recorded for each network fetch. Warning: this histogram was + expired from M90 to M92; data may be missing. </summary> </histogram> <histogram name="PasswordManager.AffiliationBackend.FirstFetchDelay" units="ms" - expires_after="M90"> - <owner>engedy@chromium.org</owner> + expires_after="M96"> + <owner>vsemeniuk@google.com</owner> + <owner>vasilii@chromium.org</owner> <summary> The time elapsed between creation of the AffiliationBackend and the first - time it needed to issue a network fetch. + time it needed to issue a network fetch. Warning: this histogram was expired + from M90 to M92; data may be missing. </summary> </histogram> <histogram name="PasswordManager.AffiliationBackend.SubsequentFetchDelay" - units="ms" expires_after="M90"> - <owner>engedy@chromium.org</owner> + units="ms" expires_after="M96"> + <owner>vsemeniuk@google.com</owner> + <owner>vasilii@chromium.org</owner> <summary> The elapsed time between subsequent network fetches. Recorded whenever the AffiliationBackend initiated a network fetch, regardless of success or - failure. + failure. Warning: this histogram was expired from M90 to M92; data may be + missing. </summary> </histogram> <histogram name="PasswordManager.AffiliationFetcher.FetchErrorCode" - enum="NetErrorCodes" expires_after="M90"> - <owner>engedy@chromium.org</owner> + enum="NetErrorCodes" expires_after="M96"> + <owner>vsemeniuk@google.com</owner> + <owner>vasilii@chromium.org</owner> <summary> The network error code, as reported by the underlying URLFetcher. Recorded only for each network fetch that failed due to network/server errors. + Warning: this histogram was expired from M90 to M92; data may be missing. </summary> </histogram> <histogram name="PasswordManager.AffiliationFetcher.FetchHttpResponseCode" - enum="HttpResponseCode" expires_after="M90"> - <owner>engedy@chromium.org</owner> + enum="HttpResponseCode" expires_after="M96"> + <owner>vsemeniuk@google.com</owner> + <owner>vasilii@chromium.org</owner> <summary> The HTTP response code, as reported by the underlying URLFetcher. Recorded only for each network fetch that failed due to network/server errors. + Warning: this histogram was expired from M90 to M92; data may be missing. </summary> </histogram> <histogram name="PasswordManager.AffiliationFetcher.FetchResult" - enum="AffiliationFetchResult" expires_after="2021-09-19"> - <owner>engedy@chromium.org</owner> + enum="AffiliationFetchResult" expires_after="M96"> + <owner>vsemeniuk@google.com</owner> + <owner>vasilii@chromium.org</owner> <summary> Whether the network fetch succeeded, failed due to network/server errors, or contained malformed data. Recorded for each network fetch.
diff --git a/tools/metrics/histograms/update_permissions_policy_enum.py b/tools/metrics/histograms/update_permissions_policy_enum.py index cec76f06..ba84a1d 100755 --- a/tools/metrics/histograms/update_permissions_policy_enum.py +++ b/tools/metrics/histograms/update_permissions_policy_enum.py
@@ -25,7 +25,7 @@ 'permissions_policy_feature.mojom' UpdateHistogramEnum(histogram_enum_name='FeaturePolicyFeature', source_enum_path=source_file, - start_marker='^enum FeaturePolicyFeature {', + start_marker='^enum PermissionsPolicyFeature {', end_marker='^};', strip_k_prefix=True, calling_script=os.path.basename(__file__))
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index c9067c4e..c0116170 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -69,6 +69,11 @@ # Benchmark: blink_perf.shadow_dom crbug.com/702319 [ android-nexus-5x ] blink_perf.shadow_dom/* [ Skip ] +# Benchmark: desktop_ui +crbug.com/1205850 [ win ] desktop_ui/tab_search:measure_memory* [ Skip ] +crbug.com/1205850 [ mac ] desktop_ui/tab_search:measure_memory* [ Skip ] +crbug.com/1205850 [ linux ] desktop_ui/tab_search:measure_memory* [ Skip ] + # Benchmark: dromaeo crbug.com/1050065 [ android-pixel-2 ] dromaeo/http://dromaeo.com?dom-modify [ Skip ] @@ -109,6 +114,12 @@ crbug.com/879833 loading.desktop/Walgreens_warm [ Skip ] crbug.com/921428 [ chromeos ] loading.desktop/TheVerge_cold [ Skip ] crbug.com/921428 [ chromeos ] loading.desktop/TheVerge_warm [ Skip ] +crbug.com/1205852 [ linux ] loading.desktop/Economist_cold [ Skip ] +crbug.com/1205852 [ linux ] loading.desktop/Economist_warm [ Skip ] +crbug.com/1205852 [ mac ] loading.desktop/Economist_cold [ Skip ] +crbug.com/1205852 [ mac ] loading.desktop/Economist_warm [ Skip ] +crbug.com/1205852 [ win ] loading.desktop/Economist_cold [ Skip ] +crbug.com/1205852 [ win ] loading.desktop/Economist_warm [ Skip ] # Benchmark: loading.mobile crbug.com/656861 loading.mobile/G1 [ Skip ]
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn index f73e737f..bf24a86 100644 --- a/ui/file_manager/file_manager/foreground/js/BUILD.gn +++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -1319,7 +1319,6 @@ deps = [ "//ui/file_manager/file_manager/common/js:volume_manager_types", "//ui/webui/resources/js:assert", - "//ui/webui/resources/js:load_time_data", ] }
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js index fc21d51e..37ba7a5 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -1918,12 +1918,6 @@ canExecute(event, fileManager) { const command = event.command; - if (!HoldingSpaceUtil.isFeatureEnabled()) { - event.canExecute = false; - command.setHidden(true); - return; - } - const allowedVolumeTypes = HoldingSpaceUtil.getAllowedVolumeTypes(); const currentRootType = fileManager.directoryModel.getCurrentRootType(); if (!util.isRecentRootType(currentRootType)) {
diff --git a/ui/file_manager/file_manager/foreground/js/holding_space_util.js b/ui/file_manager/file_manager/foreground/js/holding_space_util.js index fe2a5c0..303b3106 100644 --- a/ui/file_manager/file_manager/foreground/js/holding_space_util.js +++ b/ui/file_manager/file_manager/foreground/js/holding_space_util.js
@@ -9,7 +9,6 @@ // clang-format off // #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js'; // #import {metrics} from '../../common/js/metrics.m.js'; -// #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; // #import {xfm} from '../../common/js/xfm.m.js'; // clang-format on @@ -34,12 +33,6 @@ return 'holdingSpaceTimeOfFirstWelcomeBannerShow'; } - /** @return {boolean} */ - static isFeatureEnabled() { - return loadTimeData.valueExists('HOLDING_SPACE_ENABLED') && - loadTimeData.getBoolean('HOLDING_SPACE_ENABLED'); - } - /** * Returns the volume types for which the holding space feature is allowed. * @return {!Array<?VolumeManagerCommon.VolumeType>}
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners.js b/ui/file_manager/file_manager/foreground/js/ui/banners.js index 3fbce87..fb64624 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/banners.js +++ b/ui/file_manager/file_manager/foreground/js/ui/banners.js
@@ -366,7 +366,6 @@ * @private */ prepareAndShowHoldingSpaceWelcomeBanner_() { - assert(HoldingSpaceUtil.isFeatureEnabled()); this.showHoldingSpaceWelcomeBanner_(true); // Do not recreate the banner. @@ -411,6 +410,7 @@ const buttonGroup = util.createChild(wrapper, 'button-group', 'div'); const dismiss = util.createChild(buttonGroup, 'text-button', 'cr-button'); + dismiss.id = 'holding-space-welcome-dismiss'; dismiss.setAttribute('aria-label', str('HOLDING_SPACE_WELCOME_DISMISS')); dismiss.textContent = str('HOLDING_SPACE_WELCOME_DISMISS'); dismiss.tabIndex = 0; @@ -623,7 +623,6 @@ * @private */ closeHoldingSpaceWelcomeBanner_() { - assert(HoldingSpaceUtil.isFeatureEnabled()); this.cleanupHoldingSpaceWelcomeBanner_(); // Stop showing the welcome banner. @@ -685,10 +684,6 @@ * @private */ async maybeShowHoldingSpaceWelcomeBanner_() { - if (!HoldingSpaceUtil.isFeatureEnabled()) { - return; - } - await this.ready_; if (!this.showWelcome_) { @@ -921,8 +916,6 @@ * @private */ showHoldingSpaceWelcomeBanner_(show) { - assert(HoldingSpaceUtil.isFeatureEnabled()); - const /** boolean */ hidden = !show; if (this.holdingSpaceWelcomeBanner_.hasAttribute('hidden') == hidden) { return; @@ -1098,7 +1091,6 @@ * @private */ cleanupHoldingSpaceWelcomeBanner_() { - assert(HoldingSpaceUtil.isFeatureEnabled()); this.showHoldingSpaceWelcomeBanner_(false); }
diff --git a/ui/file_manager/integration_tests/file_manager/holding_space.js b/ui/file_manager/integration_tests/file_manager/holding_space.js index 3c6ef61..6b04b66 100644 --- a/ui/file_manager/integration_tests/file_manager/holding_space.js +++ b/ui/file_manager/integration_tests/file_manager/holding_space.js
@@ -4,22 +4,10 @@ 'use strict'; /** - * Tests that the holding space welcome banner is hidden when the feature is - * disabled. + * Tests that the holding space welcome banner appears and that it can be + * dismissed. */ -testcase.holdingSpaceWelcomeBannerWithFeatureDisabled = async () => { - // Open Files app on Downloads. - const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS); - - // Check: the holding space welcome banner should be hidden. - await remoteCall.waitForElement(appId, '.holding-space-welcome[hidden]'); -}; - -/** - * Tests that the holding space welcome banner appears when the feature is - * enabled and that it can be dismissed. - */ -testcase.holdingSpaceWelcomeBannerWithFeatureEnabled = async () => { +testcase.holdingSpaceWelcomeBanner = async () => { // Open Files app on Downloads. const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
diff --git a/ui/file_manager/integration_tests/file_manager/tab_index.js b/ui/file_manager/integration_tests/file_manager/tab_index.js index 8728b1f..3ad61e4 100644 --- a/ui/file_manager/integration_tests/file_manager/tab_index.js +++ b/ui/file_manager/integration_tests/file_manager/tab_index.js
@@ -91,6 +91,8 @@ await remoteCall.checkNextTabFocus(appId, 'sort-button')); chrome.test.assertTrue( await remoteCall.checkNextTabFocus(appId, 'gear-button')); + chrome.test.assertTrue(await remoteCall.checkNextTabFocus( + appId, 'holding-space-welcome-dismiss')); chrome.test.assertTrue( await remoteCall.checkNextTabFocus(appId, 'file-list')); };
diff --git a/ui/gfx/font_render_params_linux.cc b/ui/gfx/font_render_params_linux.cc index 3ab8b2e..7e42a2e 100644 --- a/ui/gfx/font_render_params_linux.cc +++ b/ui/gfx/font_render_params_linux.cc
@@ -12,7 +12,6 @@ #include "base/command_line.h" #include "base/containers/mru_cache.h" -#include "base/hash/hash.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/macros.h" @@ -90,7 +89,7 @@ // Keyed by hashes of FontRenderParamQuery structs from // HashFontRenderParamsQuery(). -typedef base::MRUCache<uint32_t, QueryResult> Cache; +typedef base::HashingMRUCache<std::string, QueryResult> Cache; // A cache and the lock that must be held while accessing it. // GetFontRenderParams() is called by both the UI thread and the sandbox IPC @@ -173,14 +172,12 @@ return true; } -// Serialize |query| into a string and hash it to a value suitable for use as a -// cache key. -uint32_t HashFontRenderParamsQuery(const FontRenderParamsQuery& query) { - return base::Hash(base::StringPrintf( +// Serialize |query| into a string value suitable for use as a cache key. +std::string GetFontRenderParamsQueryKey(const FontRenderParamsQuery& query) { + return base::StringPrintf( "%d|%d|%d|%d|%s|%f", query.pixel_size, query.point_size, query.style, static_cast<int>(query.weight), - base::JoinString(query.families, ",").c_str(), - query.device_scale_factor)); + base::JoinString(query.families, ",").c_str(), query.device_scale_factor); } } // namespace @@ -193,15 +190,15 @@ if (actual_query.device_scale_factor == 0) actual_query.device_scale_factor = device_scale_factor_; - const uint32_t hash = HashFontRenderParamsQuery(actual_query); + std::string query_key = GetFontRenderParamsQueryKey(actual_query); SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer(); { // Try to find a cached result so Fontconfig doesn't need to be queried. base::AutoLock lock(synchronized_cache->lock); - Cache::const_iterator it = synchronized_cache->cache.Get(hash); + Cache::const_iterator it = synchronized_cache->cache.Get(query_key); if (it != synchronized_cache->cache.end()) { - DVLOG(1) << "Returning cached params for " << hash; + DVLOG(1) << "Returning cached params for " << query_key; const QueryResult& result = it->second; if (family_out) *family_out = result.family; @@ -209,7 +206,7 @@ } } - DVLOG(1) << "Computing params for " << hash; + DVLOG(1) << "Computing params for " << query_key; if (family_out) family_out->clear(); @@ -251,7 +248,8 @@ // Store the result. It's fine if this overwrites a result that was cached // by a different thread in the meantime; the values should be identical. base::AutoLock lock(synchronized_cache->lock); - synchronized_cache->cache.Put(hash, + synchronized_cache->cache.Put( + query_key, QueryResult(params, family_out ? *family_out : std::string())); }
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc index 2d7686ef..92edb57 100644 --- a/ui/ozone/platform/wayland/host/wayland_connection.cc +++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -83,6 +83,7 @@ // value. constexpr uint32_t kMinWlDrmVersion = 2; constexpr uint32_t kMinWlOutputVersion = 2; +constexpr uint32_t kMinZwpPointerGesturesVersion = 1; // gtk_shell1 exposes request_focus() since version 3. Below that, it is not // interesting for us, although it provides some shell integration that might be @@ -578,7 +579,8 @@ connection->zaura_shell_ = std::make_unique<WaylandZAuraShell>(zaura_shell.release(), connection); } else if (!connection->wayland_zwp_pointer_gestures_ && - (strcmp(interface, "zwp_pointer_gestures_v1") == 0)) { + strcmp(interface, "zwp_pointer_gestures_v1") == 0 && + version >= kMinZwpPointerGesturesVersion) { auto zwp_pointer_gestures_v1 = wl::Bind<struct zwp_pointer_gestures_v1>(registry, name, version); if (!zwp_pointer_gestures_v1) {
diff --git a/weblayer/browser/tab_impl.cc b/weblayer/browser/tab_impl.cc index a3dd04e..27fd82b 100644 --- a/weblayer/browser/tab_impl.cc +++ b/weblayer/browser/tab_impl.cc
@@ -7,7 +7,6 @@ #include <cmath> #include "base/auto_reset.h" -#include "base/bind.h" #include "base/feature_list.h" #include "base/guid.h" #include "base/logging.h" @@ -16,7 +15,6 @@ #include "base/time/default_tick_clock.h" #include "cc/layers/layer.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" -#include "components/autofill/core/browser/android_autofill_manager.h" #include "components/autofill/core/browser/autofill_provider.h" #include "components/autofill/core/common/autofill_features.h" #include "components/blocked_content/popup_blocker.h" @@ -288,14 +286,6 @@ web_contents, SubresourceFilterProfileContextFactory::GetForBrowserContext( web_contents->GetBrowserContext()), - // Infobars are supported only on Android in WebLayer. This is not a - // problem as the subresource filter shows the infobar only on Android - // as well. -#if defined(OS_ANDROID) - infobars::ContentInfoBarManager::FromWebContents(web_contents), -#else - nullptr, -#endif GetDatabaseManagerFromSafeBrowsingService(), dealer); } @@ -1417,8 +1407,7 @@ autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( web_contents, AutofillClientImpl::FromWebContents(web_contents), i18n::GetApplicationLocale(), enable_autofill_download_manager, - base::BindRepeating(&autofill::AndroidAutofillManager::Create, - autofill_provider_.get())); + autofill_provider_.get()); } find_in_page::FindTabHelper* TabImpl::GetFindTabHelper() {