diff --git a/DEPS b/DEPS index 44025c2..834e405 100644 --- a/DEPS +++ b/DEPS
@@ -126,11 +126,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'b00f7b34751b64a7dc3051e452f5a63afe222891', + 'skia_revision': '7a74c7cb6da0809e2ea2121932b889844e249157', # 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': '3c4ae81e70e9046ea501ff0ce7169cc33cb68ece', + 'v8_revision': 'ad16165cca87b0bdaf39feb026844252fd3c724c', # 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. @@ -138,15 +138,15 @@ # 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': '366df2b26dd1809be283beb01824ec0a9d899bd5', + 'angle_revision': 'aead8edf8c46ace321f0a5583cea21194a77baf1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': 'de16f327d051dd5a33b3b7c4666feea071cd877a', + 'swiftshader_revision': '2bb0864b22e70df9907bb71ca985a110f33d29da', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '4679e62edbe5cf62286606e0fe3323d64faa97c2', + 'pdfium_revision': '333ac4ae60ac700fe9089ffe60135b19984e0b89', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -189,7 +189,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': '778eee07409eb2f2a5589c2bfdb050b61b60fde2', + 'catapult_revision': '309c28a6328bf11bb2863afab0b28691a783941f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -253,7 +253,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': '4dec7371a221faf30d037a6bca0618cb94ca4210', + 'dawn_revision': '108bcbd5c9b83c545e6466d787035527a35f909f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -732,7 +732,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '25ca3f40d18c40de46f990f54413ddc4b0299f34', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'd70d87c663f37683f805eb5d8ffe5679d48acb72', 'condition': 'checkout_linux', }, @@ -1255,7 +1255,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'a0f51b2e123f39c9ff12e621b0b47dd28dd64424', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'd036c6582e130eb558ac12b56ea2d86909100f6e', + Var('webrtc_git') + '/src.git' + '@' + '397c06fe9db8512e18ffa401ead1dd7cf4e725d0', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1296,7 +1296,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@9b5028a4743a553c981ae845b89f17604ee5a381', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@211efe6b022c41e74d7c740e11e635eee36e861d', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/aw_settings.cc b/android_webview/browser/aw_settings.cc index 7d17d42..af9f731 100644 --- a/android_webview/browser/aw_settings.cc +++ b/android_webview/browser/aw_settings.cc
@@ -19,9 +19,9 @@ #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/renderer_preferences_util.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/renderer_preferences_util.h" #include "content/public/common/web_preferences.h" #include "jni/AwSettings_jni.h" #include "net/http/http_util.h" @@ -233,6 +233,7 @@ if (!renderer_prefs_initialized_) { content::UpdateFontRendererPreferencesFromSystemSettings(prefs); + content::UpdateFocusRingPreferencesFromSystemSettings(prefs); renderer_prefs_initialized_ = true; update_prefs = true; }
diff --git a/ash/public/interfaces/login_user_info.mojom b/ash/public/interfaces/login_user_info.mojom index a58732b..16f8b69b 100644 --- a/ash/public/interfaces/login_user_info.mojom +++ b/ash/public/interfaces/login_user_info.mojom
@@ -10,7 +10,7 @@ import "mojo/public/mojom/base/values.mojom"; // Supported multi-profile user behavior values. -// Keep in sync with the enum in md_user_pod_row.js and user_pod_row.js +// Keep in sync with the enum in chromeos_user_pod_row.js and user_pod_row.js enum MultiProfileUserBehavior { UNRESTRICTED = 0, PRIMARY_ONLY = 1,
diff --git a/ash/system/message_center/unified_message_center_view.cc b/ash/system/message_center/unified_message_center_view.cc index d1cd29bd..58b9b256 100644 --- a/ash/system/message_center/unified_message_center_view.cc +++ b/ash/system/message_center/unified_message_center_view.cc
@@ -320,6 +320,9 @@ } void UnifiedMessageCenterView::NotifyRectBelowScroll() { + if (!visible()) + return; + gfx::Rect rect_below_scroll; rect_below_scroll.set_height( std::max(0, message_list_view_->GetLastNotificationBounds().bottom() -
diff --git a/ash/system/unified/unified_system_tray_view.cc b/ash/system/unified/unified_system_tray_view.cc index 1a4b496..973c0c2 100644 --- a/ash/system/unified/unified_system_tray_view.cc +++ b/ash/system/unified/unified_system_tray_view.cc
@@ -60,6 +60,7 @@ flags.setAntiAlias(true); gfx::Rect rect = rect_below_scroll_; + rect.set_height(std::min(rect.height(), kUnifiedTrayCornerRadius * 2)); rect.Inset(gfx::Insets(-kUnifiedTrayCornerRadius * 4, 0, 0, 0)); canvas->DrawRoundRect(gfx::RectF(rect), kUnifiedTrayCornerRadius, flags); }
diff --git a/base/logging.cc b/base/logging.cc index fb64437..58f3d15f 100644 --- a/base/logging.cc +++ b/base/logging.cc
@@ -768,15 +768,21 @@ priority = ANDROID_LOG_FATAL; break; } + const char kAndroidLogTag[] = "chromium"; #if DCHECK_IS_ON() // Split the output by new lines to prevent the Android system from // truncating the log. - for (const auto& line : base::SplitString( - str_newline, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) - __android_log_write(priority, "chromium", line.c_str()); + std::vector<std::string> lines = base::SplitString( + str_newline, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + // str_newline has an extra newline appended to it (at the top of this + // function), so skip the last split element to avoid needlessly + // logging an empty string. + lines.pop_back(); + for (const auto& line : lines) + __android_log_write(priority, kAndroidLogTag, line.c_str()); #else // The Android system may truncate the string if it's too long. - __android_log_write(priority, "chromium", str_newline.c_str()); + __android_log_write(priority, kAndroidLogTag, str_newline.c_str()); #endif #endif // OS_ANDROID ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr));
diff --git a/base/task/sequence_manager/sequence_manager_impl_unittest.cc b/base/task/sequence_manager/sequence_manager_impl_unittest.cc index 2fdb2bd..795ce042 100644 --- a/base/task/sequence_manager/sequence_manager_impl_unittest.cc +++ b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
@@ -8,6 +8,7 @@ #include <memory> #include <utility> +#include "base/auto_reset.h" #include "base/bind.h" #include "base/callback.h" #include "base/location.h" @@ -18,6 +19,7 @@ #include "base/optional.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/synchronization/waitable_event.h" #include "base/task/sequence_manager/real_time_domain.h" @@ -63,13 +65,34 @@ // To avoid symbol collisions in jumbo builds. namespace sequence_manager_impl_unittest { -enum class TestType : int { - kCustom = 0, - kUseMockTaskRunner = 1, - kUseMessageLoop = 2, - kUseMessagePump = 3, +enum class TestType { + kCustom, + kMockTaskRunner, + kMessageLoop, + kMessagePump, }; +std::string ToString(TestType type) { + switch (type) { + case TestType::kMockTaskRunner: + return "kMockTaskRunner"; + case TestType::kMessagePump: + return "kMessagePump"; + case TestType::kMessageLoop: + return "kMessageLoop"; + case TestType::kCustom: + return "kCustom"; + } +} + +std::string GetTestNameSuffix(const testing::TestParamInfo<TestType>& info) { + return StrCat({"With", ToString(info.param).substr(1)}); +} + +void PrintTo(const TestType type, std::ostream* os) { + *os << ToString(type); +} + using MockTask = MockCallback<base::RepeatingCallback<void()>>; // This class abstracts the details of how the SequenceManager runs tasks. @@ -150,9 +173,9 @@ std::unique_ptr<SequenceManagerForTest> sequence_manager_; }; -class FixtureWithWithMockMessagePump : public Fixture { +class FixtureWithMockMessagePump : public Fixture { public: - FixtureWithWithMockMessagePump() { + FixtureWithMockMessagePump() { // A null clock triggers some assertions. mock_clock_.Advance(TimeDelta::FromMilliseconds(1)); @@ -211,6 +234,80 @@ std::unique_ptr<SequenceManagerForTest> sequence_manager_; }; +class FixtureWithMessageLoop : public Fixture { + public: + FixtureWithMessageLoop() + : auto_reset_global_clock_(&global_clock_, &mock_clock_) { + // A null clock triggers some assertions. + mock_clock_.Advance(TimeDelta::FromMilliseconds(1)); + scoped_clock_override_ = + std::make_unique<base::subtle::ScopedTimeClockOverrides>( + nullptr, TicksNowOverride, nullptr); + + auto pump = std::make_unique<MockTimeMessagePump>(&mock_clock_); + pump_ = pump.get(); + message_loop_ = std::make_unique<MessageLoop>(std::move(pump)); + + sequence_manager_ = SequenceManagerForTest::Create( + message_loop_->GetMessageLoopBase(), ThreadTaskRunnerHandle::Get(), + &mock_clock_, + SequenceManager::Settings{.randomised_sampling_enabled = false}); + } + + void AdvanceMockTickClock(TimeDelta delta) override { + mock_clock_.Advance(delta); + } + + const TickClock* mock_tick_clock() const override { return &mock_clock_; } + + TimeDelta NextPendingTaskDelay() const override { + return pump_->next_wake_up_time() - mock_clock_.NowTicks(); + } + + void FastForwardBy(TimeDelta delta) override { + pump_->SetAllowTimeToAutoAdvanceUntil(mock_clock_.NowTicks() + delta); + pump_->SetStopWhenMessagePumpIsIdle(true); + RunLoop().Run(); + pump_->SetStopWhenMessagePumpIsIdle(false); + } + + void FastForwardUntilNoTasksRemain() override { + pump_->SetAllowTimeToAutoAdvanceUntil(TimeTicks::Max()); + pump_->SetStopWhenMessagePumpIsIdle(true); + RunLoop().Run(); + pump_->SetStopWhenMessagePumpIsIdle(false); + pump_->SetAllowTimeToAutoAdvanceUntil(mock_clock_.NowTicks()); + } + + void RunDoWorkOnce() override { + pump_->SetQuitAfterDoSomeWork(true); + RunLoop().Run(); + pump_->SetQuitAfterDoSomeWork(false); + } + + SequenceManagerForTest* sequence_manager() const override { + return sequence_manager_.get(); + } + + void DestroySequenceManager() override { + pump_ = nullptr; + sequence_manager_.reset(); + } + + private: + static TickClock* global_clock_; + static TimeTicks TicksNowOverride() { return global_clock_->NowTicks(); } + SimpleTestTickClock mock_clock_; + AutoReset<TickClock*> auto_reset_global_clock_; + std::unique_ptr<base::subtle::ScopedTimeClockOverrides> + scoped_clock_override_; + std::unique_ptr<MessageLoop> message_loop_; + MockTimeMessagePump* pump_ = nullptr; + std::unique_ptr<SequenceManagerForTest> sequence_manager_; +}; + +TickClock* FixtureWithMessageLoop::global_clock_; + // SequenceManagerImpl uses TestMockTimeTaskRunner which controls // both task execution and mock clock. // TODO(kraynov): Make this class to support all TestTypes. @@ -221,14 +318,17 @@ public: SequenceManagerTest() { switch (GetParam()) { - case TestType::kUseMockTaskRunner: + case TestType::kMockTaskRunner: fixture_ = std::make_unique<FixtureWithMockTaskRunner>(); break; - case TestType::kUseMessagePump: - fixture_ = std::make_unique<FixtureWithWithMockMessagePump>(); + case TestType::kMessagePump: + fixture_ = std::make_unique<FixtureWithMockMessagePump>(); + break; + case TestType::kMessageLoop: + fixture_ = std::make_unique<FixtureWithMessageLoop>(); break; default: - DCHECK(false); + NOTREACHED(); } } @@ -296,19 +396,6 @@ std::unique_ptr<Fixture> fixture_; }; -std::string GetTestNameSuffix(const testing::TestParamInfo<TestType>& info) { - switch (info.param) { - case TestType::kUseMockTaskRunner: - return "MockTaskRunner"; - case TestType::kUseMessagePump: - return "MessagePump"; - case TestType::kUseMessageLoop: - return "MessageLoop"; - case TestType::kCustom: - return "Custom"; - } -} - // TODO(carlscab): Remove once the classes below have been migrated to // SequenceManagerTest class SequenceManagerTestBase : public testing::TestWithParam<TestType> { @@ -343,46 +430,10 @@ // TODO(kraynov): Generalize as many tests as possible to run it // in all supported environments. // TODO(carlscab): Migrate to SequenceManagerTest and remove -class SequenceManagerTestWithMessageLoop : public SequenceManagerTestBase { +class SequenceManagerTestWithCustomInitialization + : public SequenceManagerTestBase { protected: - void SetUp() override { - switch (GetParam()) { - case TestType::kUseMessageLoop: - SetUpWithMessageLoop(); - break; - case TestType::kUseMessagePump: - SetUpWithMessagePump(); - break; - default: - FAIL(); - } - } - - void SetUpWithMessageLoop() { - message_loop_.reset(new MessageLoop()); - // A null clock triggers some assertions. - mock_clock_.Advance(TimeDelta::FromMilliseconds(1)); - start_time_ = mock_clock_.NowTicks(); - - manager_ = SequenceManagerForTest::Create( - message_loop_->GetMessageLoopBase(), ThreadTaskRunnerHandle::Get(), - &mock_clock_, - SequenceManager::Settings{.randomised_sampling_enabled = false}); - } - - void SetUpWithMessagePump() { - mock_clock_.Advance(TimeDelta::FromMilliseconds(1)); - start_time_ = mock_clock_.NowTicks(); - manager_ = SequenceManagerForTest::Create( - std::make_unique<ThreadControllerWithMessagePumpImpl>( - std::make_unique<MessagePumpDefault>(), &mock_clock_), - SequenceManager::Settings{.randomised_sampling_enabled = false}); - // ThreadControllerWithMessagePumpImpl doesn't provide - // a default task runner. - default_task_queue_ = manager_->CreateTaskQueueWithType<TestTaskQueue>( - TaskQueue::Spec("default")); - manager_->SetDefaultTaskRunner(default_task_queue_->task_runner()); - } + void SetUp() override { ASSERT_EQ(GetParam(), TestType::kCustom); } const TickClock* GetTickClock() { return &mock_clock_; } @@ -391,22 +442,12 @@ SimpleTestTickClock mock_clock_; }; -// TODO(carlscab): Migrate to SequenceManagerTest and remove -class SequenceManagerTestWithCustomInitialization - : public SequenceManagerTestWithMessageLoop { - protected: - void SetUp() override { ASSERT_EQ(GetParam(), TestType::kCustom); } -}; - INSTANTIATE_TEST_SUITE_P(, SequenceManagerTest, - testing::Values(TestType::kUseMockTaskRunner, - TestType::kUseMessagePump)); - -INSTANTIATE_TEST_SUITE_P(, - SequenceManagerTestWithMessageLoop, - testing::Values(TestType::kUseMessageLoop, - TestType::kUseMessagePump)); + testing::Values(TestType::kMockTaskRunner, + TestType::kMessageLoop, + TestType::kMessagePump), + GetTestNameSuffix); INSTANTIATE_TEST_SUITE_P(, SequenceManagerTestWithCustomInitialization, @@ -571,7 +612,7 @@ EXPECT_THAT(run_order, ElementsAre(1u, 2u, 3u, 4u, 5u, 6u)); } -TEST_P(SequenceManagerTestWithMessageLoop, NonNestableTaskPosting) { +TEST_P(SequenceManagerTest, NonNestableTaskPosting) { auto queue = CreateTaskQueue(); std::vector<EnqueueOrder> run_order; @@ -582,8 +623,7 @@ EXPECT_THAT(run_order, ElementsAre(1u)); } -TEST_P(SequenceManagerTestWithMessageLoop, - NonNestableTaskExecutesInExpectedOrder) { +TEST_P(SequenceManagerTest, NonNestableTaskExecutesInExpectedOrder) { auto queue = CreateTaskQueue(); std::vector<EnqueueOrder> run_order; @@ -598,8 +638,9 @@ EXPECT_THAT(run_order, ElementsAre(1u, 2u, 3u, 4u, 5u)); } -TEST_P(SequenceManagerTestWithMessageLoop, - NonNestableTasksDoesntExecuteInNestedLoop) { +TEST_P(SequenceManagerTest, NonNestableTasksDoesntExecuteInNestedLoop) { + if (GetParam() == TestType::kMockTaskRunner) + return; auto queue = CreateTaskQueue(); std::vector<EnqueueOrder> run_order; @@ -643,7 +684,9 @@ } // namespace -TEST_P(SequenceManagerTestWithMessageLoop, TaskQueueDisabledFromNestedLoop) { +TEST_P(SequenceManagerTest, TaskQueueDisabledFromNestedLoop) { + if (GetParam() == TestType::kMockTaskRunner) + return; auto queue = CreateTaskQueue(); std::vector<EnqueueOrder> run_order; @@ -653,7 +696,7 @@ std::make_pair(BindOnce(&TestTask, 1, &run_order), false)); tasks_to_post_from_nested_loop.push_back( std::make_pair(BindOnce(&InsertFenceAndPostTestTask, 2, &run_order, queue, - manager_.get()), + sequence_manager()), true)); queue->task_runner()->PostTask( @@ -1385,7 +1428,7 @@ DestroySequenceManager(); queue->task_runner()->PostTask(FROM_HERE, counter.WrapCallback(task.Get())); - if (GetParam() != TestType::kUseMessagePump) { + if (GetParam() != TestType::kMessagePump) { RunLoop().RunUntilIdle(); } @@ -1397,7 +1440,7 @@ runner->task_runner()->PostTask(FROM_HERE, BindOnce(&TestTask, 1, run_order)); } -TEST_P(SequenceManagerTestWithMessageLoop, PostFromThread) { +TEST_P(SequenceManagerTest, PostFromThread) { auto queue = CreateTaskQueue(); std::vector<EnqueueOrder> run_order; @@ -1430,7 +1473,7 @@ EXPECT_EQ(1, run_count); } -TEST_P(SequenceManagerTestWithMessageLoop, PostFromNestedRunloop) { +TEST_P(SequenceManagerTest, PostFromNestedRunloop) { auto queue = CreateTaskQueue(); std::vector<EnqueueOrder> run_order; @@ -1475,12 +1518,12 @@ MOCK_METHOD1(WillProcessTask, void(const PendingTask& task)); }; -TEST_P(SequenceManagerTestWithMessageLoop, TaskObserverAdding) { +TEST_P(SequenceManagerTest, TaskObserverAdding) { auto queue = CreateTaskQueue(); MockTaskObserver observer; - manager_->SetWorkBatchSize(2); - manager_->AddTaskObserver(&observer); + sequence_manager()->SetWorkBatchSize(2); + sequence_manager()->AddTaskObserver(&observer); std::vector<EnqueueOrder> run_order; queue->task_runner()->PostTask(FROM_HERE, BindOnce(&TestTask, 1, &run_order)); @@ -1491,12 +1534,12 @@ RunLoop().RunUntilIdle(); } -TEST_P(SequenceManagerTestWithMessageLoop, TaskObserverRemoving) { +TEST_P(SequenceManagerTest, TaskObserverRemoving) { auto queue = CreateTaskQueue(); MockTaskObserver observer; - manager_->SetWorkBatchSize(2); - manager_->AddTaskObserver(&observer); - manager_->RemoveTaskObserver(&observer); + sequence_manager()->SetWorkBatchSize(2); + sequence_manager()->AddTaskObserver(&observer); + sequence_manager()->RemoveTaskObserver(&observer); std::vector<EnqueueOrder> run_order; queue->task_runner()->PostTask(FROM_HERE, BindOnce(&TestTask, 1, &run_order)); @@ -1511,25 +1554,25 @@ manager->RemoveTaskObserver(observer); } -TEST_P(SequenceManagerTestWithMessageLoop, TaskObserverRemovingInsideTask) { +TEST_P(SequenceManagerTest, TaskObserverRemovingInsideTask) { auto queue = CreateTaskQueue(); MockTaskObserver observer; - manager_->SetWorkBatchSize(3); - manager_->AddTaskObserver(&observer); + sequence_manager()->SetWorkBatchSize(3); + sequence_manager()->AddTaskObserver(&observer); queue->task_runner()->PostTask( - FROM_HERE, BindOnce(&RemoveObserverTask, manager_.get(), &observer)); + FROM_HERE, BindOnce(&RemoveObserverTask, sequence_manager(), &observer)); EXPECT_CALL(observer, WillProcessTask(_)).Times(1); EXPECT_CALL(observer, DidProcessTask(_)).Times(0); RunLoop().RunUntilIdle(); } -TEST_P(SequenceManagerTestWithMessageLoop, QueueTaskObserverAdding) { - auto queues = CreateTaskQueues(2u); +TEST_P(SequenceManagerTest, QueueTaskObserverAdding) { + auto queues = CreateTaskQueues(2); MockTaskObserver observer; - manager_->SetWorkBatchSize(2); + sequence_manager()->SetWorkBatchSize(2); queues[0]->AddTaskObserver(&observer); std::vector<EnqueueOrder> run_order; @@ -1543,10 +1586,10 @@ RunLoop().RunUntilIdle(); } -TEST_P(SequenceManagerTestWithMessageLoop, QueueTaskObserverRemoving) { +TEST_P(SequenceManagerTest, QueueTaskObserverRemoving) { auto queue = CreateTaskQueue(); MockTaskObserver observer; - manager_->SetWorkBatchSize(2); + sequence_manager()->SetWorkBatchSize(2); queue->AddTaskObserver(&observer); queue->RemoveTaskObserver(&observer); @@ -1564,8 +1607,7 @@ queue->RemoveTaskObserver(observer); } -TEST_P(SequenceManagerTestWithMessageLoop, - QueueTaskObserverRemovingInsideTask) { +TEST_P(SequenceManagerTest, QueueTaskObserverRemovingInsideTask) { auto queue = CreateTaskQueue(); MockTaskObserver observer; queue->AddTaskObserver(&observer); @@ -1836,11 +1878,13 @@ run_loop->Run(); } -TEST_P(SequenceManagerTestWithMessageLoop, QuitWhileNested) { +TEST_P(SequenceManagerTest, QuitWhileNested) { + if (GetParam() == TestType::kMockTaskRunner) + return; // This test makes sure we don't continue running a work batch after a nested // run loop has been exited in the middle of the batch. auto queue = CreateTaskQueue(); - manager_->SetWorkBatchSize(2); + sequence_manager()->SetWorkBatchSize(2); bool was_nested = true; RunLoop run_loop(RunLoop::Type::kNestableTasksAllowed); @@ -2020,7 +2064,7 @@ } // namespace -TEST_P(SequenceManagerTestWithMessageLoop, ShutdownTaskQueueInNestedLoop) { +TEST_P(SequenceManagerTest, ShutdownTaskQueueInNestedLoop) { auto queue = CreateTaskQueue(); // We retain a reference to the task queue even when the manager has deleted @@ -2701,8 +2745,7 @@ } } // namespace -TEST_P(SequenceManagerTestWithMessageLoop, - CurrentlyExecutingTaskQueue_NestedLoop) { +TEST_P(SequenceManagerTest, CurrentlyExecutingTaskQueue_NestedLoop) { auto queues = CreateTaskQueues(3u); TestTaskQueue* queue0 = queues[0].get(); @@ -2714,27 +2757,29 @@ tasks_to_post_from_nested_loop; tasks_to_post_from_nested_loop.push_back( std::make_pair(BindOnce(&CurrentlyExecutingTaskQueueTestTask, - manager_.get(), &task_sources), + sequence_manager(), &task_sources), queue1)); tasks_to_post_from_nested_loop.push_back( std::make_pair(BindOnce(&CurrentlyExecutingTaskQueueTestTask, - manager_.get(), &task_sources), + sequence_manager(), &task_sources), queue2)); queue0->task_runner()->PostTask( FROM_HERE, - BindOnce(&RunloopCurrentlyExecutingTaskQueueTestTask, manager_.get(), + BindOnce(&RunloopCurrentlyExecutingTaskQueueTestTask, sequence_manager(), &task_sources, &tasks_to_post_from_nested_loop)); RunLoop().RunUntilIdle(); - EXPECT_THAT( - task_sources, - ElementsAre(queue0->GetTaskQueueImpl(), queue1->GetTaskQueueImpl(), - queue2->GetTaskQueueImpl(), queue0->GetTaskQueueImpl())); - EXPECT_EQ(nullptr, manager_->currently_executing_task_queue()); + EXPECT_THAT(task_sources, UnorderedElementsAre(queue0->GetTaskQueueImpl(), + queue1->GetTaskQueueImpl(), + queue2->GetTaskQueueImpl(), + queue0->GetTaskQueueImpl())); + EXPECT_EQ(nullptr, sequence_manager()->currently_executing_task_queue()); } -TEST_P(SequenceManagerTestWithMessageLoop, BlameContextAttribution) { +TEST_P(SequenceManagerTest, BlameContextAttribution) { + if (GetParam() == TestType::kMessagePump) + return; using trace_analyzer::Query; auto queue = CreateTaskQueue(); @@ -3153,22 +3198,24 @@ } namespace { -void MessageLoopTaskWithDelayedQuit(SimpleTestTickClock* now_src, +void MessageLoopTaskWithDelayedQuit(Fixture* fixture, scoped_refptr<TestTaskQueue> task_queue) { RunLoop run_loop(RunLoop::Type::kNestableTasksAllowed); task_queue->task_runner()->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(), TimeDelta::FromMilliseconds(100)); - now_src->Advance(TimeDelta::FromMilliseconds(200)); + fixture->AdvanceMockTickClock(TimeDelta::FromMilliseconds(200)); run_loop.Run(); } } // namespace -TEST_P(SequenceManagerTestWithMessageLoop, DelayedTaskRunsInNestedMessageLoop) { +TEST_P(SequenceManagerTest, DelayedTaskRunsInNestedMessageLoop) { + if (GetParam() == TestType::kMockTaskRunner) + return; auto queue = CreateTaskQueue(); RunLoop run_loop; queue->task_runner()->PostTask( - FROM_HERE, BindOnce(&MessageLoopTaskWithDelayedQuit, &mock_clock_, - RetainedRef(queue))); + FROM_HERE, + BindOnce(&MessageLoopTaskWithDelayedQuit, this, RetainedRef(queue))); run_loop.RunUntilIdle(); } @@ -3185,8 +3232,9 @@ } } // namespace -TEST_P(SequenceManagerTestWithMessageLoop, - DelayedNestedMessageLoopDoesntPreventTasksRunning) { +TEST_P(SequenceManagerTest, DelayedNestedMessageLoopDoesntPreventTasksRunning) { + if (GetParam() == TestType::kMockTaskRunner) + return; auto queue = CreateTaskQueue(); RunLoop run_loop; queue->task_runner()->PostDelayedTask( @@ -3195,7 +3243,7 @@ RetainedRef(queue)), TimeDelta::FromMilliseconds(100)); - mock_clock_.Advance(TimeDelta::FromMilliseconds(200)); + AdvanceMockTickClock(TimeDelta::FromMilliseconds(200)); run_loop.Run(); } @@ -3252,9 +3300,23 @@ std::unique_ptr<TaskQueue::QueueEnabledVoter> voter = queue->CreateQueueEnabledVoter(); voter->SetQueueEnabled(false); - EXPECT_EQ(GetParam() == TestType::kUseMessagePump ? TimeDelta::FromDays(1) - : TimeDelta::Max(), - NextPendingTaskDelay()); + + switch (GetParam()) { + case TestType::kMessagePump: + EXPECT_EQ(TimeDelta::FromDays(1), NextPendingTaskDelay()); + break; + + case TestType::kMessageLoop: + EXPECT_EQ(TimeDelta::FromMilliseconds(1), NextPendingTaskDelay()); + break; + + case TestType::kMockTaskRunner: + EXPECT_EQ(TimeDelta::Max(), NextPendingTaskDelay()); + break; + + default: + NOTREACHED(); + } voter->SetQueueEnabled(true); EXPECT_EQ(TimeDelta::FromMilliseconds(1), NextPendingTaskDelay()); @@ -3279,15 +3341,36 @@ EXPECT_EQ(TimeDelta::FromMilliseconds(1), NextPendingTaskDelay()); voter0->SetQueueEnabled(false); - EXPECT_EQ(TimeDelta::FromMilliseconds(10), NextPendingTaskDelay()); + if (GetParam() == TestType::kMessageLoop) { + EXPECT_EQ(TimeDelta::FromMilliseconds(1), NextPendingTaskDelay()); + } else { + EXPECT_EQ(TimeDelta::FromMilliseconds(10), NextPendingTaskDelay()); + } voter1->SetQueueEnabled(false); - EXPECT_EQ(TimeDelta::FromMilliseconds(100), NextPendingTaskDelay()); + if (GetParam() == TestType::kMessageLoop) { + EXPECT_EQ(TimeDelta::FromMilliseconds(1), NextPendingTaskDelay()); + } else { + EXPECT_EQ(TimeDelta::FromMilliseconds(100), NextPendingTaskDelay()); + } voter2->SetQueueEnabled(false); - EXPECT_EQ(GetParam() == TestType::kUseMessagePump ? TimeDelta::FromDays(1) - : TimeDelta::Max(), - NextPendingTaskDelay()); + switch (GetParam()) { + case TestType::kMessagePump: + EXPECT_EQ(TimeDelta::FromDays(1), NextPendingTaskDelay()); + break; + + case TestType::kMessageLoop: + EXPECT_EQ(TimeDelta::FromMilliseconds(1), NextPendingTaskDelay()); + break; + + case TestType::kMockTaskRunner: + EXPECT_EQ(TimeDelta::Max(), NextPendingTaskDelay()); + break; + + default: + NOTREACHED(); + } } TEST_P(SequenceManagerTest, GetNextScheduledWakeUp) { @@ -3600,7 +3683,8 @@ // thread. DestroySequenceManager(); - if (GetParam() != TestType::kUseMessagePump) { + if (GetParam() != TestType::kMessagePump && + GetParam() != TestType::kMessageLoop) { FastForwardUntilNoTasksRemain(); } @@ -3643,7 +3727,8 @@ // Ensure that all queues-to-gracefully-shutdown are properly unregistered. DestroySequenceManager(); - if (GetParam() != TestType::kUseMessagePump) { + if (GetParam() != TestType::kMessagePump && + GetParam() != TestType::kMessageLoop) { FastForwardUntilNoTasksRemain(); } @@ -4174,13 +4259,13 @@ EXPECT_TRUE(destruction_observer_called); } -TEST_P(SequenceManagerTestWithMessageLoop, GetMessagePump) { +TEST_P(SequenceManagerTest, GetMessagePump) { switch (GetParam()) { default: - EXPECT_THAT(manager_->GetMessagePump(), testing::IsNull()); + EXPECT_THAT(sequence_manager()->GetMessagePump(), testing::IsNull()); break; - case TestType::kUseMessagePump: - EXPECT_THAT(manager_->GetMessagePump(), testing::NotNull()); + case TestType::kMessagePump: + EXPECT_THAT(sequence_manager()->GetMessagePump(), testing::NotNull()); break; } } @@ -4215,8 +4300,8 @@ } // namespace -TEST_P(SequenceManagerTestWithMessageLoop, OnSystemIdleTimeDomainNotification) { - if (GetParam() != TestType::kUseMessagePump) +TEST_P(SequenceManagerTest, OnSystemIdleTimeDomainNotification) { + if (GetParam() != TestType::kMessagePump) return; auto queue = CreateTaskQueue(); @@ -4225,11 +4310,11 @@ // to MaybeFastForwardToNextTask. If no run loop has requested quit on idle, // the parameter passed in should be false. StrictMock<MockTimeDomain> mock_time_domain; - manager_->RegisterTimeDomain(&mock_time_domain); + sequence_manager()->RegisterTimeDomain(&mock_time_domain); EXPECT_CALL(mock_time_domain, MaybeFastForwardToNextTask(false)) .WillOnce(Return(false)); - manager_->OnSystemIdle(); - manager_->UnregisterTimeDomain(&mock_time_domain); + sequence_manager()->OnSystemIdle(); + sequence_manager()->UnregisterTimeDomain(&mock_time_domain); Mock::VerifyAndClearExpectations(&mock_time_domain); // However if RunUntilIdle is called it should be true. @@ -4238,9 +4323,9 @@ StrictMock<MockTimeDomain> mock_time_domain; EXPECT_CALL(mock_time_domain, MaybeFastForwardToNextTask(true)) .WillOnce(Return(false)); - manager_->RegisterTimeDomain(&mock_time_domain); - manager_->OnSystemIdle(); - manager_->UnregisterTimeDomain(&mock_time_domain); + sequence_manager()->RegisterTimeDomain(&mock_time_domain); + sequence_manager()->OnSystemIdle(); + sequence_manager()->UnregisterTimeDomain(&mock_time_domain); })); RunLoop().RunUntilIdle();
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 4414659..936b1bb 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -688f2ce0afdcc2bb7537b99790ef273c65eeefd2 \ No newline at end of file +3b01f76cec3e1be290b0cff261ebd1bcb429e61d \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 6f2664af..03c66092 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -4a90784d62733367a977d7c65593b3aef019a741 \ No newline at end of file +2f2a8092ed00985040b8635d51324ef19791f342 \ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION index a3beede..b1489d7 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=74 MINOR=0 -BUILD=3706 +BUILD=3707 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java index 0ebec871..3b95b179 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -688,6 +688,7 @@ @Override public void onBottomControlsHeightChanged(int bottomControlsHeight) { if (mTabVisible == null) return; + mTabVisible.setBottomControlsHeight(bottomControlsHeight); Point viewportSize = getViewportSize(); setSize(mTabVisible.getWebContents(), mTabVisible.getContentView(), viewportSize.x, viewportSize.y); @@ -696,6 +697,7 @@ @Override public void onTopControlsHeightChanged(int topControlsHeight, boolean controlsResizeView) { if (mTabVisible == null) return; + mTabVisible.setTopControlsHeight(topControlsHeight, controlsResizeView); Point viewportSize = getViewportSize(); setSize(mTabVisible.getWebContents(), mTabVisible.getContentView(), viewportSize.x, viewportSize.y); @@ -1074,6 +1076,8 @@ webContents, mCompositorView.getWidth(), mCompositorView.getHeight()); } if (tab.getView() == null) return; + tab.setTopControlsHeight(getTopControlsHeightPixels(), controlsResizeView()); + tab.setBottomControlsHeight(getBottomControlsHeightPixels()); // TextView with compound drawables in the NTP gets a wrong width when measure/layout is // performed in the unattached state. Delay the layout till #onLayoutChange().
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java index 246f67b..4e87d81 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
@@ -498,6 +498,10 @@ } mControlsResizeView = controlsResizeView; + Tab tab = getTab(); + if (tab == null) return; + tab.setTopControlsHeight(getTopControlsHeight(), controlsResizeView); + tab.setBottomControlsHeight(getBottomControlsHeight()); for (FullscreenListener listener : mListeners) listener.onUpdateViewportSize(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java index 0de0d97..3debaed 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -354,6 +354,10 @@ /** Whether or not the tab closing the tab can send the user back to the app that opened it. */ private boolean mIsAllowedToReturnToExternalApp; + private int mTopControlsHeight; + private int mBottomControlsHeight; + private boolean mControlsResizeView; + /** * The publisher URL for pages hosted on a trusted CDN, or null otherwise. */ @@ -2367,6 +2371,27 @@ return constraints; } + public void setTopControlsHeight(int height, boolean controlsResizeView) { + mTopControlsHeight = height; + mControlsResizeView = controlsResizeView; + } + + public void setBottomControlsHeight(int height) { + mBottomControlsHeight = height; + } + + int getTopControlsHeight() { + return mTopControlsHeight; + } + + int getBottomControlsHeight() { + return mBottomControlsHeight; + } + + boolean controlsResizeView() { + return mControlsResizeView; + } + /** * @param manager The fullscreen manager that should be notified of changes to this tab (if * set to null, no more updates will come from this tab).
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java index f0fb9e0..fe3fa515 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
@@ -34,8 +34,6 @@ import org.chromium.chrome.browser.document.DocumentWebContentsDelegate; import org.chromium.chrome.browser.findinpage.FindMatchRectsDetails; import org.chromium.chrome.browser.findinpage.FindNotificationDetails; -import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; -import org.chromium.chrome.browser.fullscreen.FullscreenManager; import org.chromium.chrome.browser.fullscreen.FullscreenOptions; import org.chromium.chrome.browser.media.MediaCaptureNotificationService; import org.chromium.chrome.browser.policy.PolicyAuditor; @@ -525,20 +523,17 @@ @Override public int getTopControlsHeight() { - FullscreenManager manager = mTab.getFullscreenManager(); - return manager != null ? manager.getTopControlsHeight() : 0; + return mTab.getTopControlsHeight(); } @Override public int getBottomControlsHeight() { - FullscreenManager manager = mTab.getFullscreenManager(); - return manager != null ? manager.getBottomControlsHeight() : 0; + return mTab.getBottomControlsHeight(); } @Override public boolean controlsResizeView() { - FullscreenManager manager = mTab.getFullscreenManager(); - return manager != null ? ((ChromeFullscreenManager) manager).controlsResizeView() : false; + return mTab.controlsResizeView(); } /**
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index db8e4de7..0c43c470 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-74.0.3705.0_rc-r1-merged.afdo.bz2 \ No newline at end of file +chromeos-chrome-amd64-74.0.3706.0_rc-r1-merged.afdo.bz2 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 974dbfa..97771c1 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -3542,6 +3542,32 @@ No description is available. </message> + <!-- Crostini export and import --> + <message name="IDS_CROSTINI_EXPORT_TITLE" desc="Title for exporting (backing up) the crostini container."> + Backup + </message> + <message name="IDS_CROSTINI_EXPORT_NOTIFICATION_IN_PROGRESS" desc="Message displayed while export is in progress in the notification for exporting (backing up) the crostini container."> + Backup up... + </message> + <message name="IDS_CROSTINI_EXPORT_NOTIFICATION_DONE" desc="Message displayed when done in the notification for exporting (backing up) the crostini container."> + Backup complete + </message> + <message name="IDS_CROSTINI_EXPORT_NOTIFICATION_FAILED" desc="Message displayed when there is a failure in the notification for exporting (backing up) the crostini container."> + Backup failed + </message> + <message name="IDS_CROSTINI_IMPORT_TITLE" desc="Title for importing (restoring) the crostini container."> + Restore + </message> + <message name="IDS_CROSTINI_IMPORT_NOTIFICATION_IN_PROGRESS" desc="Message displayed while import is in progress in the notification for importing (restoring) the crostini container."> + Restoring... + </message> + <message name="IDS_CROSTINI_IMPORT_NOTIFICATION_DONE" desc="Message displayed when done in the notification for importing (restoring) the crostini container."> + Restore complete + </message> + <message name="IDS_CROSTINI_IMPORT_NOTIFICATION_FAILED" desc="Message displayed when there is a failure in the notification for importing (restoring) the crostini container."> + Restore failed + </message> + <!-- Time limit notification --> <message name="IDS_SCREEN_TIME_NOTIFICATION_TITLE" desc="The title of the notification when screen usage limit reaches before locking the device."> Almost time for a break
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_DONE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_DONE.png.sha1 new file mode 100644 index 0000000..afd7bd82 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_DONE.png.sha1
@@ -0,0 +1 @@ +f4d76e1c540780ba80e4b6568367695c93d73f68 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_FAILED.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_FAILED.png.sha1 new file mode 100644 index 0000000..afd7bd82 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_FAILED.png.sha1
@@ -0,0 +1 @@ +f4d76e1c540780ba80e4b6568367695c93d73f68 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_IN_PROGRESS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_IN_PROGRESS.png.sha1 new file mode 100644 index 0000000..afd7bd82 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_IN_PROGRESS.png.sha1
@@ -0,0 +1 @@ +f4d76e1c540780ba80e4b6568367695c93d73f68 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_TITLE.png.sha1 new file mode 100644 index 0000000..afd7bd82 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_TITLE.png.sha1
@@ -0,0 +1 @@ +f4d76e1c540780ba80e4b6568367695c93d73f68 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_DONE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_DONE.png.sha1 new file mode 100644 index 0000000..bceb036 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_DONE.png.sha1
@@ -0,0 +1 @@ +67a7f5b5f40ee10862fdb1ce486f99f99812a5cf \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_FAILED.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_FAILED.png.sha1 new file mode 100644 index 0000000..bceb036 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_FAILED.png.sha1
@@ -0,0 +1 @@ +67a7f5b5f40ee10862fdb1ce486f99f99812a5cf \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_IN_PROGRESS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_IN_PROGRESS.png.sha1 new file mode 100644 index 0000000..bceb036 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_IN_PROGRESS.png.sha1
@@ -0,0 +1 @@ +67a7f5b5f40ee10862fdb1ce486f99f99812a5cf \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_TITLE.png.sha1 new file mode 100644 index 0000000..bceb036 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_TITLE.png.sha1
@@ -0,0 +1 @@ +67a7f5b5f40ee10862fdb1ce486f99f99812a5cf \ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index d31b79b..f4e05359 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -5688,6 +5688,9 @@ <message name="IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes next track action."> Next track </message> + <message name="IDS_PICTURE_IN_PICTURE_PREVIOUS_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes previous track action."> + Previous track + </message> <message name="IDS_PICTURE_IN_PICTURE_CONFIRM_CLOSE_TITLE" desc="Text label of the title for the confirmation dialog. This dialog appears when the user tries to close a tab / window while in Picture-in-Picture mode."> Are you sure you want to close this tab? </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index d685680a..d4226ab 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -521,6 +521,21 @@ <message name="IDS_SETTINGS_CROSTINI_SHARED_PATHS_REMOVE_SHARING" desc="Tooltip to show when hovering on the remove icon for a crostini shared folder."> Remove sharing </message> + <message name="IDS_SETTINGS_CROSTINI_EXPORT_IMPORT_TITLE" desc="Title for crostini container export and imoprt (backup and restore) section"> + Backup & restore + </message> + <message name="IDS_SETTINGS_CROSTINI_EXPORT" desc="Tile for exporting (backing up) the crostini container."> + Backup + </message> + <message name="IDS_SETTINGS_CROSTINI_EXPORT_LABEL" desc="Description shown next to the button to export (backup) Crostini."> + Backup Linux apps and files + </message> + <message name="IDS_SETTINGS_CROSTINI_IMPORT" desc="Title for importing (restoring) the crostini container."> + Restore + </message> + <message name="IDS_SETTINGS_CROSTINI_IMPORT_LABEL" desc="Description shown next to the button to import (restore) Crostini."> + Replace your Linux apps and files with a previous backup + </message> <message name="IDS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_LABEL" desc="Label for managing shared USB devices."> USB Device preferences </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_EXPORT.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_EXPORT.png.sha1 new file mode 100644 index 0000000..e81d0cb --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_EXPORT.png.sha1
@@ -0,0 +1 @@ +15fd0f16293c47a24987f389ceb4a76dbb775206 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_EXPORT_IMPORT_TITLE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_EXPORT_IMPORT_TITLE.png.sha1 new file mode 100644 index 0000000..e81d0cb --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_EXPORT_IMPORT_TITLE.png.sha1
@@ -0,0 +1 @@ +15fd0f16293c47a24987f389ceb4a76dbb775206 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_EXPORT_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_EXPORT_LABEL.png.sha1 new file mode 100644 index 0000000..e81d0cb --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_EXPORT_LABEL.png.sha1
@@ -0,0 +1 @@ +15fd0f16293c47a24987f389ceb4a76dbb775206 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_IMPORT.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_IMPORT.png.sha1 new file mode 100644 index 0000000..e81d0cb --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_IMPORT.png.sha1
@@ -0,0 +1 @@ +15fd0f16293c47a24987f389ceb4a76dbb775206 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_IMPORT_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_IMPORT_LABEL.png.sha1 new file mode 100644 index 0000000..e81d0cb --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CROSTINI_IMPORT_LABEL.png.sha1
@@ -0,0 +1 @@ +15fd0f16293c47a24987f389ceb4a76dbb775206 \ No newline at end of file
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn index 46462167..a5663fe 100644 --- a/chrome/app/vector_icons/BUILD.gn +++ b/chrome/app/vector_icons/BUILD.gn
@@ -58,6 +58,7 @@ "google_pay_logo.icon", "horizontal_menu.icon", "incognito.icon", + "incognito_profile.icon", "input.icon", "key.icon", "laptop.icon",
diff --git a/chrome/app/vector_icons/incognito_profile.icon b/chrome/app/vector_icons/incognito_profile.icon new file mode 100644 index 0000000..060d9f7 --- /dev/null +++ b/chrome/app/vector_icons/incognito_profile.icon
@@ -0,0 +1,48 @@ +// 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. +// This icon has a bigger circle to figure ratio in compare to incognito.icon. + +CANVAS_DIMENSIONS, 40, +CIRCLE, 20, 20, 20, +MOVE_TO, 16.51f, 11.29f, +R_CUBIC_TO, 0.26f, 0.13f, 2.39f, 0.49f, 2.39f, 0.49f, +R_CUBIC_TO, 0, 0, 4.68f, -0.68f, 4.85f, -0.72f, +R_CUBIC_TO, 0.11f, -0.03f, 0.16f, 0.03f, 0.19f, 0.11f, +R_CUBIC_TO, 0.01f, 0.05f, 0.81f, 2.65f, 1.48f, 4.83f, +R_H_LINE_TO, -10.82f, +R_ARC_TO, 951.85f, 951.85f, 0, 0, 0, 1.54f, -4.61f, +R_CUBIC_TO, 0.04f, -0.14f, 0.18f, -0.19f, 0.38f, -0.1f, +CLOSE, +MOVE_TO, 23.84f, 27.05f, +R_CUBIC_TO, -1.7f, 0, -3.08f, -1.37f, -3.08f, -3.05f, +R_CUBIC_TO, 0, -0.09f, 0, -0.18f, 0.01f, -0.27f, +R_ARC_TO, 2.63f, 2.63f, 0, 0, 0, -1.64f, 0.01f, +R_CUBIC_TO, 0.01f, 0.08f, 0.01f, 0.17f, 0.01f, 0.25f, +R_CUBIC_TO, 0, 1.69f, -1.38f, 3.05f, -3.08f, 3.05f, +R_CUBIC_TO, -1.7f, 0, -3.08f, -1.37f, -3.08f, -3.05f, +R_CUBIC_TO, 0, -1.68f, 1.38f, -3.05f, 3.08f, -3.05f, +R_CUBIC_TO, 1.29f, 0, 2.39f, 0.78f, 2.85f, 1.89f, +R_ARC_TO, 3.58f, 3.58f, 0, 0, 1, 2.08f, -0.01f, +R_LINE_TO, 0, 0, +R_ARC_TO, 3.08f, 3.08f, 0, 0, 1, 2.84f, -1.88f, +R_CUBIC_TO, 1.7f, 0, 3.08f, 1.37f, 3.08f, 3.05f, +CUBIC_TO_SHORTHAND, 25.54f, 27.05f, 23.84f, 27.05f, +CLOSE, +R_MOVE_TO, 0, -5.22f, +R_ARC_TO, 2.18f, 2.18f, 0, 0, 0, -2.19f, 2.17f, +R_CUBIC_TO, 0, 1.2f, 0.98f, 2.17f, 2.19f, 2.17f, +R_ARC_TO, 2.18f, 2.18f, 0, 0, 0, 2.19f, -2.17f, +R_ARC_TO, 2.18f, 2.18f, 0, 0, 0, -2.19f, -2.17f, +CLOSE, +R_MOVE_TO, -7.77f, 0, +R_ARC_TO, 2.18f, 2.18f, 0, 0, 0, -2.19f, 2.17f, +R_CUBIC_TO, 0, 1.2f, 0.98f, 2.17f, 2.19f, 2.17f, +R_ARC_TO, 2.18f, 2.18f, 0, 0, 0, 2.19f, -2.17f, +R_ARC_TO, 2.18f, 2.18f, 0, 0, 0, -2.19f, -2.17f, +CLOSE, +R_MOVE_TO, 3.92f, -3.98f, +CUBIC_TO, 26.03f, 17.85f, 30, 20, 30, 20, +H_LINE_TO, 10, +R_CUBIC_TO, 0, 0, 3.95f, -2.15f, 9.99f, -2.15f, +CLOSE
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 3c50c39..9f460eeb 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -127,6 +127,7 @@ #include "services/network/public/cpp/network_switches.h" #include "services/resource_coordinator/public/cpp/resource_coordinator_features.h" #include "services/service_manager/sandbox/switches.h" +#include "storage/browser/fileapi/file_system_features.h" #include "third_party/blink/public/common/experiments/memory_ablation_experiment.h" #include "third_party/blink/public/common/features.h" #include "third_party/leveldatabase/leveldb_features.h" @@ -1707,9 +1708,6 @@ {"gesture-typing", flag_descriptions::kGestureTypingName, flag_descriptions::kGestureTypingDescription, kOsCrOS, SINGLE_DISABLE_VALUE_TYPE(keyboard::switches::kDisableGestureTyping)}, - {"gesture-editing", flag_descriptions::kGestureEditingName, - flag_descriptions::kGestureEditingDescription, kOsCrOS, - SINGLE_DISABLE_VALUE_TYPE(keyboard::switches::kDisableGestureEditing)}, #endif // OS_CHROMEOS #if BUILDFLAG(ENABLE_SERVICE_DISCOVERY) {"device-discovery-notifications", @@ -4078,6 +4076,11 @@ flag_descriptions::kEnableBlinkHeapUnifiedGarbageCollectionDescription, kOsAll, FEATURE_VALUE_TYPE(features::kBlinkHeapUnifiedGarbageCollection)}, + {"enable-filesystem-in-incognito", + flag_descriptions::kEnableFilesystemInIncognitoName, + flag_descriptions::kEnableFilesystemInIncognitoDescription, kOsAll, + FEATURE_VALUE_TYPE(storage::features::kEnableFilesystemInIncognito)}, + {"enable-incognito-window-counter", flag_descriptions::kEnableIncognitoWindowCounterName, flag_descriptions::kEnableIncognitoWindowCounterDescription, kOsDesktop,
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index e8dba9c..80b45e9 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -245,6 +245,8 @@ <include name="IDR_APP_MANAGEMENT_CHROME_APP_PERMISSION_VIEW_JS" file="resources\app_management\chrome_app_permission_view.js" type="BINDATA"/> <include name="IDR_APP_MANAGEMENT_CONSTANTS_HTML" file="resources\app_management\constants.html" type="BINDATA"/> <include name="IDR_APP_MANAGEMENT_CONSTANTS_JS" file="resources\app_management\constants.js" type="BINDATA"/> + <include name="IDR_APP_MANAGEMENT_EXPANDABLE_APP_LIST_HTML" file="resources\app_management\expandable_app_list.html" type="BINDATA"/> + <include name="IDR_APP_MANAGEMENT_EXPANDABLE_APP_LIST_JS" file="resources\app_management\expandable_app_list.js" type="BINDATA"/> <include name="IDR_APP_MANAGEMENT_DOM_SWITCH_HTML" file="resources\app_management\dom_switch.html" type="BINDATA"/> <include name="IDR_APP_MANAGEMENT_DOM_SWITCH_JS" file="resources\app_management\dom_switch.js" type="BINDATA"/> <include name="IDR_APP_MANAGEMENT_FAKE_PAGE_HANDLER_JS" file="resources\app_management\fake_page_handler.js" type="BINDATA" />
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 54125ae..ddb1759b 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -646,6 +646,10 @@ "chrome_content_browser_client_chromeos_part.h", "chrome_service_name.cc", "chrome_service_name.h", + "crostini/crostini_export_import.cc", + "crostini/crostini_export_import.h", + "crostini/crostini_export_import_notification.cc", + "crostini/crostini_export_import_notification.h", "crostini/crostini_manager.cc", "crostini/crostini_manager.h", "crostini/crostini_manager_factory.cc", @@ -2216,6 +2220,7 @@ "child_accounts/time_limit_test_utils.cc", "child_accounts/usage_time_limit_processor_unittest.cc", "child_accounts/usage_time_state_notifier_unittest.cc", + "crostini/crostini_export_import_unittest.cc", "crostini/crostini_manager_unittest.cc", "crostini/crostini_package_service_unittest.cc", "crostini/crostini_share_path_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc index abe34ec8..a48a691 100644 --- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc +++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
@@ -99,4 +99,8 @@ // Should be a no-op on ARC. This is managed on the Android side. } +void ArcPictureInPictureWindowControllerImpl::PreviousTrack() { + // Should be a no-op on ARC. This is managed on the Android side. +} + } // namespace arc
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h index 00f6e12..2af214a 100644 --- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h +++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
@@ -52,6 +52,7 @@ void SetAlwaysHidePlayPauseButton(bool is_visible) override; void SkipAd() override; void NextTrack() override; + void PreviousTrack() override; private: arc::ArcPipBridge* const arc_pip_bridge_;
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.cc b/chrome/browser/chromeos/crostini/crostini_export_import.cc new file mode 100644 index 0000000..51298074 --- /dev/null +++ b/chrome/browser/chromeos/crostini/crostini_export_import.cc
@@ -0,0 +1,303 @@ +// 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. + +#include "chrome/browser/chromeos/crostini/crostini_export_import.h" + +#include "base/bind.h" +#include "base/strings/stringprintf.h" +#include "base/time/time.h" +#include "chrome/browser/chromeos/crostini/crostini_manager_factory.h" +#include "chrome/browser/chromeos/crostini/crostini_share_path.h" +#include "chrome/browser/chromeos/crostini/crostini_share_path_factory.h" +#include "chrome/browser/chromeos/crostini/crostini_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/chrome_select_file_policy.h" +#include "chrome/common/pref_names.h" +#include "chrome/grit/generated_resources.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/web_contents.h" +#include "ui/base/l10n/l10n_util.h" + +namespace crostini { + +class CrostiniExportImportFactory : public BrowserContextKeyedServiceFactory { + public: + static CrostiniExportImport* GetForProfile(Profile* profile) { + return static_cast<CrostiniExportImport*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); + } + + static CrostiniExportImportFactory* GetInstance() { + static base::NoDestructor<CrostiniExportImportFactory> factory; + return factory.get(); + } + + private: + friend class base::NoDestructor<CrostiniExportImportFactory>; + + CrostiniExportImportFactory() + : BrowserContextKeyedServiceFactory( + "CrostiniExportImportService", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(CrostiniSharePathFactory::GetInstance()); + DependsOn(CrostiniManagerFactory::GetInstance()); + } + + ~CrostiniExportImportFactory() override = default; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override { + Profile* profile = Profile::FromBrowserContext(context); + return new CrostiniExportImport(profile); + } +}; + +CrostiniExportImport* CrostiniExportImport::GetForProfile(Profile* profile) { + return CrostiniExportImportFactory::GetForProfile(profile); +} + +CrostiniExportImport::CrostiniExportImport(Profile* profile) + : profile_(profile), weak_ptr_factory_(this) { + CrostiniManager* manager = CrostiniManager::GetForProfile(profile_); + manager->AddExportContainerProgressObserver(this); + manager->AddImportContainerProgressObserver(this); +} + +CrostiniExportImport::~CrostiniExportImport() = default; + +void CrostiniExportImport::Shutdown() { + CrostiniManager* manager = CrostiniManager::GetForProfile(profile_); + manager->RemoveExportContainerProgressObserver(this); + manager->RemoveImportContainerProgressObserver(this); +} + +void CrostiniExportImport::ExportContainer(content::WebContents* web_contents) { + if (!IsCrostiniExportImportUIAllowedForProfile(profile_)) { + return; + } + OpenFileDialog(ExportImportType::EXPORT, web_contents); +} + +void CrostiniExportImport::ImportContainer(content::WebContents* web_contents) { + if (!IsCrostiniExportImportUIAllowedForProfile(profile_)) { + return; + } + OpenFileDialog(ExportImportType::IMPORT, web_contents); +} + +void CrostiniExportImport::OpenFileDialog(ExportImportType type, + content::WebContents* web_contents) { + PrefService* pref_service = profile_->GetPrefs(); + ui::SelectFileDialog::Type file_selector_mode; + unsigned title = 0; + base::FilePath default_path; + ui::SelectFileDialog::FileTypeInfo file_types; + file_types.allowed_paths = + ui::SelectFileDialog::FileTypeInfo::NATIVE_OR_DRIVE_PATH; + file_types.extensions = {{"tar.gz", "tgz"}}; + + switch (type) { + case ExportImportType::EXPORT: + file_selector_mode = ui::SelectFileDialog::SELECT_SAVEAS_FILE; + title = IDS_CROSTINI_EXPORT_TITLE; + base::Time::Exploded exploded; + base::Time::Now().LocalExplode(&exploded); + default_path = pref_service->GetFilePath(prefs::kDownloadDefaultDirectory) + .Append(base::StringPrintf( + "crostini-%04d-%02d-%02d.tar.gz", exploded.year, + exploded.month, exploded.day_of_month)); + break; + case ExportImportType::IMPORT: + file_selector_mode = ui::SelectFileDialog::SELECT_OPEN_FILE, + title = IDS_CROSTINI_IMPORT_TITLE; + default_path = + pref_service->GetFilePath(prefs::kDownloadDefaultDirectory); + break; + } + + select_folder_dialog_ = ui::SelectFileDialog::Create( + this, std::make_unique<ChromeSelectFilePolicy>(web_contents)); + select_folder_dialog_->SelectFile( + file_selector_mode, l10n_util::GetStringUTF16(title), default_path, + &file_types, 0, base::FilePath::StringType(), + web_contents->GetTopLevelNativeWindow(), reinterpret_cast<void*>(type)); +} + +void CrostiniExportImport::FileSelected(const base::FilePath& path, + int index, + void* params) { + ExportImportType type = + static_cast<ExportImportType>(reinterpret_cast<uintptr_t>(params)); + ContainerId container_id(crostini::kCrostiniDefaultVmName, + crostini::kCrostiniDefaultContainerName); + notifications_[container_id] = + std::make_unique<CrostiniExportImportNotification>( + profile_, type, GetUniqueNotificationId(), path); + + switch (type) { + case ExportImportType::EXPORT: + crostini::CrostiniSharePath::GetForProfile(profile_)->SharePath( + crostini::kCrostiniDefaultVmName, path.DirName(), false, + base::BindOnce(&CrostiniExportImport::ExportAfterSharing, + weak_ptr_factory_.GetWeakPtr(), container_id, + path.BaseName())); + break; + case ExportImportType::IMPORT: + crostini::CrostiniSharePath::GetForProfile(profile_)->SharePath( + crostini::kCrostiniDefaultVmName, path, false, + base::BindOnce(&CrostiniExportImport::ImportAfterSharing, + weak_ptr_factory_.GetWeakPtr(), container_id)); + break; + } +} + +void CrostiniExportImport::ExportAfterSharing( + const ContainerId& container_id, + const base::FilePath& filename, + const base::FilePath& container_path, + bool result, + const std::string failure_reason) { + if (!result) { + LOG(ERROR) << "Error sharing for export " << container_path.value() << ": " + << failure_reason; + auto it = notifications_.find(container_id); + DCHECK(it != notifications_.end()) << ContainerIdToString(container_id) + << " has no notification to update"; + it->second->UpdateStatus(CrostiniExportImportNotification::Status::FAILED, + 0); + return; + } + CrostiniManager::GetForProfile(profile_)->ExportLxdContainer( + crostini::kCrostiniDefaultVmName, crostini::kCrostiniDefaultContainerName, + container_path.Append(filename), + base::BindOnce(&CrostiniExportImport::OnExportComplete, + weak_ptr_factory_.GetWeakPtr(), container_id)); +} + +void CrostiniExportImport::OnExportComplete(const ContainerId& container_id, + CrostiniResult result) { + auto it = notifications_.find(container_id); + DCHECK(it != notifications_.end()) + << ContainerIdToString(container_id) << " has no notification to update"; + + if (result != crostini::CrostiniResult::SUCCESS) { + LOG(ERROR) << "Error exporting " << int(result); + it->second->UpdateStatus(CrostiniExportImportNotification::Status::FAILED, + 0); + } else { + it->second->UpdateStatus(CrostiniExportImportNotification::Status::DONE, 0); + } + notifications_.erase(it); +} + +void CrostiniExportImport::OnExportContainerProgress( + const std::string& vm_name, + const std::string& container_name, + crostini::ExportContainerProgressStatus status, + int progress_percent, + uint64_t progress_speed) { + ContainerId container_id(vm_name, container_name); + auto it = notifications_.find(container_id); + DCHECK(it != notifications_.end()) + << ContainerIdToString(container_id) << " has no notification to update"; + + switch (status) { + // Rescale PACK:1-100 => 0-50. + case crostini::ExportContainerProgressStatus::PACK: + it->second->UpdateStatus( + CrostiniExportImportNotification::Status::RUNNING, + progress_percent / 2); + break; + // Rescale DOWNLOAD:1-100 => 50-100. + case crostini::ExportContainerProgressStatus::DOWNLOAD: + it->second->UpdateStatus( + CrostiniExportImportNotification::Status::RUNNING, + 50 + progress_percent / 2); + break; + default: + LOG(WARNING) << "Unknown Export progress status " << int(status); + } +} + +void CrostiniExportImport::ImportAfterSharing( + const ContainerId& container_id, + const base::FilePath& container_path, + bool result, + const std::string failure_reason) { + if (!result) { + LOG(ERROR) << "Error sharing for import " << container_path.value() << ": " + << failure_reason; + auto it = notifications_.find(container_id); + DCHECK(it != notifications_.end()) << ContainerIdToString(container_id) + << " has no notification to update"; + it->second->UpdateStatus(CrostiniExportImportNotification::Status::FAILED, + 0); + return; + } + CrostiniManager::GetForProfile(profile_)->ImportLxdContainer( + crostini::kCrostiniDefaultVmName, crostini::kCrostiniDefaultContainerName, + container_path, + base::BindOnce(&CrostiniExportImport::OnImportComplete, + weak_ptr_factory_.GetWeakPtr(), container_id)); +} + +void CrostiniExportImport::OnImportComplete(const ContainerId& container_id, + CrostiniResult result) { + auto it = notifications_.find(container_id); + DCHECK(it != notifications_.end()) + << ContainerIdToString(container_id) << " has no notification to update"; + if (result != crostini::CrostiniResult::SUCCESS) { + LOG(ERROR) << "Error importing " << int(result); + it->second->UpdateStatus(CrostiniExportImportNotification::Status::FAILED, + 0); + } else { + it->second->UpdateStatus(CrostiniExportImportNotification::Status::DONE, 0); + } + notifications_.erase(it); +} + +void CrostiniExportImport::OnImportContainerProgress( + const std::string& vm_name, + const std::string& container_name, + crostini::ImportContainerProgressStatus status, + int progress_percent, + uint64_t progress_speed) { + ContainerId container_id(vm_name, container_name); + auto it = notifications_.find(container_id); + DCHECK(it != notifications_.end()) + << ContainerIdToString(container_id) << " has no notification to update"; + + switch (status) { + // Rescale UPLOAD:1-100 => 0-50. + case crostini::ImportContainerProgressStatus::UPLOAD: + it->second->UpdateStatus( + CrostiniExportImportNotification::Status::RUNNING, + progress_percent / 2); + break; + // Rescale UNPACK:1-100 => 50-100. + case crostini::ImportContainerProgressStatus::UNPACK: + it->second->UpdateStatus( + CrostiniExportImportNotification::Status::RUNNING, + 50 + progress_percent / 2); + break; + default: + LOG(WARNING) << "Unknown Export progress status " << int(status); + } +} + +std::string CrostiniExportImport::GetUniqueNotificationId() { + return base::StringPrintf("crostini_export_import_%d", + next_notification_id_++); +} + +CrostiniExportImportNotification* +CrostiniExportImport::GetNotificationForTesting(ContainerId container_id) { + auto it = notifications_.find(container_id); + return it != notifications_.end() ? it->second.get() : nullptr; +} + +} // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.h b/chrome/browser/chromeos/crostini/crostini_export_import.h new file mode 100644 index 0000000..12f792e --- /dev/null +++ b/chrome/browser/chromeos/crostini/crostini_export_import.h
@@ -0,0 +1,114 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_EXPORT_IMPORT_H_ +#define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_EXPORT_IMPORT_H_ + +#include <map> +#include <memory> +#include <string> + +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/crostini/crostini_export_import_notification.h" +#include "chrome/browser/chromeos/crostini/crostini_manager.h" +#include "components/keyed_service/core/keyed_service.h" + +class Profile; + +namespace content { +class WebContents; +} + +namespace crostini { + +enum class CrostiniResult; + +enum class ExportImportType { EXPORT, IMPORT }; + +// CrostiniExportImport is a keyed profile service to manage exporting and +// importing containers with crostini. It manages a file dialog for selecting +// files and a notification to show the progress of export/import. +// +// TODO(crbug.com/932339): Ensure we have enough free space before doing +// backup or restore. +class CrostiniExportImport : public KeyedService, + public ui::SelectFileDialog::Listener, + public crostini::ExportContainerProgressObserver, + public crostini::ImportContainerProgressObserver { + public: + static CrostiniExportImport* GetForProfile(Profile* profile); + + explicit CrostiniExportImport(Profile* profile); + ~CrostiniExportImport() override; + + // KeyedService: + void Shutdown() override; + + // Export the crostini container. + void ExportContainer(content::WebContents* web_contents); + // Import the crostini container. + void ImportContainer(content::WebContents* web_contents); + + CrostiniExportImportNotification* GetNotificationForTesting( + ContainerId container_id); + + private: + FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestExportSuccess); + FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestExportFail); + FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportSuccess); + FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportFail); + + // ui::SelectFileDialog::Listener implementation. + void FileSelected(const base::FilePath& path, + int index, + void* params) override; + + // crostini::ExportContainerProgressObserver implementation. + void OnExportContainerProgress(const std::string& vm_name, + const std::string& container_name, + crostini::ExportContainerProgressStatus status, + int progress_percent, + uint64_t progress_speed) override; + + // crostini::ImportContainerProgressObserver implementation. + void OnImportContainerProgress(const std::string& vm_name, + const std::string& container_name, + crostini::ImportContainerProgressStatus status, + int progress_percent, + uint64_t progress_speed) override; + + void ExportAfterSharing(const ContainerId& container_id, + const base::FilePath& filename, + const base::FilePath& container_path, + bool result, + const std::string failure_reason); + void OnExportComplete(const ContainerId& container_id, CrostiniResult result); + + void ImportAfterSharing(const ContainerId& container_id, + const base::FilePath& container_path, + bool result, + const std::string failure_reason); + void OnImportComplete(const ContainerId& container_id, CrostiniResult result); + + void OpenFileDialog(ExportImportType type, + content::WebContents* web_contents); + + std::string GetUniqueNotificationId(); + + Profile* profile_; + scoped_refptr<ui::SelectFileDialog> select_folder_dialog_; + std::map<ContainerId, std::unique_ptr<CrostiniExportImportNotification>> + notifications_; + // Notifications must have unique-per-profile identifiers. + // A non-static member on a profile-keyed-service will suffice. + int next_notification_id_; + // weak_ptr_factory_ should always be last member. + base::WeakPtrFactory<CrostiniExportImport> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(CrostiniExportImport); +}; + +} // namespace crostini + +#endif // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_EXPORT_IMPORT_H_
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc b/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc new file mode 100644 index 0000000..6af4316 --- /dev/null +++ b/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc
@@ -0,0 +1,119 @@ +// 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. + +#include "chrome/browser/chromeos/crostini/crostini_export_import_notification.h" + +#include "ash/public/cpp/notification_utils.h" +#include "ash/public/cpp/vector_icons/vector_icons.h" +#include "chrome/browser/chromeos/crostini/crostini_export_import.h" +#include "chrome/browser/notifications/notification_display_service.h" +#include "chrome/browser/platform_util_chromeos.cc" +#include "chrome/browser/profiles/profile.h" +#include "chrome/grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_delegate.h" + +namespace crostini { + +namespace { + +constexpr char kNotifierCrostiniExportImportOperation[] = + "crostini.export_operation"; + +} // namespace + +CrostiniExportImportNotification::CrostiniExportImportNotification( + Profile* profile, + ExportImportType type, + const std::string& notification_id, + const base::FilePath& path) + : profile_(profile), type_(type), path_(path), weak_ptr_factory_(this) { + // Messages. + switch (type) { + case ExportImportType::EXPORT: + message_title_ = IDS_CROSTINI_EXPORT_TITLE; + message_running_ = IDS_CROSTINI_EXPORT_NOTIFICATION_IN_PROGRESS; + message_done_ = IDS_CROSTINI_EXPORT_NOTIFICATION_DONE; + message_failed_ = IDS_CROSTINI_EXPORT_NOTIFICATION_FAILED; + break; + case ExportImportType::IMPORT: + message_title_ = IDS_CROSTINI_IMPORT_TITLE; + message_running_ = IDS_CROSTINI_IMPORT_NOTIFICATION_IN_PROGRESS; + message_done_ = IDS_CROSTINI_IMPORT_NOTIFICATION_DONE; + message_failed_ = IDS_CROSTINI_IMPORT_NOTIFICATION_FAILED; + break; + default: + NOTREACHED(); + } + + message_center::RichNotificationData rich_notification_data; + rich_notification_data.vector_small_image = &ash::kNotificationLinuxIcon; + rich_notification_data.accent_color = ash::kSystemNotificationColorNormal; + + notification_ = std::make_unique<message_center::Notification>( + message_center::NOTIFICATION_TYPE_PROGRESS, notification_id, + base::string16(), base::string16(), + gfx::Image(), // icon + l10n_util::GetStringUTF16(message_title_), + GURL(), // origin_url + message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT, + kNotifierCrostiniExportImportOperation), + rich_notification_data, + base::MakeRefCounted<message_center::ThunkNotificationDelegate>( + weak_ptr_factory_.GetWeakPtr())); + + UpdateStatus(Status::RUNNING, 0); +} + +CrostiniExportImportNotification::~CrostiniExportImportNotification() = default; + +void CrostiniExportImportNotification::UpdateStatus(Status status, + int progress_percent) { + status_ = status; + switch (status) { + case Status::RUNNING: + if (closed_) { + return; + } + notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); + notification_->set_progress(progress_percent); + notification_->set_message(l10n_util::GetStringUTF16(message_running_)); + notification_->set_never_timeout(true); + break; + case Status::DONE: + notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); + notification_->set_message(l10n_util::GetStringUTF16(message_done_)); + notification_->set_never_timeout(false); + break; + case Status::FAILED: + notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); + notification_->set_accent_color( + ash::kSystemNotificationColorCriticalWarning); + notification_->set_message(l10n_util::GetStringUTF16(message_failed_)); + notification_->set_never_timeout(false); + break; + default: + NOTREACHED(); + } + NotificationDisplayService* display_service = + NotificationDisplayService::GetForProfile(profile_); + display_service->Display(NotificationHandler::Type::TRANSIENT, + *notification_); +} + +void CrostiniExportImportNotification::Close(bool by_user) { + closed_ = true; +} + +void CrostiniExportImportNotification::Click( + const base::Optional<int>& button_index, + const base::Optional<base::string16>& reply) { + if (type_ == ExportImportType::EXPORT) { + platform_util::ShowItemInFolder(profile_, path_); + } +} + +} // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_notification.h b/chrome/browser/chromeos/crostini/crostini_export_import_notification.h new file mode 100644 index 0000000..a7f90f0 --- /dev/null +++ b/chrome/browser/chromeos/crostini/crostini_export_import_notification.h
@@ -0,0 +1,68 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_EXPORT_IMPORT_NOTIFICATION_H_ +#define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_EXPORT_IMPORT_NOTIFICATION_H_ + +#include <memory> +#include <string> + +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "ui/message_center/public/cpp/notification_delegate.h" + +class Profile; + +namespace message_center { +class Notification; +} + +namespace crostini { + +enum class ExportImportType; + +// Notification for Crostini export and import. +class CrostiniExportImportNotification + : public message_center::NotificationObserver { + public: + enum class Status { RUNNING, DONE, FAILED }; + + CrostiniExportImportNotification(Profile* profile, + ExportImportType type, + const std::string& notification_id, + const base::FilePath& path); + virtual ~CrostiniExportImportNotification(); + + void UpdateStatus(Status status, int progress_percent); + + // Getters for testing. + Status get_status() { return status_; } + message_center::Notification* get_notification() { + return notification_.get(); + } + + // message_center::NotificationObserver: + void Close(bool by_user) override; + void Click(const base::Optional<int>& button_index, + const base::Optional<base::string16>& reply) override; + + private: + Profile* profile_; + ExportImportType type_; + base::FilePath path_; + // These notifications are owned by the export service. + Status status_ = Status::RUNNING; + int message_title_; + int message_running_; + int message_done_; + int message_failed_; + std::unique_ptr<message_center::Notification> notification_; + bool closed_ = false; + base::WeakPtrFactory<CrostiniExportImportNotification> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(CrostiniExportImportNotification); +}; + +} // namespace crostini + +#endif // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_EXPORT_IMPORT_NOTIFICATION_H_
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc b/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc new file mode 100644 index 0000000..28de2c3 --- /dev/null +++ b/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc
@@ -0,0 +1,227 @@ +// 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. + +#include "chrome/browser/chromeos/crostini/crostini_export_import.h" + +#include "base/files/file_path.h" +#include "base/run_loop.h" +#include "chrome/browser/chromeos/crostini/crostini_util.h" +#include "chrome/browser/chromeos/file_manager/path_util.h" +#include "chrome/test/base/testing_profile.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_cicerone_client.h" +#include "chromeos/dbus/fake_seneschal_client.h" +#include "chromeos/dbus/seneschal/seneschal_service.pb.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "storage/browser/fileapi/external_mount_points.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/message_center/public/cpp/notification.h" + +namespace crostini { + +class CrostiniExportImportTest : public testing::Test { + public: + void SendExportProgress( + vm_tools::cicerone::ExportLxdContainerProgressSignal_Status status, + int progress_percent) { + vm_tools::cicerone::ExportLxdContainerProgressSignal signal; + signal.set_owner_id(CryptohomeIdForProfile(profile())); + signal.set_vm_name(kCrostiniDefaultVmName); + signal.set_container_name(kCrostiniDefaultContainerName); + signal.set_status(status); + signal.set_progress_percent(progress_percent); + fake_cicerone_client_->NotifyExportLxdContainerProgress(signal); + } + + void SendImportProgress( + vm_tools::cicerone::ImportLxdContainerProgressSignal_Status status, + int progress_percent) { + vm_tools::cicerone::ImportLxdContainerProgressSignal signal; + signal.set_owner_id(CryptohomeIdForProfile(profile())); + signal.set_vm_name(kCrostiniDefaultVmName); + signal.set_container_name(kCrostiniDefaultContainerName); + signal.set_status(status); + signal.set_progress_percent(progress_percent); + fake_cicerone_client_->NotifyImportLxdContainerProgress(signal); + } + + CrostiniExportImportTest() + : test_browser_thread_bundle_( + content::TestBrowserThreadBundle::REAL_IO_THREAD) { + chromeos::DBusThreadManager::Initialize(); + fake_seneschal_client_ = static_cast<chromeos::FakeSeneschalClient*>( + chromeos::DBusThreadManager::Get()->GetSeneschalClient()); + fake_cicerone_client_ = static_cast<chromeos::FakeCiceroneClient*>( + chromeos::DBusThreadManager::Get()->GetCiceroneClient()); + } + + ~CrostiniExportImportTest() override { + chromeos::DBusThreadManager::Shutdown(); + } + + void SetUp() override { + run_loop_ = std::make_unique<base::RunLoop>(); + profile_ = std::make_unique<TestingProfile>(); + crostini_export_import_ = std::make_unique<CrostiniExportImport>(profile()); + CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting( + kCrostiniDefaultVmName); + container_id_ = + ContainerId(kCrostiniDefaultVmName, kCrostiniDefaultContainerName); + + storage::ExternalMountPoints* mount_points = + storage::ExternalMountPoints::GetSystemInstance(); + mount_points->RegisterFileSystem( + file_manager::util::GetDownloadsMountPointName(profile()), + storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), + file_manager::util::GetMyFilesFolderForProfile(profile())); + tarball_ = file_manager::util::GetMyFilesFolderForProfile(profile()).Append( + "tarball.tar.gz"); + } + + void TearDown() override { + run_loop_.reset(); + profile_.reset(); + } + + protected: + base::RunLoop* run_loop() { return run_loop_.get(); } + Profile* profile() { return profile_.get(); } + CrostiniExportImport* crostini_export_import() { + return crostini_export_import_.get(); + } + + // Owned by chromeos::DBusThreadManager + chromeos::FakeCiceroneClient* fake_cicerone_client_; + chromeos::FakeSeneschalClient* fake_seneschal_client_; + + std::unique_ptr<base::RunLoop> run_loop_; + std::unique_ptr<TestingProfile> profile_; + std::unique_ptr<CrostiniExportImport> crostini_export_import_; + ContainerId container_id_; + base::FilePath tarball_; + + private: + content::TestBrowserThreadBundle test_browser_thread_bundle_; + DISALLOW_COPY_AND_ASSIGN(CrostiniExportImportTest); +}; + +TEST_F(CrostiniExportImportTest, DISABLED_TestExportSuccess) { + crostini_export_import()->FileSelected( + tarball_, 0, reinterpret_cast<void*>(ExportImportType::EXPORT)); + run_loop_->RunUntilIdle(); + CrostiniExportImportNotification* notification = + crostini_export_import()->GetNotificationForTesting(container_id_); + EXPECT_NE(notification, nullptr); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::RUNNING); + EXPECT_EQ(notification->get_notification()->progress(), 0); + + // 20% PACK = 10% overall. + SendExportProgress(vm_tools::cicerone:: + ExportLxdContainerProgressSignal_Status_EXPORTING_PACK, + 20); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::RUNNING); + EXPECT_EQ(notification->get_notification()->progress(), 10); + + // 20% DOWNLOAD = 60% overall. + SendExportProgress( + vm_tools::cicerone:: + ExportLxdContainerProgressSignal_Status_EXPORTING_DOWNLOAD, + 20); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::RUNNING); + EXPECT_EQ(notification->get_notification()->progress(), 60); + + // Close notification and update progress. Should not update notification. + notification->Close(false); + SendExportProgress( + vm_tools::cicerone:: + ExportLxdContainerProgressSignal_Status_EXPORTING_DOWNLOAD, + 40); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::RUNNING); + EXPECT_EQ(notification->get_notification()->progress(), 60); + + // Done. + SendExportProgress( + vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE, 0); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::DONE); +} + +TEST_F(CrostiniExportImportTest, DISABLED_TestExportFail) { + crostini_export_import()->FileSelected( + tarball_, 0, reinterpret_cast<void*>(ExportImportType::EXPORT)); + run_loop_->RunUntilIdle(); + CrostiniExportImportNotification* notification = + crostini_export_import()->GetNotificationForTesting(container_id_); + + // Failed. + SendExportProgress( + vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_FAILED, 0); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::FAILED); +} + +TEST_F(CrostiniExportImportTest, DISABLED_TestImportSuccess) { + crostini_export_import()->FileSelected( + tarball_, 0, reinterpret_cast<void*>(ExportImportType::IMPORT)); + run_loop_->RunUntilIdle(); + CrostiniExportImportNotification* notification = + crostini_export_import()->GetNotificationForTesting(container_id_); + EXPECT_NE(notification, nullptr); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::RUNNING); + EXPECT_EQ(notification->get_notification()->progress(), 0); + + // 20% UPLOAD = 10% overall. + SendImportProgress( + vm_tools::cicerone:: + ImportLxdContainerProgressSignal_Status_IMPORTING_UPLOAD, + 20); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::RUNNING); + EXPECT_EQ(notification->get_notification()->progress(), 10); + + // 20% UNPACK = 60% overall. + SendImportProgress( + vm_tools::cicerone:: + ImportLxdContainerProgressSignal_Status_IMPORTING_UNPACK, + 20); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::RUNNING); + EXPECT_EQ(notification->get_notification()->progress(), 60); + + // Close notification and update progress. Should not update notification. + notification->Close(false); + SendImportProgress( + vm_tools::cicerone:: + ImportLxdContainerProgressSignal_Status_IMPORTING_UNPACK, + 40); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::RUNNING); + EXPECT_EQ(notification->get_notification()->progress(), 60); + + // Done. + SendImportProgress( + vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_DONE, 0); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::DONE); +} + +TEST_F(CrostiniExportImportTest, DISABLED_TestImportFail) { + crostini_export_import()->FileSelected( + tarball_, 0, reinterpret_cast<void*>(ExportImportType::IMPORT)); + run_loop_->RunUntilIdle(); + CrostiniExportImportNotification* notification = + crostini_export_import()->GetNotificationForTesting(container_id_); + + // Failed. + SendImportProgress( + vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_FAILED, 0); + EXPECT_EQ(notification->get_status(), + CrostiniExportImportNotification::Status::FAILED); +} +} // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc index 64dabaa5..687bac8 100644 --- a/chrome/browser/chromeos/crostini/crostini_manager.cc +++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -1106,7 +1106,7 @@ return; } - auto key = std::make_pair(vm_name, container_name); + ContainerId key(vm_name, container_name); if (export_lxd_container_callbacks_.find(key) != export_lxd_container_callbacks_.end()) { LOG(ERROR) << "Export currently in progress for " << vm_name << ", " @@ -1147,7 +1147,7 @@ std::move(callback).Run(CrostiniResult::CLIENT_ERROR); return; } - auto key = std::make_pair(vm_name, container_name); + ContainerId key(vm_name, container_name); if (import_lxd_container_callbacks_.find(key) != import_lxd_container_callbacks_.end()) { LOG(ERROR) << "Import currently in progress for " << vm_name << ", " @@ -1745,8 +1745,8 @@ std::string vm_name, std::string container_name, ShutdownContainerCallback shutdown_callback) { - shutdown_container_callbacks_.emplace( - std::make_tuple(vm_name, container_name), std::move(shutdown_callback)); + shutdown_container_callbacks_.emplace(ContainerId(vm_name, container_name), + std::move(shutdown_callback)); } void CrostiniManager::AddRemoveCrostiniCallback( @@ -2129,7 +2129,7 @@ // The callback will be called when we receive the LxdContainerCreated // signal. create_lxd_container_callbacks_.emplace( - std::make_tuple(vm_name, container_name), std::move(callback)); + ContainerId(vm_name, container_name), std::move(callback)); return; } if (response.status() != @@ -2179,7 +2179,7 @@ // The callback will be called when we receive the LxdContainerStarting // signal. start_lxd_container_callbacks_.emplace( - std::make_tuple(vm_name, container_name), std::move(callback)); + ContainerId(vm_name, container_name), std::move(callback)); break; default: NOTREACHED(); @@ -2210,7 +2210,7 @@ } if (!GetContainerInfo(vm_name, container_name)) { - start_container_callbacks_.emplace(std::make_tuple(vm_name, container_name), + start_container_callbacks_.emplace(ContainerId(vm_name, container_name), std::move(callback)); return; } @@ -2535,7 +2535,7 @@ std::string vm_name, std::string container_name, base::Optional<vm_tools::cicerone::ExportLxdContainerResponse> reply) { - auto key = std::make_pair(vm_name, container_name); + ContainerId key(vm_name, container_name); auto it = export_lxd_container_callbacks_.find(key); if (it == export_lxd_container_callbacks_.end()) { LOG(ERROR) << "No export callback for " << vm_name << ", " @@ -2571,14 +2571,9 @@ ExportContainerProgressStatus status; CrostiniResult result; switch (signal.status()) { - case vm_tools::cicerone::ExportLxdContainerProgressSignal::EXPORTING_TAR: + case vm_tools::cicerone::ExportLxdContainerProgressSignal::EXPORTING_PACK: exporting = true; - status = ExportContainerProgressStatus::TAR; - break; - case vm_tools::cicerone::ExportLxdContainerProgressSignal:: - EXPORTING_COMPRESS: - exporting = true; - status = ExportContainerProgressStatus::COMPRESS; + status = ExportContainerProgressStatus::PACK; break; case vm_tools::cicerone::ExportLxdContainerProgressSignal:: EXPORTING_DOWNLOAD: @@ -2620,7 +2615,7 @@ std::string vm_name, std::string container_name, base::Optional<vm_tools::cicerone::ImportLxdContainerResponse> reply) { - auto key = std::make_pair(vm_name, container_name); + ContainerId key(vm_name, container_name); auto it = import_lxd_container_callbacks_.find(key); if (it == import_lxd_container_callbacks_.end()) { LOG(ERROR) << "No import callback for " << vm_name << ", "
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h index 4b9f79a2..d319fca 100644 --- a/chrome/browser/chromeos/crostini/crostini_manager.h +++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -90,8 +90,7 @@ }; enum class ExportContainerProgressStatus { - TAR, - COMPRESS, + PACK, DOWNLOAD, };
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc index 0b9ec266..bc0245c 100644 --- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc +++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -1120,18 +1120,13 @@ base::Unretained(this), run_loop()->QuitClosure(), CrostiniResult::SUCCESS)); - // Send signals, TAR, COMPRESS, DOWNLOAD, DONE. + // Send signals, PACK, DOWNLOAD, DONE. vm_tools::cicerone::ExportLxdContainerProgressSignal signal; signal.set_owner_id(CryptohomeIdForProfile(profile())); signal.set_vm_name(kVmName); signal.set_container_name(kContainerName); signal.set_status(vm_tools::cicerone:: - ExportLxdContainerProgressSignal_Status_EXPORTING_TAR); - fake_cicerone_client_->NotifyExportLxdContainerProgress(signal); - - signal.set_status( - vm_tools::cicerone:: - ExportLxdContainerProgressSignal_Status_EXPORTING_COMPRESS); + ExportLxdContainerProgressSignal_Status_EXPORTING_PACK); fake_cicerone_client_->NotifyExportLxdContainerProgress(signal); signal.set_status(
diff --git a/chrome/browser/chromeos/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc index 0c09058..e40765a 100644 --- a/chrome/browser/chromeos/crostini/crostini_util.cc +++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -35,6 +35,7 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/common/chrome_features.h" #include "chrome/grit/chrome_unscaled_resources.h" +#include "chromeos/constants/chromeos_features.h" #include "components/prefs/pref_service.h" #include "google_apis/gaia/gaia_auth_util.h" @@ -260,6 +261,13 @@ return IsCrostiniAllowedForProfileImpl(profile); } +bool IsCrostiniExportImportUIAllowedForProfile(Profile* profile) { + return IsCrostiniUIAllowedForProfile(profile, true) && + base::FeatureList::IsEnabled(chromeos::features::kCrostiniBackup) && + profile->GetPrefs()->GetBoolean( + crostini::prefs::kUserCrostiniExportImportUIAllowedByPolicy); +} + bool IsCrostiniEnabled(Profile* profile) { return IsCrostiniUIAllowedForProfile(profile) && profile->GetPrefs()->GetBoolean(crostini::prefs::kCrostiniEnabled);
diff --git a/chrome/browser/chromeos/crostini/crostini_util.h b/chrome/browser/chromeos/crostini/crostini_util.h index 5365ac4..343540e 100644 --- a/chrome/browser/chromeos/crostini/crostini_util.h +++ b/chrome/browser/chromeos/crostini/crostini_util.h
@@ -46,6 +46,9 @@ // UI uses this to indicate that crostini is available but disabled by policy. bool IsCrostiniUIAllowedForProfile(Profile* profile, bool check_policy = true); +// Returns true if policy allows export import UI. +bool IsCrostiniExportImportUIAllowedForProfile(Profile* profile); + // Returns whether if Crostini has been enabled, i.e. the user has launched it // at least once and not deleted it. bool IsCrostiniEnabled(Profile* profile);
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.cc b/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.cc index bc1b222..35b5ce7 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.cc
@@ -38,8 +38,8 @@ void FileStreamMd5Digester::ReadNextChunk(const ResultCallback& callback) { const int result = reader_->Read(buffer_.get(), kMd5DigestBufferSize, - base::Bind(&FileStreamMd5Digester::OnChunkRead, - base::Unretained(this), callback)); + base::BindOnce(&FileStreamMd5Digester::OnChunkRead, + base::Unretained(this), callback)); if (result != net::ERR_IO_PENDING) OnChunkRead(callback, result); }
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc index 240592d..a1a90eb 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc
@@ -73,14 +73,10 @@ } file_manager::util::GetSelectedFileInfo( - render_frame_host(), - GetProfile(), - file_paths, - option, - base::Bind( + render_frame_host(), GetProfile(), file_paths, option, + base::BindOnce( &FileManagerPrivateSelectFileFunction::GetSelectedFileInfoResponse, - this, - params->index)); + this, params->index)); return true; } @@ -107,13 +103,11 @@ file_urls.emplace_back(params->selected_paths[i]); file_manager::util::GetSelectedFileInfo( - render_frame_host(), - GetProfile(), - file_urls, - params->should_return_local_path ? - file_manager::util::NEED_LOCAL_PATH_FOR_OPENING : - file_manager::util::NO_LOCAL_PATH_RESOLUTION, - base::Bind( + render_frame_host(), GetProfile(), file_urls, + params->should_return_local_path + ? file_manager::util::NEED_LOCAL_PATH_FOR_OPENING + : file_manager::util::NO_LOCAL_PATH_RESOLUTION, + base::BindOnce( &FileManagerPrivateSelectFilesFunction::GetSelectedFileInfoResponse, this)); return true;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc index f92e2b8..6d8e9a8d 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
@@ -254,20 +254,20 @@ class SingleEntryPropertiesGetterForDrive { public: - typedef base::Callback<void(std::unique_ptr<EntryProperties> properties, - base::File::Error error)> + typedef base::OnceCallback<void(std::unique_ptr<EntryProperties> properties, + base::File::Error error)> ResultCallback; // Creates an instance and starts the process. static void Start(const base::FilePath local_path, const std::set<EntryPropertyName>& names, Profile* const profile, - const ResultCallback& callback) { + ResultCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); SingleEntryPropertiesGetterForDrive* instance = new SingleEntryPropertiesGetterForDrive(local_path, names, profile, - callback); + std::move(callback)); instance->StartProcess(); // The instance will be destroyed by itself. @@ -280,8 +280,8 @@ const base::FilePath local_path, const std::set<EntryPropertyName>& /* names */, Profile* const profile, - const ResultCallback& callback) - : callback_(callback), + ResultCallback callback) + : callback_(std::move(callback)), local_path_(local_path), running_profile_(profile), properties_(new EntryProperties), @@ -415,13 +415,13 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!callback_.is_null()); - callback_.Run(std::move(properties_), - drive::FileErrorToBaseFileError(error)); + std::move(callback_).Run(std::move(properties_), + drive::FileErrorToBaseFileError(error)); BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); } // Given parameters. - const ResultCallback callback_; + ResultCallback callback_; const base::FilePath local_path_; Profile* const running_profile_; @@ -436,19 +436,19 @@ class SingleEntryPropertiesGetterForFileSystemProvider { public: - typedef base::Callback<void(std::unique_ptr<EntryProperties> properties, - base::File::Error error)> + typedef base::OnceCallback<void(std::unique_ptr<EntryProperties> properties, + base::File::Error error)> ResultCallback; // Creates an instance and starts the process. static void Start(const storage::FileSystemURL file_system_url, const std::set<EntryPropertyName>& names, - const ResultCallback& callback) { + ResultCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); SingleEntryPropertiesGetterForFileSystemProvider* instance = - new SingleEntryPropertiesGetterForFileSystemProvider(file_system_url, - names, callback); + new SingleEntryPropertiesGetterForFileSystemProvider( + file_system_url, names, std::move(callback)); instance->StartProcess(); // The instance will be destroyed by itself. @@ -460,8 +460,8 @@ SingleEntryPropertiesGetterForFileSystemProvider( const storage::FileSystemURL& file_system_url, const std::set<EntryPropertyName>& names, - const ResultCallback& callback) - : callback_(callback), + ResultCallback callback) + : callback_(std::move(callback)), file_system_url_(file_system_url), names_(names), properties_(new EntryProperties), @@ -556,12 +556,12 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!callback_.is_null()); - callback_.Run(std::move(properties_), result); + std::move(callback_).Run(std::move(properties_), result); BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); } // Given parameters. - const ResultCallback callback_; + ResultCallback callback_; const storage::FileSystemURL file_system_url_; const std::set<EntryPropertyName> names_; @@ -887,16 +887,18 @@ case storage::kFileSystemTypeDrive: SingleEntryPropertiesGetterForDrive::Start( file_system_url.path(), names_as_set, GetProfile(), - base::Bind(&FileManagerPrivateInternalGetEntryPropertiesFunction:: - CompleteGetEntryProperties, - this, i, file_system_url)); + base::BindOnce( + &FileManagerPrivateInternalGetEntryPropertiesFunction:: + CompleteGetEntryProperties, + this, i, file_system_url)); break; case storage::kFileSystemTypeProvided: SingleEntryPropertiesGetterForFileSystemProvider::Start( file_system_url, names_as_set, - base::Bind(&FileManagerPrivateInternalGetEntryPropertiesFunction:: - CompleteGetEntryProperties, - this, i, file_system_url)); + base::BindOnce( + &FileManagerPrivateInternalGetEntryPropertiesFunction:: + CompleteGetEntryProperties, + this, i, file_system_url)); break; case storage::kFileSystemTypeDriveFs: SingleEntryPropertiesGetterForDriveFs::Start(
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc index 3132235..38767bb 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -214,12 +214,12 @@ storage::FileSystemOperationRunner::OperationID* operation_id = new storage::FileSystemOperationRunner::OperationID; *operation_id = file_system_context->operation_runner()->Copy( - source_url, destination_url, - storage::FileSystemOperation::OPTION_NONE, + source_url, destination_url, storage::FileSystemOperation::OPTION_NONE, storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT, - base::Bind(&OnCopyProgress, profile_id, base::Unretained(operation_id)), - base::Bind(&OnCopyCompleted, profile_id, base::Owned(operation_id), - source_url, destination_url)); + base::BindRepeating(&OnCopyProgress, profile_id, + base::Unretained(operation_id)), + base::BindOnce(&OnCopyCompleted, profile_id, base::Owned(operation_id), + source_url, destination_url)); return *operation_id; } @@ -239,7 +239,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); file_system_context->operation_runner()->Cancel( - operation_id, base::Bind(&OnCopyCancelled)); + operation_id, base::BindOnce(&OnCopyCancelled)); } // Converts a status code to a bool value and calls the |callback| with it. @@ -511,7 +511,7 @@ auto* manager = storage_monitor->media_transfer_protocol_manager(); manager->GetStorageInfoFromDevice( storage_name, - base::Bind( + base::BindOnce( &FileManagerPrivateGetSizeStatsFunction::OnGetMtpAvailableSpace, this)); } else { @@ -595,11 +595,11 @@ base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, - base::Bind(&GetFileNameMaxLengthAsync, - file_system_url.path().AsUTF8Unsafe()), - base::Bind(&FileManagerPrivateInternalValidatePathNameLengthFunction:: - OnFilePathLimitRetrieved, - this, params->name.size())); + base::BindOnce(&GetFileNameMaxLengthAsync, + file_system_url.path().AsUTF8Unsafe()), + base::BindOnce(&FileManagerPrivateInternalValidatePathNameLengthFunction:: + OnFilePathLimitRetrieved, + this, params->name.size())); return true; } @@ -803,9 +803,9 @@ GetProfile(), render_frame_host()); const bool result = base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, {BrowserThread::IO}, - base::Bind(&StartCopyOnIOThread, GetProfile(), file_system_context, - source_url_, destination_url_), - base::Bind( + base::BindOnce(&StartCopyOnIOThread, GetProfile(), file_system_context, + source_url_, destination_url_), + base::BindOnce( &FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy, this)); if (!result) @@ -1181,10 +1181,10 @@ base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, - base::Bind(&base::ComputeDirectorySize, root_path), - base::Bind(&FileManagerPrivateInternalGetDirectorySizeFunction:: - OnDirectorySizeRetrieved, - this)); + base::BindOnce(&base::ComputeDirectorySize, root_path), + base::BindOnce(&FileManagerPrivateInternalGetDirectorySizeFunction:: + OnDirectorySizeRetrieved, + this)); return true; }
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc index 14c2787..e06dd54c 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -608,7 +608,7 @@ service->GetProvidedFileSystem(volume->provider_id(), volume->file_system_id()); if (file_system) - file_system->Configure(base::Bind( + file_system->Configure(base::BindOnce( &FileManagerPrivateConfigureVolumeFunction::OnCompleted, this)); break; } @@ -946,7 +946,7 @@ DCHECK(file_system); file_system->ExecuteAction( paths, params->action_id, - base::Bind( + base::BindOnce( &FileManagerPrivateInternalExecuteCustomActionFunction::OnCompleted, this)); return RespondLater();
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc index 71a85ef..c6575c5 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
@@ -37,15 +37,15 @@ // Does chmod o+r for the given path to ensure the file is readable from avfs. void EnsureReadableFilePermissionAsync( const base::FilePath& path, - const base::Callback<void(drive::FileError, const base::FilePath&)>& + base::OnceCallback<void(drive::FileError, const base::FilePath&)> callback) { int mode = 0; if (!base::GetPosixFilePermissions(path, &mode) || !base::SetPosixFilePermissions(path, mode | S_IROTH)) { - callback.Run(drive::FILE_ERROR_ACCESS_DENIED, base::FilePath()); + std::move(callback).Run(drive::FILE_ERROR_ACCESS_DENIED, base::FilePath()); return; } - callback.Run(drive::FILE_ERROR_OK, path); + std::move(callback).Run(drive::FILE_ERROR_OK, path); } } // namespace @@ -80,9 +80,9 @@ const base::FilePath drive_path = drive::util::ExtractDrivePath(path); file_system->GetFile( drive_path, - base::Bind(&FileManagerPrivateAddMountFunction::RunAfterGetDriveFile, - this, - drive_path)); + base::BindOnce( + &FileManagerPrivateAddMountFunction::RunAfterGetDriveFile, this, + drive_path)); } else { file_manager::VolumeManager* volume_manager = file_manager::VolumeManager::Get(GetProfile()); @@ -105,10 +105,10 @@ base::PostTaskWithTraits( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, base::BindOnce(&EnsureReadableFilePermissionAsync, path, - google_apis::CreateRelayCallback( - base::Bind(&FileManagerPrivateAddMountFunction:: - RunAfterMarkCacheFileAsMounted, - this, path.BaseName())))); + google_apis::CreateRelayCallback(base::BindOnce( + &FileManagerPrivateAddMountFunction:: + RunAfterMarkCacheFileAsMounted, + this, path.BaseName())))); } else { RunAfterMarkCacheFileAsMounted( path.BaseName(), drive::FILE_ERROR_OK, path); @@ -285,7 +285,7 @@ const base::FilePath drive_path = drive::util::ExtractDrivePath(path); file_system->GetFile( drive_path, - base::Bind( + base::BindOnce( &FileManagerPrivateMarkCacheAsMountedFunction::RunAfterGetDriveFile, this, drive_path, is_mounted)); return true;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc index 97711b0..d0f6af23 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
@@ -107,8 +107,9 @@ const bool result = file_manager::file_tasks::ExecuteFileTask( GetProfile(), source_url(), task, urls, - base::Bind(&FileManagerPrivateInternalExecuteTaskFunction::OnTaskExecuted, - this)); + base::BindOnce( + &FileManagerPrivateInternalExecuteTaskFunction::OnTaskExecuted, + this)); if (!result) { results_ = Create(extensions::api::file_manager_private::TASK_RESULT_FAILED); @@ -188,7 +189,7 @@ file_manager::file_tasks::FindAllTypesOfTasks( GetProfile(), entries, urls_, - base::Bind( + base::BindOnce( &FileManagerPrivateInternalGetFileTasksFunction::OnFileTasksListed, this)); }
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc index c4c6a13..d67bbc2e 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
@@ -52,61 +52,62 @@ // The callback type for GetFileNativeLocalPathFor{Opening,Saving}. It receives // the resolved local path when successful, and receives empty path for failure. -typedef base::Callback<void(const base::FilePath&)> LocalPathCallback; +typedef base::OnceCallback<void(const base::FilePath&)> LocalPathCallback; // Converts a callback from Drive file system to LocalPathCallback. void OnDriveGetFile(const base::FilePath& path, - const LocalPathCallback& callback, + LocalPathCallback callback, drive::FileError error, const base::FilePath& local_file_path, std::unique_ptr<drive::ResourceEntry> entry) { if (error != drive::FILE_ERROR_OK) DLOG(ERROR) << "Failed to get " << path.value() << " with: " << error; - callback.Run(local_file_path); + std::move(callback).Run(local_file_path); } // Gets a resolved local file path of a non native |path| for file opening. void GetFileNativeLocalPathForOpening(Profile* profile, const base::FilePath& path, - const LocalPathCallback& callback) { + LocalPathCallback callback) { if (drive::util::IsUnderDriveMountPoint(path)) { drive::FileSystemInterface* file_system = drive::util::GetFileSystemByProfile(profile); if (!file_system) { DLOG(ERROR) << "Drive file selected while disabled: " << path.value(); - callback.Run(base::FilePath()); + std::move(callback).Run(base::FilePath()); return; } - file_system->GetFile(drive::util::ExtractDrivePath(path), - base::BindOnce(&OnDriveGetFile, path, callback)); + file_system->GetFile( + drive::util::ExtractDrivePath(path), + base::BindOnce(&OnDriveGetFile, path, std::move(callback))); return; } VolumeManager::Get(profile)->snapshot_manager()->CreateManagedSnapshot( - path, callback); + path, std::move(callback)); } // Gets a resolved local file path of a non native |path| for file saving. void GetFileNativeLocalPathForSaving(Profile* profile, const base::FilePath& path, - const LocalPathCallback& callback) { + LocalPathCallback callback) { if (drive::util::IsUnderDriveMountPoint(path)) { drive::FileSystemInterface* file_system = drive::util::GetFileSystemByProfile(profile); if (!file_system) { DLOG(ERROR) << "Drive file selected while disabled: " << path.value(); - callback.Run(base::FilePath()); + std::move(callback).Run(base::FilePath()); return; } file_system->GetFileForSaving( drive::util::ExtractDrivePath(path), - base::BindOnce(&OnDriveGetFile, path, callback)); + base::BindOnce(&OnDriveGetFile, path, std::move(callback))); return; } // TODO(kinaba): For now, the only writable non-local volume is Drive. NOTREACHED(); - callback.Run(base::FilePath()); + std::move(callback).Run(base::FilePath()); } // Forward declarations of helper functions for GetSelectedFileInfo(). @@ -150,20 +151,16 @@ } case NEED_LOCAL_PATH_FOR_OPENING: { GetFileNativeLocalPathForOpening( - profile, - file_path, - base::Bind(&ContinueGetSelectedFileInfo, - profile, - base::Passed(¶ms))); + profile, file_path, + base::BindOnce(&ContinueGetSelectedFileInfo, profile, + std::move(params))); return; // Remaining work is done in ContinueGetSelectedFileInfo. } case NEED_LOCAL_PATH_FOR_SAVING: { GetFileNativeLocalPathForSaving( - profile, - file_path, - base::Bind(&ContinueGetSelectedFileInfo, - profile, - base::Passed(¶ms))); + profile, file_path, + base::BindOnce(&ContinueGetSelectedFileInfo, profile, + std::move(params))); return; // Remaining work is done in ContinueGetSelectedFileInfo. } } @@ -188,7 +185,7 @@ params->selected_files.emplace_back(file_path, file_path); } } - params->callback.Run(params->selected_files); + std::move(params->callback).Run(params->selected_files); } // Part of GetSelectedFileInfo(). @@ -197,7 +194,7 @@ std::unique_ptr<GetSelectedFileInfoParams> params, const base::FilePath& local_path) { if (local_path.empty()) { - params->callback.Run(std::vector<ui::SelectedFileInfo>()); + std::move(params->callback).Run(std::vector<ui::SelectedFileInfo>()); return; } const int index = params->selected_files.size(); @@ -432,7 +429,7 @@ std::unique_ptr<GetSelectedFileInfoParams> params( new GetSelectedFileInfoParams); params->local_path_option = local_path_option; - params->callback = callback; + params->callback = std::move(callback); for (size_t i = 0; i < file_urls.size(); ++i) { const GURL& file_url = file_urls[i]; @@ -445,8 +442,8 @@ } base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&GetSelectedFileInfoInternal, profile, - base::Passed(¶ms))); + FROM_HERE, + base::BindOnce(&GetSelectedFileInfoInternal, profile, std::move(params))); } void SetupProfileFileAccessPermissions(int render_view_process_id,
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_util.h b/chrome/browser/chromeos/extensions/file_manager/private_api_util.h index f630142..2d288ef 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_util.h +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_util.h
@@ -69,7 +69,7 @@ const GURL& url); // The callback type is used for GetSelectedFileInfo(). -typedef base::Callback<void(const std::vector<ui::SelectedFileInfo>&)> +typedef base::OnceCallback<void(const std::vector<ui::SelectedFileInfo>&)> GetSelectedFileInfoCallback; // Option enum to control how to set the ui::SelectedFileInfo::local_path
diff --git a/chrome/browser/chromeos/file_manager/path_util.cc b/chrome/browser/chromeos/file_manager/path_util.cc index 24846573..7e615476 100644 --- a/chrome/browser/chromeos/file_manager/path_util.cc +++ b/chrome/browser/chromeos/file_manager/path_util.cc
@@ -61,9 +61,11 @@ FILE_PATH_LITERAL("/download"); constexpr base::FilePath::CharType kArcExternalFilesRoot[] = FILE_PATH_LITERAL("/external_files"); -// Sync with the removable media provider in ARC++ side. -constexpr char kArcRemovableMediaProviderUrl[] = - "content://org.chromium.arc.removablemediaprovider/"; +// Sync with the volume provider in ARC++ side. +constexpr char kArcRemovableMediaContentUrlPrefix[] = + "content://org.chromium.arc.volumeprovider/removable/"; +constexpr char kArcMyFilesContentUrlPrefix[] = + "content://org.chromium.arc.volumeprovider/MyFiles/"; Profile* GetPrimaryProfile() { if (!user_manager::UserManager::IsInitialized()) @@ -385,7 +387,15 @@ base::FilePath relative_path; if (base::FilePath(kRemovableMediaPath) .AppendRelativePath(path, &relative_path)) { - *arc_url_out = GURL(kArcRemovableMediaProviderUrl) + *arc_url_out = GURL(kArcRemovableMediaContentUrlPrefix) + .Resolve(net::EscapePath(relative_path.AsUTF8Unsafe())); + return true; + } + + // Convert paths under MyFiles + if (base::FilePath(GetMyFilesFolderForProfile(primary_profile)) + .AppendRelativePath(path, &relative_path)) { + *arc_url_out = GURL(kArcMyFilesContentUrlPrefix) .Resolve(net::EscapePath(relative_path.AsUTF8Unsafe())); return true; }
diff --git a/chrome/browser/chromeos/file_manager/path_util_unittest.cc b/chrome/browser/chromeos/file_manager/path_util_unittest.cc index fa85091..3ed556e 100644 --- a/chrome/browser/chromeos/file_manager/path_util_unittest.cc +++ b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
@@ -697,7 +697,21 @@ GURL url; EXPECT_TRUE(ConvertPathToArcUrl( base::FilePath::FromUTF8Unsafe("/media/removable/a/b/c"), &url)); - EXPECT_EQ(GURL("content://org.chromium.arc.removablemediaprovider/a/b/c"), + EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/removable/a/b/c"), + url); +} + +TEST_F(FileManagerPathUtilConvertUrlTest, ConvertPathToArcUrl_MyFiles) { + chromeos::ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, + base::Time()); + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(chromeos::features::kMyFilesVolume); + GURL url; + const base::FilePath myfiles = GetMyFilesFolderForProfile( + chromeos::ProfileHelper::Get()->GetProfileByUserIdHashForTest( + "user@gmail.com-hash")); + EXPECT_TRUE(ConvertPathToArcUrl(myfiles.AppendASCII("a/b/c"), &url)); + EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/MyFiles/a/b/c"), url); } @@ -769,8 +783,32 @@ [](base::RunLoop* run_loop, const std::vector<GURL>& urls) { run_loop->Quit(); ASSERT_EQ(1U, urls.size()); + EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/" + "removable/a/b/c"), + urls[0]); + }, + &run_loop)); + run_loop.Run(); +} + +TEST_F(FileManagerPathUtilConvertUrlTest, ConvertToContentUrls_MyFiles) { + chromeos::ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, + base::Time()); + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(chromeos::features::kMyFilesVolume); + const base::FilePath myfiles = GetMyFilesFolderForProfile( + chromeos::ProfileHelper::Get()->GetProfileByUserIdHashForTest( + "user@gmail.com-hash")); + base::RunLoop run_loop; + ConvertToContentUrls( + std::vector<FileSystemURL>{ + CreateExternalURL(myfiles.AppendASCII("a/b/c"))}, + base::BindOnce( + [](base::RunLoop* run_loop, const std::vector<GURL>& urls) { + run_loop->Quit(); + ASSERT_EQ(1U, urls.size()); EXPECT_EQ( - GURL("content://org.chromium.arc.removablemediaprovider/a/b/c"), + GURL("content://org.chromium.arc.volumeprovider/MyFiles/a/b/c"), urls[0]); }, &run_loop)); @@ -953,9 +991,9 @@ run_loop->Quit(); ASSERT_EQ(4U, urls.size()); EXPECT_EQ(GURL(), urls[0]); // Invalid URL. - EXPECT_EQ( - GURL("content://org.chromium.arc.removablemediaprovider/a/b/c"), - urls[1]); + EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/" + "removable/a/b/c"), + urls[1]); EXPECT_EQ(GURL("content://org.chromium.arc.chromecontentprovider/" "externalfile%3Adrive-user%252540gmail.com-hash%2Fa%" "2Fb%2Fc"),
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc index 693c95e..a359d11d9 100644 --- a/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc
@@ -35,7 +35,7 @@ EnrollmentScreenTest() = default; ~EnrollmentScreenTest() override = default; - // Overridden from InProcessBrowserTest: + // InProcessBrowserTest: void SetUpCommandLine(base::CommandLine* command_line) override { InProcessBrowserTest::SetUpCommandLine(command_line); command_line->AppendArg(switches::kLoginManager); @@ -81,8 +81,7 @@ run_loop.Run(); } -// Flaky test: crbug.com/394069 -IN_PROC_BROWSER_TEST_F(EnrollmentScreenTest, DISABLED_TestSuccess) { +IN_PROC_BROWSER_TEST_F(EnrollmentScreenTest, TestSuccess) { WizardController::SkipEnrollmentPromptsForTesting(); base::RunLoop run_loop; EXPECT_FALSE(StartupUtils::IsDeviceRegistered()); @@ -100,7 +99,7 @@ ~AttestationAuthEnrollmentScreenTest() override = default; private: - // Overridden from EnrollmentScreenTest: + // EnrollmentScreenTest: void SetUpCommandLine(base::CommandLine* command_line) override { EnrollmentScreenTest::SetUpCommandLine(command_line); command_line->AppendSwitch(switches::kEnterpriseEnableZeroTouchEnrollment); @@ -151,7 +150,7 @@ ~ForcedAttestationAuthEnrollmentScreenTest() override = default; private: - // Overridden from EnrollmentScreenTest: + // EnrollmentScreenTest: void SetUpCommandLine(base::CommandLine* command_line) override { EnrollmentScreenTest::SetUpCommandLine(command_line); command_line->AppendSwitchASCII( @@ -177,7 +176,7 @@ ~MultiAuthEnrollmentScreenTest() override = default; private: - // Overridden from EnrollmentScreenTest: + // EnrollmentScreenTest: void SetUpCommandLine(base::CommandLine* command_line) override { EnrollmentScreenTest::SetUpCommandLine(command_line); command_line->AppendSwitch(switches::kEnterpriseEnableZeroTouchEnrollment); @@ -209,7 +208,7 @@ ~ProvisionedEnrollmentScreenTest() override = default; private: - // Overridden from EnrollmentScreenTest: + // EnrollmentScreenTest: void SetUpCommandLine(base::CommandLine* command_line) override { EnrollmentScreenTest::SetUpCommandLine(command_line); base::FilePath test_data_dir;
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc index aab985b..c9241c3 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.cc +++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -673,14 +673,12 @@ void ExistingUserController::OnSigninScreenReady() { // Used to debug crbug.com/902315. Feel free to remove after that is fixed. VLOG(1) << "OnSigninScreenReady"; - auto_launch_ready_ = true; StartAutoLoginTimer(); } void ExistingUserController::OnGaiaScreenReady() { // Used to debug crbug.com/902315. Feel free to remove after that is fixed. VLOG(1) << "OnGaiaScreenReady"; - auto_launch_ready_ = true; StartAutoLoginTimer(); } @@ -1466,7 +1464,7 @@ } void ExistingUserController::OnPublicSessionAutoLoginTimerFire() { - CHECK(auto_launch_ready_ && public_session_auto_login_account_id_.is_valid()); + CHECK(public_session_auto_login_account_id_.is_valid()); VLOG(2) << "Public session autologin fired"; SigninSpecifics signin_specifics; signin_specifics.is_auto_login = true; @@ -1476,7 +1474,7 @@ } void ExistingUserController::OnArcKioskAutoLoginTimerFire() { - CHECK(auto_launch_ready_ && (arc_kiosk_auto_login_account_id_.is_valid())); + CHECK(arc_kiosk_auto_login_account_id_.is_valid()); VLOG(2) << "ARC kiosk autologin fired"; SigninSpecifics signin_specifics; signin_specifics.is_auto_login = true; @@ -1515,11 +1513,10 @@ } void ExistingUserController::StartAutoLoginTimer() { - if (!auto_launch_ready_ || is_login_in_progress_ || + if (is_login_in_progress_ || (!public_session_auto_login_account_id_.is_valid() && !arc_kiosk_auto_login_account_id_.is_valid())) { VLOG(2) << "Not starting autologin timer, because:"; - VLOG_IF(2, !auto_launch_ready_) << "* Not ready;"; VLOG_IF(2, is_login_in_progress_) << "* Login is in process;"; VLOG_IF(2, (!public_session_auto_login_account_id_.is_valid() && !arc_kiosk_auto_login_account_id_.is_valid()))
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h index 5c3352a2..4cb575d 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.h +++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -377,10 +377,6 @@ LoginPerformer::AuthorizationMode auth_mode_ = LoginPerformer::AUTH_MODE_EXTENSION; - // When the sign-in or GAIA UI is finished loading - // public session or ARC kiosk are ready to auto-launch. - bool auto_launch_ready_ = false; - // Indicates use of local (not GAIA) authentication. bool auth_flow_offline_ = false;
diff --git a/chrome/browser/chromeos/login/existing_user_controller_auto_login_unittest.cc b/chrome/browser/chromeos/login/existing_user_controller_auto_login_unittest.cc index 487b42a..4883d7c 100644 --- a/chrome/browser/chromeos/login/existing_user_controller_auto_login_unittest.cc +++ b/chrome/browser/chromeos/login/existing_user_controller_auto_login_unittest.cc
@@ -151,15 +151,10 @@ }; TEST_F(ExistingUserControllerAutoLoginTest, StartAutoLoginTimer) { - // Timer shouldn't start until signin screen is ready. - set_auto_login_account_id(auto_login_account_id_); set_auto_login_delay(kAutoLoginDelay2); - existing_user_controller()->StartAutoLoginTimer(); - EXPECT_FALSE(auto_login_timer()); // Timer shouldn't start if the policy isn't set. set_auto_login_account_id(EmptyAccountId()); - existing_user_controller()->OnSigninScreenReady(); existing_user_controller()->StartAutoLoginTimer(); EXPECT_FALSE(auto_login_timer()); @@ -179,7 +174,6 @@ } TEST_F(ExistingUserControllerAutoLoginTest, StopAutoLoginTimer) { - existing_user_controller()->OnSigninScreenReady(); set_auto_login_account_id(auto_login_account_id_); set_auto_login_delay(kAutoLoginDelay2); @@ -193,7 +187,6 @@ } TEST_F(ExistingUserControllerAutoLoginTest, ResetAutoLoginTimer) { - existing_user_controller()->OnSigninScreenReady(); set_auto_login_account_id(auto_login_account_id_); // Timer starts off not running. @@ -222,8 +215,6 @@ } TEST_F(ExistingUserControllerAutoLoginTest, ConfigureAutoLogin) { - existing_user_controller()->OnSigninScreenReady(); - // Timer shouldn't start when the policy is disabled. ConfigureAutoLogin(); EXPECT_FALSE(auto_login_timer());
diff --git a/chrome/browser/client_hints/client_hints.cc b/chrome/browser/client_hints/client_hints.cc index a72ae92..09f73ed5 100644 --- a/chrome/browser/client_hints/client_hints.cc +++ b/chrome/browser/client_hints/client_hints.cc
@@ -12,8 +12,10 @@ #include "base/metrics/field_trial_params.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/client_hints/client_hints.h" @@ -24,6 +26,7 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/content_features.h" +#include "content/public/common/content_switches.h" #include "content/public/common/origin_util.h" #include "net/base/url_util.h" #include "net/http/http_request_headers.h" @@ -157,6 +160,12 @@ return effective_connection_type; } +bool UserAgentClientHintEnabled() { + return base::FeatureList::IsEnabled(features::kUserAgentClientHint) || + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableExperimentalWebPlatformFeatures); +} + } // namespace namespace client_hints { @@ -378,12 +387,53 @@ profile->GetPrefs()->GetString(language::prefs::kAcceptLanguages))); } + if (UserAgentClientHintEnabled()) { + blink::UserAgentMetadata ua = ::GetUserAgentMetadata(); + + // The `Sec-CH-UA` client hint is attached to all outgoing requests. The + // opt-in controls the header's value, not its presence. This is + // (intentionally) different than other client hints. + // + // https://tools.ietf.org/html/draft-west-ua-client-hints-00#section-2.4 + additional_headers->SetHeader( + blink::kClientHintsHeaderMapping[static_cast<int>( + blink::mojom::WebClientHintsType::kUA)], + // TODO(mkwst): This should include only the major version if the + // recipient hasn't opted into the hint. + ua.version.empty() ? ua.brand.c_str() + : base::StringPrintf("%s %s", ua.brand.c_str(), + ua.version.c_str())); + + if (web_client_hints.IsEnabled(blink::mojom::WebClientHintsType::kUAArch)) { + additional_headers->SetHeader( + blink::kClientHintsHeaderMapping[static_cast<int>( + blink::mojom::WebClientHintsType::kUAArch)], + ua.architecture); + } + + if (web_client_hints.IsEnabled( + blink::mojom::WebClientHintsType::kUAPlatform)) { + additional_headers->SetHeader( + blink::kClientHintsHeaderMapping[static_cast<int>( + blink::mojom::WebClientHintsType::kUAPlatform)], + ua.platform); + } + + if (web_client_hints.IsEnabled( + blink::mojom::WebClientHintsType::kUAModel)) { + additional_headers->SetHeader( + blink::kClientHintsHeaderMapping[static_cast<int>( + blink::mojom::WebClientHintsType::kUAModel)], + ua.model); + } + } + // Static assert that triggers if a new client hint header is added. If a // new client hint header is added, the following assertion should be updated. // If possible, logic should be added above so that the request headers for // the newly added client hint can be added to the request. static_assert( - blink::mojom::WebClientHintsType::kLang == + blink::mojom::WebClientHintsType::kUAModel == blink::mojom::WebClientHintsType::kMaxValue, "Consider adding client hint request headers from the browser process");
diff --git a/chrome/browser/client_hints/client_hints_browsertest.cc b/chrome/browser/client_hints/client_hints_browsertest.cc index 39ba63c..e7ce545f 100644 --- a/chrome/browser/client_hints/client_hints_browsertest.cc +++ b/chrome/browser/client_hints/client_hints_browsertest.cc
@@ -4,6 +4,7 @@ #include <cctype> +#include "base/base_switches.h" #include "base/bind.h" #include "base/command_line.h" #include "base/metrics/field_trial_param_associator.h" @@ -138,6 +139,7 @@ https_cross_origin_server_(net::EmbeddedTestServer::TYPE_HTTPS), expect_client_hints_on_main_frame_(false), expect_client_hints_on_subresources_(false), + count_user_agent_hint_headers_seen_(0), count_client_hints_headers_seen_(0), request_interceptor_(nullptr) { http_server_.ServeFilesFromSourceDirectory("chrome/test/data/client_hints"); @@ -234,6 +236,17 @@ ~ClientHintsBrowserTest() override {} + virtual std::unique_ptr<base::FeatureList> EnabledFeatures() { + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + feature_list->InitializeFromCommandLine("UserAgentClientHint", ""); + return feature_list; + } + + void SetUp() override { + scoped_feature_list_.InitWithFeatureList(EnabledFeatures()); + InProcessBrowserTest::SetUp(); + } + void SetUpOnMainThread() override { host_resolver()->AddRule("*", "127.0.0.1"); @@ -369,6 +382,10 @@ const GURL& redirect_url() const { return redirect_url_; } + size_t count_user_agent_hint_headers_seen() const { + return count_user_agent_hint_headers_seen_; + } + size_t count_client_hints_headers_seen() const { return count_client_hints_headers_seen_; } @@ -536,7 +553,12 @@ for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) { if (base::ContainsKey(request.headers, blink::kClientHintsHeaderMapping[i])) { - count_client_hints_headers_seen_++; + // The user agent hint is special: + if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua") { + count_user_agent_hint_headers_seen_++; + } else { + count_client_hints_headers_seen_++; + } } } } @@ -550,6 +572,12 @@ if (std::string(blink::kClientHintsHeaderMapping[i]) == "width") { continue; } + + // `Sec-CH-UA` is attached on all requests. + if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua") { + continue; + } + EXPECT_EQ(expect_client_hints, base::ContainsKey(request.headers, blink::kClientHintsHeaderMapping[i])); @@ -650,6 +678,7 @@ // Expect client hints on all the subresource requests. bool expect_client_hints_on_subresources_; + size_t count_user_agent_hint_headers_seen_; size_t count_client_hints_headers_seen_; std::unique_ptr<ThirdPartyURLLoaderInterceptor> request_interceptor_; @@ -669,10 +698,11 @@ testing::Bool()); class ClientHintsAllowThirdPartyBrowserTest : public ClientHintsBrowserTest { - void SetUpCommandLine(base::CommandLine* cmd) override { - scoped_feature_list_.InitFromCommandLine("AllowClientHintsToThirdParty", - ""); - ClientHintsBrowserTest::SetUpCommandLine(cmd); + std::unique_ptr<base::FeatureList> EnabledFeatures() override { + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + feature_list->InitializeFromCommandLine( + "AllowClientHintsToThirdParty,UserAgentClientHint", ""); + return feature_list; } }; @@ -708,8 +738,8 @@ content::FetchHistogramsFromChildProcesses(); SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - // client_hints_url() sets seven client hints. - histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 7, 1); + // client_hints_url() sets eleven client hints. + histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11, 1); // accept_ch_with_lifetime_url() sets client hints persist duration to 3600 // seconds. histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration", @@ -764,9 +794,12 @@ content::FetchHistogramsFromChildProcesses(); SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - // seven client hints are attached to the image request, and seven to the main - // frame request. - EXPECT_EQ(14u, count_client_hints_headers_seen()); + // The user agent hint is attached to all three requests: + EXPECT_EQ(3u, count_user_agent_hint_headers_seen()); + + // Ten client hints are attached to the image request, and ten to the + // main frame request. + EXPECT_EQ(20u, count_client_hints_headers_seen()); // Navigating to without_accept_ch_without_lifetime_img_foo_com() should not // attach client hints to the image subresouce contained in that page since @@ -779,13 +812,15 @@ // The device-memory and dprheader is attached to the main frame request. #if defined(OS_ANDROID) - EXPECT_EQ(7u, count_client_hints_headers_seen()); + EXPECT_EQ(10u, count_client_hints_headers_seen()); #else - EXPECT_EQ(21u, count_client_hints_headers_seen()); + EXPECT_EQ(30u, count_client_hints_headers_seen()); #endif - // Requests to third party servers should not have client hints attached. + + // Requests to third party servers should have only one client hint attached + // (`Sec-CH-UA`). EXPECT_EQ(1u, third_party_request_count_seen()); - EXPECT_EQ(0u, third_party_client_hints_count_seen()); + EXPECT_EQ(1u, third_party_client_hints_count_seen()); } // Test that client hints are attached to third party subresources if @@ -805,7 +840,7 @@ ui_test_utils::NavigateToURL(browser(), gurl); histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0); - EXPECT_EQ(7u, count_client_hints_headers_seen()); + EXPECT_EQ(11u, count_client_hints_headers_seen()); // Requests to third party servers should not have client hints attached. EXPECT_EQ(1u, third_party_request_count_seen()); @@ -832,14 +867,16 @@ ui_test_utils::NavigateToURL(browser(), gurl); histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0); - EXPECT_EQ(7u, count_client_hints_headers_seen()); + EXPECT_EQ(2u, count_user_agent_hint_headers_seen()); + EXPECT_EQ(10u, count_client_hints_headers_seen()); // Requests to third party servers should not have client hints attached. EXPECT_EQ(1u, third_party_request_count_seen()); // Client hints should not be sent to the third-party when feature - // "AllowClientHintsToThirdParty" is not enabled. - EXPECT_EQ(0u, third_party_client_hints_count_seen()); + // "AllowClientHintsToThirdParty" is not enabled, with the exception of the + // `Sec-CH-UA` hint, which is sent with every request. + EXPECT_EQ(1u, third_party_client_hints_count_seen()); } // Loads a HTTPS webpage that does not request persisting of client hints. @@ -1001,7 +1038,7 @@ content::FetchHistogramsFromChildProcesses(); SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 7, 1); + histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1); // |gurl| sets client hints persist duration to 3600 seconds. histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration", 3600 * 1000, 1); @@ -1019,9 +1056,12 @@ ui_test_utils::NavigateToURL(browser(), without_accept_ch_without_lifetime_local_url()); - // seven client hints are attached to the image request, and seven to the main - // frame request. - EXPECT_EQ(14u, count_client_hints_headers_seen()); + // The user agent hint is attached to all three requests: + EXPECT_EQ(3u, count_user_agent_hint_headers_seen()); + + // Ten client hints are attached to the image request, and ten to the + // main frame request. + EXPECT_EQ(20u, count_client_hints_headers_seen()); } // Loads a webpage that does not request persisting of client hints. @@ -1061,7 +1101,7 @@ content::FetchHistogramsFromChildProcesses(); SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 7, 1); + histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1); // accept_ch_with_lifetime_url() sets client hints persist duration to 3600 // seconds. histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration", @@ -1079,9 +1119,12 @@ ui_test_utils::NavigateToURL(browser(), without_accept_ch_without_lifetime_url()); - // seven client hints are attached to the image request, and seven to the main - // frame request. - EXPECT_EQ(14u, count_client_hints_headers_seen()); + // The user agent hint is attached to all three requests: + EXPECT_EQ(3u, count_user_agent_hint_headers_seen()); + + // Ten client hints are attached to the image request, and ten to the + // main frame request. + EXPECT_EQ(20u, count_client_hints_headers_seen()); } // The test first fetches a page that sets Accept-CH-Lifetime. Next, it fetches @@ -1111,7 +1154,7 @@ content::FetchHistogramsFromChildProcesses(); SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 7, 1); + histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1); // accept_ch_with_lifetime_url() sets client hints persist duration to 3600 // seconds. histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration", @@ -1128,9 +1171,12 @@ SetClientHintExpectationsOnSubresources(true); ui_test_utils::NavigateToURL(browser(), redirect_url()); - // seven client hints are attached to the image request, and seven to the main - // frame request. - EXPECT_EQ(14u, count_client_hints_headers_seen()); + // The user agent hint is attached to all three requests: + EXPECT_EQ(3u, count_user_agent_hint_headers_seen()); + + // Ten client hints are attached to the image request, and ten to the + // main frame request. + EXPECT_EQ(20u, count_client_hints_headers_seen()); } // Ensure that even when cookies are blocked, client hint preferences are @@ -1182,7 +1228,7 @@ content::FetchHistogramsFromChildProcesses(); SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 7, 1); + histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1); // |gurl_with| tries to set client hints persist duration to 3600 seconds. histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration", 3600 * 1000, 1); @@ -1205,9 +1251,12 @@ ui_test_utils::NavigateToURL(browser(), without_accept_ch_without_lifetime_url()); - // seven client hints are attached to the image request, and seven to the main - // frame request. - EXPECT_EQ(14u, count_client_hints_headers_seen()); + // The user agent hint is attached to all three requests: + EXPECT_EQ(3u, count_user_agent_hint_headers_seen()); + + // Ten client hints are attached to the image request, and ten to the + // main frame request. + EXPECT_EQ(20u, count_client_hints_headers_seen()); // Clear settings. HostContentSettingsMapFactory::GetForProfile(browser()->profile()) @@ -1278,8 +1327,9 @@ histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1); content::FetchHistogramsFromChildProcesses(); SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); + EXPECT_EQ(1u, count_user_agent_hint_headers_seen()); - histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 7, 1); + histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1); // accept_ch_with_lifetime_url() tries to set client hints persist duration to // 3600 seconds. histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration", @@ -1301,6 +1351,7 @@ without_accept_ch_without_lifetime_url()); EXPECT_EQ(0u, count_client_hints_headers_seen()); VerifyContentSettingsNotNotified(); + EXPECT_EQ(1u, count_user_agent_hint_headers_seen()); // Allow the Javascript: Client hints should now be attached. HostContentSettingsMapFactory::GetForProfile(browser()->profile()) @@ -1313,9 +1364,12 @@ ui_test_utils::NavigateToURL(browser(), without_accept_ch_without_lifetime_url()); - // seven client hints are attached to the image request, and seven to the main - // frame request. - EXPECT_EQ(14u, count_client_hints_headers_seen()); + // The user agent hint is attached to all three requests: + EXPECT_EQ(3u, count_user_agent_hint_headers_seen()); + + // Ten client hints are attached to the image request, and ten to the + // main frame request. + EXPECT_EQ(20u, count_client_hints_headers_seen()); // Clear settings. HostContentSettingsMapFactory::GetForProfile(browser()->profile()) @@ -1346,6 +1400,7 @@ CONTENT_SETTING_BLOCK); ui_test_utils::NavigateToURL(browser(), accept_ch_without_lifetime_img_localhost()); + EXPECT_EQ(0u, count_user_agent_hint_headers_seen()); EXPECT_EQ(0u, count_client_hints_headers_seen()); EXPECT_EQ(1u, third_party_request_count_seen()); EXPECT_EQ(0u, third_party_client_hints_count_seen()); @@ -1361,9 +1416,10 @@ ui_test_utils::NavigateToURL(browser(), accept_ch_without_lifetime_img_localhost()); - EXPECT_EQ(7u, count_client_hints_headers_seen()); + EXPECT_EQ(2u, count_user_agent_hint_headers_seen()); + EXPECT_EQ(10u, count_client_hints_headers_seen()); EXPECT_EQ(2u, third_party_request_count_seen()); - EXPECT_EQ(0u, third_party_client_hints_count_seen()); + EXPECT_EQ(1u, third_party_client_hints_count_seen()); VerifyContentSettingsNotNotified(); // Clear settings. @@ -1379,9 +1435,10 @@ CONTENT_SETTING_BLOCK); ui_test_utils::NavigateToURL(browser(), accept_ch_without_lifetime_img_localhost()); - EXPECT_EQ(7u, count_client_hints_headers_seen()); + EXPECT_EQ(2u, count_user_agent_hint_headers_seen()); + EXPECT_EQ(10u, count_client_hints_headers_seen()); EXPECT_EQ(3u, third_party_request_count_seen()); - EXPECT_EQ(0u, third_party_client_hints_count_seen()); + EXPECT_EQ(1u, third_party_client_hints_count_seen()); // Clear settings. HostContentSettingsMapFactory::GetForProfile(browser()->profile()) @@ -1415,9 +1472,10 @@ SetClientHintExpectationsOnSubresources(true); ui_test_utils::NavigateToURL(browser(), gurl); - EXPECT_EQ(7u, count_client_hints_headers_seen()); + EXPECT_EQ(2u, count_user_agent_hint_headers_seen()); + EXPECT_EQ(10u, count_client_hints_headers_seen()); EXPECT_EQ(1u, third_party_request_count_seen()); - EXPECT_EQ(0u, third_party_client_hints_count_seen()); + EXPECT_EQ(1u, third_party_client_hints_count_seen()); // Clear settings. HostContentSettingsMapFactory::GetForProfile(browser()->profile()) @@ -1448,7 +1506,7 @@ content::FetchHistogramsFromChildProcesses(); SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 7, 1); + histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1); // accept_ch_with_lifetime_url() sets client hints persist duration to 3600 // seconds. histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration", @@ -1466,9 +1524,12 @@ ui_test_utils::NavigateToURL(incognito, without_accept_ch_without_lifetime_url()); - // Seven client hints are attached to the image request, and seven to the main - // frame request. - EXPECT_EQ(14u, count_client_hints_headers_seen()); + // The user agent hint is attached to all three requests: + EXPECT_EQ(3u, count_user_agent_hint_headers_seen()); + + // Ten client hints are attached to the image request, and ten to the + // main frame request. + EXPECT_EQ(20u, count_client_hints_headers_seen()); // Navigate using regular profile. Client hints should not be send. SetClientHintExpectationsOnMainFrame(false); @@ -1476,9 +1537,11 @@ ui_test_utils::NavigateToURL(browser(), without_accept_ch_without_lifetime_url()); - // Seven client hints are attached to the image request, and seven to the main - // frame request. - EXPECT_EQ(14u, count_client_hints_headers_seen()); + // The user agent hint is attached to the two new requests. + EXPECT_EQ(5u, count_user_agent_hint_headers_seen()); + + // No additional hints are sent. + EXPECT_EQ(20u, count_client_hints_headers_seen()); } class ClientHintsWebHoldbackBrowserTest : public ClientHintsBrowserTest { @@ -1491,8 +1554,7 @@ return web_effective_connection_type_override_; } - private: - void ConfigureHoldbackExperiment() { + std::unique_ptr<base::FeatureList> EnabledFeatures() override { base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting(); const std::string kTrialName = "TrialFoo"; const std::string kGroupName = "GroupFoo"; // Value not used @@ -1505,17 +1567,21 @@ params["web_effective_connection_type_override"] = net::GetNameForEffectiveConnectionType( web_effective_connection_type_override_); - ASSERT_TRUE( + EXPECT_TRUE( base::FieldTrialParamAssociator::GetInstance() ->AssociateFieldTrialParams(kTrialName, kGroupName, params)); std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + feature_list->InitializeFromCommandLine("UserAgentClientHint", ""); feature_list->RegisterFieldTrialOverride( features::kNetworkQualityEstimatorWebHoldback.name, base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get()); - scoped_feature_list_override_.InitWithFeatureList(std::move(feature_list)); + return feature_list; } + private: + void ConfigureHoldbackExperiment() {} + const net::EffectiveConnectionType web_effective_connection_type_override_ = net::EFFECTIVE_CONNECTION_TYPE_3G; @@ -1548,7 +1614,8 @@ content::FetchHistogramsFromChildProcesses(); SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - EXPECT_EQ(14u, count_client_hints_headers_seen()); + EXPECT_EQ(3u, count_user_agent_hint_headers_seen()); + EXPECT_EQ(20u, count_client_hints_headers_seen()); EXPECT_EQ(0u, third_party_request_count_seen()); EXPECT_EQ(0u, third_party_client_hints_count_seen()); }
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc index e390712..4df9767d 100644 --- a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc +++ b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
@@ -302,15 +302,10 @@ test_util->HidePopup(); } -#if defined(OS_LINUX) -#define MAYBE_TestOpenPopupDoesNotCloseOtherPopups DISABLED_TestOpenPopupDoesNotCloseOtherPopups -#else -#define MAYBE_TestOpenPopupDoesNotCloseOtherPopups TestOpenPopupDoesNotCloseOtherPopups -#endif // Tests if there is already a popup open (by a user click or otherwise), that // the openPopup API does not override it. IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, - MAYBE_TestOpenPopupDoesNotCloseOtherPopups) { + TestOpenPopupDoesNotCloseOtherPopups) { if (!ShouldRunPopupTest()) return;
diff --git a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc index ec62ba7..cb8a9e0 100644 --- a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc +++ b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
@@ -4,14 +4,14 @@ #include "chrome/browser/extensions/api/identity/identity_get_auth_token_function.h" -#include <memory> #include <set> -#include <string> #include <vector> #include "base/bind.h" +#include "base/location.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" +#include "base/task/post_task.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/identity/identity_api.h" @@ -24,6 +24,8 @@ #include "chrome/common/extensions/api/identity.h" #include "components/prefs/pref_service.h" #include "components/signin/core/browser/signin_pref_names.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" #include "content/public/common/service_manager_connection.h" #include "extensions/common/extension_l10n_util.h" #include "google_apis/gaia/gaia_urls.h" @@ -33,7 +35,6 @@ #if defined(OS_CHROMEOS) #include "chrome/browser/app_mode/app_mode_utils.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/session/user_session_manager.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h" @@ -76,7 +77,8 @@ token_key_(/*extension_id=*/std::string(), /*account_id=*/std::string(), /*scopes=*/std::set<std::string>()), - scoped_identity_manager_observer_(this) { + scoped_identity_manager_observer_(this), + weak_ptr_factory_(this) { } IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() { @@ -142,9 +144,12 @@ if (gaia_id.empty() || IsPrimaryAccountOnly()) { // Try the primary account. - GetMojoIdentityManager()->GetPrimaryAccountInfo(base::BindOnce( - &IdentityGetAuthTokenFunction::OnReceivedPrimaryAccountInfo, this, - gaia_id)); + // TODO(https://crbug.com/932400): collapse the asynchronicity + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce( + &IdentityGetAuthTokenFunction::GetAuthTokenForPrimaryAccount, + weak_ptr_factory_.GetWeakPtr(), gaia_id)); } else { // Get the AccountInfo for the account that the extension wishes to use. GetMojoIdentityManager()->GetAccountInfoFromGaiaId( @@ -157,35 +162,36 @@ return true; } -void IdentityGetAuthTokenFunction::OnReceivedPrimaryAccountInfo( - const std::string& extension_gaia_id, - const base::Optional<AccountInfo>& account_info, - const ::identity::AccountState& account_state) { - std::string primary_gaia_id; - if (account_info) - primary_gaia_id = account_info->gaia; - +void IdentityGetAuthTokenFunction::GetAuthTokenForPrimaryAccount( + const std::string& extension_gaia_id) { + AccountInfo primary_account_info = + IdentityManagerFactory::GetForProfile(GetProfile()) + ->GetPrimaryAccountInfo(); bool primary_account_only = IsPrimaryAccountOnly(); // Detect and handle the case where the extension is using an account other // than the primary account. if (primary_account_only && !extension_gaia_id.empty() && - extension_gaia_id != primary_gaia_id) { + extension_gaia_id != primary_account_info.gaia) { // TODO(courage): should this be a different error? CompleteFunctionWithError(identity_constants::kUserNotSignedIn); return; } - if (primary_account_only || !primary_gaia_id.empty()) { + auto* identity_manager = IdentityManagerFactory::GetForProfile(GetProfile()); + if (primary_account_only || !primary_account_info.gaia.empty()) { // The extension is using the primary account. - OnReceivedExtensionAccountInfo(primary_gaia_id, account_info, - account_state); + ::identity::AccountState account_state; + account_state.has_refresh_token = + identity_manager->HasAccountWithRefreshToken( + primary_account_info.account_id); + OnReceivedExtensionAccountInfo( + primary_account_info.gaia, + base::Optional<AccountInfo>(primary_account_info), account_state); } else { // No primary account, try the first account in cookies. DCHECK_EQ(AccountListeningMode::kNotListening, account_listening_mode_); account_listening_mode_ = AccountListeningMode::kListeningCookies; - identity::IdentityManager* identity_manager = - IdentityManagerFactory::GetForProfile(GetProfile()); identity::AccountsInCookieJarInfo accounts_in_cookies = identity_manager->GetAccountsInCookieJar(); if (accounts_in_cookies.accounts_are_fresh) {
diff --git a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h index b980e6d..294eb2c 100644 --- a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h +++ b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h
@@ -6,8 +6,11 @@ #define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_GET_AUTH_TOKEN_FUNCTION_H_ #include <memory> +#include <string> #include "base/callback_list.h" +#include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "base/scoped_observer.h" #include "chrome/browser/extensions/api/identity/gaia_web_auth_flow.h" #include "chrome/browser/extensions/api/identity/identity_mint_queue.h" @@ -126,15 +129,10 @@ FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest, InteractiveQueueShutdown); FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest, NoninteractiveShutdown); - // Called by the IdentityManager in response to this class' request for the - // primary account info. Extra arguments that are bound internally at the time - // of calling the IdentityManager: + // Request the primary account info. // |extension_gaia_id|: The GAIA ID that was set in the parameters for this // instance, or empty if this was not in the parameters. - void OnReceivedPrimaryAccountInfo( - const std::string& extension_gaia_id, - const base::Optional<AccountInfo>& account_info, - const identity::AccountState& account_state); + void GetAuthTokenForPrimaryAccount(const std::string& extension_gaia_id); // Called when the AccountInfo that this instance should use is available. void OnReceivedExtensionAccountInfo( @@ -242,6 +240,8 @@ }; AccountListeningMode account_listening_mode_ = AccountListeningMode::kNotListening; + + base::WeakPtrFactory<IdentityGetAuthTokenFunction> weak_ptr_factory_; }; } // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 6bfbcb15..45cb427 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1194,6 +1194,11 @@ "expiry_milestone": -1 }, { + "name": "enable-filesystem-in-incognito", + "owners": [ "rhalavati" ], + "expiry_milestone": 76 + }, + { "name": "enable-first-run-ui-transitions", // "owners": [ "your-team" ], "expiry_milestone": 76 @@ -2213,11 +2218,6 @@ "expiry_milestone": 76 }, { - "name": "gesture-editing", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "gesture-typing", // "owners": [ "your-team" ], "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 2fb4cf6..d2853aa 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -523,6 +523,10 @@ "Enable support for specifying a target element using a css selector in " "the fragment identifier."; +const char kEnableFilesystemInIncognitoName[] = "Filesystem API in Incognito"; +const char kEnableFilesystemInIncognitoDescription[] = + "Enable Filesystem API in incognito mode."; + const char kEnableNoScriptPreviewsName[] = "NoScript previews"; const char kEnableNoScriptPreviewsDescription[] = @@ -3350,11 +3354,6 @@ "Forces display of the stylus tools menu in the shelf and the stylus " "section in settings, even if there is no attached stylus device."; -const char kGestureEditingName[] = "Gesture editing for the virtual keyboard."; -const char kGestureEditingDescription[] = - "Enable/Disable gesture editing option in the settings page for the " - "virtual keyboard."; - const char kGestureTypingName[] = "Gesture typing for the virtual keyboard."; const char kGestureTypingDescription[] = "Enable/Disable gesture typing option in the settings page for the virtual "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index dc8b9023a..2587f718 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -345,6 +345,9 @@ extern const char kEnableCSSFragmentIdentifiersName[]; extern const char kEnableCSSFragmentIdentifiersDescription[]; +extern const char kEnableFilesystemInIncognitoName[]; +extern const char kEnableFilesystemInIncognitoDescription[]; + extern const char kEnableNoScriptPreviewsName[]; extern const char kEnableNoScriptPreviewsDescription[]; @@ -2012,9 +2015,6 @@ extern const char kForceEnableStylusToolsName[]; extern const char kForceEnableStylusToolsDescription[]; -extern const char kGestureEditingName[]; -extern const char kGestureEditingDescription[]; - extern const char kGestureTypingName[]; extern const char kGestureTypingDescription[];
diff --git a/chrome/browser/picture_in_picture/DEPS b/chrome/browser/picture_in_picture/DEPS index 169b1b5..0217078 100644 --- a/chrome/browser/picture_in_picture/DEPS +++ b/chrome/browser/picture_in_picture/DEPS
@@ -2,9 +2,9 @@ "picture_in_picture_window_controller_browsertest\.cc": [ "+ash/accelerators/accelerator_controller.h", "+ash/shell.h", - "+chrome/browser/ui/views/overlay/next_track_image_button.h", "+chrome/browser/ui/views/overlay/overlay_window_views.h", "+chrome/browser/ui/views/overlay/playback_image_button.h", "+chrome/browser/ui/views/overlay/skip_ad_label_button.h", + "+chrome/browser/ui/views/overlay/track_image_button.h", ], }
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc index 1e504057..a91d698 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -44,10 +44,10 @@ #include "ui/gfx/codec/png_codec.h" #if !defined(OS_ANDROID) -#include "chrome/browser/ui/views/overlay/next_track_image_button.h" #include "chrome/browser/ui/views/overlay/overlay_window_views.h" #include "chrome/browser/ui/views/overlay/playback_image_button.h" #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h" +#include "chrome/browser/ui/views/overlay/track_image_button.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/widget/widget_observer.h" #endif @@ -90,6 +90,7 @@ MOCK_METHOD1(SetAlwaysHidePlayPauseButton, void(bool)); MOCK_METHOD0(SkipAd, void()); MOCK_METHOD0(NextTrack, void()); + MOCK_METHOD0(PreviousTrack, void()); private: DISALLOW_COPY_AND_ASSIGN(MockPictureInPictureWindowController); @@ -2072,6 +2073,52 @@ overlay_window->next_track_controls_view_for_testing()->IsDrawn()); } +// Tests that a Previous Track button is displayed in the Picture-in-Picture +// window when Media Session Action "previoustrack" is handled by the website. +IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, + PreviousTrackButtonVisibility) { + LoadTabAndEnterPictureInPicture(browser()); + OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>( + window_controller()->GetWindowForTesting()); + ASSERT_TRUE(overlay_window); + + // Previous Track button is not displayed initially when mouse is hovering + // over the window. + MoveMouseOver(overlay_window); + EXPECT_FALSE( + overlay_window->previous_track_controls_view_for_testing()->IsDrawn()); + + content::WebContents* active_web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + // Previous Track button is not displayed if video is not playing even if + // mouse is hovering over the window and media session action handler has been + // set. + ASSERT_TRUE(content::ExecuteScript( + active_web_contents, "setMediaSessionActionHandler('previoustrack');")); + base::RunLoop().RunUntilIdle(); + MoveMouseOver(overlay_window); + EXPECT_FALSE( + overlay_window->previous_track_controls_view_for_testing()->IsDrawn()); + + // Play video and check that Previous Track button is now displayed when + // video plays and mouse is hovering over the window. + ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();")); + base::RunLoop().RunUntilIdle(); + MoveMouseOver(overlay_window); + EXPECT_TRUE( + overlay_window->previous_track_controls_view_for_testing()->IsDrawn()); + + // Unset action handler and check that Previous Track button is not displayed + // when video plays and mouse is hovering over the window. + ASSERT_TRUE(content::ExecuteScript( + active_web_contents, "unsetMediaSessionActionHandler('previoustrack');")); + base::RunLoop().RunUntilIdle(); + MoveMouseOver(overlay_window); + EXPECT_FALSE( + overlay_window->previous_track_controls_view_for_testing()->IsDrawn()); +} + // Tests that clicking the Skip Ad button in the Picture-in-Picture window // calls the Media Session Action "skipad" handler function. IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, @@ -2146,6 +2193,27 @@ .WaitAndGetTitle()); } +// Tests that clicking the Previous Track button in the Picture-in-Picture +// window calls the Media Session Action "previoustrack" handler function. +IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest, + PreviousTrackHandlerCalled) { + LoadTabAndEnterPictureInPicture(browser()); + content::WebContents* active_web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();")); + ASSERT_TRUE(content::ExecuteScript( + active_web_contents, "setMediaSessionActionHandler('previoustrack');")); + base::RunLoop().RunUntilIdle(); + + // Simulates user clicking "Previous Track" and check the handler function is + // called. + window_controller()->PreviousTrack(); + base::string16 expected_title = base::ASCIIToUTF16("previoustrack"); + EXPECT_EQ(expected_title, + content::TitleWatcher(active_web_contents, expected_title) + .WaitAndGetTitle()); +} + // Show/hide page and check that Auto Picture-in-Picture is not triggered. This // test is most likely going to be flaky the day the tested thing fails. // Do NOT disable test. Ping /chrome/browser/picture_in_picture/OWNERS instead.
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index 9ab37ce..a8a11c5 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc
@@ -1654,7 +1654,7 @@ identity::IdentityManager* identity_manager = IdentityManagerFactory::GetForProfile(profile); - AccountInfo account_info = identity_manager->GetPrimaryAccountInfo(); + CoreAccountInfo account_info = identity_manager->GetPrimaryAccountInfo(); base::string16 username = base::UTF8ToUTF16(account_info.email); ProfileAttributesStorage& storage = GetProfileAttributesStorage();
diff --git a/chrome/browser/profiles/profiles_state.cc b/chrome/browser/profiles/profiles_state.cc index e0201f1..9642a8e4 100644 --- a/chrome/browser/profiles/profiles_state.cc +++ b/chrome/browser/profiles/profiles_state.cc
@@ -153,7 +153,7 @@ // The vector returned by GetAccountsWithRefreshTokens() contains // the primary account too, so we need to remove it from the list. DCHECK(identity_manager->HasPrimaryAccount()); - AccountInfo primary_account = identity_manager->GetPrimaryAccountInfo(); + CoreAccountInfo primary_account = identity_manager->GetPrimaryAccountInfo(); auto primary_index = std::find_if( accounts.begin(), accounts.end(),
diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc index f3fc761c..f5ed7f0 100644 --- a/chrome/browser/renderer_preferences_util.cc +++ b/chrome/browser/renderer_preferences_util.cc
@@ -14,7 +14,7 @@ #include "chrome/common/pref_names.h" #include "components/language/core/browser/pref_names.h" #include "components/prefs/pref_service.h" -#include "content/public/common/renderer_preferences_util.h" +#include "content/public/browser/renderer_preferences_util.h" #include "content/public/common/webrtc_ip_handling_policy.h" #include "media/media_buildflags.h" #include "third_party/blink/public/mojom/renderer_preferences.mojom.h" @@ -150,6 +150,7 @@ #if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_WIN) content::UpdateFontRendererPreferencesFromSystemSettings(prefs); + content::UpdateFocusRingPreferencesFromSystemSettings(prefs); #endif #if !defined(OS_MACOSX)
diff --git a/chrome/browser/resources/app_management/BUILD.gn b/chrome/browser/resources/app_management/BUILD.gn index 09e156c..3573cff 100644 --- a/chrome/browser/resources/app_management/BUILD.gn +++ b/chrome/browser/resources/app_management/BUILD.gn
@@ -17,6 +17,7 @@ ":chrome_app_permission_view", ":constants", ":dom_switch", + ":expandable_app_list", ":fake_page_handler", ":main_view", ":metadata_view", @@ -112,6 +113,13 @@ js_library("dom_switch") { } + js_library("expandable_app_list") { + deps = [ + ":app_item", + ":store_client", + ] + } + js_library("fake_page_handler") { deps = [ ":constants",
diff --git a/chrome/browser/resources/app_management/expandable_app_list.html b/chrome/browser/resources/app_management/expandable_app_list.html new file mode 100644 index 0000000..d1add13a --- /dev/null +++ b/chrome/browser/resources/app_management/expandable_app_list.html
@@ -0,0 +1,85 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="app_item.html"> +<link rel="import" href="shared_style.html"> +<link rel="import" href="store_client.html"> +<link rel="import" href="permission_toggle.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> + +<dom-module id="app-management-expandable-app-list"> + <template> + <style include="app-management-shared-css"> + .app-management-item-arrow { + margin-inline-end: 8px; + padding: 12px; + } + + #app-list-title { + padding: 16px 24px; + } + + app-management-permission-toggle { + margin-inline-end: 24px; + } + </style> + <!-- TODO(ceciliani) Avoid using dom-if, and use slot by getting |items| + from dom-repeat --> + <!-- TODO(calamity) Make a more generic polymer element for expandable + list. --> + <div class="card-container"> + <div id="app-list-title" class="header-text">[[listTitle]]</div> + <template is="dom-repeat" items="[[displayedApps]]"> + <template is="dom-if" if="[[!notificationsViewSelected_()]]"> + <app-management-app-item app="[[item]]"> + <paper-icon-button-light slot="right-content" + class="subpage-arrow app-management-item-arrow" actionable> + <button></button> + </paper-icon-button-light> + </app-management-app-item> + </template> + <template is="dom-if" if="[[notificationsViewSelected_()]]"> + <app-management-app-item app="[[item]]"> + <app-management-permission-toggle slot="right-content" + app="[[item]]" + permission-type="CONTENT_SETTINGS_TYPE_NOTIFICATIONS"> + </app-management-permission-toggle> + </app-management-app-item> + </template> + </template> + + <iron-collapse opened="[[listExpanded_]]"> + <template is="dom-repeat" items="[[collapsedApps]]"> + <template is="dom-if" if="[[!notificationsViewSelected_()]]"> + <app-management-app-item app="[[item]]"> + <paper-icon-button-light slot="right-content" + class="subpage-arrow app-management-item-arrow" actionable> + <button></button> + </paper-icon-button-light> + </app-management-app-item> + </template> + <template is="dom-if" if="[[notificationsViewSelected_()]]"> + <app-management-app-item app="[[item]]"> + <app-management-permission-toggle slot="right-content" + app="[[item]]" + permission-type="CONTENT_SETTINGS_TYPE_NOTIFICATIONS"> + </app-management-permission-toggle> + </app-management-app-item> + </template> + </template> + </iron-collapse> + + <div id="expander-row" class="expander-list-row" + on-click="toggleListExpanded_"> + <span>[[moreAppsString_(collapsedApps.length,listExpanded_)]]</span> + <paper-icon-button-light class="expand-button"> + <button> + <iron-icon icon="[[getCollapsedIcon_(listExpanded_)]]"> + </iron-icon> + </button> + </paper-icon-button-light> + </div> + </div> + </template> + <script src="expandable_app_list.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/app_management/expandable_app_list.js b/chrome/browser/resources/app_management/expandable_app_list.js new file mode 100644 index 0000000..b4dc9aa --- /dev/null +++ b/chrome/browser/resources/app_management/expandable_app_list.js
@@ -0,0 +1,101 @@ +// Copyright 2018 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. + +Polymer({ + is: 'app-management-expandable-app-list', + + behaviors: [ + app_management.StoreClient, + ], + + properties: { + /** + * @private {Page} + */ + currentPage_: { + type: Object, + observer: 'onViewChanged_', + }, + + /** + * List of apps displayed before expanding the app list. + * @type {Array<App>} + */ + displayedApps: Array, + + /** + * Title of the expandable list. + * @type {String} + */ + listTitle: String, + + /** + * List of apps displayed after expanding app list. + * @type {Array<App>} + */ + collapsedApps: { + type: Array, + observer: 'onAppsChanged_', + }, + + /** + * @private {boolean} + */ + listExpanded_: Boolean, + }, + + attached: function() { + this.watch('currentPage_', state => state.currentPage); + + this.updateFromStore(); + }, + + /** + * @private + */ + onAppsChanged_: function() { + this.$['expander-row'].hidden = this.collapsedApps.length === 0; + }, + + /** + * Collapse the list when changing a page if it is open so that list is always + * collapsed when entering the page. + * @private + */ + onViewChanged_: function() { + this.$['app-list-title'].hidden = !this.listTitle; + this.listExpanded_ = false; + }, + + /** + * @private + */ + toggleListExpanded_: function() { + this.listExpanded_ = !this.listExpanded_; + }, + + /** + * @param {boolean} listExpanded + * @return {string} + * @private + */ + getCollapsedIcon_: function(listExpanded) { + return listExpanded ? 'cr:expand-less' : 'cr:expand-more'; + }, + + /** + * @param {number} numApps + * @param {boolean} listExpanded + * @return {string} + * @private + */ + moreAppsString_: function(numApps, listExpanded) { + return listExpanded ? loadTimeData.getString('lessApps') : + loadTimeData.getStringF('moreApps', numApps); + }, + + notificationsViewSelected_: function() { + return this.currentPage_.pageType === PageType.NOTIFICATIONS; + }, +});
diff --git a/chrome/browser/resources/app_management/main_view.html b/chrome/browser/resources/app_management/main_view.html index d00cae4..0492fb0 100644 --- a/chrome/browser/resources/app_management/main_view.html +++ b/chrome/browser/resources/app_management/main_view.html
@@ -1,6 +1,6 @@ <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="app_item.html"> +<link rel="import" href="expandable_app_list.html"> <link rel="import" href="shared_style.html"> <link rel="import" href="store_client.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html"> @@ -9,27 +9,6 @@ <dom-module id="app-management-main-view"> <template> <style include="app-management-shared-css"> - #app-list-title { - padding: 16px 24px; - } - - #expand-button { - height: 36px; - margin-inline-end: 12px; - width: 36px; - } - - #expander-row { - align-items: center; - border-top: var(--card-separator); - color: var(--secondary-text-color); - display: flex; - height: 50px; - justify-content: space-between; - padding-inline-end: 8px; - padding-inline-start: 24px; - } - .notification-row-sublabel { display: flex; flex-direction: column; @@ -59,46 +38,12 @@ justify-content: space-between; padding: 0 24px; } - - .app-management-item-arrow { - margin-inline-end: 8px; - padding: 12px; - } </style> - - <div class="card-container"> - <div id="app-list-title" class="header-text">$i18n{appListTitle}</div> - <template is="dom-repeat" items="[[displayedApps_]]"> - <app-management-app-item app="[[item]]"> - <paper-icon-button-light slot="right-content" - class="subpage-arrow app-management-item-arrow" actionable> - <button></button> - </paper-icon-button-light> - </app-management-app-item> - </template> - - <iron-collapse opened="[[listExpanded_]]"> - <template is="dom-repeat" items="[[collapsedApps_]]"> - <app-management-app-item app="[[item]]"> - <paper-icon-button-light slot="right-content" - class="subpage-arrow app-management-item-arrow" actionable> - <button></button> - </paper-icon-button-light> - </app-management-app-item> - </template> - </iron-collapse> - - <div id="expander-row" class="expander-list-row" - on-click="toggleListExpanded_"> - <span>[[moreAppsString_(apps_, listExpanded_)]]</span> - <paper-icon-button-light class="expand-button"> - <button> - <iron-icon icon="[[getCollapsedIcon_(listExpanded_)]]"> - </iron-icon> - </button> - </paper-icon-button-light> - </div> - </div> + <app-management-expandable-app-list + displayed-apps="[[displayedApps_]]" + collapsed-apps="[[collapsedApps_]]" + list-title="$i18n{appListTitle}"> + </app-management-expandable-app-list> <div class="card-container"> <span class="notification-row" on-click="onClickNotificationSublabel_">
diff --git a/chrome/browser/resources/app_management/main_view.js b/chrome/browser/resources/app_management/main_view.js index f84e00a..82b87487 100644 --- a/chrome/browser/resources/app_management/main_view.js +++ b/chrome/browser/resources/app_management/main_view.js
@@ -37,14 +37,6 @@ }, /** - * @private {boolean} - */ - listExpanded_: { - type: Boolean, - value: false, - }, - - /** * A set containing the ids of all the apps with notifications enabled. * @private {!Set<string>} */ @@ -61,52 +53,15 @@ }, /** - * @param {AppMap} apps - * @param {boolean} listExpanded - * @return {?string} - * @private - */ - moreAppsString_: function(apps, listExpanded) { - if (apps === undefined || listExpanded === undefined) { - return null; - } - - const numApps = Object.keys(apps).length; - return listExpanded ? - loadTimeData.getString('lessApps') : - loadTimeData.getStringF( - 'moreApps', numApps - NUMBER_OF_APPS_DISPLAYED_DEFAULT); - }, - - /** - * @private - */ - toggleListExpanded_: function() { - this.listExpanded_ = !this.listExpanded_; - this.onAppsChanged_(); - }, - - /** * @private */ onAppsChanged_: function() { const appList = Object.values(this.apps_); - this.$['expander-row'].hidden = - appList.length <= NUMBER_OF_APPS_DISPLAYED_DEFAULT; this.displayedApps_ = appList.slice(0, NUMBER_OF_APPS_DISPLAYED_DEFAULT); this.collapsedApps_ = appList.slice(NUMBER_OF_APPS_DISPLAYED_DEFAULT, appList.length); }, - /** - * @param {boolean} listExpanded - * @return {string} - * @private - */ - getCollapsedIcon_: function(listExpanded) { - return listExpanded ? 'cr:expand-less' : 'cr:expand-more'; - }, - /** @private */ onClickNotificationSublabel_: function() { this.dispatch(app_management.actions.changePage(PageType.NOTIFICATIONS));
diff --git a/chrome/browser/resources/app_management/notifications_view.html b/chrome/browser/resources/app_management/notifications_view.html index db3a8f2..d3f8d96 100644 --- a/chrome/browser/resources/app_management/notifications_view.html +++ b/chrome/browser/resources/app_management/notifications_view.html
@@ -1,20 +1,13 @@ <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="app_item.html"> +<link rel="import" href="expandable_app_list.html"> <link rel="import" href="shared_style.html"> <link rel="import" href="store_client.html"> -<link rel="import" href="permission_toggle.html"> -<link rel="import" href="chrome://resources/html/icon.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <dom-module id="app-management-notifications-view"> <template> <style include="app-management-shared-css"> - app-management-permission-toggle { - margin-inline-end: 24px; - } - paper-icon-button-light { margin-inline-start: 0; } @@ -30,8 +23,6 @@ padding-inline-start: 12px; } </style> - <!-- TODO(ceciliani) Make this view a separate element to avoid duplicate - code with main view --> <!-- TODO(crbug.com/906508): Implement display when there is no apps at all --> <div id="notification-view-header"> @@ -43,39 +34,10 @@ </paper-icon-button-light> <div id="notification-title" class="page-title">$i18n{notifications}</div> </div> - - <div class="card-container"> - <template is="dom-repeat" items="[[displayedApps_]]"> - <app-management-app-item app="[[item]]"> - <app-management-permission-toggle slot="right-content" - app="[[item]]" - permission-type="[[notificationsPermissionType_(item)]]"> - </app-management-permission-toggle> - </app-management-app-item> - </template> - - <iron-collapse opened="[[listExpanded_]]"> - <template is="dom-repeat" items="[[collapsedApps_]]"> - <app-management-app-item app="[[item]]"> - <app-management-permission-toggle slot="right-content" - app="[[item]]" - permission-type="[[notificationsPermissionType_(item)]]"> - </app-management-permission-toggle> - </app-management-app-item> - </template> - </iron-collapse> - - <div id="expander-row" class="expander-list-row" - on-click="toggleListExpanded_"> - <span>[[moreAppsString_(listExpanded_, collapsedApps_)]]</span> - <paper-icon-button-light class="expand-button"> - <button> - <iron-icon icon="[[getCollapsedIcon_(listExpanded_)]]"> - </iron-icon> - </button> - </paper-icon-button-light> - </div> - </div> + <app-management-expandable-app-list + displayed-apps="[[displayedApps_]]" + collapsed-apps="[[collapsedApps_]]"> + </app-management-expandable-app-list> </template> <script src="notifications_view.js"></script> </dom-module>
diff --git a/chrome/browser/resources/app_management/notifications_view.js b/chrome/browser/resources/app_management/notifications_view.js index 2220170..2252b4c0 100644 --- a/chrome/browser/resources/app_management/notifications_view.js +++ b/chrome/browser/resources/app_management/notifications_view.js
@@ -75,7 +75,6 @@ this.displayedApps_ = this.collapsedApps_; this.collapsedApps_ = []; } - this.$['expander-row'].hidden = this.collapsedApps_.length === 0; }, /** @@ -128,25 +127,6 @@ return newApps; }, - /** - * @param {boolean} listExpanded - * @param {Array<App>} collapsedApps - * @return {string} - * @private - */ - moreAppsString_: function(listExpanded, collapsedApps) { - return listExpanded ? - loadTimeData.getString('lessApps') : - loadTimeData.getStringF('moreApps', collapsedApps.length); - }, - - /** - * @private - */ - toggleListExpanded_: function() { - this.listExpanded_ = !this.listExpanded_; - }, - /** @private */ onClickBackButton_: function() { this.listExpanded_ = false; @@ -158,15 +138,6 @@ }, /** - * @param {boolean} listExpanded - * @return {string} - * @private - */ - getCollapsedIcon_: function(listExpanded) { - return listExpanded ? 'cr:expand-less' : 'cr:expand-more'; - }, - - /** * Returns a boolean representation of the permission value, which used to * determine the position of the permission toggle. * @param {App} app
diff --git a/chrome/browser/resources/app_management/shared_style.html b/chrome/browser/resources/app_management/shared_style.html index 9193bb4..9cb1aaa 100644 --- a/chrome/browser/resources/app_management/shared_style.html +++ b/chrome/browser/resources/app_management/shared_style.html
@@ -25,6 +25,7 @@ .permission-card-row { border-top: var(--card-separator); + cursor: pointer; padding: 0 24px; }
diff --git a/chrome/browser/resources/chromeos/login/accessibility_menu.css b/chrome/browser/resources/chromeos/login/accessibility_menu.css deleted file mode 100644 index 1936c78..0000000 --- a/chrome/browser/resources/chromeos/login/accessibility_menu.css +++ /dev/null
@@ -1,42 +0,0 @@ -/* Copyright (c) 2012 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. */ - -#accessibility-menu { - padding-bottom: 25px; - padding-inline-end: 80px; - padding-inline-start: 25px; - padding-top: 15px; - z-index: 1; -} - -.checkboxrow { - display: -webkit-box; - margin-top: 10px; -} - -.checkboxlabel { - margin-inline-start: 10px; -} - -.close-button { - background: url(chrome://theme/IDR_CLOSE_DIALOG) center no-repeat; - height: 14px; - position: absolute; - right: 7px; - top: 7px; - width: 14px; -} - -.close-button:hover { - background-image: url(chrome://theme/IDR_CLOSE_DIALOG_H); -} - -.close-button:active { - background-image: url(chrome://theme/IDR_CLOSE_DIALOG_P); -} - -html[dir=rtl] .close-button { - left: 10px; - right: auto; -}
diff --git a/chrome/browser/resources/chromeos/login/accessibility_menu.html b/chrome/browser/resources/chromeos/login/accessibility_menu.html deleted file mode 100644 index 86c50e87..0000000 --- a/chrome/browser/resources/chromeos/login/accessibility_menu.html +++ /dev/null
@@ -1,47 +0,0 @@ -<div id="accessibility-menu" class="bubble faded" hidden> - <div class="checkboxrow"> - <input id="spoken-feedback" type="checkbox"> - <label for="spoken-feedback" class="checkboxlabel" - i18n-content="spokenFeedbackOption"> - </label> - </div> - <div class="checkboxrow"> - <input id="large-cursor" type="checkbox"> - <label for="large-cursor" class="checkboxlabel" - i18n-content="largeCursorOption"> - </label> - </div> - <div class="checkboxrow"> - <input id="high-contrast" type="checkbox"> - <label for="high-contrast" class="checkboxlabel" - i18n-content="highContrastOption"> - </label> - </div> - <div class="checkboxrow"> - <input id="screen-magnifier" type="checkbox"> - <label for="screen-magnifier" class="checkboxlabel" - i18n-content="screenMagnifierOption"> - </label> - </div> - <div class="checkboxrow" id="select-to-speak-row"> - <input id="select-to-speak" type="checkbox"> - <label for="select-to-speak" class="checkboxlabel" - i18n-content="selectToSpeakOption"> - </label> - </div> - <div class="checkboxrow" id="docked-magnifier-row"> - <input id="docked-magnifier" type="checkbox"> - <label for="docked-magnifier" class="checkboxlabel" - i18n-content="dockedMagnifierOption"> - </label> - </div> - <div class="checkboxrow"> - <input id="virtual-keyboard" type="checkbox"> - <label for="virtual-keyboard" class="checkboxlabel" - i18n-content="virtualKeyboardOption"> - </label> - </div> - <div id="close-accessibility-menu" class="close-button" - i18n-values="title:closeAccessibilityMenu" tabindex="0"> - </div> -</div>
diff --git a/chrome/browser/resources/chromeos/login/cr_ui.js b/chrome/browser/resources/chromeos/login/cr_ui.js index f5eb50b..a143d1d 100644 --- a/chrome/browser/resources/chromeos/login/cr_ui.js +++ b/chrome/browser/resources/chromeos/login/cr_ui.js
@@ -187,12 +187,9 @@ }; /** - * Clears error bubble as well as optional menus that could be open. + * Clears error bubble. */ Oobe.clearErrors = function() { - var accessibilityMenu = $('accessibility-menu'); - if (accessibilityMenu) - accessibilityMenu.hide(); DisplayManager.clearErrors(); };
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_login.html b/chrome/browser/resources/chromeos/login/custom_elements_login.html index 4f39445..2192ac3 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_login.html +++ b/chrome/browser/resources/chromeos/login/custom_elements_login.html
@@ -5,7 +5,6 @@ <include src="gaia_input.html"> <include src="gaia_password_changed.html"> <include src="hd-iron-icon.html"> -<include src="html-echo.html"> <include src="offline_gaia.html"> <include src="saml_confirm_password.html"> <include src="saml_interstitial.html"> @@ -21,12 +20,10 @@ <include src="oobe_buttons.html"> <include src="oobe_change_picture.html"> <include src="oobe_dialog.html"> -<include src="oobe_enrollment.html"> <include src="oobe_reset.html"> <include src="oobe_reset_confirmation_overlay.html"> <include src="oobe_supervision_transition.html"> <include src="encryption_migration.html"> -<include src="enrollment_license_card.html"> <include src="sync_consent.html"> <include src="fingerprint_setup.html"> <include src="recommend_apps.html">
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_login.js b/chrome/browser/resources/chromeos/login/custom_elements_login.js index 146da25f..5bacf38 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_login.js +++ b/chrome/browser/resources/chromeos/login/custom_elements_login.js
@@ -10,7 +10,6 @@ // <include src="gaia_input.js"> // <include src="gaia_password_changed.js"> // <include src="hd-iron-icon.js"> -// <include src="html-echo.js"> // <include src="offline_gaia.js"> // <include src="saml_confirm_password.js"> // <include src="saml_interstitial.js"> @@ -25,13 +24,11 @@ // <include src="oobe_buttons.js"> // <include src="oobe_change_picture.js"> // <include src="oobe_dialog.js"> -// <include src="oobe_enrollment.js"> // <include src="arc_terms_of_service.js"> // <include src="oobe_reset.js"> // <include src="oobe_reset_confirmation_overlay.js"> // <include src="encryption_migration.js"> // <include src="oobe_supervision_transition.js"> -// <include src="enrollment_license_card.js"> // <include src="sync_consent.js"> // <include src="fingerprint_setup.js"> // <include src="recommend_apps.js">
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_oobe.html b/chrome/browser/resources/chromeos/login/custom_elements_oobe.html index 3e206d96..7a171df1 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_oobe.html +++ b/chrome/browser/resources/chromeos/login/custom_elements_oobe.html
@@ -5,7 +5,6 @@ <include src="gaia_input.html"> <include src="gaia_password_changed.html"> <include src="hd-iron-icon.html"> -<include src="html-echo.html"> <include src="network_select_login.html"> <include src="notification_card.html"> <include src="offline_gaia.html">
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_oobe.js b/chrome/browser/resources/chromeos/login/custom_elements_oobe.js index 8d15efb..616e50c6 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_oobe.js +++ b/chrome/browser/resources/chromeos/login/custom_elements_oobe.js
@@ -17,7 +17,6 @@ // <include src="gaia_input.js"> // <include src="gaia_password_changed.js"> // <include src="hd-iron-icon.js"> -// <include src="html-echo.js"> // <include src="network_select_login.js"> // <include src="notification_card.js"> // <include src="offline_gaia.js">
diff --git a/chrome/browser/resources/chromeos/login/md_login.html b/chrome/browser/resources/chromeos/login/md_login.html index d73973df..9ae8e23 100644 --- a/chrome/browser/resources/chromeos/login/md_login.html +++ b/chrome/browser/resources/chromeos/login/md_login.html
@@ -27,8 +27,8 @@ <link rel="stylesheet" href="oobe_popup_overlay.css"> <link rel="stylesheet" href="oobe_screen.css"> <link rel="stylesheet" href="../../../../../ui/login/md_screen_container.css"> -<link rel="stylesheet" href="../../../../../ui/login/account_picker/md_screen_account_picker.css"> -<link rel="stylesheet" href="../../../../../ui/login/account_picker/md_user_pod_row.css"> +<link rel="stylesheet" href="../../../../../ui/login/account_picker/chromeos_screen_account_picker.css"> +<link rel="stylesheet" href="../../../../../ui/login/account_picker/chromeos_user_pod_row.css"> <script src="chrome://resources/js/cr.js"></script> <script src="chrome://resources/js/event_tracker.js"></script> <script src="chrome://resources/js/cr/event_target.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/md_login.js b/chrome/browser/resources/chromeos/login/md_login.js index 4132607..bf1f578 100644 --- a/chrome/browser/resources/chromeos/login/md_login.js +++ b/chrome/browser/resources/chromeos/login/md_login.js
@@ -9,7 +9,6 @@ // <include src="test_util.js"> // <include src="../../../../../ui/login/screen.js"> // <include src="screen_context.js"> -// <include src="../user_images_grid.js"> // <include src="apps_menu.js"> // <include src="../../../../../ui/login/bubble.js"> // <include src="../../../../../ui/login/display_manager.js"> @@ -17,10 +16,11 @@ // <include src="demo_mode_test_helper.js"> // <include -// src="../../../../../ui/login/account_picker/md_screen_account_picker.js"> +// src="../../../../../ui/login/account_picker/chromeos_screen_account_picker.js"> // <include src="../../../../../ui/login/login_ui_tools.js"> -// <include src="../../../../../ui/login/account_picker/md_user_pod_row.js"> +// <include +// src="../../../../../ui/login/account_picker/chromeos_user_pod_row.js"> // <include src="../../../../../ui/login/resource_loader.js"> // <include src="cr_ui.js"> // <include src="oobe_screen_reset.js"> @@ -56,28 +56,6 @@ // <include src="screen_multidevice_setup.js"> // <include src="../../gaia_auth_host/authenticator.js"> - -// Register assets for async loading. -[{ - id: SCREEN_OOBE_ENROLLMENT, - html: [{url: 'chrome://oobe/enrollment.html', targetID: 'inner-container'}], - css: ['chrome://oobe/enrollment.css'], - js: ['chrome://oobe/enrollment.js'] -}].forEach(cr.ui.login.ResourceLoader.registerAssets); - -(function() { -'use strict'; - -document.addEventListener('DOMContentLoaded', function() { - // Immediately load async assets. - cr.ui.login.ResourceLoader.loadAssets(SCREEN_OOBE_ENROLLMENT, function() { - // This screen is async-loaded so we manually trigger i18n processing. - i18nTemplate.process($('oauth-enrollment'), loadTimeData); - // Delayed binding since this isn't defined yet. - login.OAuthEnrollmentScreen.register(); - }); -}); -})(); // <include src="notification_card.js"> /** @@ -144,11 +122,6 @@ }, // Dummy Oobe functions not present with stripped login UI. - initializeA11yMenu: function(e) {}, - handleAccessibilityLinkClick: function(e) {}, - handleSpokenFeedbackClick: function(e) {}, - handleHighContrastClick: function(e) {}, - handleScreenMagnifierClick: function(e) {}, setUsageStats: function(checked) {}, setTpmPassword: function(password) {}, refreshA11yInfo: function(data) {},
diff --git a/chrome/browser/resources/chromeos/login/md_login_screens.html b/chrome/browser/resources/chromeos/login/md_login_screens.html index 0e33276a..12dc1abc 100644 --- a/chrome/browser/resources/chromeos/login/md_login_screens.html +++ b/chrome/browser/resources/chromeos/login/md_login_screens.html
@@ -5,7 +5,7 @@ <include src="oobe_screen_user_image.html"> <include src="oobe_screen_supervision_transition.html"> <include src="oobe_screen_assistant_optin_flow.html"> -<include src="../../../../../ui/login/account_picker/md_screen_account_picker.html"> +<include src="../../../../../ui/login/account_picker/chromeos_screen_account_picker.html"> <include src="screen_arc_terms_of_service.html"> <include src="screen_error_message.html"> <include src="screen_gaia_signin.html">
diff --git a/chrome/browser/resources/chromeos/login/md_screen_container.html b/chrome/browser/resources/chromeos/login/md_screen_container.html index 480c4c15..069b4e1 100644 --- a/chrome/browser/resources/chromeos/login/md_screen_container.html +++ b/chrome/browser/resources/chromeos/login/md_screen_container.html
@@ -18,5 +18,5 @@ <div id="bubble" class="bubble faded" hidden></div> <include src="md_top_header_bar.html"> <include src="md_header_bar.html"> -<include src="../../../../../ui/login/account_picker/md_user_pod_template.html"> +<include src="../../../../../ui/login/account_picker/chromeos_user_pod_template.html"> <include src="oobe_screen_reset_confirmation_overlay.html">
diff --git a/chrome/browser/resources/chromeos/login/oobe.html b/chrome/browser/resources/chromeos/login/oobe.html index 2cc1b66..f7c3c386 100644 --- a/chrome/browser/resources/chromeos/login/oobe.html +++ b/chrome/browser/resources/chromeos/login/oobe.html
@@ -30,8 +30,8 @@ <link rel="stylesheet" href="oobe_screen.css"> <link rel="stylesheet" href="../../../../../ui/login/md_screen_container.css"> -<link rel="stylesheet" href="../../../../../ui/login/account_picker/md_screen_account_picker.css"> -<link rel="stylesheet" href="../../../../../ui/login/account_picker/md_user_pod_row.css"> +<link rel="stylesheet" href="../../../../../ui/login/account_picker/chromeos_screen_account_picker.css"> +<link rel="stylesheet" href="../../../../../ui/login/account_picker/chromeos_user_pod_row.css"> <script src="chrome://resources/js/cr.js"></script> <script src="chrome://resources/js/event_tracker.js"></script> @@ -86,12 +86,10 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://oobe/custom_elements.html"> -<link rel="stylesheet" href="accessibility_menu.css"> <script src="chrome://oobe/oobe.js"></script> </head> <body class="oobe-display chromeos" i18n-values=".style.fontFamily:fontfamily;"> <include src="md_screen_container.html"> - <include src="accessibility_menu.html"> <div id="popup-overlay" class="popup-overlay" hidden> <include src="oobe_screen_eula_installation_settings_overlay.html"> </div>
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js index 3446c7cc..5bebe511e 100644 --- a/chrome/browser/resources/chromeos/login/oobe.js +++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -10,7 +10,6 @@ // <include src="test_util.js"> // <include src="../../../../../ui/login/screen.js"> // <include src="screen_context.js"> -// <include src="../user_images_grid.js"> // <include src="apps_menu.js"> // <include src="../../../../../ui/login/bubble.js"> // <include src="../../../../../ui/login/display_manager.js"> @@ -18,10 +17,11 @@ // <include src="demo_mode_test_helper.js"> // <include -// src="../../../../../ui/login/account_picker/md_screen_account_picker.js"> +// src="../../../../../ui/login/account_picker/chromeos_screen_account_picker.js"> // <include src="../../../../../ui/login/login_ui_tools.js"> -// <include src="../../../../../ui/login/account_picker/md_user_pod_row.js"> +// <include +// src="../../../../../ui/login/account_picker/chromeos_user_pod_row.js"> // <include src="../../../../../ui/login/resource_loader.js"> // <include src="cr_ui.js"> // <include src="oobe_screen_reset.js"> @@ -144,152 +144,10 @@ cr.ui.Bubble.decorate($('bubble')); login.HeaderBar.decorate($('login-header-bar')); - Oobe.initializeA11yMenu(); - chrome.send('screenStateInitialize'); }, /** - * Initializes OOBE accessibility menu. - */ - initializeA11yMenu: function() { - cr.ui.Bubble.decorate($('accessibility-menu')); - // Same behaviour on hitting spacebar. See crbug.com/342991. - function reactOnSpace(event) { - if (event.keyCode == 32) - Oobe.handleAccessibilityLinkClick(event); - } - - $('high-contrast') - .addEventListener('click', Oobe.handleHighContrastClick); - $('large-cursor').addEventListener('click', Oobe.handleLargeCursorClick); - $('spoken-feedback') - .addEventListener('click', Oobe.handleSpokenFeedbackClick); - $('select-to-speak') - .addEventListener('click', Oobe.handleSelectToSpeakClick); - $('screen-magnifier') - .addEventListener('click', Oobe.handleScreenMagnifierClick); - $('virtual-keyboard') - .addEventListener('click', Oobe.handleVirtualKeyboardClick); - - $('high-contrast').addEventListener('keypress', Oobe.handleA11yKeyPress); - $('large-cursor').addEventListener('keypress', Oobe.handleA11yKeyPress); - $('spoken-feedback') - .addEventListener('keypress', Oobe.handleA11yKeyPress); - $('select-to-speak') - .addEventListener('keypress', Oobe.handleA11yKeyPress); - $('screen-magnifier') - .addEventListener('keypress', Oobe.handleA11yKeyPress); - $('virtual-keyboard') - .addEventListener('keypress', Oobe.handleA11yKeyPress); - - // A11y menu should be accessible i.e. disable autohide on any - // keydown or click inside menu. - $('accessibility-menu').hideOnKeyPress = false; - $('accessibility-menu').hideOnSelfClick = false; - }, - - /** - * Accessibility link handler. - */ - handleAccessibilityLinkClick: function(e) { - /** @const */ var BUBBLE_OFFSET = 5; - /** @const */ var BUBBLE_PADDING = 10; - $('accessibility-menu') - .showForElement( - e.target, cr.ui.Bubble.Attachment.BOTTOM, BUBBLE_OFFSET, - BUBBLE_PADDING); - - var maxHeight = cr.ui.LoginUITools.getMaxHeightBeforeShelfOverlapping( - $('accessibility-menu')); - if (maxHeight < $('accessibility-menu').offsetHeight) { - $('accessibility-menu') - .showForElement( - e.target, cr.ui.Bubble.Attachment.TOP, BUBBLE_OFFSET, - BUBBLE_PADDING); - } - - $('accessibility-menu').firstBubbleElement = $('spoken-feedback'); - $('accessibility-menu').lastBubbleElement = $('close-accessibility-menu'); - $('spoken-feedback').focus(); - - if (Oobe.getInstance().currentScreen && - Oobe.getInstance().currentScreen.defaultControl) { - $('accessibility-menu').elementToFocusOnHide = - Oobe.getInstance().currentScreen.defaultControl; - } else { - // Update screen falls into this category. Since it doesn't have any - // controls other than a11y link we don't want that link to receive - // focus when screen is shown i.e. defaultControl is not defined. - // Focus a11y link instead. - $('accessibility-menu').elementToFocusOnHide = e.target; - } - e.stopPropagation(); - }, - - /** - * handle a11y menu checkboxes keypress event by simulating click event. - */ - handleA11yKeyPress: function(e) { - if (e.key != 'Enter') - return; - - if (e.target.tagName != 'INPUT' || e.target.type != 'checkbox') - return; - - // Simulate click on the checkbox. - e.target.click(); - }, - - /** - * Spoken feedback checkbox handler. - */ - handleSpokenFeedbackClick: function(e) { - chrome.send('enableSpokenFeedback', [$('spoken-feedback').checked]); - e.stopPropagation(); - }, - - /** - * Select to speak checkbox handler. - */ - handleSelectToSpeakClick: function(e) { - chrome.send('enableSelectToSpeak', [$('select-to-speak').checked]); - e.stopPropagation(); - }, - - /** - * Large cursor checkbox handler. - */ - handleLargeCursorClick: function(e) { - chrome.send('enableLargeCursor', [$('large-cursor').checked]); - e.stopPropagation(); - }, - - /** - * High contrast mode checkbox handler. - */ - handleHighContrastClick: function(e) { - chrome.send('enableHighContrast', [$('high-contrast').checked]); - e.stopPropagation(); - }, - - /** - * Screen magnifier checkbox handler. - */ - handleScreenMagnifierClick: function(e) { - chrome.send('enableScreenMagnifier', [$('screen-magnifier').checked]); - e.stopPropagation(); - }, - - /** - * On-screen keyboard checkbox handler. - */ - handleVirtualKeyboardClick: function(e) { - chrome.send('enableVirtualKeyboard', [$('virtual-keyboard').checked]); - e.stopPropagation(); - }, - - /** * Sets usage statistics checkbox. * @param {boolean} checked Is the checkbox checked? */ @@ -310,18 +168,6 @@ * @param {!Object} data New dictionary with a11y features state. */ refreshA11yInfo: function(data) { - $('high-contrast').checked = data.highContrastEnabled; - $('spoken-feedback').checked = data.spokenFeedbackEnabled; - $('select-to-speak').checked = data.selectToSpeakEnabled; - $('screen-magnifier').checked = data.screenMagnifierEnabled; - $('docked-magnifier').checked = data.dockedMagnifierEnabled; - $('large-cursor').checked = data.largeCursorEnabled; - $('virtual-keyboard').checked = data.virtualKeyboardEnabled; - - // TODO(katie): Remove this when launching features in OOBE screen. - if (!data.enableExperimentalA11yFeatures) - $('docked-magnifier-row').setAttribute('hidden', true); - $('oobe-welcome-md').a11yStatus = data; },
diff --git a/chrome/browser/resources/chromeos/login/oobe_screens.html b/chrome/browser/resources/chromeos/login/oobe_screens.html index 714694f..ba033078 100644 --- a/chrome/browser/resources/chromeos/login/oobe_screens.html +++ b/chrome/browser/resources/chromeos/login/oobe_screens.html
@@ -14,7 +14,7 @@ <include src="oobe_screen_demo_setup.html"> <include src="oobe_screen_demo_preferences.html"> <include src="oobe_screen_assistant_optin_flow.html"> -<include src="../../../../../ui/login/account_picker/md_screen_account_picker.html"> +<include src="../../../../../ui/login/account_picker/chromeos_screen_account_picker.html"> <include src="screen_error_message.html"> <include src="screen_arc_terms_of_service.html"> <include src="screen_gaia_signin.html">
diff --git a/chrome/browser/resources/chromeos/login/saml_interstitial.html b/chrome/browser/resources/chromeos/login/saml_interstitial.html index 61b82a06..76c9f43c 100644 --- a/chrome/browser/resources/chromeos/login/saml_interstitial.html +++ b/chrome/browser/resources/chromeos/login/saml_interstitial.html
@@ -1,5 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> +<include src="html-echo.html"> + <!-- UI for the SAML interstitial page. Example:
diff --git a/chrome/browser/resources/chromeos/login/saml_interstitial.js b/chrome/browser/resources/chromeos/login/saml_interstitial.js index 7da3ee2..a4ae4854 100644 --- a/chrome/browser/resources/chromeos/login/saml_interstitial.js +++ b/chrome/browser/resources/chromeos/login/saml_interstitial.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// <include src="html-echo.js"> + Polymer({ is: 'saml-interstitial',
diff --git a/chrome/browser/resources/chromeos/user_images_grid.js b/chrome/browser/resources/chromeos/user_images_grid.js deleted file mode 100644 index b0002cfa..0000000 --- a/chrome/browser/resources/chromeos/user_images_grid.js +++ /dev/null
@@ -1,653 +0,0 @@ -// Copyright (c) 2012 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. - -cr.define('options', function() { - /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; - /** @const */ var Grid = cr.ui.Grid; - /** @const */ var GridItem = cr.ui.GridItem; - /** @const */ var GridSelectionController = cr.ui.GridSelectionController; - /** @const */ var ListSingleSelectionModel = cr.ui.ListSingleSelectionModel; - - /** - * Dimensions for camera capture. - * @const - */ - var CAPTURE_SIZE = {height: 576, width: 576}; - - /** - * Path for internal URLs. - * @const - */ - var CHROME_THEME_PATH = 'chrome://theme'; - - /** - * Creates a new user images grid item. - * @param {{url: string, title: (string|undefined), - * decorateFn: (!Function|undefined), - * clickHandler: (!Function|undefined)}} imageInfo User image URL, - * optional title, decorator callback and click handler. - * @constructor - * @extends {cr.ui.GridItem} - */ - function UserImagesGridItem(imageInfo) { - var el = new GridItem(imageInfo); - el.__proto__ = UserImagesGridItem.prototype; - return el; - } - - UserImagesGridItem.prototype = { - __proto__: GridItem.prototype, - - /** @override */ - decorate: function() { - GridItem.prototype.decorate.call(this); - var imageEl = cr.doc.createElement('img'); - // Force 1x scale for chrome://theme URLs. Grid elements are much smaller - // than actual images so there is no need in full scale on HDPI. - var url = this.dataItem.url; - if (url.slice(0, CHROME_THEME_PATH.length) == CHROME_THEME_PATH) - imageEl.src = this.dataItem.url + '[0]@1x'; - else - imageEl.src = this.dataItem.url; - imageEl.title = this.dataItem.title || ''; - imageEl.alt = imageEl.title; - if (typeof this.dataItem.clickHandler == 'function') - imageEl.addEventListener('mousedown', this.dataItem.clickHandler); - // Remove any garbage added by GridItem and ListItem decorators. - this.textContent = ''; - this.appendChild(imageEl); - if (typeof this.dataItem.decorateFn == 'function') - this.dataItem.decorateFn(this); - this.setAttribute('role', 'option'); - this.oncontextmenu = function(e) { - e.preventDefault(); - }; - } - }; - - /** - * Creates a selection controller that wraps selection on grid ends - * and translates Enter presses into 'activate' events. - * @param {cr.ui.ListSelectionModel} selectionModel The selection model to - * interact with. - * @param {cr.ui.Grid} grid The grid to interact with. - * @constructor - * @extends {cr.ui.GridSelectionController} - */ - function UserImagesGridSelectionController(selectionModel, grid) { - GridSelectionController.call(this, selectionModel, grid); - } - - UserImagesGridSelectionController.prototype = { - __proto__: GridSelectionController.prototype, - - /** @override */ - getIndexBefore: function(index) { - var result = - GridSelectionController.prototype.getIndexBefore.call(this, index); - return result == -1 ? this.getLastIndex() : result; - }, - - /** @override */ - getIndexAfter: function(index) { - var result = - GridSelectionController.prototype.getIndexAfter.call(this, index); - return result == -1 ? this.getFirstIndex() : result; - }, - - /** @override */ - handleKeyDown: function(e) { - if (e.key == 'Enter') - cr.dispatchSimpleEvent(this.grid_, 'activate'); - else - GridSelectionController.prototype.handleKeyDown.call(this, e); - } - }; - - /** - * Creates a new user images grid element. - * @param {Object=} opt_propertyBag Optional properties. - * @constructor - * @extends {cr.ui.Grid} - */ - var UserImagesGrid = cr.ui.define('grid'); - - UserImagesGrid.prototype = { - __proto__: Grid.prototype, - - /** @override */ - createSelectionController: function(sm) { - return new UserImagesGridSelectionController(sm, this); - }, - - /** @override */ - decorate: function() { - Grid.prototype.decorate.call(this); - this.dataModel = new ArrayDataModel([]); - this.itemConstructor = - /** @type {function(new:cr.ui.ListItem, *)} */ (UserImagesGridItem); - this.selectionModel = new ListSingleSelectionModel(); - this.inProgramSelection_ = false; - this.addEventListener('dblclick', this.handleDblClick_.bind(this)); - this.addEventListener('change', this.handleChange_.bind(this)); - this.setAttribute('role', 'listbox'); - this.autoExpands = true; - }, - - /** - * Handles double click on the image grid. - * @param {Event} e Double click Event. - * @private - */ - handleDblClick_: function(e) { - // If a child element is double-clicked and not the grid itself, handle - // this as 'Enter' keypress. - if (e.target != this) - cr.dispatchSimpleEvent(this, 'activate'); - }, - - /** - * Handles selection change. - * @param {Event} e Double click Event. - * @private - */ - handleChange_: function(e) { - if (this.selectedItem === null) - return; - - var oldSelectionType = this.selectionType; - - // Update current selection type. - this.selectionType = this.selectedItem.type; - - // Show grey silhouette with the same border as stock images. - if (/^chrome:\/\/theme\//.test(this.selectedItemUrl)) - this.previewElement.classList.add('default-image'); - - this.updatePreview_(); - - var e = new Event('select'); - e.oldSelectionType = oldSelectionType; - this.dispatchEvent(e); - }, - - /** - * Updates the preview image, if present. - * @private - */ - updatePreview_: function() { - var url = this.selectedItemUrl; - if (url && this.previewImage_) { - if (url.slice(0, CHROME_THEME_PATH.length) == CHROME_THEME_PATH) - this.previewImage_.src = url + '@2x'; - else - this.previewImage_.src = url; - } - }, - - /** - * Whether a camera is present or not. - * @type {boolean} - */ - get cameraPresent() { - return this.cameraPresent_; - }, - set cameraPresent(value) { - this.cameraPresent_ = value; - if (this.cameraLive) - this.cameraImage = null; - }, - - /** - * Whether camera is actually streaming video. May be |false| even when - * camera is present and shown but still initializing. - * @type {boolean} - */ - get cameraOnline() { - return this.previewElement.classList.contains('online'); - }, - set cameraOnline(value) { - this.previewElement.classList.toggle('online', value); - }, - - /** - * Tries to starts camera stream capture. - * @param {function(): boolean} onAvailable Callback that is called if - * camera is available. If it returns |true|, capture is started - * immediately. - */ - startCamera: function(onAvailable, onAbsent) { - this.stopCamera(); - this.cameraStartInProgress_ = true; - navigator.webkitGetUserMedia( - {video: true}, this.handleCameraAvailable_.bind(this, onAvailable), - this.handleCameraAbsent_.bind(this)); - }, - - /** - * Stops camera capture, if it's currently active. - */ - stopCamera: function() { - this.cameraOnline = false; - if (this.cameraVideo_) - this.cameraVideo_.srcObject = null; - if (this.cameraStream_) { - this.stopVideoTracks_(this.cameraStream_); - this.cameraStream_ = null; - } - // Cancel any pending getUserMedia() checks. - this.cameraStartInProgress_ = false; - }, - - /** - * Stops all video tracks associated with a MediaStream object. - * @param {MediaStream} stream - */ - stopVideoTracks_: function(stream) { - var tracks = stream.getVideoTracks(); - for (var t of tracks) - t.stop(); - }, - - /** - * Handles successful camera check. - * @param {function(): boolean} onAvailable Callback to call. If it returns - * |true|, capture is started immediately. - * @param {!MediaStream} stream Stream object as returned by getUserMedia. - * @private - * @suppress {deprecated} - */ - handleCameraAvailable_: function(onAvailable, stream) { - if (this.cameraStartInProgress_ && onAvailable()) { - this.cameraVideo_.srcObject = stream; - this.cameraStream_ = stream; - } else { - this.stopVideoTracks_(stream); - } - this.cameraStartInProgress_ = false; - }, - - /** - * Handles camera check failure. - * @param {NavigatorUserMediaError=} err Error object. - * @private - */ - handleCameraAbsent_: function(err) { - this.cameraPresent = false; - this.cameraOnline = false; - this.cameraStartInProgress_ = false; - }, - - /** - * Handles successful camera capture start. - * @private - */ - handleVideoStarted_: function() { - this.cameraOnline = true; - this.handleVideoUpdate_(); - }, - - /** - * Handles camera stream update. Called regularly (at rate no greater than - * 4/sec) while camera stream is live. - * @private - */ - handleVideoUpdate_: function() { - this.lastFrameTime_ = new Date().getTime(); - }, - - /** - * Type of the selected image (one of 'default', 'profile', 'camera'). - * Setting it will update class list of |previewElement|. - * @type {string} - */ - get selectionType() { - return this.selectionType_; - }, - set selectionType(value) { - this.selectionType_ = value; - var previewClassList = this.previewElement.classList; - previewClassList[value == 'default' ? 'add' : 'remove']('default-image'); - previewClassList[value == 'profile' ? 'add' : 'remove']('profile-image'); - previewClassList[value == 'camera' ? 'add' : 'remove']('camera'); - if (!$('user-image-grid')) - return; - - var setFocusIfLost = function() { - // Set focus to the grid, if focus is not on UI. - if (!document.activeElement || - document.activeElement.tagName == 'BODY') { - $('user-image-grid').focus(); - } - }; - // Timeout guarantees processing AFTER style changes display attribute. - setTimeout(setFocusIfLost, 0); - }, - - /** - * Current image captured from camera as data URL. Setting to null will - * return to the live camera stream. - * @type {(string|undefined)} - */ - get cameraImage() { - return this.cameraImage_; - }, - set cameraImage(imageUrl) { - this.cameraLive = !imageUrl; - if (this.cameraPresent && !imageUrl) - imageUrl = UserImagesGrid.ButtonImages.TAKE_PHOTO; - if (imageUrl) { - this.cameraImage_ = this.cameraImage_ ? - this.updateItem(this.cameraImage_, imageUrl, this.cameraTitle_) : - this.addItem(imageUrl, this.cameraTitle_, undefined, 0); - this.cameraImage_.type = 'camera'; - } else { - this.removeItem(this.cameraImage_); - this.cameraImage_ = null; - } - }, - - /** - * Updates the titles for the camera element. - * @param {string} placeholderTitle Title when showing a placeholder. - * @param {string} capturedImageTitle Title when showing a captured photo. - */ - setCameraTitles: function(placeholderTitle, capturedImageTitle) { - this.placeholderTitle_ = placeholderTitle; - this.capturedImageTitle_ = capturedImageTitle; - this.cameraTitle_ = this.placeholderTitle_; - }, - - /** - * True when camera is in live mode (i.e. no still photo selected). - * @type {boolean} - */ - get cameraLive() { - return this.cameraLive_; - }, - set cameraLive(value) { - this.cameraLive_ = value; - this.previewElement.classList[value ? 'add' : 'remove']('live'); - }, - - /** - * Should only be queried from the 'change' event listener, true if the - * change event was triggered by a programmatical selection change. - * @type {boolean} - */ - get inProgramSelection() { - return this.inProgramSelection_; - }, - - /** - * URL of the image selected. - * @type {string?} - */ - get selectedItemUrl() { - var selectedItem = this.selectedItem; - return selectedItem ? selectedItem.url : null; - }, - set selectedItemUrl(url) { - for (var i = 0, el; el = this.dataModel.item(i); i++) { - if (el.url === url) - this.selectedItemIndex = i; - } - }, - - /** - * Set index to the image selected. - * @type {number} index The index of selected image. - */ - set selectedItemIndex(index) { - this.inProgramSelection_ = true; - this.selectionModel.selectedIndex = index; - this.inProgramSelection_ = false; - }, - - /** @override */ - get selectedItem() { - var index = this.selectionModel.selectedIndex; - return index != -1 ? this.dataModel.item(index) : null; - }, - set selectedItem(selectedItem) { - var index = this.indexOf(selectedItem); - this.inProgramSelection_ = true; - this.selectionModel.selectedIndex = index; - this.selectionModel.leadIndex = index; - this.inProgramSelection_ = false; - }, - - /** - * Element containing the preview image (the first IMG element) and the - * camera live stream (the first VIDEO element). - * @type {HTMLElement} - */ - get previewElement() { - // TODO(ivankr): temporary hack for non-HTML5 version. - return this.previewElement_ || this; - }, - set previewElement(value) { - this.previewElement_ = value; - this.previewImage_ = value.querySelector('img'); - this.cameraVideo_ = value.querySelector('video'); - this.cameraVideo_.addEventListener( - 'canplay', this.handleVideoStarted_.bind(this)); - this.cameraVideo_.addEventListener( - 'timeupdate', this.handleVideoUpdate_.bind(this)); - this.updatePreview_(); - // Initialize camera state and check for its presence. - this.cameraLive = true; - this.cameraPresent = false; - }, - - /** - * Performs photo capture from the live camera stream. 'phototaken' event - * will be fired as soon as captured photo is available, with 'dataURL' - * property containing the photo encoded as a data URL. - * @return {boolean} Whether photo capture was successful. - */ - takePhoto: function() { - if (!this.cameraOnline) - return false; - var canvas = - /** @type {HTMLCanvasElement} */ (document.createElement('canvas')); - canvas.width = CAPTURE_SIZE.width; - canvas.height = CAPTURE_SIZE.height; - this.captureFrame_( - this.cameraVideo_, - /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d')), - CAPTURE_SIZE); - // Preload image before displaying it. - var previewImg = new Image(); - previewImg.addEventListener('load', function(e) { - this.cameraTitle_ = this.capturedImageTitle_; - this.cameraImage = previewImg.src; - }.bind(this)); - var imageUrl = this.flipFrame_(canvas); - previewImg.src = imageUrl; - var e = new Event('phototaken'); - e.dataURL = imageUrl; - this.dispatchEvent(e); - return true; - }, - - /** - * Discard current photo and return to the live camera stream. - */ - discardPhoto: function() { - this.cameraTitle_ = this.placeholderTitle_; - this.cameraImage = null; - }, - - /** - * Capture a single still frame from a <video> element, placing it at the - * current drawing origin of a canvas context. - * @param {HTMLVideoElement} video Video element to capture from. - * @param {CanvasRenderingContext2D} ctx Canvas context to draw onto. - * @param {{width: number, height: number}} destSize Capture size. - * @private - */ - captureFrame_: function(video, ctx, destSize) { - var width = video.videoWidth; - var height = video.videoHeight; - if (width < destSize.width || height < destSize.height) { - console.error( - 'Video capture size too small: ' + width + 'x' + height + '!'); - } - var src = {}; - if (width / destSize.width > height / destSize.height) { - // Full height, crop left/right. - src.height = height; - src.width = height * destSize.width / destSize.height; - } else { - // Full width, crop top/bottom. - src.width = width; - src.height = width * destSize.height / destSize.width; - } - src.x = (width - src.width) / 2; - src.y = (height - src.height) / 2; - ctx.drawImage( - video, src.x, src.y, src.width, src.height, 0, 0, destSize.width, - destSize.height); - }, - - /** - * Flips frame horizontally. - * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} source - * Frame to flip. - * @return {string} Flipped frame as data URL. - */ - flipFrame_: function(source) { - var canvas = document.createElement('canvas'); - canvas.width = CAPTURE_SIZE.width; - canvas.height = CAPTURE_SIZE.height; - var ctx = canvas.getContext('2d'); - ctx.translate(CAPTURE_SIZE.width, 0); - ctx.scale(-1.0, 1.0); - ctx.drawImage(source, 0, 0); - return canvas.toDataURL('image/png'); - }, - - /** - * Adds new image to the user image grid. - * @param {string} url Image URL. - * @param {string=} opt_title Image tooltip. - * @param {Function=} opt_clickHandler Image click handler. - * @param {number=} opt_position If given, inserts new image into - * that position (0-based) in image list. - * @param {Function=} opt_decorateFn Function called with the list element - * as argument to do any final decoration. - * @return {!Object} Image data inserted into the data model. - */ - // TODO(ivankr): this function needs some argument list refactoring. - addItem: function( - url, opt_title, opt_clickHandler, opt_position, opt_decorateFn) { - var imageInfo = { - url: url, - title: opt_title, - clickHandler: opt_clickHandler, - decorateFn: opt_decorateFn - }; - this.inProgramSelection_ = true; - if (opt_position !== undefined) - this.dataModel.splice(opt_position, 0, imageInfo); - else - this.dataModel.push(imageInfo); - this.inProgramSelection_ = false; - return imageInfo; - }, - - /** - * Returns index of an image in grid. - * @param {Object} imageInfo Image data returned from addItem() call. - * @return {number} Image index (0-based) or -1 if image was not found. - */ - indexOf: function(imageInfo) { - return this.dataModel.indexOf(imageInfo); - }, - - /** - * Replaces an image in the grid. - * @param {Object} imageInfo Image data returned from addItem() call. - * @param {string} imageUrl New image URL. - * @param {string=} opt_title New image tooltip (if undefined, tooltip - * is left unchanged). - * @return {!Object} Image data of the added or updated image. - */ - updateItem: function(imageInfo, imageUrl, opt_title) { - var imageIndex = this.indexOf(imageInfo); - var wasSelected = this.selectionModel.selectedIndex == imageIndex; - this.removeItem(imageInfo); - var newInfo = this.addItem( - imageUrl, opt_title === undefined ? imageInfo.title : opt_title, - imageInfo.clickHandler, imageIndex, imageInfo.decorateFn); - // Update image data with the reset of the keys from the old data. - for (var k in imageInfo) { - if (!(k in newInfo)) - newInfo[k] = imageInfo[k]; - } - if (wasSelected) - this.selectedItem = newInfo; - return newInfo; - }, - - /** - * Removes previously added image from the grid. - * @param {Object} imageInfo Image data returned from the addItem() call. - */ - removeItem: function(imageInfo) { - var index = this.indexOf(imageInfo); - if (index != -1) { - var wasSelected = this.selectionModel.selectedIndex == index; - this.inProgramSelection_ = true; - this.dataModel.splice(index, 1); - if (wasSelected) { - // If item removed was selected, select the item next to it. - this.selectedItem = - this.dataModel.item(Math.min(this.dataModel.length - 1, index)); - } - this.inProgramSelection_ = false; - } - }, - - /** - * Forces re-display, size re-calculation and focuses grid. - */ - updateAndFocus: function() { - // Recalculate the measured item size. - this.measured_ = null; - this.columns = 0; - this.redraw(); - this.focus(); - }, - - /** - * Appends default images to the image grid. Should only be called once. - * @param {Array<{url: string, author: string, - * website: string, title: string}>} imagesData - * An array of default images data, including URL, author, title and - * website. - */ - setDefaultImages: function(imagesData) { - for (var i = 0, data; data = imagesData[i]; i++) { - var item = this.addItem(data.url, data.title); - item.type = 'default'; - item.author = data.author || ''; - item.website = data.website || ''; - } - } - }; - - /** - * URLs of special button images. - * @enum {string} - */ - UserImagesGrid.ButtonImages = { - TAKE_PHOTO: 'chrome://theme/IDR_BUTTON_USER_IMAGE_TAKE_PHOTO', - CHOOSE_FILE: 'chrome://theme/IDR_BUTTON_USER_IMAGE_CHOOSE_FILE', - PROFILE_PICTURE: 'chrome://theme/IDR_LOGIN_DEFAULT_USER' - }; - - return {UserImagesGrid: UserImagesGrid}; -});
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_browser_proxy.js b/chrome/browser/resources/settings/crostini_page/crostini_browser_proxy.js index d4eba5b..6e4c97aa 100644 --- a/chrome/browser/resources/settings/crostini_page/crostini_browser_proxy.js +++ b/chrome/browser/resources/settings/crostini_page/crostini_browser_proxy.js
@@ -29,6 +29,12 @@ /** @param {string} path Path to stop sharing. */ removeCrostiniSharedPath(path) {} + + /* Export crostini container. */ + exportCrostiniContainer() {} + + /* Import crostini container. */ + importCrostiniContainer() {} } /** @implements {settings.CrostiniBrowserProxy} */ @@ -52,6 +58,16 @@ removeCrostiniSharedPath(path) { chrome.send('removeCrostiniSharedPath', [path]); } + + /** @override */ + exportCrostiniContainer() { + chrome.send('exportCrostiniContainer'); + } + + /** @override */ + importCrostiniContainer() { + chrome.send('importCrostiniContainer'); + } } // The singleton instance_ can be replaced with a test version of this wrapper
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_subpage.html b/chrome/browser/resources/settings/crostini_page/crostini_subpage.html index f6fc52b..a83dd31e 100644 --- a/chrome/browser/resources/settings/crostini_page/crostini_subpage.html +++ b/chrome/browser/resources/settings/crostini_page/crostini_subpage.html
@@ -27,6 +27,23 @@ </paper-icon-button-light> </div> </template> + <template is="dom-if" if="[[showCrostiniExportImport_]]"> + <div class="settings-box">$i18n{crostiniExportImportTitle}</div> + <div class="list-frame vertical-list"> + <div id="export" class="list-item"> + <div class="start secondary">$i18n{crostiniExportLabel}</div> + <paper-button on-click="onExportClick_"> + $i18n{crostiniExport} + </paper-button> + </div> + <div id="import" class="list-item"> + <div class="start secondary">$i18n{crostiniImportLabel}</div> + <paper-button on-click="onImportClick_"> + $i18n{crostiniImport} + </paper-button> + </div> + </div> + </template> <div id="remove" class="settings-box" actionable on-click="onRemoveTap_"> <div class="start">$i18n{crostiniRemove}</div>
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_subpage.js b/chrome/browser/resources/settings/crostini_page/crostini_subpage.js index 7d8ac3c..d671051 100644 --- a/chrome/browser/resources/settings/crostini_page/crostini_subpage.js +++ b/chrome/browser/resources/settings/crostini_page/crostini_subpage.js
@@ -30,6 +30,16 @@ }, }, + /** + * Whether export / import UI should be displayed. + * @private {boolean} + */ + showCrostiniExportImport_: { + type: Boolean, + value: function() { + return loadTimeData.getBoolean('showCrostiniExportImport'); + }, + }, }, observers: ['onCrostiniEnabledChanged_(prefs.crostini.enabled.value)'], @@ -57,6 +67,16 @@ }, /** @private */ + onExportClick_: function(event) { + settings.CrostiniBrowserProxyImpl.getInstance().exportCrostiniContainer(); + }, + + /** @private */ + onImportClick_: function(event) { + settings.CrostiniBrowserProxyImpl.getInstance().importCrostiniContainer(); + }, + + /** @private */ onSharedUsbDevicesTap_: function(event) { settings.navigateTo(settings.routes.CROSTINI_SHARED_USB_DEVICES); },
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc index 095c989..67d5f776 100644 --- a/chrome/browser/sessions/better_session_restore_browsertest.cc +++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -552,15 +552,8 @@ // Check that cookies are cleared on a wrench menu quit only if cookies are set // to current session only, regardless of whether background mode is enabled. -// Flaky on Windows and Linux: https://crbug.com/931777 -#if defined(OS_WIN) || defined(OS_LINUX) -#define MAYBE_CookiesClearedOnCloseAllBrowsers \ - DISABLED_CookiesClearedOnCloseAllBrowsers -#else -#define MAYBE_CookiesClearedOnCloseAllBrowsers CookiesClearedOnCloseAllBrowsers -#endif IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, - MAYBE_CookiesClearedOnCloseAllBrowsers) { + CookiesClearedOnCloseAllBrowsers) { StoreDataWithPage("cookies.html"); // Normally cookies are restored. Browser* new_browser = QuitBrowserAndRestore(browser(), true);
diff --git a/chrome/browser/signin/identity_manager_factory.cc b/chrome/browser/signin/identity_manager_factory.cc index 4da6fa5..58cd487 100644 --- a/chrome/browser/signin/identity_manager_factory.cc +++ b/chrome/browser/signin/identity_manager_factory.cc
@@ -52,7 +52,7 @@ return std::make_unique<identity::AccountsMutatorImpl>( ProfileOAuth2TokenServiceFactory::GetForProfile(profile), AccountTrackerServiceFactory::GetForProfile(profile), - SigninManagerFactory::GetForProfile(profile)); + SigninManagerFactory::GetForProfile(profile), profile->GetPrefs()); #else return nullptr; #endif
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 5ef6a665..fbe8461 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -2655,8 +2655,6 @@ "views/overlay/close_image_button.h", "views/overlay/control_image_button.cc", "views/overlay/control_image_button.h", - "views/overlay/next_track_image_button.cc", - "views/overlay/next_track_image_button.h", "views/overlay/overlay_window_views.cc", "views/overlay/overlay_window_views.h", "views/overlay/playback_image_button.cc", @@ -2665,6 +2663,8 @@ "views/overlay/resize_handle_button.h", "views/overlay/skip_ad_label_button.cc", "views/overlay/skip_ad_label_button.h", + "views/overlay/track_image_button.cc", + "views/overlay/track_image_button.h", "views/page_action/page_action_icon_container_view.cc", "views/page_action/page_action_icon_container_view.h", "views/page_action/page_action_icon_view.cc",
diff --git a/chrome/browser/ui/views/overlay/back_to_tab_image_button.h b/chrome/browser/ui/views/overlay/back_to_tab_image_button.h index 8436964..813527a 100644 --- a/chrome/browser/ui/views/overlay/back_to_tab_image_button.h +++ b/chrome/browser/ui/views/overlay/back_to_tab_image_button.h
@@ -14,7 +14,7 @@ // the button, a grey circular background appears as an indicator. class BackToTabImageButton : public views::ImageButton { public: - explicit BackToTabImageButton(ButtonListener* listener); + explicit BackToTabImageButton(ButtonListener*); ~BackToTabImageButton() override = default; // views::Button:
diff --git a/chrome/browser/ui/views/overlay/close_image_button.h b/chrome/browser/ui/views/overlay/close_image_button.h index 6ff8e9a..7b58e6a 100644 --- a/chrome/browser/ui/views/overlay/close_image_button.h +++ b/chrome/browser/ui/views/overlay/close_image_button.h
@@ -14,7 +14,7 @@ // with the button, a grey circular background appears as an indicator. class CloseImageButton : public views::ImageButton { public: - explicit CloseImageButton(ButtonListener* listener); + explicit CloseImageButton(ButtonListener*); ~CloseImageButton() override = default; // views::Button:
diff --git a/chrome/browser/ui/views/overlay/control_image_button.h b/chrome/browser/ui/views/overlay/control_image_button.h index dee2eb4..3063802 100644 --- a/chrome/browser/ui/views/overlay/control_image_button.h +++ b/chrome/browser/ui/views/overlay/control_image_button.h
@@ -12,7 +12,7 @@ // An image button with an associated id. class ControlImageButton : public views::ImageButton { public: - explicit ControlImageButton(ButtonListener* listener); + explicit ControlImageButton(ButtonListener*); ~ControlImageButton() override;
diff --git a/chrome/browser/ui/views/overlay/next_track_image_button.cc b/chrome/browser/ui/views/overlay/next_track_image_button.cc deleted file mode 100644 index 2d19dad..0000000 --- a/chrome/browser/ui/views/overlay/next_track_image_button.cc +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/overlay/next_track_image_button.h" - -#include "chrome/app/vector_icons/vector_icons.h" -#include "chrome/grit/generated_resources.h" -#include "components/vector_icons/vector_icons.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/vector_icons.h" - -namespace { - -SkColor kNextTrackIconColor = SK_ColorWHITE; - -} // namespace - -namespace views { - -NextTrackImageButton::NextTrackImageButton(ButtonListener* listener) - : ImageButton(listener) { - SetImageAlignment(views::ImageButton::ALIGN_CENTER, - views::ImageButton::ALIGN_MIDDLE); - - // Accessibility. - SetFocusForPlatform(); - const base::string16 next_track_button_label(l10n_util::GetStringUTF16( - IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT)); - SetAccessibleName(next_track_button_label); - SetTooltipText(next_track_button_label); - SetInstallFocusRingOnFocus(true); -} - -NextTrackImageButton::~NextTrackImageButton() = default; - -gfx::Size NextTrackImageButton::GetLastVisibleSize() const { - return size().IsEmpty() ? last_visible_size_ : size(); -} - -void NextTrackImageButton::OnBoundsChanged(const gfx::Rect&) { - SetImage(views::Button::STATE_NORMAL, - gfx::CreateVectorIcon(vector_icons::kMediaNextTrackIcon, - GetLastVisibleSize().width() / 2, - kNextTrackIconColor)); -} - -void NextTrackImageButton::ToggleVisibility(bool is_visible) { - if (is_visible && !size().IsEmpty()) { - last_visible_size_ = size(); - } - - SetVisible(is_visible); - SetEnabled(is_visible); - SetSize(is_visible ? GetLastVisibleSize() : gfx::Size()); -} - -} // namespace views
diff --git a/chrome/browser/ui/views/overlay/next_track_image_button.h b/chrome/browser/ui/views/overlay/next_track_image_button.h deleted file mode 100644 index 3f265cb30..0000000 --- a/chrome/browser/ui/views/overlay/next_track_image_button.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_OVERLAY_NEXT_TRACK_IMAGE_BUTTON_H_ -#define CHROME_BROWSER_UI_VIEWS_OVERLAY_NEXT_TRACK_IMAGE_BUTTON_H_ - -#include "chrome/browser/ui/views/overlay/overlay_window_views.h" -#include "ui/views/controls/button/image_button.h" - -namespace views { - -// A resizable next track image button. -class NextTrackImageButton : public views::ImageButton { - public: - explicit NextTrackImageButton(ButtonListener*); - ~NextTrackImageButton() override; - - // Get button size when visible. - gfx::Size GetLastVisibleSize() const; - - // Toggle visibility. - void ToggleVisibility(bool is_visible); - - protected: - // Overridden from views::View. - void OnBoundsChanged(const gfx::Rect& previous_bounds) override; - - private: - // Last visible size of the image button. - gfx::Size last_visible_size_; - - DISALLOW_COPY_AND_ASSIGN(NextTrackImageButton); -}; - -} // namespace views - -#endif // CHROME_BROWSER_UI_VIEWS_OVERLAY_NEXT_TRACK_IMAGE_BUTTON_H_
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc index 08d35ae4..07d1e76 100644 --- a/chrome/browser/ui/views/overlay/overlay_window_views.cc +++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -16,10 +16,10 @@ #include "chrome/browser/ui/views/overlay/back_to_tab_image_button.h" #include "chrome/browser/ui/views/overlay/close_image_button.h" #include "chrome/browser/ui/views/overlay/control_image_button.h" -#include "chrome/browser/ui/views/overlay/next_track_image_button.h" #include "chrome/browser/ui/views/overlay/playback_image_button.h" #include "chrome/browser/ui/views/overlay/resize_handle_button.h" #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h" +#include "chrome/browser/ui/views/overlay/track_image_button.h" #include "chrome/grit/generated_resources.h" #include "components/vector_icons/vector_icons.h" #include "content/public/browser/picture_in_picture_window_controller.h" @@ -128,7 +128,8 @@ window->GetFirstCustomControlsBounds().Contains(point) || window->GetSecondCustomControlsBounds().Contains(point) || window->GetPlayPauseControlsBounds().Contains(point) || - window->GetNextTrackControlsBounds().Contains(point))) { + window->GetNextTrackControlsBounds().Contains(point) || + window->GetPreviousTrackControlsBounds().Contains(point))) { return window_component; } @@ -202,7 +203,16 @@ resize_handle_view_(new views::ResizeHandleButton(this)), #endif play_pause_controls_view_(new views::PlaybackImageButton(this)), - next_track_controls_view_(new views::NextTrackImageButton(this)), + next_track_controls_view_(new views::TrackImageButton( + this, + vector_icons::kMediaNextTrackIcon, + l10n_util::GetStringUTF16( + IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT))), + previous_track_controls_view_(new views::TrackImageButton( + this, + vector_icons::kMediaPreviousTrackIcon, + l10n_util::GetStringUTF16( + IDS_PICTURE_IN_PICTURE_PREVIOUS_TRACK_CONTROL_ACCESSIBLE_TEXT))), hide_controls_timer_( FROM_HERE, base::TimeDelta::FromMilliseconds(2500 /* 2.5 seconds */), @@ -386,6 +396,9 @@ // views::View that holds the next-track image button. ---------------------- next_track_controls_view_->set_owned_by_client(); + // views::View that holds the previous-track image button. ------------------ + previous_track_controls_view_->set_owned_by_client(); + #if defined(OS_CHROMEOS) // views::View that shows the affordance that the window can be resized. ---- resize_handle_view_->SetPaintToLayer(ui::LAYER_TEXTURED); @@ -397,6 +410,7 @@ // Set up view::Views hierarchy. -------------------------------------------- controls_parent_view_->AddChildView(play_pause_controls_view_.get()); controls_parent_view_->AddChildView(next_track_controls_view_.get()); + controls_parent_view_->AddChildView(previous_track_controls_view_.get()); GetContentsView()->AddChildView(controls_scrim_view_.get()); GetContentsView()->AddChildView(controls_parent_view_.get()); GetContentsView()->AddChildView(skip_ad_controls_view_.get()); @@ -442,6 +456,8 @@ !always_hide_play_pause_button_); next_track_controls_view_->ToggleVisibility(is_visible && show_next_track_button_); + previous_track_controls_view_->ToggleVisibility(is_visible && + show_previous_track_button_); GetControlsScrimLayer()->SetVisible(is_visible); GetControlsParentLayer()->SetVisible(is_visible); GetBackToTabControlsLayer()->SetVisible(is_visible); @@ -476,13 +492,20 @@ gfx::Rect(gfx::Point(0, 0), GetBounds().size())); // FIXME: Merge with UpdateControlsPositions when custom controls are removed. - if (show_next_track_button_) { + if (show_next_track_button_ || show_previous_track_button_) { int mid_window_x = GetBounds().size().width() / 2; play_pause_controls_view_->SetBoundsRect(CalculateControlsBounds( mid_window_x - button_size_.width() / 2, button_size_)); - next_track_controls_view_->SetBoundsRect(CalculateControlsBounds( - mid_window_x + button_size_.width() / 2 + kControlButtonMargin, - next_track_controls_view_->GetLastVisibleSize())); + if (show_next_track_button_) + next_track_controls_view_->SetBoundsRect(CalculateControlsBounds( + mid_window_x + button_size_.width() / 2 + kControlButtonMargin, + next_track_controls_view_->GetLastVisibleSize())); + if (show_previous_track_button_) + previous_track_controls_view_->SetBoundsRect(CalculateControlsBounds( + mid_window_x - button_size_.width() / 2 - + previous_track_controls_view_->GetLastVisibleSize().width() - + kControlButtonMargin, + previous_track_controls_view_->GetLastVisibleSize())); } else { UpdateControlsPositions(); } @@ -534,6 +557,7 @@ gfx::Size track_button_size = gfx::ScaleToRoundedSize(button_size_, kTrackButtonSizeScale); next_track_controls_view_->SetSize(track_button_size); + previous_track_controls_view_->SetSize(track_button_size); } void OverlayWindowViews::CreateCustomControl( @@ -683,6 +707,14 @@ UpdateControlsBounds(); } +void OverlayWindowViews::SetPreviousTrackButtonVisibility(bool is_visible) { + if (show_previous_track_button_ == is_visible) + return; + + show_previous_track_button_ = is_visible; + UpdateControlsBounds(); +} + void OverlayWindowViews::SetPictureInPictureCustomControls( const std::vector<blink::PictureInPictureControlInfo>& controls) { // Clear any existing controls. @@ -871,6 +903,9 @@ } else if (GetNextTrackControlsBounds().Contains(event->location())) { controller_->NextTrack(); event->SetHandled(); + } else if (GetPreviousTrackControlsBounds().Contains(event->location())) { + controller_->PreviousTrack(); + event->SetHandled(); } } @@ -892,6 +927,9 @@ if (sender == next_track_controls_view_.get()) controller_->NextTrack(); + if (sender == previous_track_controls_view_.get()) + controller_->PreviousTrack(); + if (sender == first_custom_controls_view_.get()) controller_->CustomControlPressed(first_custom_controls_view_->id()); @@ -923,6 +961,10 @@ return next_track_controls_view_->GetMirroredBounds(); } +gfx::Rect OverlayWindowViews::GetPreviousTrackControlsBounds() { + return previous_track_controls_view_->GetMirroredBounds(); +} + gfx::Rect OverlayWindowViews::GetFirstCustomControlsBounds() { if (!first_custom_controls_view_) return gfx::Rect(); @@ -976,11 +1018,16 @@ return play_pause_controls_view_.get(); } -views::NextTrackImageButton* +views::TrackImageButton* OverlayWindowViews::next_track_controls_view_for_testing() const { return next_track_controls_view_.get(); } +views::TrackImageButton* +OverlayWindowViews::previous_track_controls_view_for_testing() const { + return previous_track_controls_view_.get(); +} + gfx::Point OverlayWindowViews::back_to_tab_image_position_for_testing() const { return back_to_tab_controls_view_->origin(); }
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h index b305837..e0c8be0 100644 --- a/chrome/browser/ui/views/overlay/overlay_window_views.h +++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -20,10 +20,10 @@ class BackToTabImageButton; class ControlImageButton; class CloseImageButton; -class NextTrackImageButton; class PlaybackImageButton; class ResizeHandleButton; class SkipAdLabelButton; +class TrackImageButton; } // namespace views // The Chrome desktop implementation of OverlayWindow. This will only be @@ -52,6 +52,7 @@ void SetAlwaysHidePlayPauseButton(bool is_visible) override; void SetSkipAdButtonVisibility(bool is_visible) override; void SetNextTrackButtonVisibility(bool is_visible) override; + void SetPreviousTrackButtonVisibility(bool is_visible) override; void SetPictureInPictureCustomControls( const std::vector<blink::PictureInPictureControlInfo>& controls) override; ui::Layer* GetWindowBackgroundLayer() override; @@ -80,6 +81,7 @@ gfx::Rect GetResizeHandleControlsBounds(); gfx::Rect GetPlayPauseControlsBounds(); gfx::Rect GetNextTrackControlsBounds(); + gfx::Rect GetPreviousTrackControlsBounds(); gfx::Rect GetFirstCustomControlsBounds(); gfx::Rect GetSecondCustomControlsBounds(); @@ -92,7 +94,8 @@ bool AreControlsVisible() const; views::PlaybackImageButton* play_pause_controls_view_for_testing() const; - views::NextTrackImageButton* next_track_controls_view_for_testing() const; + views::TrackImageButton* next_track_controls_view_for_testing() const; + views::TrackImageButton* previous_track_controls_view_for_testing() const; gfx::Point back_to_tab_image_position_for_testing() const; views::SkipAdLabelButton* skip_ad_controls_view_for_testing() const; gfx::Point close_image_position_for_testing() const; @@ -206,7 +209,8 @@ std::unique_ptr<views::CloseImageButton> close_controls_view_; std::unique_ptr<views::ResizeHandleButton> resize_handle_view_; std::unique_ptr<views::PlaybackImageButton> play_pause_controls_view_; - std::unique_ptr<views::NextTrackImageButton> next_track_controls_view_; + std::unique_ptr<views::TrackImageButton> next_track_controls_view_; + std::unique_ptr<views::TrackImageButton> previous_track_controls_view_; std::unique_ptr<views::ControlImageButton> first_custom_controls_view_; std::unique_ptr<views::ControlImageButton> second_custom_controls_view_; #if defined(OS_CHROMEOS) @@ -228,6 +232,10 @@ // case when Media Session "nexttrack" action is handled by the website. bool show_next_track_button_ = false; + // Whether or not the previous track button will be shown. This is the + // case when Media Session "previoustrack" action is handled by the website. + bool show_previous_track_button_ = false; + DISALLOW_COPY_AND_ASSIGN(OverlayWindowViews); };
diff --git a/chrome/browser/ui/views/overlay/resize_handle_button.h b/chrome/browser/ui/views/overlay/resize_handle_button.h index b6b52d9..f37cf478 100644 --- a/chrome/browser/ui/views/overlay/resize_handle_button.h +++ b/chrome/browser/ui/views/overlay/resize_handle_button.h
@@ -13,7 +13,7 @@ // An image button representing a white resize handle affordance. class ResizeHandleButton : public views::ImageButton { public: - explicit ResizeHandleButton(ButtonListener* listener); + explicit ResizeHandleButton(ButtonListener*); ~ResizeHandleButton() override; void SetPosition(const gfx::Size& size,
diff --git a/chrome/browser/ui/views/overlay/skip_ad_label_button.h b/chrome/browser/ui/views/overlay/skip_ad_label_button.h index 1b17b9a..91128c0 100644 --- a/chrome/browser/ui/views/overlay/skip_ad_label_button.h +++ b/chrome/browser/ui/views/overlay/skip_ad_label_button.h
@@ -13,7 +13,7 @@ // A label button representing a skip-ad button. class SkipAdLabelButton : public views::LabelButton { public: - explicit SkipAdLabelButton(ButtonListener* listener); + explicit SkipAdLabelButton(ButtonListener*); ~SkipAdLabelButton() override = default; // Sets the position of itself with an offset from the given window size.
diff --git a/chrome/browser/ui/views/overlay/track_image_button.cc b/chrome/browser/ui/views/overlay/track_image_button.cc new file mode 100644 index 0000000..11ef735e --- /dev/null +++ b/chrome/browser/ui/views/overlay/track_image_button.cc
@@ -0,0 +1,57 @@ +// 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. + +#include "chrome/browser/ui/views/overlay/track_image_button.h" + +#include "chrome/app/vector_icons/vector_icons.h" +#include "chrome/grit/generated_resources.h" +#include "components/vector_icons/vector_icons.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/vector_icons.h" + +namespace { + +SkColor kTrackIconColor = SK_ColorWHITE; + +} // namespace + +namespace views { + +TrackImageButton::TrackImageButton(ButtonListener* listener, + const gfx::VectorIcon& icon, + base::string16 label) + : ImageButton(listener), icon_(icon) { + SetImageAlignment(views::ImageButton::ALIGN_CENTER, + views::ImageButton::ALIGN_MIDDLE); + + // Accessibility. + SetFocusForPlatform(); + SetAccessibleName(label); + SetTooltipText(label); + SetInstallFocusRingOnFocus(true); +} + +TrackImageButton::~TrackImageButton() = default; + +gfx::Size TrackImageButton::GetLastVisibleSize() const { + return size().IsEmpty() ? last_visible_size_ : size(); +} + +void TrackImageButton::OnBoundsChanged(const gfx::Rect&) { + SetImage(views::Button::STATE_NORMAL, + gfx::CreateVectorIcon(icon_, size().width() / 2, kTrackIconColor)); +} + +void TrackImageButton::ToggleVisibility(bool is_visible) { + if (is_visible && !size().IsEmpty()) + last_visible_size_ = size(); + + SetVisible(is_visible); + SetEnabled(is_visible); + SetSize(is_visible ? GetLastVisibleSize() : gfx::Size()); +} + +} // namespace views
diff --git a/chrome/browser/ui/views/overlay/track_image_button.h b/chrome/browser/ui/views/overlay/track_image_button.h new file mode 100644 index 0000000..a67bc8a --- /dev/null +++ b/chrome/browser/ui/views/overlay/track_image_button.h
@@ -0,0 +1,46 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_OVERLAY_TRACK_IMAGE_BUTTON_H_ +#define CHROME_BROWSER_UI_VIEWS_OVERLAY_TRACK_IMAGE_BUTTON_H_ + +#include "chrome/browser/ui/views/overlay/overlay_window_views.h" +#include "ui/views/controls/button/image_button.h" + +namespace gfx { +struct VectorIcon; +} + +namespace views { + +// A resizable previous/next track image button. +class TrackImageButton : public views::ImageButton { + public: + explicit TrackImageButton(ButtonListener*, + const gfx::VectorIcon& icon, + base::string16 label); + ~TrackImageButton() override; + + // Get button size when visible. + gfx::Size GetLastVisibleSize() const; + + // Toggle visibility. + void ToggleVisibility(bool is_visible); + + protected: + // Overridden from views::View. + void OnBoundsChanged(const gfx::Rect& previous_bounds) override; + + private: + const gfx::VectorIcon& icon_; + + // Last visible size of the image button. + gfx::Size last_visible_size_; + + DISALLOW_COPY_AND_ASSIGN(TrackImageButton); +}; + +} // namespace views + +#endif // CHROME_BROWSER_UI_VIEWS_OVERLAY_TRACK_IMAGE_BUTTON_H_
diff --git a/chrome/browser/ui/views/profiles/incognito_window_count_view.cc b/chrome/browser/ui/views/profiles/incognito_window_count_view.cc index 6b4bdc9..48e04e0 100644 --- a/chrome/browser/ui/views/profiles/incognito_window_count_view.cc +++ b/chrome/browser/ui/views/profiles/incognito_window_count_view.cc
@@ -82,7 +82,7 @@ const SkColor icon_color = ThemeProperties::GetDefaultColor( ThemeProperties::COLOR_NTP_BACKGROUND, true /* incognito */); incognito_icon->SetImage( - gfx::CreateVectorIcon(kIncognitoIcon, 40, icon_color)); + gfx::CreateVectorIcon(kIncognitoProfileIcon, icon_color)); // TODO(https://crbug.com/915120): This Button is never clickable. Replace // by an alternative list item.
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view_browsertest.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view_browsertest.cc index 47434a7..f076ecf 100644 --- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view_browsertest.cc
@@ -4,6 +4,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" +#include "build/build_config.h" #include "chrome/browser/browser_features.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -147,8 +148,14 @@ base::test::ScopedFeatureList scoped_feature_list_; }; +// Fails on win7 (dbg): http://crbug.com/932402. +#if defined(OS_WIN) && !defined(NDEBUG) +#define MAYBE_InvokeUi_tab_hover_card DISABLED_InvokeUi_tab_hover_card +#else +#define MAYBE_InvokeUi_tab_hover_card InvokeUi_tab_hover_card +#endif IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest, - InvokeUi_tab_hover_card) { + MAYBE_InvokeUi_tab_hover_card) { ShowAndVerifyUi(); }
diff --git a/chrome/browser/ui/webui/app_management/app_management_ui.cc b/chrome/browser/ui/webui/app_management/app_management_ui.cc index 30350d68..f716c6d2 100644 --- a/chrome/browser/ui/webui/app_management/app_management_ui.cc +++ b/chrome/browser/ui/webui/app_management/app_management_ui.cc
@@ -94,6 +94,10 @@ IDR_APP_MANAGEMENT_CHROME_APP_PERMISSION_VIEW_JS); source->AddResourcePath("constants.html", IDR_APP_MANAGEMENT_CONSTANTS_HTML); source->AddResourcePath("constants.js", IDR_APP_MANAGEMENT_CONSTANTS_JS); + source->AddResourcePath("expandable_app_list.html", + IDR_APP_MANAGEMENT_EXPANDABLE_APP_LIST_HTML); + source->AddResourcePath("expandable_app_list.js", + IDR_APP_MANAGEMENT_EXPANDABLE_APP_LIST_JS); source->AddResourcePath("dom_switch.html", IDR_APP_MANAGEMENT_DOM_SWITCH_HTML); source->AddResourcePath("dom_switch.js", IDR_APP_MANAGEMENT_DOM_SWITCH_JS);
diff --git a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc index 69d507c0..df251be 100644 --- a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "chrome/browser/chromeos/crostini/crostini_export_import.h" #include "chrome/browser/chromeos/crostini/crostini_manager.h" #include "chrome/browser/chromeos/crostini/crostini_share_path.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" @@ -39,6 +40,14 @@ "removeCrostiniSharedPath", base::BindRepeating(&CrostiniHandler::HandleRemoveCrostiniSharedPath, weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "exportCrostiniContainer", + base::BindRepeating(&CrostiniHandler::HandleExportCrostiniContainer, + weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "importCrostiniContainer", + base::BindRepeating(&CrostiniHandler::HandleImportCrostiniContainer, + weak_ptr_factory_.GetWeakPtr())); } void CrostiniHandler::HandleRequestCrostiniInstallerView( @@ -89,5 +98,19 @@ path)); } +void CrostiniHandler::HandleExportCrostiniContainer( + const base::ListValue* args) { + CHECK_EQ(0U, args->GetSize()); + crostini::CrostiniExportImport::GetForProfile(profile_)->ExportContainer( + web_ui()->GetWebContents()); +} + +void CrostiniHandler::HandleImportCrostiniContainer( + const base::ListValue* args) { + CHECK_EQ(0U, args->GetSize()); + crostini::CrostiniExportImport::GetForProfile(profile_)->ImportContainer( + web_ui()->GetWebContents()); +} + } // namespace settings } // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.h b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.h index 37b71f5..f0e6c0d1 100644 --- a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.h
@@ -36,6 +36,10 @@ void HandleGetCrostiniSharedPathsDisplayText(const base::ListValue* args); // Remove a specified path from being shared. void HandleRemoveCrostiniSharedPath(const base::ListValue* args); + // Export the crostini container. + void HandleExportCrostiniContainer(const base::ListValue* args); + // Import the crostini container. + void HandleImportCrostiniContainer(const base::ListValue* args); Profile* profile_; // weak_ptr_factory_ should always be last member.
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 7291835..bc03ac0 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -438,7 +438,8 @@ } #if defined(OS_CHROMEOS) -void AddCrostiniStrings(content::WebUIDataSource* html_source) { +void AddCrostiniStrings(content::WebUIDataSource* html_source, + Profile* profile) { static constexpr LocalizedString kLocalizedStrings[] = { {"crostiniPageTitle", IDS_SETTINGS_CROSTINI_TITLE}, {"crostiniPageLabel", IDS_SETTINGS_CROSTINI_LABEL}, @@ -453,6 +454,11 @@ IDS_SETTINGS_CROSTINI_SHARED_PATHS_INSTRUCTIONS_REMOVE}, {"crostiniSharedPathsRemoveSharing", IDS_SETTINGS_CROSTINI_SHARED_PATHS_REMOVE_SHARING}, + {"crostiniExportImportTitle", IDS_SETTINGS_CROSTINI_EXPORT_IMPORT_TITLE}, + {"crostiniExport", IDS_SETTINGS_CROSTINI_EXPORT}, + {"crostiniExportLabel", IDS_SETTINGS_CROSTINI_EXPORT_LABEL}, + {"crostiniImport", IDS_SETTINGS_CROSTINI_IMPORT}, + {"crostiniImportLabel", IDS_SETTINGS_CROSTINI_IMPORT_LABEL}, {"crostiniSharedUsbDevicesLabel", IDS_SETTINGS_CROSTINI_SHARED_USB_DEVICES_LABEL}, {"crostiniSharedUsbDevicesDescription", @@ -472,6 +478,9 @@ base::ASCIIToUTF16( crostini::ContainerChromeOSBaseDirectory().value()))); html_source->AddBoolean( + "showCrostiniExportImport", + crostini::IsCrostiniExportImportUIAllowedForProfile(profile)); + html_source->AddBoolean( "enableCrostiniUsbDeviceSupport", base::FeatureList::IsEnabled(chromeos::features::kCrostiniUsbSupport)); } @@ -2825,7 +2834,7 @@ AddWebContentStrings(html_source); #if defined(OS_CHROMEOS) - AddCrostiniStrings(html_source); + AddCrostiniStrings(html_source, profile); AddContainedShellStrings(html_source); AddAndroidAppStrings(html_source); AddBluetoothStrings(html_source);
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc index 5291a78..87f6502 100644 --- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc +++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
@@ -33,7 +33,6 @@ #include "components/prefs/pref_service.h" #include "components/signin/core/browser/account_consistency_method.h" #include "components/signin/core/browser/account_info.h" -#include "components/signin/core/browser/device_id_helper.h" #include "components/signin/core/browser/signin_metrics.h" #include "components/signin/core/browser/signin_pref_names.h" #include "components/sync/base/sync_prefs.h" @@ -413,11 +412,6 @@ IdentityManagerFactory::GetForProfile(new_profile)->GetAccountsMutator(); accounts_mutator->MoveAccount(new_profile_accounts_mutator, account_info_.account_id); - // Reset the device ID from the source profile: the exported token is linked - // to the device ID of the current profile on the server. Reset the device ID - // of the current profile to avoid tying it with the new profile. See - // https://crbug.com/813928#c16 - signin::RecreateSigninScopedDeviceId(profile_->GetPrefs()); SwitchToProfile(new_profile); DCHECK_EQ(profile_, new_profile);
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_mac.mm b/chrome/browser/web_applications/components/web_app_shortcut_mac.mm index cf5447d..e3ebf4c9 100644 --- a/chrome/browser/web_applications/components/web_app_shortcut_mac.mm +++ b/chrome/browser/web_applications/components/web_app_shortcut_mac.mm
@@ -61,10 +61,10 @@ #include "ui/gfx/image/image_family.h" // A TerminationObserver observes a NSRunningApplication for when it -// terminates. On termination, it will run the specified callback, and then -// release itself. +// terminates. On termination, it will run the specified callback on the UI +// thread and release itself. @interface TerminationObserver : NSObject { - NSRunningApplication* app_; + base::scoped_nsobject<NSRunningApplication> app_; base::OnceClosure callback_; } - (id)initWithRunningApplication:(NSRunningApplication*)app @@ -75,25 +75,38 @@ - (id)initWithRunningApplication:(NSRunningApplication*)app callback:(base::OnceClosure)callback { if (self = [super init]) { - app_ = app; callback_ = std::move(callback); - [app_ retain]; + app_.reset(app, base::scoped_policy::RETAIN); + // Note that |observeValueForKeyPath| will be called with the initial value + // within the |addObserver| call. [app_ addObserver:self forKeyPath:@"isTerminated" - options:NSKeyValueObservingOptionNew + options:NSKeyValueObservingOptionNew | + NSKeyValueObservingOptionInitial context:nullptr]; } return self; } + - (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context { + NSNumber* newNumberValue = [change objectForKey:NSKeyValueChangeNewKey]; + BOOL newValue = [newNumberValue boolValue]; + if (newValue) { + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce( + [](TerminationObserver* observer) { [observer onTerminated]; }, + self)); + } +} + +- (void)onTerminated { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + std::move(callback_).Run(); [app_ removeObserver:self forKeyPath:@"isTerminated" context:nullptr]; - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, - std::move(callback_)); - [app_ release]; - app_ = nil; [self release]; } @end
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc index 6f7c76b4..eaeb021 100644 --- a/chrome/installer/setup/setup_util_unittest.cc +++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -27,6 +27,7 @@ #include "base/version.h" #include "base/win/registry.h" #include "base/win/scoped_handle.h" +#include "build/build_config.h" #include "chrome/install_static/install_details.h" #include "chrome/install_static/install_util.h" #include "chrome/install_static/test/scoped_install_details.h" @@ -192,7 +193,14 @@ } // namespace // Launching a subprocess at normal priority class is a noop. -TEST(SetupUtilTest, AdjustFromNormalPriority) { +// See crbug.com/930336: win-asap bots run unit tests using +// BELOW_NORMAL_PRIORITY_CLASS (0x4000) which prevents running some tests. +#if defined(OS_WIN) && defined(ADDRESS_SANITIZER) +#define MAYBE_AdjustFromNormalPriority DISABLED_AdjustFromNormalPriority +#else +#define MAYBE_AdjustFromNormalPriority AdjustFromNormalPriority +#endif +TEST(SetupUtilTest, MAYBE_AdjustFromNormalPriority) { ASSERT_EQ(static_cast<DWORD>(NORMAL_PRIORITY_CLASS), ::GetPriorityClass(::GetCurrentProcess())); EXPECT_EQ(PCCR_UNCHANGED, RelaunchAndDoProcessPriorityAdjustment()); @@ -200,7 +208,15 @@ // Launching a subprocess below normal priority class drops it to bg mode for // sufficiently recent operating systems. -TEST(SetupUtilTest, AdjustFromBelowNormalPriority) { +// See crbug.com/930336: win-asap bots run unit tests using +// BELOW_NORMAL_PRIORITY_CLASS (0x4000) which prevents running some tests. +#if defined(OS_WIN) && defined(ADDRESS_SANITIZER) +#define MAYBE_AdjustFromBelowNormalPriority \ + DISABLED_AdjustFromBelowNormalPriority +#else +#define MAYBE_AdjustFromBelowNormalPriority AdjustFromBelowNormalPriority +#endif +TEST(SetupUtilTest, MAYBE_AdjustFromBelowNormalPriority) { std::unique_ptr<ScopedPriorityClass> below_normal = ScopedPriorityClass::Create(BELOW_NORMAL_PRIORITY_CLASS); ASSERT_TRUE(below_normal);
diff --git a/chrome/test/data/chromeos/oobe_webui_browsertest.js b/chrome/test/data/chromeos/oobe_webui_browsertest.js index 742f52c..de09a39 100644 --- a/chrome/test/data/chromeos/oobe_webui_browsertest.js +++ b/chrome/test/data/chromeos/oobe_webui_browsertest.js
@@ -92,18 +92,6 @@ 'badAriaAttribute', badAriaAttributeSelectors); - var tabIndexGreaterThanZeroSelectors = [ - '#user-image-grid', - '#discard-photo', - '#take-photo', - ]; - - // Enable when failure is resolved. - // AX_FOCUS_03: http://crbug.com/560928 - this.accessibilityAuditConfig.ignoreSelectors( - 'tabIndexGreaterThanZero', - tabIndexGreaterThanZeroSelectors); - var controlsWithoutLabelSelectors = [ '#supervised-user-creation-managers-pane', '#supervised-user-creation-name',
diff --git a/chrome/test/data/client_hints/accept_ch_with_lifetime.html.mock-http-headers b/chrome/test/data/client_hints/accept_ch_with_lifetime.html.mock-http-headers index 6e22fe119..93ad1f1 100644 --- a/chrome/test/data/client_hints/accept_ch_with_lifetime.html.mock-http-headers +++ b/chrome/test/data/client_hints/accept_ch_with_lifetime.html.mock-http-headers
@@ -1,3 +1,3 @@ HTTP/1.1 200 OK -Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang +Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,ua,arch,platform,model Accept-CH-Lifetime: 3600
diff --git a/chrome/test/data/client_hints/accept_ch_without_lifetime.html.mock-http-headers b/chrome/test/data/client_hints/accept_ch_without_lifetime.html.mock-http-headers index 0234b8c..9c3216a7 100644 --- a/chrome/test/data/client_hints/accept_ch_without_lifetime.html.mock-http-headers +++ b/chrome/test/data/client_hints/accept_ch_without_lifetime.html.mock-http-headers
@@ -1,2 +1,2 @@ HTTP/1.1 200 OK -Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang +Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,ua,arch,platform,model
diff --git a/chrome/test/data/client_hints/accept_ch_without_lifetime_img_localhost.html.mock-http-headers b/chrome/test/data/client_hints/accept_ch_without_lifetime_img_localhost.html.mock-http-headers index 0234b8c..9c3216a7 100644 --- a/chrome/test/data/client_hints/accept_ch_without_lifetime_img_localhost.html.mock-http-headers +++ b/chrome/test/data/client_hints/accept_ch_without_lifetime_img_localhost.html.mock-http-headers
@@ -1,2 +1,2 @@ HTTP/1.1 200 OK -Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang +Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,ua,arch,platform,model
diff --git a/chrome/test/data/client_hints/http_equiv_accept_ch_with_lifetime.html b/chrome/test/data/client_hints/http_equiv_accept_ch_with_lifetime.html index d3c6d8cf..bdb172ad 100644 --- a/chrome/test/data/client_hints/http_equiv_accept_ch_with_lifetime.html +++ b/chrome/test/data/client_hints/http_equiv_accept_ch_with_lifetime.html
@@ -1,5 +1,5 @@ <html> -<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang"> +<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang,ua,arch,platform,model"> <meta http-equiv="Accept-CH-Lifetime" content="3600"> <link rel="icon" href="data:;base64,="> </html>
diff --git a/chrome/test/data/client_hints/http_equiv_accept_ch_without_lifetime.html b/chrome/test/data/client_hints/http_equiv_accept_ch_without_lifetime.html index 19f02f1..6d77646bd 100644 --- a/chrome/test/data/client_hints/http_equiv_accept_ch_without_lifetime.html +++ b/chrome/test/data/client_hints/http_equiv_accept_ch_without_lifetime.html
@@ -1,5 +1,5 @@ <html> -<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang"> +<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang,ua,arch,platform,model"> <link rel="icon" href="data:;base64,="> <head></head> Empty file which uses link-rel to disable favicon fetches. The corresponding
diff --git a/chrome/test/data/client_hints/http_equiv_accept_ch_without_lifetime_img_localhost.html b/chrome/test/data/client_hints/http_equiv_accept_ch_without_lifetime_img_localhost.html index 02e61fa..9c7ae7b2 100644 --- a/chrome/test/data/client_hints/http_equiv_accept_ch_without_lifetime_img_localhost.html +++ b/chrome/test/data/client_hints/http_equiv_accept_ch_without_lifetime_img_localhost.html
@@ -1,5 +1,5 @@ <html> -<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang"> +<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang,ua,arch,platform,model"> <link rel="icon" href="data:;base64,="> <head></head> Empty file which uses link-rel to disable favicon fetches. The corresponding
diff --git a/chrome/test/data/webui/app_management/main_view_test.js b/chrome/test/data/webui/app_management/main_view_test.js index f14d9c0..ddfde28f 100644 --- a/chrome/test/data/webui/app_management/main_view_test.js +++ b/chrome/test/data/webui/app_management/main_view_test.js
@@ -31,12 +31,16 @@ test('simple app addition', async function() { // Ensure there is no apps initially expectEquals( - 0, mainView.root.querySelectorAll('app-management-app-item').length); + 0, + mainView.$$('app-management-expandable-app-list') + .root.querySelectorAll('app-management-app-item') + .length); const appId = '1'; await fakeHandler.addApp(appId); - let appItems = mainView.root.querySelectorAll('app-management-app-item'); + let appItems = mainView.$$('app-management-expandable-app-list') + .root.querySelectorAll('app-management-app-item'); expectEquals(1, appItems.length); expectEquals(appId, appItems[0].app.id); @@ -46,14 +50,24 @@ // The more apps bar shouldn't appear when there are 4 apps. await addApps(4); expectEquals( - 4, mainView.root.querySelectorAll('app-management-app-item').length); - expectTrue(mainView.$['expander-row'].hidden); + 4, + mainView.$$('app-management-expandable-app-list') + .root.querySelectorAll('app-management-app-item') + .length); + expectTrue(mainView.$$('app-management-expandable-app-list') + .$['expander-row'] + .hidden); // The more apps bar appears when there are 5 apps. await addApps(1); expectEquals( - 5, mainView.root.querySelectorAll('app-management-app-item').length); - expectFalse(mainView.$['expander-row'].hidden); + 5, + mainView.$$('app-management-expandable-app-list') + .root.querySelectorAll('app-management-app-item') + .length); + expectFalse(mainView.$$('app-management-expandable-app-list') + .$['expander-row'] + .hidden); }); test('notifications sublabel collapsibility', async function() {
diff --git a/chrome/test/data/webui/settings/crostini_page_test.js b/chrome/test/data/webui/settings/crostini_page_test.js index 90897c2..98cb4733 100644 --- a/chrome/test/data/webui/settings/crostini_page_test.js +++ b/chrome/test/data/webui/settings/crostini_page_test.js
@@ -80,6 +80,10 @@ setup(function() { setCrostiniPrefs(true); + loadTimeData.overrideValues({ + showCrostiniExportImport: true, + }); + settings.navigateTo(settings.routes.CROSTINI); crostiniPage.$$('#crostini').click(); return flushAsync().then(() => { @@ -90,6 +94,8 @@ test('Sanity', function() { assertTrue(!!subpage.$$('#crostini-shared-paths')); + assertTrue(!!subpage.$$('#export')); + assertTrue(!!subpage.$$('#import')); assertTrue(!!subpage.$$('#remove')); }); @@ -102,6 +108,19 @@ }); }); + test('Export', function() { + assertTrue(!!subpage.$$('#export paper-button')); + subpage.$$('#export paper-button').click(); + assertEquals( + 1, crostiniBrowserProxy.getCallCount('exportCrostiniContainer')); + }); + + test('Import', function() { + assertTrue(!!subpage.$$('#import paper-button')); + subpage.$$('#import paper-button').click(); + assertEquals( + 1, crostiniBrowserProxy.getCallCount('importCrostiniContainer')); + }); test('Remove', function() { assertTrue(!!subpage.$$('#remove .subpage-arrow'));
diff --git a/chrome/test/data/webui/settings/test_crostini_browser_proxy.js b/chrome/test/data/webui/settings/test_crostini_browser_proxy.js index 2fe2083..660b3a2 100644 --- a/chrome/test/data/webui/settings/test_crostini_browser_proxy.js +++ b/chrome/test/data/webui/settings/test_crostini_browser_proxy.js
@@ -10,6 +10,8 @@ 'requestRemoveCrostini', 'getCrostiniSharedPathsDisplayText', 'removeCrostiniSharedPath', + 'exportCrostiniContainer', + 'importCrostiniContainer', ]); this.enabled = false; this.sharedPaths = ['path1', 'path2']; @@ -37,4 +39,14 @@ removeCrostiniSharedPath(path) { this.sharedPaths = this.sharedPaths.filter(p => p !== path); } + + /** override */ + exportCrostiniContainer() { + this.methodCalled('exportCrostiniContainer'); + } + + /** override */ + importCrostiniContainer() { + this.methodCalled('importCrostiniContainer'); + } }
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java index 41efef4e..7979ddcd 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
@@ -36,8 +36,9 @@ static final int BACKGROUND_TASK_DEPRECATED_EXPLORE_SITES_REFRESH = 16; static final int BACKGROUND_TASK_EXPLORE_SITES_REFRESH = 17; static final int BACKGROUND_TASK_DOWNLOAD_AUTO_RESUMPTION = 18; + static final int BACKGROUND_TASK_ONE_SHOT_SYNC_WAKE_UP = 19; // Keep this one at the end and increment appropriately when adding new tasks. - static final int BACKGROUND_TASK_COUNT = 19; + static final int BACKGROUND_TASK_COUNT = 20; static final String KEY_CACHED_UMA = "bts_cached_uma"; @@ -279,6 +280,8 @@ return BACKGROUND_TASK_DEPRECATED_EXPLORE_SITES_REFRESH; case TaskIds.EXPLORE_SITES_REFRESH_JOB_ID: return BACKGROUND_TASK_EXPLORE_SITES_REFRESH; + case TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID: + return BACKGROUND_TASK_ONE_SHOT_SYNC_WAKE_UP; default: assert false; }
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java index 905c63d..5f04f1cf 100644 --- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java +++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java
@@ -96,7 +96,10 @@ assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_DEPRECATED_EXPLORE_SITES_REFRESH, BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId( TaskIds.DEPRECATED_EXPLORE_SITES_REFRESH_JOB_ID)); - assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_COUNT, 19); + assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_ONE_SHOT_SYNC_WAKE_UP, + BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId( + TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID)); + assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_COUNT, 20); } @Test
diff --git a/components/drive/chromeos/drive_test_util.h b/components/drive/chromeos/drive_test_util.h index e2b12ea..c65fff11 100644 --- a/components/drive/chromeos/drive_test_util.h +++ b/components/drive/chromeos/drive_test_util.h
@@ -12,17 +12,11 @@ #include "components/drive/chromeos/file_cache.h" #include "content/public/test/test_utils.h" #include "google_apis/drive/test_util.h" -#include "net/base/completion_callback.h" #include "net/base/io_buffer.h" -#include "net/base/network_change_notifier.h" #include "net/base/test_completion_callback.h" class PrefRegistrySimple; -namespace net { -class IOBuffer; -} // namespace net - namespace drive { namespace test_util {
diff --git a/components/password_manager/ios/resources/password_controller.js b/components/password_manager/ios/resources/password_controller.js index 4ac09b0..7599dc1 100644 --- a/components/password_manager/ios/resources/password_controller.js +++ b/components/password_manager/ios/resources/password_controller.js
@@ -210,7 +210,7 @@ * @param {string} confirmPasswordIdentifier The id of confirm password element * to fill. * @param {string} password The password to fill. - * @return {boolean} Whether a password field has been filled. + * @return {boolean} Whether new password field has been filled. */ __gCrWeb.passwords['fillPasswordFormWithGeneratedPassword'] = function( formName, newPasswordIdentifier, confirmPasswordIdentifier, password) { @@ -220,15 +220,18 @@ var inputs = getFormInputElements_(form); var newPasswordField = findInputByFieldIdentifier_(inputs, newPasswordIdentifier); - if (newPasswordField) { - newPasswordField.value = password; + if (!newPasswordField) + return false; + // Avoid resetting if same value, as it moves cursor to the end. + if (newPasswordField.value != password) { + __gCrWeb.fill.setInputElementValue(password, newPasswordField); } var confirmPasswordField = findInputByFieldIdentifier_(inputs, confirmPasswordIdentifier); - if (confirmPasswordField) { - confirmPasswordField.value = password; + if (confirmPasswordField && confirmPasswordField.value != password) { + __gCrWeb.fill.setInputElementValue(password, confirmPasswordField); } - return !!newPasswordField || !!confirmPasswordField; + return true; }; /**
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 3a2c2750..b60104c4 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -5847,7 +5847,7 @@ Note that it is not recommended to block internal 'chrome://*' URLs since this may lead to unexpected errors. - Note that this policy does not prevent the page updating dynamically through JavaScript. For example, if you block 'example.com/abc', users might still be able to visit 'example.com' and click on a link to visit 'example.com/abc', as long as the page does not refresh. + From M73 you can block 'javascript://*' URLs. However, it affects only JavaScript typed in address bar (or, for example, bookmarklets). Note that in-page JavaScript URLs, as long as dynamically loaded data, are not subject to this policy. For example, if you block 'example.com/abc', page 'example.com' will still be able to load 'example.com/abc' via XMLHTTPRequest. If this policy is not set no URL will be blacklisted in the browser.''', 'arc_support': 'Android apps may voluntarily choose to honor this list. You cannot force them to honor it.',
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h index ae9c2d5..8815bc9 100644 --- a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h +++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
@@ -49,6 +49,8 @@ // Subsequent calls to |RefreshTokenIsAvailable| will return |false|. void RevokeAllCredentials() override; + void AddAccountFromSystem(const std::string& account_id) override; + void ReloadAccountsFromSystem(const std::string& primary_account_id) override; // Reloads accounts from the provider. Fires |OnRefreshTokenAvailable| for
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm index 9ee4a20a..d931066f 100644 --- a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm +++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
@@ -270,6 +270,11 @@ ClearExcludedSecondaryAccounts(); } +void ProfileOAuth2TokenServiceIOSDelegate::AddAccountFromSystem( + const std::string& account_id) { + AddOrUpdateAccount(account_id); +} + void ProfileOAuth2TokenServiceIOSDelegate::ReloadAccountsFromSystem( const std::string& primary_account_id) { if (primary_account_id.empty())
diff --git a/components/viz/common/frame_sinks/begin_frame_args.cc b/components/viz/common/frame_sinks/begin_frame_args.cc index 3366378..0466d99 100644 --- a/components/viz/common/frame_sinks/begin_frame_args.cc +++ b/components/viz/common/frame_sinks/begin_frame_args.cc
@@ -98,20 +98,6 @@ state->SetBoolean("animate_only", animate_only); } -// This is a hard-coded deadline adjustment that assumes 60Hz, to be used in -// cases where a good estimated draw time is not known. Using 1/3 of the vsync -// as the default adjustment gives the Browser the last 1/3 of a frame to -// produce output, the Renderer Impl thread the middle 1/3 of a frame to produce -// ouput, and the Renderer Main thread the first 1/3 of a frame to produce -// output. -base::TimeDelta BeginFrameArgs::DefaultEstimatedParentDrawTime() { - return base::TimeDelta::FromMicroseconds(16666 / 3); -} - -base::TimeDelta BeginFrameArgs::DefaultInterval() { - return base::TimeDelta::FromMicroseconds(16666); -} - BeginFrameAck::BeginFrameAck() : source_id(0), sequence_number(BeginFrameArgs::kInvalidFrameNumber),
diff --git a/components/viz/common/frame_sinks/begin_frame_args.h b/components/viz/common/frame_sinks/begin_frame_args.h index 6364247..faf8491 100644 --- a/components/viz/common/frame_sinks/begin_frame_args.h +++ b/components/viz/common/frame_sinks/begin_frame_args.h
@@ -80,13 +80,21 @@ base::TimeDelta interval, BeginFrameArgsType type); - // This is the default delta that will be used to adjust the deadline when - // proper draw-time estimations are not yet available. - static base::TimeDelta DefaultEstimatedParentDrawTime(); + // This is the default interval assuming 60Hz to use to avoid sprinkling the + // code with magic numbers. + static constexpr base::TimeDelta DefaultInterval() { + return base::TimeDelta::FromMicroseconds(16666); + } - // This is the default interval to use to avoid sprinkling the code with - // magic numbers. - static base::TimeDelta DefaultInterval(); + // This is a hard-coded deadline adjustment that assumes 60Hz, to be used in + // cases where a good estimated draw time is not known. Using 1/3 of the vsync + // as the default adjustment gives the Browser the last 1/3 of a frame to + // produce output, the Renderer Impl thread the middle 1/3 of a frame to + // produce ouput, and the Renderer Main thread the first 1/3 of a frame to + // produce output. + static constexpr base::TimeDelta DefaultEstimatedParentDrawTime() { + return base::TimeDelta::FromMicroseconds(16666 / 3); + } bool IsValid() const { return interval >= base::TimeDelta(); }
diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc index 53053fc..22578e2 100644 --- a/components/viz/service/display_embedder/gpu_display_provider.cc +++ b/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -122,7 +122,8 @@ if (!gpu_compositing) { output_surface = std::make_unique<SoftwareOutputSurface>( - CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client)); + CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client), + synthetic_begin_frame_source); } else if (renderer_settings.use_skia_renderer) { #if defined(OS_MACOSX) || defined(OS_WIN) // TODO(penghuang): Support DDL for all platforms.
diff --git a/components/viz/service/display_embedder/software_output_device_win.cc b/components/viz/service/display_embedder/software_output_device_win.cc index 16b946d..a339eaa 100644 --- a/components/viz/service/display_embedder/software_output_device_win.cc +++ b/components/viz/service/display_embedder/software_output_device_win.cc
@@ -19,6 +19,7 @@ #include "ui/gfx/gdi_util.h" #include "ui/gfx/skia_util.h" #include "ui/gfx/win/hwnd_util.h" +#include "ui/gl/vsync_provider_win.h" namespace viz { namespace { @@ -26,7 +27,10 @@ // Shared base class for Windows SoftwareOutputDevice implementations. class SoftwareOutputDeviceWinBase : public SoftwareOutputDevice { public: - explicit SoftwareOutputDeviceWinBase(HWND hwnd) : hwnd_(hwnd) {} + explicit SoftwareOutputDeviceWinBase(HWND hwnd) : hwnd_(hwnd) { + vsync_provider_ = std::make_unique<gl::VSyncProviderWin>(hwnd); + } + ~SoftwareOutputDeviceWinBase() override { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!in_paint_);
diff --git a/components/viz/service/display_embedder/software_output_surface.cc b/components/viz/service/display_embedder/software_output_surface.cc index e48ab54..fcb4c75 100644 --- a/components/viz/service/display_embedder/software_output_surface.cc +++ b/components/viz/service/display_embedder/software_output_surface.cc
@@ -11,6 +11,7 @@ #include "base/memory/ref_counted.h" #include "base/time/time.h" #include "build/build_config.h" +#include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/service/display/output_surface_client.h" #include "components/viz/service/display/output_surface_frame.h" #include "components/viz/service/display/software_output_device.h" @@ -21,8 +22,11 @@ namespace viz { SoftwareOutputSurface::SoftwareOutputSurface( - std::unique_ptr<SoftwareOutputDevice> software_device) - : OutputSurface(std::move(software_device)), weak_factory_(this) {} + std::unique_ptr<SoftwareOutputDevice> software_device, + SyntheticBeginFrameSource* synthetic_begin_frame_source) + : OutputSurface(std::move(software_device)), + synthetic_begin_frame_source_(synthetic_begin_frame_source), + weak_factory_(this) {} SoftwareOutputSurface::~SoftwareOutputSurface() = default; @@ -72,14 +76,15 @@ << "arrive before the previous latency info is processed."; stored_latency_info_ = std::move(frame.latency_info); - // TODO(danakj): Update vsync params. - // gfx::VSyncProvider* vsync_provider = software_device()->GetVSyncProvider(); - // if (vsync_provider) - // vsync_provider->GetVSyncParameters(update_vsync_parameters_callback_); - // Update refresh_interval_ as well. - software_device()->OnSwapBuffers(base::BindOnce( &SoftwareOutputSurface::SwapBuffersCallback, weak_factory_.GetWeakPtr())); + + gfx::VSyncProvider* vsync_provider = software_device()->GetVSyncProvider(); + if (vsync_provider && synthetic_begin_frame_source_) { + vsync_provider->GetVSyncParameters( + base::BindOnce(&SoftwareOutputSurface::UpdateVSyncParametersCallback, + weak_factory_.GetWeakPtr())); + } } bool SoftwareOutputSurface::IsDisplayedAsOverlayPlane() const { @@ -117,8 +122,22 @@ client_->DidFinishLatencyInfo(stored_latency_info_); std::vector<ui::LatencyInfo>().swap(stored_latency_info_); client_->DidReceiveSwapBuffersAck(); + + base::TimeTicks now = base::TimeTicks::Now(); + base::TimeDelta interval_to_next_refresh = + now.SnappedToNextTick(refresh_timebase_, refresh_interval_) - now; + client_->DidReceivePresentationFeedback( - gfx::PresentationFeedback(base::TimeTicks::Now(), refresh_interval_, 0u)); + gfx::PresentationFeedback(now, interval_to_next_refresh, 0u)); +} + +void SoftwareOutputSurface::UpdateVSyncParametersCallback( + base::TimeTicks timebase, + base::TimeDelta interval) { + DCHECK(synthetic_begin_frame_source_); + refresh_timebase_ = timebase; + refresh_interval_ = interval; + synthetic_begin_frame_source_->OnUpdateVSyncParameters(timebase, interval); } #if BUILDFLAG(ENABLE_VULKAN)
diff --git a/components/viz/service/display_embedder/software_output_surface.h b/components/viz/service/display_embedder/software_output_surface.h index c371a846..95c032b2 100644 --- a/components/viz/service/display_embedder/software_output_surface.h +++ b/components/viz/service/display_embedder/software_output_surface.h
@@ -6,6 +6,7 @@ #define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_SURFACE_H_ #include "base/memory/weak_ptr.h" +#include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/viz_service_export.h" #include "ui/latency/latency_info.h" @@ -13,11 +14,13 @@ namespace viz { class SoftwareOutputDevice; +class SyntheticBeginFrameSource; class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface { public: - explicit SoftwareOutputSurface( - std::unique_ptr<SoftwareOutputDevice> software_device); + SoftwareOutputSurface( + std::unique_ptr<SoftwareOutputDevice> software_device, + SyntheticBeginFrameSource* synthetic_begin_frame_source); ~SoftwareOutputSurface() override; // OutputSurface implementation. @@ -46,11 +49,18 @@ private: void SwapBuffersCallback(); + void UpdateVSyncParametersCallback(base::TimeTicks timebase, + base::TimeDelta interval); OutputSurfaceClient* client_ = nullptr; - base::TimeDelta refresh_interval_; + + SyntheticBeginFrameSource* const synthetic_begin_frame_source_; + base::TimeTicks refresh_timebase_; + base::TimeDelta refresh_interval_ = BeginFrameArgs::DefaultInterval(); + std::vector<ui::LatencyInfo> stored_latency_info_; ui::LatencyTracker latency_tracker_; + base::WeakPtrFactory<SoftwareOutputSurface> weak_factory_; DISALLOW_COPY_AND_ASSIGN(SoftwareOutputSurface);
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index db9dae3e..c03305f 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -316,6 +316,8 @@ "after_startup_task_utils.h", "android/android_overlay_provider_impl.cc", "android/android_overlay_provider_impl.h", + "android/android_ui_constants.cc", + "android/android_ui_constants.h", "android/app_web_message_port.cc", "android/app_web_message_port.h", "android/background_sync_network_observer_android.cc",
diff --git a/content/browser/android/android_ui_constants.cc b/content/browser/android/android_ui_constants.cc new file mode 100644 index 0000000..f62c87d --- /dev/null +++ b/content/browser/android/android_ui_constants.cc
@@ -0,0 +1,27 @@ +// 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. + +#include "content/browser/android/android_ui_constants.h" + +#include "base/android/jni_android.h" +#include "jni/UiConstants_jni.h" + +bool AndroidUiConstants::IsFocusRingOutset() { + JNIEnv* env = base::android::AttachCurrentThread(); + return Java_UiConstants_isFocusRingOutset(env); +} + +base::Optional<float> AndroidUiConstants::GetMinimumStrokeWidthForFocusRing() { + JNIEnv* env = base::android::AttachCurrentThread(); + if (!Java_UiConstants_hasCustomMinimumStrokeWidthForFocusRing(env)) + return base::nullopt; + return Java_UiConstants_getMinimumStrokeWidthForFocusRing(env); +} + +base::Optional<SkColor> AndroidUiConstants::GetFocusRingColor() { + JNIEnv* env = base::android::AttachCurrentThread(); + if (!Java_UiConstants_hasCustomFocusRingColor(env)) + return base::nullopt; + return Java_UiConstants_getFocusRingColor(env); +}
diff --git a/content/browser/android/android_ui_constants.h b/content/browser/android/android_ui_constants.h new file mode 100644 index 0000000..735f67a --- /dev/null +++ b/content/browser/android/android_ui_constants.h
@@ -0,0 +1,22 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_ANDROID_ANDROID_UI_CONSTANTS_H_ +#define CONTENT_BROWSER_ANDROID_ANDROID_UI_CONSTANTS_H_ + +#include "base/macros.h" +#include "base/optional.h" +#include "third_party/skia/include/core/SkColor.h" + +class AndroidUiConstants { + public: + static bool IsFocusRingOutset(); + static base::Optional<float> GetMinimumStrokeWidthForFocusRing(); + static base::Optional<SkColor> GetFocusRingColor(); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(AndroidUiConstants); +}; + +#endif // CONTENT_BROWSER_ANDROID_ANDROID_UI_CONSTANTS_H_
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc index 5169f88..46813b6 100644 --- a/content/browser/child_process_security_policy_impl.cc +++ b/content/browser/child_process_security_policy_impl.cc
@@ -34,6 +34,7 @@ #include "content/public/common/bindings_policy.h" #include "content/public/common/url_constants.h" #include "net/base/filename_util.h" +#include "net/base/url_util.h" #include "net/url_request/url_request.h" #include "services/network/public/cpp/resource_request_body.h" #include "storage/browser/fileapi/file_permission_policy.h" @@ -1207,10 +1208,7 @@ int child_id, const GURL& url) { DCHECK(url.SchemeIsWSOrWSS()); - GURL::Replacements replace_scheme; - replace_scheme.SetSchemeStr(url.SchemeIs(url::kWssScheme) ? url::kHttpsScheme - : url::kHttpScheme); - GURL url_to_check = url.ReplaceComponents(replace_scheme); + GURL url_to_check = net::ChangeWebSocketSchemeToHttpScheme(url); return CanAccessDataForOrigin(child_id, url_to_check); }
diff --git a/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc b/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc index e12fab7..5ac8128f 100644 --- a/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc +++ b/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc
@@ -26,8 +26,8 @@ FakeVSyncProvider() : call_count_(0) {} ~FakeVSyncProvider() override {} - void GetVSyncParameters(const UpdateVSyncCallback& callback) override { - callback.Run(timebase_, interval_); + void GetVSyncParameters(UpdateVSyncCallback callback) override { + std::move(callback).Run(timebase_, interval_); call_count_++; }
diff --git a/content/browser/cookie_store/cookie_store_manager_unittest.cc b/content/browser/cookie_store/cookie_store_manager_unittest.cc index 5981dd12..59c18ff 100644 --- a/content/browser/cookie_store/cookie_store_manager_unittest.cc +++ b/content/browser/cookie_store/cookie_store_manager_unittest.cc
@@ -11,6 +11,8 @@ #include "content/browser/cookie_store/cookie_store_context.h" #include "content/browser/cookie_store/cookie_store_manager.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" +#include "content/browser/service_worker/fake_service_worker.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/storage_partition_impl.h" #include "content/public/test/test_browser_context.h" @@ -86,6 +88,94 @@ public: using EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper; + explicit CookieStoreWorkerTestHelper( + const base::FilePath& user_data_directory) + : EmbeddedWorkerTestHelper(user_data_directory) {} + ~CookieStoreWorkerTestHelper() override = default; + + class EmbeddedWorkerInstanceClient : public FakeEmbeddedWorkerInstanceClient { + public: + explicit EmbeddedWorkerInstanceClient( + CookieStoreWorkerTestHelper* worker_helper) + : FakeEmbeddedWorkerInstanceClient(worker_helper), + worker_helper_(worker_helper) {} + ~EmbeddedWorkerInstanceClient() override = default; + + // Collects the worker's registration ID for OnInstallEvent(). + void StartWorker( + blink::mojom::EmbeddedWorkerStartParamsPtr params) override { + ServiceWorkerVersion* service_worker_version = + worker_helper_->context()->GetLiveVersion( + params->service_worker_version_id); + DCHECK(service_worker_version); + worker_helper_->service_worker_registration_id_ = + service_worker_version->registration_id(); + + FakeEmbeddedWorkerInstanceClient::StartWorker(std::move(params)); + } + + private: + CookieStoreWorkerTestHelper* const worker_helper_; + + DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceClient); + }; + + class ServiceWorker : public FakeServiceWorker { + public: + explicit ServiceWorker(CookieStoreWorkerTestHelper* worker_helper) + : FakeServiceWorker(worker_helper), worker_helper_(worker_helper) {} + ~ServiceWorker() override = default; + + // Cookie change subscriptions can only be created in this event handler. + void DispatchInstallEvent(DispatchInstallEventCallback callback) override { + for (auto& subscriptions : + worker_helper_->install_subscription_batches_) { + worker_helper_->cookie_store_service_->AppendSubscriptions( + worker_helper_->service_worker_registration_id_, + std::move(subscriptions), base::BindOnce([](bool success) { + CHECK(success) << "AppendSubscriptions failed"; + })); + } + worker_helper_->install_subscription_batches_.clear(); + + FakeServiceWorker::DispatchInstallEvent(std::move(callback)); + } + + // Used to implement WaitForActivateEvent(). + void DispatchActivateEvent( + DispatchActivateEventCallback callback) override { + if (worker_helper_->quit_on_activate_) { + worker_helper_->quit_on_activate_->Quit(); + worker_helper_->quit_on_activate_ = nullptr; + } + + FakeServiceWorker::DispatchActivateEvent(std::move(callback)); + } + + void DispatchCookieChangeEvent( + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + DispatchCookieChangeEventCallback callback) override { + worker_helper_->changes_.emplace_back(cookie, cause); + std::move(callback).Run( + blink::mojom::ServiceWorkerEventStatus::COMPLETED); + } + + private: + CookieStoreWorkerTestHelper* const worker_helper_; + + DISALLOW_COPY_AND_ASSIGN(ServiceWorker); + }; + + std::unique_ptr<FakeEmbeddedWorkerInstanceClient> CreateInstanceClient() + override { + return std::make_unique<EmbeddedWorkerInstanceClient>(this); + } + + std::unique_ptr<FakeServiceWorker> CreateServiceWorker() override { + return std::make_unique<ServiceWorker>(this); + } + // Sets the cookie change subscriptions requested in the next install event. void SetOnInstallSubscriptions( std::vector<CookieStoreSync::Subscriptions> subscription_batches, @@ -108,68 +198,6 @@ return changes_; } - protected: - // Collects the worker's registration ID for OnInstallEvent(). - void OnStartWorker( - int embedded_worker_id, - int64_t service_worker_version_id, - const GURL& scope, - const GURL& script_url, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) - override { - ServiceWorkerVersion* service_worker_version = - context()->GetLiveVersion(service_worker_version_id); - DCHECK(service_worker_version); - service_worker_registration_id_ = service_worker_version->registration_id(); - - EmbeddedWorkerTestHelper::OnStartWorker( - embedded_worker_id, service_worker_version_id, scope, script_url, - pause_after_download, std::move(service_worker_request), - std::move(controller_request), std::move(instance_host), - std::move(provider_info), std::move(installed_scripts_info)); - } - - // Cookie change subscriptions can only be created in this event handler. - void OnInstallEvent(blink::mojom::ServiceWorker::DispatchInstallEventCallback - callback) override { - for (auto& subscriptions : install_subscription_batches_) { - cookie_store_service_->AppendSubscriptions( - service_worker_registration_id_, std::move(subscriptions), - base::BindOnce([](bool success) { - CHECK(success) << "AppendSubscriptions failed"; - })); - } - install_subscription_batches_.clear(); - - EmbeddedWorkerTestHelper::OnInstallEvent(std::move(callback)); - } - - // Used to implement WaitForActivateEvent(). - void OnActivateEvent( - blink::mojom::ServiceWorker::DispatchActivateEventCallback callback) - override { - if (quit_on_activate_) { - quit_on_activate_->Quit(); - quit_on_activate_ = nullptr; - } - - EmbeddedWorkerTestHelper::OnActivateEvent(std::move(callback)); - } - - void OnCookieChangeEvent( - const net::CanonicalCookie& cookie, - ::network::mojom::CookieChangeCause cause, - blink::mojom::ServiceWorker::DispatchCookieChangeEventCallback callback) - override { - changes_.emplace_back(cookie, cause); - std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED); - } - private: // Used to add cookie change subscriptions during OnInstallEvent(). blink::mojom::CookieStore* cookie_store_service_ = nullptr;
diff --git a/content/browser/devtools/browser_devtools_agent_host.cc b/content/browser/devtools/browser_devtools_agent_host.cc index 362a62ed..2862801 100644 --- a/content/browser/devtools/browser_devtools_agent_host.cc +++ b/content/browser/devtools/browser_devtools_agent_host.cc
@@ -87,8 +87,8 @@ session->AddHandler(std::make_unique<protocol::TetheringHandler>( socket_callback_, tethering_task_runner_)); } - session->AddHandler( - std::make_unique<protocol::TracingHandler>(nullptr, GetIOContext())); + session->AddHandler(std::make_unique<protocol::TracingHandler>( + nullptr, GetIOContext(), session->client()->UsesBinaryProtocol())); return true; }
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc index adf9a4f..990a9bdf7 100644 --- a/content/browser/devtools/devtools_session.cc +++ b/content/browser/devtools/devtools_session.cc
@@ -336,10 +336,10 @@ std::string patched; bool patched_ok; if (client_->UsesBinaryProtocol()) { - patched_ok = protocol::AppendStringValueToMapBinary(message, "sessionId", + patched_ok = protocol::AppendStringValueToMapBinary(message, kSessionId, session_id, &patched); } else { - patched_ok = protocol::AppendStringValueToMapJSON(message, "sessionId", + patched_ok = protocol::AppendStringValueToMapJSON(message, kSessionId, session_id, &patched); } if (!patched_ok)
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc index b62b5892..bc31d2c 100644 --- a/content/browser/devtools/protocol/target_handler.cc +++ b/content/browser/devtools/protocol/target_handler.cc
@@ -331,6 +331,11 @@ return agent_host_->GetId() == target_id; } + bool UsesBinaryProtocol() override { + auto* client = handler_->root_session_->client(); + return client->UsesBinaryProtocol(); + } + private: friend class TargetHandler;
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc index 6609d738..fbca49f6 100644 --- a/content/browser/devtools/protocol/tracing_handler.cc +++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -211,8 +211,10 @@ } // namespace TracingHandler::TracingHandler(FrameTreeNode* frame_tree_node_, - DevToolsIOContext* io_context) + DevToolsIOContext* io_context, + bool use_binary_protocol) : DevToolsDomainHandler(Tracing::Metainfo::domainName), + use_binary_protocol_(use_binary_protocol), io_context_(io_context), frame_tree_node_(frame_tree_node_), did_initiate_recording_(false), @@ -276,7 +278,12 @@ message.append(valid_trace_fragment.c_str() + trace_data_buffer_state_.offset); message += "] } }"; - frontend_->sendRawNotification(std::move(message)); + if (use_binary_protocol_) { + auto parsed = protocol::StringUtil::parseMessage(message, false); + frontend_->sendRawNotification(parsed->serializeToBinary()); + } else { + frontend_->sendRawNotification(std::move(message)); + } } void TracingHandler::OnTraceComplete() {
diff --git a/content/browser/devtools/protocol/tracing_handler.h b/content/browser/devtools/protocol/tracing_handler.h index 97ba228..b07104f8 100644 --- a/content/browser/devtools/protocol/tracing_handler.h +++ b/content/browser/devtools/protocol/tracing_handler.h
@@ -46,7 +46,8 @@ class TracingHandler : public DevToolsDomainHandler, public Tracing::Backend { public: CONTENT_EXPORT TracingHandler(FrameTreeNode* frame_tree_node, - DevToolsIOContext* io_context); + DevToolsIOContext* io_context, + bool use_binary_protocol); CONTENT_EXPORT ~TracingHandler() override; static std::vector<TracingHandler*> ForAgentHost(DevToolsAgentHostImpl* host); @@ -123,6 +124,7 @@ std::unordered_set<base::ProcessId>* process_set); void OnProcessReady(RenderProcessHost*); + const bool use_binary_protocol_; std::unique_ptr<base::RepeatingTimer> buffer_usage_poll_timer_; std::unique_ptr<Tracing::Frontend> frontend_;
diff --git a/content/browser/devtools/protocol/tracing_handler_unittest.cc b/content/browser/devtools/protocol/tracing_handler_unittest.cc index a3927429..9db9c9c8 100644 --- a/content/browser/devtools/protocol/tracing_handler_unittest.cc +++ b/content/browser/devtools/protocol/tracing_handler_unittest.cc
@@ -72,7 +72,7 @@ class TracingHandlerTest : public testing::Test { public: void SetUp() override { - tracing_handler_.reset(new TracingHandler(nullptr, nullptr)); + tracing_handler_.reset(new TracingHandler(nullptr, nullptr, false)); } void TearDown() override { tracing_handler_.reset(); }
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc index cade752..768ae60f 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.cc +++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -305,7 +305,8 @@ session->AddHandler(base::WrapUnique(new protocol::SecurityHandler())); if (!frame_tree_node_ || !frame_tree_node_->parent()) { session->AddHandler(base::WrapUnique( - new protocol::TracingHandler(frame_tree_node_, GetIOContext()))); + new protocol::TracingHandler(frame_tree_node_, GetIOContext(), + session->client()->UsesBinaryProtocol()))); } if (sessions().empty()) {
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 2d622736..24b06a7a 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -24,6 +24,7 @@ #include "base/numerics/safe_conversions.h" #include "base/process/kill.h" #include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" #include "base/task/post_task.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" @@ -6053,6 +6054,33 @@ VLOG(1) << "Blocked URL " << validated_params->url.spec(); LogRendererKillCrashKeys(GetSiteInstance()->GetSiteURL()); + // Temporary instrumentation to debug the root cause of + // https://crbug.com/931895. + auto bool_to_crash_key = [](bool b) { return b ? "true" : "false"; }; + base::debug::SetCrashKeyString( + base::debug::AllocateCrashKeyString("is_same_document", + base::debug::CrashKeySize::Size32), + bool_to_crash_key(is_same_document_navigation)); + + base::debug::SetCrashKeyString( + base::debug::AllocateCrashKeyString("is_subframe", + base::debug::CrashKeySize::Size32), + bool_to_crash_key(!frame_tree_node_->IsMainFrame())); + + if (navigation_request_ && navigation_request_->navigation_handle()) { + NavigationHandleImpl* handle = navigation_request_->navigation_handle(); + base::debug::SetCrashKeyString( + base::debug::AllocateCrashKeyString( + "is_error_page", base::debug::CrashKeySize::Size32), + bool_to_crash_key(handle->IsErrorPage())); + if (handle->IsErrorPage()) { + base::debug::SetCrashKeyString( + base::debug::AllocateCrashKeyString( + "is_error_page", base::debug::CrashKeySize::Size32), + base::IntToString(handle->GetNetErrorCode())); + } + } + // Kills the process. bad_message::ReceivedBadMessage(process, bad_message::RFH_CAN_COMMIT_URL_BLOCKED);
diff --git a/content/browser/payments/payment_app_content_unittest_base.cc b/content/browser/payments/payment_app_content_unittest_base.cc index 5194da83..5fcacbd 100644 --- a/content/browser/payments/payment_app_content_unittest_base.cc +++ b/content/browser/payments/payment_app_content_unittest_base.cc
@@ -14,6 +14,8 @@ #include "base/run_loop.h" #include "base/stl_util.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" +#include "content/browser/service_worker/fake_service_worker.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/storage_partition_impl.h" #include "content/public/test/test_browser_context.h" @@ -61,68 +63,74 @@ blink::mojom::kInvalidServiceWorkerRegistrationId) {} ~PaymentAppForWorkerTestHelper() override {} - void OnStartWorker( - int embedded_worker_id, - int64_t service_worker_version_id, - const GURL& scope, - const GURL& script_url, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) - override { - ServiceWorkerVersion* version = - context()->GetLiveVersion(service_worker_version_id); - last_sw_registration_id_ = version->registration_id(); - last_sw_scope_ = scope; - EmbeddedWorkerTestHelper::OnStartWorker( - embedded_worker_id, service_worker_version_id, scope, script_url, - pause_after_download, std::move(service_worker_request), - std::move(controller_request), std::move(instance_host), - std::move(provider_info), std::move(installed_scripts_info)); - } + class EmbeddedWorkerInstanceClient : public FakeEmbeddedWorkerInstanceClient { + public: + explicit EmbeddedWorkerInstanceClient( + PaymentAppForWorkerTestHelper* worker_helper) + : FakeEmbeddedWorkerInstanceClient(worker_helper), + worker_helper_(worker_helper) {} + ~EmbeddedWorkerInstanceClient() override = default; - void OnPaymentRequestEvent( - payments::mojom::PaymentRequestEventDataPtr event_data, - payments::mojom::PaymentHandlerResponseCallbackPtr response_callback, - blink::mojom::ServiceWorker::DispatchPaymentRequestEventCallback callback) - override { - if (respond_payment_request_immediately) { - EmbeddedWorkerTestHelper::OnPaymentRequestEvent( - std::move(event_data), std::move(response_callback), - std::move(callback)); - } else { - pending_response_callback_ = std::move(response_callback); - std::move(callback).Run( - blink::mojom::ServiceWorkerEventStatus::COMPLETED); + void StartWorker( + blink::mojom::EmbeddedWorkerStartParamsPtr params) override { + ServiceWorkerVersion* version = worker_helper_->context()->GetLiveVersion( + params->service_worker_version_id); + worker_helper_->last_sw_registration_id_ = version->registration_id(); + worker_helper_->last_sw_scope_ = version->scope(); + + FakeEmbeddedWorkerInstanceClient::StartWorker(std::move(params)); } + + private: + PaymentAppForWorkerTestHelper* const worker_helper_; + + DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceClient); + }; + + class ServiceWorker : public FakeServiceWorker { + public: + explicit ServiceWorker(PaymentAppForWorkerTestHelper* worker_helper) + : FakeServiceWorker(worker_helper), worker_helper_(worker_helper) {} + ~ServiceWorker() override = default; + + void DispatchPaymentRequestEvent( + payments::mojom::PaymentRequestEventDataPtr event_data, + payments::mojom::PaymentHandlerResponseCallbackPtr response_callback, + DispatchPaymentRequestEventCallback callback) override { + if (!worker_helper_) + return; + if (worker_helper_->respond_payment_request_immediately_) { + FakeServiceWorker::DispatchPaymentRequestEvent( + std::move(event_data), std::move(response_callback), + std::move(callback)); + } else { + worker_helper_->pending_response_callback_ = + std::move(response_callback); + std::move(callback).Run( + blink::mojom::ServiceWorkerEventStatus::COMPLETED); + } + } + + private: + PaymentAppForWorkerTestHelper* const worker_helper_; + + DISALLOW_COPY_AND_ASSIGN(ServiceWorker); + }; + + std::unique_ptr<FakeEmbeddedWorkerInstanceClient> CreateInstanceClient() + override { + return std::make_unique<EmbeddedWorkerInstanceClient>(this); } - void OnCanMakePaymentEvent( - payments::mojom::CanMakePaymentEventDataPtr event_data, - payments::mojom::PaymentHandlerResponseCallbackPtr response_callback, - blink::mojom::ServiceWorker::DispatchCanMakePaymentEventCallback callback) - override { - EmbeddedWorkerTestHelper::OnCanMakePaymentEvent( - std::move(event_data), std::move(response_callback), - std::move(callback)); - } - - void OnAbortPaymentEvent( - payments::mojom::PaymentHandlerResponseCallbackPtr response_callback, - blink::mojom::ServiceWorker::DispatchCanMakePaymentEventCallback callback) - override { - EmbeddedWorkerTestHelper::OnAbortPaymentEvent(std::move(response_callback), - std::move(callback)); + std::unique_ptr<FakeServiceWorker> CreateServiceWorker() override { + return std::make_unique<ServiceWorker>(this); } int64_t last_sw_registration_id_; GURL last_sw_scope_; // Variables to delay payment request response. - bool respond_payment_request_immediately = true; + bool respond_payment_request_immediately_ = true; payments::mojom::PaymentHandlerResponseCallbackPtr pending_response_callback_; private: @@ -222,7 +230,7 @@ } void PaymentAppContentUnitTestBase::SetNoPaymentRequestResponseImmediately() { - worker_helper_->respond_payment_request_immediately = false; + worker_helper_->respond_payment_request_immediately_ = false; } void PaymentAppContentUnitTestBase::RespondPendingPaymentRequest() {
diff --git a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc index ef61e91..6fc0fc2a9 100644 --- a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc +++ b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
@@ -62,6 +62,7 @@ gfx::Rect GetVideoBounds() override { return gfx::Rect(); } void SetSkipAdButtonVisibility(bool is_visible) override {} void SetNextTrackButtonVisibility(bool is_visible) override {} + void SetPreviousTrackButtonVisibility(bool is_visible) override {} private: DISALLOW_COPY_AND_ASSIGN(TestOverlayWindow);
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc index ae11346a..824a42b3 100644 --- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc +++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
@@ -74,19 +74,24 @@ DCHECK(surface_id_.is_valid()); MediaSessionImpl* media_session = MediaSessionImpl::Get(initiator_); - media_session_action_next_track_handled_ = media_session->ShouldRouteAction( - media_session::mojom::MediaSessionAction::kNextTrack); media_session_action_play_handled_ = media_session->ShouldRouteAction( media_session::mojom::MediaSessionAction::kPlay); media_session_action_pause_handled_ = media_session->ShouldRouteAction( media_session::mojom::MediaSessionAction::kPause); media_session_action_skip_ad_handled_ = media_session->ShouldRouteAction( media_session::mojom::MediaSessionAction::kSkipAd); + media_session_action_next_track_handled_ = media_session->ShouldRouteAction( + media_session::mojom::MediaSessionAction::kNextTrack); + media_session_action_previous_track_handled_ = + media_session->ShouldRouteAction( + media_session::mojom::MediaSessionAction::kPreviousTrack); UpdatePlayPauseButtonVisibility(); window_->SetSkipAdButtonVisibility(media_session_action_skip_ad_handled_); window_->SetNextTrackButtonVisibility( media_session_action_next_track_handled_); + window_->SetPreviousTrackButtonVisibility( + media_session_action_previous_track_handled_); window_->ShowInactive(); initiator_->SetHasPictureInPictureVideo(true); @@ -258,6 +263,11 @@ MediaSession::Get(initiator_)->NextTrack(); } +void PictureInPictureWindowControllerImpl::PreviousTrack() { + if (media_session_action_previous_track_handled_) + MediaSession::Get(initiator_)->PreviousTrack(); +} + void PictureInPictureWindowControllerImpl::MediaSessionActionsChanged( const std::set<media_session::mojom::MediaSessionAction>& actions) { // TODO(crbug.com/919842): Currently, the first Media Session to be created @@ -265,9 +275,6 @@ // Skip Ad button for a PiP video from another frame. Ideally, we should have // a Media Session per frame, not per tab. This is not implemented yet. - media_session_action_next_track_handled_ = - actions.find(media_session::mojom::MediaSessionAction::kNextTrack) != - actions.end(); media_session_action_pause_handled_ = actions.find(media_session::mojom::MediaSessionAction::kPause) != actions.end(); @@ -277,6 +284,12 @@ media_session_action_skip_ad_handled_ = actions.find(media_session::mojom::MediaSessionAction::kSkipAd) != actions.end(); + media_session_action_next_track_handled_ = + actions.find(media_session::mojom::MediaSessionAction::kNextTrack) != + actions.end(); + media_session_action_previous_track_handled_ = + actions.find(media_session::mojom::MediaSessionAction::kPreviousTrack) != + actions.end(); if (!window_) return; @@ -285,6 +298,8 @@ window_->SetSkipAdButtonVisibility(media_session_action_skip_ad_handled_); window_->SetNextTrackButtonVisibility( media_session_action_next_track_handled_); + window_->SetPreviousTrackButtonVisibility( + media_session_action_previous_track_handled_); } void PictureInPictureWindowControllerImpl::MediaStartedPlaying(
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h index e4655cdd..9e2516c 100644 --- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h +++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
@@ -61,6 +61,7 @@ CONTENT_EXPORT void SetAlwaysHidePlayPauseButton(bool is_visible) override; CONTENT_EXPORT void SkipAd() override; CONTENT_EXPORT void NextTrack() override; + CONTENT_EXPORT void PreviousTrack() override; CONTENT_EXPORT void MediaSessionActionsChanged( const std::set<media_session::mojom::MediaSessionAction>& actions); @@ -118,10 +119,11 @@ // Used to show/hide some actions in Picture-in-Picture window. These are set // to true when website handles some Media Session actions. - bool media_session_action_next_track_handled_ = false; bool media_session_action_play_handled_ = false; bool media_session_action_pause_handled_ = false; bool media_session_action_skip_ad_handled_ = false; + bool media_session_action_next_track_handled_ = false; + bool media_session_action_previous_track_handled_ = false; // Used to hide play/pause button if video is a MediaStream or has infinite // duration. Play/pause button visibility can be overridden by the Media
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index b33f30b..7298233 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2833,7 +2833,7 @@ if (!SiteInstanceImpl::IsOriginLockASite(lock_url)) return; - GetRendererInterface()->SetIsLockedToSite(); + GetRendererInterface()->SetIsLockedToSite(lock_url); } bool RenderProcessHostImpl::IsForGuestsOnly() {
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc index 706e2c5d..c3b969f 100644 --- a/content/browser/service_worker/embedded_worker_instance.cc +++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -177,7 +177,8 @@ // ServiceWorkerScriptLoaderFactory and the other is for passing to the // renderer. These bundles include factories for non-network URLs like // chrome-extension:// as needed. -void SetupOnUIThread(base::WeakPtr<ServiceWorkerProcessManager> process_manager, +void SetupOnUIThread(int embedded_worker_id, + base::WeakPtr<ServiceWorkerProcessManager> process_manager, bool can_use_existing_process, blink::mojom::EmbeddedWorkerStartParamsPtr params, blink::mojom::EmbeddedWorkerInstanceClientRequest request, @@ -207,8 +208,8 @@ // Get a process. blink::ServiceWorkerStatusCode status = process_manager->AllocateWorkerProcess( - params->embedded_worker_id, params->script_url, - can_use_existing_process, process_info.get()); + embedded_worker_id, params->script_url, can_use_existing_process, + process_info.get()); if (status != blink::ServiceWorkerStatusCode::kOk) { base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO}, @@ -534,7 +535,6 @@ bool can_use_existing_process = context->GetVersionFailureCount(params->service_worker_version_id) < kMaxSameProcessFailureCount; - DCHECK_EQ(params->embedded_worker_id, instance_->embedded_worker_id_); TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("ServiceWorker", "ALLOCATING_PROCESS", this); base::WeakPtr<ServiceWorkerProcessManager> process_manager = @@ -545,8 +545,9 @@ base::PostTaskWithTraits( FROM_HERE, {BrowserThread::UI}, base::BindOnce( - &SetupOnUIThread, process_manager, can_use_existing_process, - std::move(params), std::move(request_), context.get(), context, + &SetupOnUIThread, instance_->embedded_worker_id(), process_manager, + can_use_existing_process, std::move(params), std::move(request_), + context.get(), context, base::BindOnce(&StartTask::OnSetupCompleted, weak_factory_.GetWeakPtr(), process_manager))); } @@ -686,7 +687,6 @@ for (auto& observer : listener_list_) observer.OnStarting(); - params->embedded_worker_id = embedded_worker_id_; params->worker_devtools_agent_route_id = MSG_ROUTING_NONE; params->wait_for_debugger = false; params->v8_cache_options = GetV8CacheOptions();
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc index 7f2492a..8ed9641 100644 --- a/content/browser/service_worker/embedded_worker_instance_unittest.cc +++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -18,6 +18,7 @@ #include "content/browser/service_worker/embedded_worker_registry.h" #include "content/browser/service_worker/embedded_worker_status.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_registration.h" @@ -215,12 +216,6 @@ return context()->embedded_worker_registry(); } - std::vector<std::unique_ptr< - EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient>>* - mock_instance_clients() { - return helper_->mock_instance_clients(); - } - // Mojo endpoints. std::vector<blink::mojom::ServiceWorkerPtr> service_workers_; std::vector<blink::mojom::ControllerServiceWorkerPtr> controllers_; @@ -238,60 +233,6 @@ DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest); }; -// A helper to simulate the start worker sequence is stalled in a worker -// process. -class StalledInStartWorkerHelper : public EmbeddedWorkerTestHelper { - public: - StalledInStartWorkerHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {} - ~StalledInStartWorkerHelper() override {} - - void OnStartWorker( - int embedded_worker_id, - int64_t service_worker_version_id, - const GURL& scope, - const GURL& script_url, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) - override { - if (force_stall_in_start_) { - // Prepare for OnStopWorker(). - instance_host_ptr_map_[embedded_worker_id].Bind(std::move(instance_host)); - // Do nothing to simulate a stall in the worker process. - return; - } - EmbeddedWorkerTestHelper::OnStartWorker( - embedded_worker_id, service_worker_version_id, scope, script_url, - pause_after_download, std::move(service_worker_request), - std::move(controller_request), std::move(instance_host), - std::move(provider_info), std::move(installed_scripts_info)); - } - - void OnStopWorker(int embedded_worker_id) override { - if (instance_host_ptr_map_[embedded_worker_id]) { - instance_host_ptr_map_[embedded_worker_id]->OnStopped(); - base::RunLoop().RunUntilIdle(); - return; - } - EmbeddedWorkerTestHelper::OnStopWorker(embedded_worker_id); - } - - void set_force_stall_in_start(bool force_stall_in_start) { - force_stall_in_start_ = force_stall_in_start; - } - - private: - bool force_stall_in_start_ = true; - - std::map<int /* embedded_worker_id */, - blink::mojom:: - EmbeddedWorkerInstanceHostAssociatedPtr /* instance_host_ptr */> - instance_host_ptr_map_; -}; - TEST_P(EmbeddedWorkerInstanceTest, StartAndStop) { const GURL scope("http://example.com/"); const GURL url("http://example.com/worker.js"); @@ -476,12 +417,14 @@ const GURL scope("http://example.com/"); const GURL url("http://example.com/worker.js"); - helper_.reset(new StalledInStartWorkerHelper()); RegistrationAndVersionPair pair = PrepareRegistrationAndVersion(scope, url); std::unique_ptr<EmbeddedWorkerInstance> worker = embedded_worker_registry()->CreateWorker(pair.second.get()); worker->AddObserver(this); + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + client->UnblockStopWorker(); StartWorkerUntilStartSent(worker.get(), CreateStartParams(pair.second)); ASSERT_EQ(2u, events_.size()); EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type); @@ -543,12 +486,12 @@ } class DontReceiveResumeAfterDownloadInstanceClient - : public EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient { + : public FakeEmbeddedWorkerInstanceClient { public: - explicit DontReceiveResumeAfterDownloadInstanceClient( + DontReceiveResumeAfterDownloadInstanceClient( EmbeddedWorkerTestHelper* helper, bool* was_resume_after_download_called) - : EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient(helper), + : FakeEmbeddedWorkerInstanceClient(helper), was_resume_after_download_called_(was_resume_after_download_called) {} private: @@ -564,7 +507,7 @@ const GURL url("http://example.com/worker.js"); bool was_resume_after_download_called = false; - helper_->RegisterMockInstanceClient( + helper_->AddPendingInstanceClient( std::make_unique<DontReceiveResumeAfterDownloadInstanceClient>( helper_.get(), &was_resume_after_download_called)); @@ -597,12 +540,15 @@ const GURL scope("http://example.com/"); const GURL url("http://example.com/worker.js"); - helper_.reset(new StalledInStartWorkerHelper); RegistrationAndVersionPair pair = PrepareRegistrationAndVersion(scope, url); std::unique_ptr<EmbeddedWorkerInstance> worker = embedded_worker_registry()->CreateWorker(pair.second.get()); worker->AddObserver(this); + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + client->UnblockStopWorker(); + StartWorkerUntilStartSent(worker.get(), CreateStartParams(pair.second)); ASSERT_EQ(2u, events_.size()); EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type); @@ -622,8 +568,6 @@ events_.clear(); // Restart the worker. - static_cast<StalledInStartWorkerHelper*>(helper_.get()) - ->set_force_stall_in_start(false); StartWorker(worker.get(), CreateStartParams(pair.second)); // The worker should be started. @@ -667,7 +611,7 @@ const GURL url("http://example.com/worker.js"); // Let StartWorker fail; mojo IPC fails to connect to a remote interface. - helper_->RegisterMockInstanceClient(nullptr); + helper_->AddPendingInstanceClient(nullptr); RegistrationAndVersionPair pair = PrepareRegistrationAndVersion(scope, url); std::unique_ptr<EmbeddedWorkerInstance> worker = @@ -695,28 +639,10 @@ EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, worker->status()); } -class FailEmbeddedWorkerInstanceClientImpl - : public EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient { - public: - explicit FailEmbeddedWorkerInstanceClientImpl( - EmbeddedWorkerTestHelper* helper) - : EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient(helper) {} - - private: - void StartWorker(blink::mojom::EmbeddedWorkerStartParamsPtr) override { - helper_->mock_instance_clients()->clear(); - } -}; - TEST_P(EmbeddedWorkerInstanceTest, RemoveRemoteInterface) { const GURL scope("http://example.com/"); const GURL url("http://example.com/worker.js"); - // Let StartWorker fail; binding is discarded in the middle of IPC - helper_->RegisterMockInstanceClient( - std::make_unique<FailEmbeddedWorkerInstanceClientImpl>(helper_.get())); - ASSERT_EQ(mock_instance_clients()->size(), 1UL); - RegistrationAndVersionPair pair = PrepareRegistrationAndVersion(scope, url); std::unique_ptr<EmbeddedWorkerInstance> worker = embedded_worker_registry()->CreateWorker(pair.second.get()); @@ -725,12 +651,17 @@ // Attempt to start the worker. base::Optional<blink::ServiceWorkerStatusCode> status; base::RunLoop loop; + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); worker->Start(CreateStartParams(pair.second), ReceiveStatus(&status, loop.QuitClosure())); loop.Run(); EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status.value()); - // Worker should handle the sudden shutdown as detach. + // Disconnect the Mojo connection. Worker should handle the sudden shutdown as + // detach. + client->RunUntilBound(); + client->Disconnect(); base::RunLoop().RunUntilIdle(); ASSERT_EQ(3u, events_.size()); EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type); @@ -739,41 +670,47 @@ EXPECT_EQ(EmbeddedWorkerStatus::STARTING, events_[2].status.value()); } -class StoreMessageInstanceClient - : public EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient { +class StoreMessageInstanceClient : public FakeEmbeddedWorkerInstanceClient { public: explicit StoreMessageInstanceClient(EmbeddedWorkerTestHelper* helper) - : EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient(helper) {} + : FakeEmbeddedWorkerInstanceClient(helper) {} + // Returns messages from AddMessageToConsole. const std::vector<std::pair<blink::mojom::ConsoleMessageLevel, std::string>>& - message() { - return messages_; + console_messages() { + return console_messages_; + } + + void SetAddMessageToConsoleReceivedCallback( + const base::RepeatingClosure& closure) { + add_message_to_console_callback_ = closure; } private: void AddMessageToConsole(blink::mojom::ConsoleMessageLevel level, const std::string& message) override { - messages_.push_back(std::make_pair(level, message)); + console_messages_.emplace_back(level, message); + if (add_message_to_console_callback_) + add_message_to_console_callback_.Run(); } std::vector<std::pair<blink::mojom::ConsoleMessageLevel, std::string>> - messages_; + console_messages_; + base::RepeatingClosure add_message_to_console_callback_; }; TEST_P(EmbeddedWorkerInstanceTest, AddMessageToConsole) { const GURL scope("http://example.com/"); const GURL url("http://example.com/worker.js"); - std::unique_ptr<StoreMessageInstanceClient> instance_client = - std::make_unique<StoreMessageInstanceClient>(helper_.get()); - StoreMessageInstanceClient* instance_client_rawptr = instance_client.get(); - helper_->RegisterMockInstanceClient(std::move(instance_client)); - ASSERT_EQ(mock_instance_clients()->size(), 1UL); - RegistrationAndVersionPair pair = PrepareRegistrationAndVersion(scope, url); std::unique_ptr<EmbeddedWorkerInstance> worker = embedded_worker_registry()->CreateWorker(pair.second.get()); worker->AddObserver(this); + auto* client = + helper_->AddNewPendingInstanceClient<StoreMessageInstanceClient>( + helper_.get()); + // Attempt to start the worker and immediate AddMessageToConsole should not // cause a crash. std::pair<blink::mojom::ConsoleMessageLevel, std::string> test_message = @@ -787,19 +724,21 @@ EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, worker->status()); // Messages sent before sending StartWorker message won't be dispatched. - ASSERT_EQ(0UL, instance_client_rawptr->message().size()); + ASSERT_EQ(0UL, client->console_messages().size()); ASSERT_EQ(3UL, events_.size()); EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type); EXPECT_EQ(START_WORKER_MESSAGE_SENT, events_[1].type); EXPECT_EQ(STARTED, events_[2].type); + base::RunLoop loop; + client->SetAddMessageToConsoleReceivedCallback(loop.QuitClosure()); worker->AddMessageToConsole(test_message.first, test_message.second); - base::RunLoop().RunUntilIdle(); + loop.Run(); // Messages sent after sending StartWorker message should be reached to // the renderer. - ASSERT_EQ(1UL, instance_client_rawptr->message().size()); - EXPECT_EQ(test_message, instance_client_rawptr->message()[0]); + ASSERT_EQ(1UL, client->console_messages().size()); + EXPECT_EQ(test_message, client->console_messages()[0]); // Ensure the worker is stopped. worker->Stop(); @@ -807,30 +746,17 @@ EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, worker->status()); } -// Records whether a CacheStoragePtr was sent as part of StartWorker. -class RecordCacheStorageHelper : public EmbeddedWorkerTestHelper { +class RecordCacheStorageInstanceClient + : public FakeEmbeddedWorkerInstanceClient { public: - RecordCacheStorageHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {} - ~RecordCacheStorageHelper() override {} + explicit RecordCacheStorageInstanceClient(EmbeddedWorkerTestHelper* helper) + : FakeEmbeddedWorkerInstanceClient(helper) {} + ~RecordCacheStorageInstanceClient() override = default; - void OnStartWorker( - int embedded_worker_id, - int64_t service_worker_version_id, - const GURL& scope, - const GURL& script_url, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) - override { - had_cache_storage_ = !!provider_info->cache_storage; - EmbeddedWorkerTestHelper::OnStartWorker( - embedded_worker_id, service_worker_version_id, scope, script_url, - pause_after_download, std::move(service_worker_request), - std::move(controller_request), std::move(instance_host), - std::move(provider_info), std::move(installed_scripts_info)); + void StartWorker( + blink::mojom::EmbeddedWorkerStartParamsPtr start_params) override { + had_cache_storage_ = !!start_params->provider_info->cache_storage; + FakeEmbeddedWorkerInstanceClient::StartWorker(std::move(start_params)); } bool had_cache_storage() const { return had_cache_storage_; } @@ -844,9 +770,6 @@ TEST_P(EmbeddedWorkerInstanceTest, CacheStorageOptimization) { const GURL scope("http://example.com/"); const GURL url("http://example.com/worker.js"); - auto helper = std::make_unique<RecordCacheStorageHelper>(); - auto* helper_rawptr = helper.get(); - helper_ = std::move(helper); RegistrationAndVersionPair pair = PrepareRegistrationAndVersion(scope, url); std::unique_ptr<EmbeddedWorkerInstance> worker = @@ -855,10 +778,13 @@ // First, test a worker without pause after download. { // Start the worker. + auto* client = + helper_->AddNewPendingInstanceClient<RecordCacheStorageInstanceClient>( + helper_.get()); StartWorker(worker.get(), CreateStartParams(pair.second)); // Cache storage should have been sent. - EXPECT_TRUE(helper_rawptr->had_cache_storage()); + EXPECT_TRUE(client->had_cache_storage()); // Stop the worker. worker->Stop(); @@ -867,6 +793,10 @@ // Second, test a worker with pause after download. { + auto* client = + helper_->AddNewPendingInstanceClient<RecordCacheStorageInstanceClient>( + helper_.get()); + // Start the worker until paused. blink::mojom::EmbeddedWorkerStartParamsPtr params = CreateStartParams(pair.second); @@ -881,7 +811,7 @@ EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, worker->status()); // Cache storage should not have been sent. - EXPECT_FALSE(helper_rawptr->had_cache_storage()); + EXPECT_FALSE(client->had_cache_storage()); // Stop the worker. worker->Stop(); @@ -898,9 +828,6 @@ const GURL scope("http://example.com/"); const GURL url("http://example.com/worker.js"); - auto helper = std::make_unique<RecordCacheStorageHelper>(); - auto* helper_rawptr = helper.get(); - helper_ = std::move(helper); RegistrationAndVersionPair pair = PrepareRegistrationAndVersion(scope, url); std::unique_ptr<EmbeddedWorkerInstance> worker = @@ -908,13 +835,17 @@ // First, test a worker without pause after download. { + auto* client = + helper_->AddNewPendingInstanceClient<RecordCacheStorageInstanceClient>( + helper_.get()); + // Start the worker. blink::mojom::EmbeddedWorkerStartParamsPtr params = CreateStartParams(pair.second); StartWorker(worker.get(), std::move(params)); // Cache storage should not have been sent. - EXPECT_FALSE(helper_rawptr->had_cache_storage()); + EXPECT_FALSE(client->had_cache_storage()); // Stop the worker. worker->Stop(); @@ -923,6 +854,10 @@ // Second, test a worker with pause after download. { + auto* client = + helper_->AddNewPendingInstanceClient<RecordCacheStorageInstanceClient>( + helper_.get()); + // Start the worker until paused. blink::mojom::EmbeddedWorkerStartParamsPtr params = CreateStartParams(pair.second); @@ -937,7 +872,7 @@ EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, worker->status()); // Cache storage should not have been sent. - EXPECT_FALSE(helper_rawptr->had_cache_storage()); + EXPECT_FALSE(client->had_cache_storage()); // Stop the worker. worker->Stop(); @@ -946,17 +881,18 @@ } // Starts the worker with kAbruptCompletion status. -class AbruptCompletionHelper : public EmbeddedWorkerTestHelper { +class AbruptCompletionInstanceClient : public FakeEmbeddedWorkerInstanceClient { public: - AbruptCompletionHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {} - ~AbruptCompletionHelper() override = default; + AbruptCompletionInstanceClient(EmbeddedWorkerTestHelper* helper) + : FakeEmbeddedWorkerInstanceClient(helper) {} + ~AbruptCompletionInstanceClient() override = default; - void OnResumeAfterDownload(int embedded_worker_id) override { - SimulateScriptEvaluationStart(embedded_worker_id); - SimulateWorkerStarted( - embedded_worker_id, - blink::mojom::ServiceWorkerStartStatus::kAbruptCompletion, - GetNextThreadId()); + protected: + void EvaluateScript() override { + host()->OnScriptEvaluationStart(); + host()->OnStarted(blink::mojom::ServiceWorkerStartStatus::kAbruptCompletion, + helper()->GetNextThreadId(), + blink::mojom::EmbeddedWorkerStartTiming::New()); } }; @@ -965,14 +901,14 @@ TEST_P(EmbeddedWorkerInstanceTest, AbruptCompletion) { const GURL scope("http://example.com/"); const GURL url("http://example.com/worker.js"); - helper_ = std::make_unique<AbruptCompletionHelper>(); - RegistrationAndVersionPair pair = PrepareRegistrationAndVersion(scope, url); std::unique_ptr<EmbeddedWorkerInstance> worker = embedded_worker_registry()->CreateWorker(pair.second.get()); EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, worker->status()); worker->AddObserver(this); + helper_->AddPendingInstanceClient( + std::make_unique<AbruptCompletionInstanceClient>(helper_.get())); StartWorker(worker.get(), CreateStartParams(pair.second)); ASSERT_EQ(3u, events_.size());
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc index 6655cfc3..f4e151c 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.cc +++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -103,237 +103,6 @@ DISALLOW_COPY_AND_ASSIGN(MockNetworkURLLoaderFactory); }; -EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient:: - MockEmbeddedWorkerInstanceClient(EmbeddedWorkerTestHelper* helper) - : helper_(helper), binding_(this) {} - -EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient:: - ~MockEmbeddedWorkerInstanceClient() {} - -void EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::StartWorker( - blink::mojom::EmbeddedWorkerStartParamsPtr params) { - embedded_worker_id_ = params->embedded_worker_id; - - EmbeddedWorkerInstance* worker = - helper_->registry()->GetWorker(params->embedded_worker_id); - ASSERT_TRUE(worker); - - helper_->OnStartWorkerStub(std::move(params)); -} - -void EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::StopWorker() { - ASSERT_TRUE(embedded_worker_id_); - EmbeddedWorkerInstance* worker = - helper_->registry()->GetWorker(embedded_worker_id_.value()); - // |worker| is possible to be null when corresponding EmbeddedWorkerInstance - // is removed right after sending StopWorker. - if (worker) - EXPECT_EQ(EmbeddedWorkerStatus::STOPPING, worker->status()); - helper_->OnStopWorkerStub(embedded_worker_id_.value()); -} - -void EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient:: - ResumeAfterDownload() { - helper_->OnResumeAfterDownloadStub(embedded_worker_id_.value()); -} - -void EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient:: - AddMessageToConsole(blink::mojom::ConsoleMessageLevel level, - const std::string& message) { - // TODO(shimazu): Pass these arguments to the test helper when a test is - // necessary to check them individually. -} - -// static -void EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::Bind( - EmbeddedWorkerTestHelper* helper, - blink::mojom::EmbeddedWorkerInstanceClientRequest request) { - std::vector<std::unique_ptr<MockEmbeddedWorkerInstanceClient>>* clients = - helper->mock_instance_clients(); - size_t next_client_index = helper->mock_instance_clients_next_index_; - - ASSERT_GE(clients->size(), next_client_index); - if (clients->size() == next_client_index) { - clients->push_back( - std::make_unique<MockEmbeddedWorkerInstanceClient>(helper)); - } - - std::unique_ptr<MockEmbeddedWorkerInstanceClient>& client = - clients->at(next_client_index); - helper->mock_instance_clients_next_index_ = next_client_index + 1; - if (client) - client->binding_.Bind(std::move(request)); -} - -class EmbeddedWorkerTestHelper::MockServiceWorker - : public blink::mojom::ServiceWorker { - public: - MockServiceWorker(blink::mojom::ServiceWorkerRequest request, - EmbeddedWorkerTestHelper* helper, - int embedded_worker_id) - : helper_(helper), - embedded_worker_id_(embedded_worker_id), - binding_(this) { - binding_.Bind(std::move(request)); - binding_.set_connection_error_handler(base::BindOnce( - &MockServiceWorker::OnConnectionError, base::Unretained(this))); - } - - ~MockServiceWorker() override = default; - - void OnConnectionError() { - // Destroys |this|. - helper_->RemoveServiceWorker(this); - } - - void InitializeGlobalScope( - blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host, - blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info) - override { - helper_->OnInitializeGlobalScope(embedded_worker_id_, - std::move(service_worker_host), - std::move(registration_info)); - } - - void DispatchInstallEvent( - DispatchInstallEventCallback callback) override { - helper_->OnInstallEventStub(std::move(callback)); - } - - void DispatchActivateEvent(DispatchActivateEventCallback callback) override { - helper_->OnActivateEventStub(std::move(callback)); - } - - void DispatchBackgroundFetchAbortEvent( - blink::mojom::BackgroundFetchRegistrationPtr registration, - DispatchBackgroundFetchAbortEventCallback callback) override { - helper_->OnBackgroundFetchAbortEventStub(std::move(registration), - std::move(callback)); - } - - void DispatchBackgroundFetchClickEvent( - blink::mojom::BackgroundFetchRegistrationPtr registration, - DispatchBackgroundFetchClickEventCallback callback) override { - helper_->OnBackgroundFetchClickEventStub(std::move(registration), - std::move(callback)); - } - - void DispatchBackgroundFetchFailEvent( - blink::mojom::BackgroundFetchRegistrationPtr registration, - DispatchBackgroundFetchFailEventCallback callback) override { - helper_->OnBackgroundFetchFailEventStub(std::move(registration), - std::move(callback)); - } - - void DispatchBackgroundFetchSuccessEvent( - blink::mojom::BackgroundFetchRegistrationPtr registration, - DispatchBackgroundFetchSuccessEventCallback callback) override { - helper_->OnBackgroundFetchSuccessEventStub(std::move(registration), - std::move(callback)); - } - - void DispatchCookieChangeEvent( - const net::CanonicalCookie& cookie, - ::network::mojom::CookieChangeCause cause, - DispatchCookieChangeEventCallback callback) override { - helper_->OnCookieChangeEventStub(cookie, cause, std::move(callback)); - } - - void DispatchFetchEvent( - blink::mojom::DispatchFetchEventParamsPtr params, - blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback, - DispatchFetchEventCallback callback) override { - helper_->OnFetchEventStub(embedded_worker_id_, std::move(params->request), - std::move(params->preload_handle), - std::move(response_callback), - std::move(callback)); - } - - void DispatchNotificationClickEvent( - const std::string& notification_id, - const blink::PlatformNotificationData& notification_data, - int action_index, - const base::Optional<base::string16>& reply, - DispatchNotificationClickEventCallback callback) override { - helper_->OnNotificationClickEventStub(notification_id, notification_data, - action_index, reply, - std::move(callback)); - } - - void DispatchNotificationCloseEvent( - const std::string& notification_id, - const blink::PlatformNotificationData& notification_data, - DispatchNotificationCloseEventCallback callback) override { - helper_->OnNotificationCloseEventStub(notification_id, notification_data, - std::move(callback)); - } - - void DispatchPushEvent(const base::Optional<std::string>& payload, - DispatchPushEventCallback callback) override { - helper_->OnPushEventStub(payload, std::move(callback)); - } - - void DispatchSyncEvent(const std::string& tag, - bool last_chance, - base::TimeDelta timeout, - DispatchSyncEventCallback callback) override { - NOTIMPLEMENTED(); - } - - void DispatchAbortPaymentEvent( - payments::mojom::PaymentHandlerResponseCallbackPtr response_callback, - DispatchAbortPaymentEventCallback callback) override { - helper_->OnAbortPaymentEventStub(std::move(response_callback), - std::move(callback)); - } - - void DispatchCanMakePaymentEvent( - payments::mojom::CanMakePaymentEventDataPtr event_data, - payments::mojom::PaymentHandlerResponseCallbackPtr response_callback, - DispatchCanMakePaymentEventCallback callback) override { - helper_->OnCanMakePaymentEventStub(std::move(event_data), - std::move(response_callback), - std::move(callback)); - } - - void DispatchPaymentRequestEvent( - payments::mojom::PaymentRequestEventDataPtr event_data, - payments::mojom::PaymentHandlerResponseCallbackPtr response_callback, - DispatchPaymentRequestEventCallback callback) override { - helper_->OnPaymentRequestEventStub(std::move(event_data), - std::move(response_callback), - std::move(callback)); - } - - void DispatchExtendableMessageEvent( - blink::mojom::ExtendableMessageEventPtr event, - DispatchExtendableMessageEventCallback callback) override { - helper_->OnExtendableMessageEventStub(std::move(event), - std::move(callback)); - } - - void DispatchExtendableMessageEventWithCustomTimeout( - blink::mojom::ExtendableMessageEventPtr event, - base::TimeDelta timeout, - DispatchExtendableMessageEventWithCustomTimeoutCallback callback) - override { - helper_->OnExtendableMessageEventStub(std::move(event), - std::move(callback)); - } - - void Ping(PingCallback callback) override { std::move(callback).Run(); } - - void SetIdleTimerDelayToZero() override { - helper_->OnSetIdleTimerDelayToZero(embedded_worker_id_); - } - - private: - // |helper_| owns |this|. - EmbeddedWorkerTestHelper* helper_; - const int embedded_worker_id_; - mojo::Binding<blink::mojom::ServiceWorker> binding_; -}; - class EmbeddedWorkerTestHelper::MockRendererInterface : public mojom::Renderer { public: // |helper| must outlive this. @@ -354,7 +123,7 @@ void SetUpEmbeddedWorkerChannelForServiceWorker( blink::mojom::EmbeddedWorkerInstanceClientRequest client_request) override { - MockEmbeddedWorkerInstanceClient::Bind(helper_, std::move(client_request)); + helper_->OnInstanceClientRequest(std::move(client_request)); } void CreateFrameProxy( int32_t routing_id, @@ -394,7 +163,7 @@ void SetProcessBackgrounded(bool backgrounded) override { NOTREACHED(); } void SetSchedulerKeepActive(bool keep_active) override { NOTREACHED(); } void ProcessPurgeAndSuspend() override { NOTREACHED(); } - void SetIsLockedToSite() override { NOTREACHED(); } + void SetIsLockedToSite(const GURL& lock_url) override { NOTREACHED(); } void EnableV8LowMemoryMode() override { NOTREACHED(); } EmbeddedWorkerTestHelper* helper_; @@ -410,7 +179,6 @@ std::make_unique<MockRenderProcessHost>(browser_context_.get())), wrapper_(base::MakeRefCounted<ServiceWorkerContextWrapper>( browser_context_.get())), - mock_instance_clients_next_index_(0), next_thread_id_(0), mock_render_process_id_(render_process_host_->GetID()), new_mock_render_process_id_(new_render_process_host_->GetID()), @@ -466,16 +234,71 @@ new_render_process_host_->OverrideURLLoaderFactory(factory); } +void EmbeddedWorkerTestHelper::AddPendingInstanceClient( + std::unique_ptr<FakeEmbeddedWorkerInstanceClient> client) { + pending_embedded_worker_instance_clients_.push(std::move(client)); +} + +void EmbeddedWorkerTestHelper::AddPendingServiceWorker( + std::unique_ptr<FakeServiceWorker> service_worker) { + pending_service_workers_.push(std::move(service_worker)); +} + +void EmbeddedWorkerTestHelper::OnInstanceClientRequest( + blink::mojom::EmbeddedWorkerInstanceClientRequest request) { + std::unique_ptr<FakeEmbeddedWorkerInstanceClient> client; + if (!pending_embedded_worker_instance_clients_.empty()) { + // Use the instance client that was registered for this message. + client = std::move(pending_embedded_worker_instance_clients_.front()); + pending_embedded_worker_instance_clients_.pop(); + if (!client) { + // Some tests provide a nullptr to drop the request. + return; + } + } else { + client = CreateInstanceClient(); + } + + client->Bind(std::move(request)); + instance_clients_.insert(std::move(client)); +} + +void EmbeddedWorkerTestHelper::OnServiceWorkerRequest( + blink::mojom::ServiceWorkerRequest request) { + std::unique_ptr<FakeServiceWorker> service_worker; + if (!pending_service_workers_.empty()) { + // Use the service worker that was registered for this message. + service_worker = std::move(pending_service_workers_.front()); + pending_service_workers_.pop(); + if (!service_worker) { + // Some tests provide a nullptr to drop the request. + return; + } + } else { + service_worker = CreateServiceWorker(); + } + + service_worker->Bind(std::move(request)); + service_workers_.insert(std::move(service_worker)); +} + +void EmbeddedWorkerTestHelper::RemoveInstanceClient( + FakeEmbeddedWorkerInstanceClient* instance_client) { + auto it = instance_clients_.find(instance_client); + instance_clients_.erase(it); +} + +void EmbeddedWorkerTestHelper::RemoveServiceWorker( + FakeServiceWorker* service_worker) { + auto it = service_workers_.find(service_worker); + service_workers_.erase(it); +} + EmbeddedWorkerTestHelper::~EmbeddedWorkerTestHelper() { if (wrapper_.get()) wrapper_->Shutdown(); } -void EmbeddedWorkerTestHelper::RegisterMockInstanceClient( - std::unique_ptr<MockEmbeddedWorkerInstanceClient> client) { - mock_instance_clients_.push_back(std::move(client)); -} - ServiceWorkerContextCore* EmbeddedWorkerTestHelper::context() { return wrapper_->context(); } @@ -497,83 +320,29 @@ return info; } -void EmbeddedWorkerTestHelper::OnStartWorker( - int embedded_worker_id, - int64_t service_worker_version_id, - const GURL& scope, - const GURL& script_url, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) { - EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); - ASSERT_TRUE(worker); - CreateServiceWorker(std::move(service_worker_request), embedded_worker_id); - embedded_worker_id_service_worker_version_id_map_[embedded_worker_id] = - service_worker_version_id; - embedded_worker_id_instance_host_ptr_map_[embedded_worker_id].Bind( - std::move(instance_host)); - embedded_worker_id_installed_scripts_info_map_[embedded_worker_id] = - std::move(installed_scripts_info); - ServiceWorkerRemoteProviderEndpoint* provider_endpoint = - &embedded_worker_id_remote_provider_map_[embedded_worker_id]; - provider_endpoint->BindWithProviderInfo(std::move(provider_info)); - - SimulateWorkerReadyForInspection(embedded_worker_id); - - // In production, new service workers would request their main script here, - // which causes the browser to write the script response in service worker - // storage. We do that manually here. - // - // TODO(falken): For new workers, this should use - // |script_loader_factory_ptr_info| from |start_params_->provider_info| - // to request the script and the browser process should be able to mock it. - // For installed workers, the map should already be populated. - PopulateScriptCacheMap( - service_worker_version_id, - base::BindOnce(&EmbeddedWorkerTestHelper::DidPopulateScriptCacheMap, - AsWeakPtr(), embedded_worker_id, pause_after_download)); -} - -void EmbeddedWorkerTestHelper::AddServiceWorker( - std::unique_ptr<MockServiceWorker> service_worker) { - service_workers_.insert(std::move(service_worker)); -} - -void EmbeddedWorkerTestHelper::RemoveServiceWorker( - MockServiceWorker* service_worker) { - auto it = service_workers_.find(service_worker); - service_workers_.erase(it); -} - -void EmbeddedWorkerTestHelper::CreateServiceWorker( - blink::mojom::ServiceWorkerRequest request, - int embedded_worker_id) { - AddServiceWorker(std::make_unique<MockServiceWorker>(std::move(request), this, - embedded_worker_id)); -} - -void EmbeddedWorkerTestHelper::DidPopulateScriptCacheMap( - int embedded_worker_id, - bool pause_after_download) { - SimulateWorkerScriptLoaded(embedded_worker_id); - if (!pause_after_download) - OnResumeAfterDownload(embedded_worker_id); -} - -void EmbeddedWorkerTestHelper::OnResumeAfterDownload(int embedded_worker_id) { - SimulateScriptEvaluationStart(embedded_worker_id); - SimulateWorkerStarted( - embedded_worker_id, - blink::mojom::ServiceWorkerStartStatus::kNormalCompletion, - GetNextThreadId()); -} - -void EmbeddedWorkerTestHelper::OnStopWorker(int embedded_worker_id) { - // By default just notify the sender that the worker is stopped. - SimulateWorkerStopped(embedded_worker_id); +void EmbeddedWorkerTestHelper::PopulateScriptCacheMap( + int64_t version_id, + base::OnceClosure callback) { + ServiceWorkerVersion* version = context()->GetLiveVersion(version_id); + if (!version) { + std::move(callback).Run(); + return; + } + if (!version->script_cache_map()->size()) { + std::vector<ServiceWorkerDatabase::ResourceRecord> records; + // Add a dummy ResourceRecord for the main script to the script cache map of + // the ServiceWorkerVersion. + records.push_back(WriteToDiskCacheAsync( + context()->storage(), version->script_url(), + context()->storage()->NewResourceId(), {} /* headers */, "I'm a body", + "I'm a meta data", std::move(callback))); + version->script_cache_map()->SetResources(records); + } + if (!version->GetMainScriptHttpResponseInfo()) + version->SetMainScriptHttpResponseInfo(CreateHttpResponseInfo()); + // Call |callback| if |version| already has ResourceRecords. + if (!callback.is_null()) + std::move(callback).Run(); } void EmbeddedWorkerTestHelper::OnActivateEvent( @@ -701,150 +470,14 @@ // Subclasses may implement this method. } -void EmbeddedWorkerTestHelper::PopulateScriptCacheMap( - int64_t version_id, - base::OnceClosure callback) { - ServiceWorkerVersion* version = context()->GetLiveVersion(version_id); - if (!version) { - std::move(callback).Run(); - return; - } - if (!version->script_cache_map()->size()) { - std::vector<ServiceWorkerDatabase::ResourceRecord> records; - // Add a dummy ResourceRecord for the main script to the script cache map of - // the ServiceWorkerVersion. - records.push_back(WriteToDiskCacheAsync( - context()->storage(), version->script_url(), - context()->storage()->NewResourceId(), {} /* headers */, "I'm a body", - "I'm a meta data", std::move(callback))); - version->script_cache_map()->SetResources(records); - } - if (!version->GetMainScriptHttpResponseInfo()) - version->SetMainScriptHttpResponseInfo(CreateHttpResponseInfo()); - // Call |callback| if |version| already has ResourceRecords. - if (!callback.is_null()) - std::move(callback).Run(); +std::unique_ptr<FakeEmbeddedWorkerInstanceClient> +EmbeddedWorkerTestHelper::CreateInstanceClient() { + return std::make_unique<FakeEmbeddedWorkerInstanceClient>(this); } -void EmbeddedWorkerTestHelper::SimulateWorkerReadyForInspection( - int embedded_worker_id) { - EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); - ASSERT_TRUE(worker); - ASSERT_TRUE(embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]); - embedded_worker_id_instance_host_ptr_map_[embedded_worker_id] - ->OnReadyForInspection(); - base::RunLoop().RunUntilIdle(); -} - -void EmbeddedWorkerTestHelper::SimulateWorkerScriptLoaded( - int embedded_worker_id) { - EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); - ASSERT_TRUE(worker); - ASSERT_TRUE(embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]); - embedded_worker_id_instance_host_ptr_map_[embedded_worker_id] - ->OnScriptLoaded(); - base::RunLoop().RunUntilIdle(); -} - -void EmbeddedWorkerTestHelper::SimulateScriptEvaluationStart( - int embedded_worker_id) { - EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); - ASSERT_TRUE(worker); - ASSERT_TRUE(embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]); - embedded_worker_id_instance_host_ptr_map_[embedded_worker_id] - ->OnScriptEvaluationStart(); - base::RunLoop().RunUntilIdle(); -} - -void EmbeddedWorkerTestHelper::SimulateWorkerStarted( - int embedded_worker_id, - blink::mojom::ServiceWorkerStartStatus status, - int thread_id) { - EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); - ASSERT_TRUE(worker); - ASSERT_TRUE(embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]); - embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]->OnStarted( - status, thread_id, blink::mojom::EmbeddedWorkerStartTiming::New()); - base::RunLoop().RunUntilIdle(); -} - -void EmbeddedWorkerTestHelper::SimulateWorkerStopped(int embedded_worker_id) { - EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); - if (worker) { - ASSERT_TRUE(embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]); - embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]->OnStopped(); - embedded_worker_id_remote_provider_map_.erase(embedded_worker_id); - base::RunLoop().RunUntilIdle(); - } -} - -void EmbeddedWorkerTestHelper::SimulateRequestTermination( - int embedded_worker_id, - base::OnceCallback<void(bool)> callback) { - base::RunLoop loop; - ASSERT_TRUE(embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]); - embedded_worker_id_instance_host_ptr_map_[embedded_worker_id] - ->RequestTermination(std::move(callback)); - base::RunLoop().RunUntilIdle(); -} - -void EmbeddedWorkerTestHelper::OnInitializeGlobalScope( - int embedded_worker_id, - blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host, - blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info) { - embedded_worker_id_host_map_[embedded_worker_id].Bind( - std::move(service_worker_host)); - // To enable the caller end points to make calls safely with no need to pass - // these associated interface requests through a message pipe endpoint. - mojo::AssociateWithDisconnectedPipe(registration_info->request.PassHandle()); - if (registration_info->installing) { - mojo::AssociateWithDisconnectedPipe( - registration_info->installing->request.PassHandle()); - } - if (registration_info->waiting) { - mojo::AssociateWithDisconnectedPipe( - registration_info->waiting->request.PassHandle()); - } - if (registration_info->active) { - mojo::AssociateWithDisconnectedPipe( - registration_info->active->request.PassHandle()); - } - // Keep all Mojo connections alive. - embedded_worker_id_registration_info_map_[embedded_worker_id] = - std::move(registration_info); -} - -void EmbeddedWorkerTestHelper::OnStartWorkerStub( - blink::mojom::EmbeddedWorkerStartParamsPtr params) { - EmbeddedWorkerInstance* worker = - registry()->GetWorker(params->embedded_worker_id); - ASSERT_TRUE(worker); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce( - &EmbeddedWorkerTestHelper::OnStartWorker, AsWeakPtr(), - params->embedded_worker_id, params->service_worker_version_id, - params->scope, params->script_url, params->pause_after_download, - std::move(params->service_worker_request), - std::move(params->controller_request), - std::move(params->instance_host), std::move(params->provider_info), - std::move(params->installed_scripts_info))); -} - -void EmbeddedWorkerTestHelper::OnResumeAfterDownloadStub( - int embedded_worker_id) { - EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); - ASSERT_TRUE(worker); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(&EmbeddedWorkerTestHelper::OnResumeAfterDownload, - AsWeakPtr(), embedded_worker_id)); -} - -void EmbeddedWorkerTestHelper::OnStopWorkerStub(int embedded_worker_id) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&EmbeddedWorkerTestHelper::OnStopWorker, - AsWeakPtr(), embedded_worker_id)); +std::unique_ptr<FakeServiceWorker> +EmbeddedWorkerTestHelper::CreateServiceWorker() { + return std::make_unique<FakeServiceWorker>(this); } void EmbeddedWorkerTestHelper::OnActivateEventStub(
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h index 3c63ce5a..f4bf3e48 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.h +++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -20,6 +20,7 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/time/time.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" #include "content/browser/service_worker/fake_service_worker.h" #include "content/browser/service_worker/service_worker_test_utils.h" #include "content/browser/url_loader_factory_getter.h" @@ -34,8 +35,6 @@ #include "third_party/blink/public/mojom/service_worker/service_worker_installed_scripts_manager.mojom.h" #include "url/gurl.h" -class GURL; - namespace blink { struct PlatformNotificationData; } @@ -43,8 +42,8 @@ namespace content { class EmbeddedWorkerRegistry; -class EmbeddedWorkerTestHelper; class MockRenderProcessHost; +class FakeServiceWorker; class ServiceWorkerContextCore; class ServiceWorkerContextWrapper; class TestBrowserContext; @@ -52,77 +51,54 @@ // In-Process EmbeddedWorker test helper. // // Usage: create an instance of this class to test browser-side embedded worker -// code without creating a child process. This class will create a +// code without creating a child process. This class will create a // ServiceWorkerContextWrapper and ServiceWorkerContextCore for you. // -// By default this class just notifies back WorkerStarted and WorkerStopped -// for StartWorker and StopWorker requests. The default implementation -// also returns success for event messages (e.g. InstallEvent, FetchEvent). +// By default, this class uses FakeEmbeddedWorkerInstanceClient which notifies +// back success for StartWorker and StopWorker requests. It also uses +// FakeServiceWorker which returns success for event messages (e.g. +// InstallEvent, FetchEvent). // -// Alternatively consumers can subclass this helper and override On*() -// methods to add their own logic/verification code. +// Alternatively consumers can use subclasses of the Fake* classes +// to add their own logic/verification code. // -// See embedded_worker_instance_unittest.cc for example usages. +// Example: +// +// class MyClient : public FakeEmbeddedWorkerInstanceClient { +// void StartWorker(...) override { +// // Do custom stuff. +// LOG(INFO) << "in start worker!"; +// } +// }; +// class MyServiceWorker : public FakeServiceWorker { +// void DispatchFetchEvent(...) override { +// // Do custom stuff. +// LOG(INFO) << "in fetch event!"; +// } +// }; +// +// // Set up the fakes. +// helper->AddPendingInstanceClient(std::make_unique<MyClient>()); +// helper->AddPendingServiceWorker(std::make_unique<MyServiceWorker>()); +// +// // Run code that starts a worker. +// StartWorker(); // "in start worker!" +// +// // Run code that dispatches a fetch event. +// Navigate(); // "in fetch event!" +// +// See embedded_worker_instance_unittest.cc for more example usages. class EmbeddedWorkerTestHelper { public: enum class Event { Install, Activate }; - class MockEmbeddedWorkerInstanceClient - : public blink::mojom::EmbeddedWorkerInstanceClient { - public: - // |helper| must outlive this. - explicit MockEmbeddedWorkerInstanceClient(EmbeddedWorkerTestHelper* helper); - ~MockEmbeddedWorkerInstanceClient() override; - - static void Bind(EmbeddedWorkerTestHelper* helper, - blink::mojom::EmbeddedWorkerInstanceClientRequest request); - - protected: - // blink::mojom::EmbeddedWorkerInstanceClient implementation. - void StartWorker( - blink::mojom::EmbeddedWorkerStartParamsPtr params) override; - void StopWorker() override; - void ResumeAfterDownload() override; - void AddMessageToConsole(blink::mojom::ConsoleMessageLevel level, - const std::string& message) override; - void BindDevToolsAgent( - blink::mojom::DevToolsAgentHostAssociatedPtrInfo, - blink::mojom::DevToolsAgentAssociatedRequest) override {} - - // |helper_| owns |this|. - EmbeddedWorkerTestHelper* helper_; - mojo::Binding<blink::mojom::EmbeddedWorkerInstanceClient> binding_; - - base::Optional<int> embedded_worker_id_; - - private: - DISALLOW_COPY_AND_ASSIGN(MockEmbeddedWorkerInstanceClient); - }; - // If |user_data_directory| is empty, the context makes storage stuff in // memory. explicit EmbeddedWorkerTestHelper(const base::FilePath& user_data_directory); virtual ~EmbeddedWorkerTestHelper(); - // Simulates Mojo calls to the browser process. - void SimulateRequestTermination(int embedded_worker_id, - base::OnceCallback<void(bool)> callback); - - // Registers a Mojo endpoint object derived from - // MockEmbeddedWorkerInstanceClient. - void RegisterMockInstanceClient( - std::unique_ptr<MockEmbeddedWorkerInstanceClient> client); - - template <typename MockType, typename... Args> - MockType* CreateAndRegisterMockInstanceClient(Args&&... args); - std::vector<Event>* dispatched_events() { return &events_; } - std::vector<std::unique_ptr<MockEmbeddedWorkerInstanceClient>>* - mock_instance_clients() { - return &mock_instance_clients_; - } - ServiceWorkerContextCore* context(); ServiceWorkerContextWrapper* context_wrapper() { return wrapper_.get(); } void ShutdownContext(); @@ -153,34 +129,53 @@ // null pointer will restore the default behavior. void SetNetworkFactory(network::mojom::URLLoaderFactory* factory); + // Adds the given client to the pending queue. The next time this helper + // receives a blink::mojom::EmbeddedWorkerInstanceClientRequest request (i.e., + // on the next start worker attempt), it uses the first client from this + // queue. + void AddPendingInstanceClient( + std::unique_ptr<FakeEmbeddedWorkerInstanceClient> instance_client); + + // Adds the given service worker to the pending queue. The next time this + // helper receives a blink::mojom::ServiceWorkerRequest request (i.e., on the + // next start worker attempt), it uses the first service worker from this + // queue. + void AddPendingServiceWorker( + std::unique_ptr<FakeServiceWorker> service_worker); + + // A convenience method useful for keeping a pointer to a + // FakeEmbeddedWorkerInstanceClient after it's added. Equivalent to: + // auto client_to_pass = std::make_unique<MockType>(args); + // auto* client = client.get(); + // AddPendingInstanceClient(std::move(client_to_pass)); + template <typename MockType, typename... Args> + MockType* AddNewPendingInstanceClient(Args&&... args); + // Same for FakeServiceWorker. + template <typename MockType, typename... Args> + MockType* AddNewPendingServiceWorker(Args&&... args); + + ///////////////////////////////////////////////////////////////////////////// + // The following are exposed to public so the fake embedded worker and service + // worker implementations and their subclasses can call them. + // + // Called when |request| is received. It takes the object from a previous + // AddPending*() call if any and calls Create*() otherwise. + void OnInstanceClientRequest( + blink::mojom::EmbeddedWorkerInstanceClientRequest request); + void OnServiceWorkerRequest(blink::mojom::ServiceWorkerRequest request); + + // Called by the fakes to destroy themselves. + void RemoveInstanceClient(FakeEmbeddedWorkerInstanceClient* instance_client); + void RemoveServiceWorker(FakeServiceWorker* service_worker); + // Writes a dummy script into the given service worker's // ServiceWorkerScriptCacheMap. |callback| is called when done. virtual void PopulateScriptCacheMap(int64_t service_worker_version_id, base::OnceClosure callback); + ///////////////////////////////////////////////////////////////////////////// protected: - // StartWorker IPC handler routed through MockEmbeddedWorkerInstanceClient. - // This simulates behaviors in the renderer process. Binds - // |service_worker_request| to MockServiceWorker by default. - virtual void OnStartWorker( - int embedded_worker_id, - int64_t service_worker_version_id, - const GURL& scope, - const GURL& script_url, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr - installed_scripts_info); - virtual void OnResumeAfterDownload(int embedded_worker_id); - // StopWorker IPC handler routed through MockEmbeddedWorkerInstanceClient. - // This calls SimulateWorkerStopped() by default. - virtual void OnStopWorker(int embedded_worker_id); - - // On*Event handlers. By default they just return success via - // SimulateSendReplyToBrowser. + // TODO(falken): Remove these and use FakeServiceWorker instead. virtual void OnActivateEvent( blink::mojom::ServiceWorker::DispatchActivateEventCallback callback); virtual void OnBackgroundFetchAbortEvent( @@ -245,15 +240,6 @@ callback); virtual void OnSetIdleTimerDelayToZero(int embedded_worker_id); - // These functions simulate making Mojo calls to the browser. - void SimulateWorkerReadyForInspection(int embedded_worker_id); - void SimulateWorkerScriptLoaded(int embedded_worker_id); - void SimulateScriptEvaluationStart(int embedded_worker_id); - void SimulateWorkerStarted(int embedded_worker_id, - blink::mojom::ServiceWorkerStartStatus status, - int thread_id); - void SimulateWorkerStopped(int embedded_worker_id); - EmbeddedWorkerRegistry* registry(); blink::mojom::ServiceWorkerHost* GetServiceWorkerHost( @@ -266,28 +252,18 @@ return embedded_worker_id_instance_host_ptr_map_[embedded_worker_id].get(); } + // Subclasses can override these to change the default fakes. This saves tests + // from calling AddPending*() for each start worker attempt. + virtual std::unique_ptr<FakeEmbeddedWorkerInstanceClient> + CreateInstanceClient(); + virtual std::unique_ptr<FakeServiceWorker> CreateServiceWorker(); + private: friend FakeServiceWorker; class MockNetworkURLLoaderFactory; - class MockServiceWorker; class MockRendererInterface; - void AddServiceWorker(std::unique_ptr<MockServiceWorker> service_worker); - void RemoveServiceWorker(MockServiceWorker* service_worker); - void CreateServiceWorker(blink::mojom::ServiceWorkerRequest request, - int embedded_worker_id); - - void DidPopulateScriptCacheMap(int embedded_worker_id, - bool pause_after_download); - // TODO(falken): Remove these and use FakeServiceWorker instead. - void OnInitializeGlobalScope( - int embedded_worker_id, - blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host, - blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info); - void OnStartWorkerStub(blink::mojom::EmbeddedWorkerStartParamsPtr params); - void OnResumeAfterDownloadStub(int embedded_worker_id); - void OnStopWorkerStub(int embedded_worker_id); void OnActivateEventStub( blink::mojom::ServiceWorker::DispatchActivateEventCallback callback); void OnBackgroundFetchAbortEventStub( @@ -358,11 +334,15 @@ scoped_refptr<ServiceWorkerContextWrapper> wrapper_; std::unique_ptr<MockRendererInterface> mock_renderer_interface_; - std::vector<std::unique_ptr<MockEmbeddedWorkerInstanceClient>> - mock_instance_clients_; - size_t mock_instance_clients_next_index_; - base::flat_set<std::unique_ptr<MockServiceWorker>, base::UniquePtrComparator> + base::queue<std::unique_ptr<FakeEmbeddedWorkerInstanceClient>> + pending_embedded_worker_instance_clients_; + base::flat_set<std::unique_ptr<FakeEmbeddedWorkerInstanceClient>, + base::UniquePtrComparator> + instance_clients_; + + base::queue<std::unique_ptr<FakeServiceWorker>> pending_service_workers_; + base::flat_set<std::unique_ptr<FakeServiceWorker>, base::UniquePtrComparator> service_workers_; int next_thread_id_; @@ -399,12 +379,21 @@ }; template <typename MockType, typename... Args> -MockType* EmbeddedWorkerTestHelper::CreateAndRegisterMockInstanceClient( +MockType* EmbeddedWorkerTestHelper::AddNewPendingInstanceClient( Args&&... args) { std::unique_ptr<MockType> mock = std::make_unique<MockType>(std::forward<Args>(args)...); MockType* mock_rawptr = mock.get(); - RegisterMockInstanceClient(std::move(mock)); + AddPendingInstanceClient(std::move(mock)); + return mock_rawptr; +} + +template <typename MockType, typename... Args> +MockType* EmbeddedWorkerTestHelper::AddNewPendingServiceWorker(Args&&... args) { + std::unique_ptr<MockType> mock = + std::make_unique<MockType>(std::forward<Args>(args)...); + MockType* mock_rawptr = mock.get(); + AddPendingServiceWorker(std::move(mock)); return mock_rawptr; }
diff --git a/content/browser/service_worker/fake_embedded_worker_instance_client.cc b/content/browser/service_worker/fake_embedded_worker_instance_client.cc index 612a885..ab886046c 100644 --- a/content/browser/service_worker/fake_embedded_worker_instance_client.cc +++ b/content/browser/service_worker/fake_embedded_worker_instance_client.cc
@@ -52,9 +52,8 @@ host_.Bind(std::move(params->instance_host)); start_params_ = std::move(params); - // TODO(falken): Uncomment this in the next patch, which implements it. - // helper_->OnServiceWorkerRequest( - // std::move(start_params_->service_worker_request)); + helper_->OnServiceWorkerRequest( + std::move(start_params_->service_worker_request)); host_->OnReadyForInspection(); if (start_params_->is_installed) { @@ -101,8 +100,7 @@ void FakeEmbeddedWorkerInstanceClient::OnConnectionError() { // Destroys |this|. - // TODO(falken): Uncomment this in the next patch, which implements it. - // helper_->RemoveInstanceClient(this); + helper_->RemoveInstanceClient(this); } void FakeEmbeddedWorkerInstanceClient::EvaluateScript() {
diff --git a/content/browser/service_worker/fake_service_worker.cc b/content/browser/service_worker/fake_service_worker.cc index f13fde58..9a84517 100644 --- a/content/browser/service_worker/fake_service_worker.cc +++ b/content/browser/service_worker/fake_service_worker.cc
@@ -191,8 +191,7 @@ void FakeServiceWorker::OnConnectionError() { // Destroys |this|. - // TODO(falken): Uncomment this in the next patch, which implements it. - // helper_->RemoveServiceWorker(this); + helper_->RemoveServiceWorker(this); } } // namespace content
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc index a31e2fb..7c5b49b 100644 --- a/content/browser/service_worker/service_worker_context_unittest.cc +++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -13,6 +13,7 @@ #include "base/time/time.h" #include "content/browser/service_worker/embedded_worker_registry.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_core_observer.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" @@ -181,31 +182,32 @@ }; class RecordableEmbeddedWorkerInstanceClient - : public EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient { + : public FakeEmbeddedWorkerInstanceClient { public: enum class Message { StartWorker, StopWorker }; explicit RecordableEmbeddedWorkerInstanceClient( EmbeddedWorkerTestHelper* helper) - : EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient(helper) {} + : FakeEmbeddedWorkerInstanceClient(helper) {} const std::vector<Message>& events() const { return events_; } protected: void StartWorker(blink::mojom::EmbeddedWorkerStartParamsPtr params) override { events_.push_back(Message::StartWorker); - EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::StartWorker( - std::move(params)); + FakeEmbeddedWorkerInstanceClient::StartWorker(std::move(params)); } void StopWorker() override { events_.push_back(Message::StopWorker); - EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::StopWorker(); + + // Let stop complete, but don't call the base class's StopWorker(), which + // would destroy |this| before the test can retrieve events(). + host()->OnStopped(); } - std::vector<Message> events_; - private: + std::vector<Message> events_; DISALLOW_COPY_AND_ASSIGN(RecordableEmbeddedWorkerInstanceClient); }; @@ -392,9 +394,10 @@ blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = scope; - RecordableEmbeddedWorkerInstanceClient* client = nullptr; - client = helper_->CreateAndRegisterMockInstanceClient< - RecordableEmbeddedWorkerInstanceClient>(helper_.get()); + auto* client = + helper_ + ->AddNewPendingInstanceClient<RecordableEmbeddedWorkerInstanceClient>( + helper_.get()); int64_t registration_id = blink::mojom::kInvalidServiceWorkerRegistrationId; bool called = false; @@ -445,9 +448,10 @@ helper_.reset(new RejectInstallTestHelper); helper_->context_wrapper()->AddObserver(this); - RecordableEmbeddedWorkerInstanceClient* client = nullptr; - client = helper_->CreateAndRegisterMockInstanceClient< - RecordableEmbeddedWorkerInstanceClient>(helper_.get()); + auto* client = + helper_ + ->AddNewPendingInstanceClient<RecordableEmbeddedWorkerInstanceClient>( + helper_.get()); int64_t registration_id = blink::mojom::kInvalidServiceWorkerRegistrationId; bool called = false; @@ -494,9 +498,10 @@ helper_.reset(new RejectActivateTestHelper); helper_->context_wrapper()->AddObserver(this); - RecordableEmbeddedWorkerInstanceClient* client = nullptr; - client = helper_->CreateAndRegisterMockInstanceClient< - RecordableEmbeddedWorkerInstanceClient>(helper_.get()); + auto* client = + helper_ + ->AddNewPendingInstanceClient<RecordableEmbeddedWorkerInstanceClient>( + helper_.get()); int64_t registration_id = blink::mojom::kInvalidServiceWorkerRegistrationId; bool called = false;
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc index e2c5dc9..d76100b 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -357,6 +357,8 @@ int64_t service_worker_version_id, const std::string& request_uuid) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!context()) + return false; ServiceWorkerVersion* version = context()->GetLiveVersion(service_worker_version_id); if (!version) @@ -368,6 +370,8 @@ int64_t service_worker_version_id, const std::string& request_uuid) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!context()) + return false; ServiceWorkerVersion* version = context()->GetLiveVersion(service_worker_version_id); if (!version) @@ -1024,8 +1028,10 @@ blink::mojom::ServiceWorkerProviderInfoForWorkerPtr* out_provider_info) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!context_core_) + return nullptr; return ServiceWorkerProviderHost::PreCreateForSharedWorker( - context()->AsWeakPtr(), process_id, out_provider_info); + context_core_->AsWeakPtr(), process_id, out_provider_info); } ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h index ef08660..b3c8807f 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.h +++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -290,6 +290,8 @@ // connect to the host. The host stays alive as long as this info stays alive // (namely, as long as |out_provider_info->host_ptr_info| stays alive). // + // Returns null if context() is null. + // // Must be called on the IO thread. base::WeakPtr<ServiceWorkerProviderHost> PreCreateHostForSharedWorker( int process_id,
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc index 7a14515..929b637 100644 --- a/content/browser/service_worker/service_worker_job_unittest.cc +++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -17,6 +17,7 @@ #include "content/browser/service_worker/embedded_worker_registry.h" #include "content/browser/service_worker/embedded_worker_status.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_disk_cache.h" @@ -112,24 +113,6 @@ return base::BindOnce(&SaveUnregistrationCallback, expected_status, called); } -bool RequestTermination(EmbeddedWorkerTestHelper* helper, - scoped_refptr<ServiceWorkerVersion> version) { - base::RunLoop loop; - base::Optional<bool> will_be_terminated; - helper->SimulateRequestTermination( - version->embedded_worker()->embedded_worker_id(), - base::BindOnce( - [](base::OnceClosure done, - base::Optional<bool>* out_will_be_terminated, - bool will_be_terminated) { - *out_will_be_terminated = will_be_terminated; - std::move(done).Run(); - }, - loop.QuitClosure(), &will_be_terminated)); - loop.Run(); - return will_be_terminated.value(); -} - } // namespace class ServiceWorkerJobTest : public testing::Test { @@ -493,31 +476,21 @@ EXPECT_EQ(new_registration_by_scope, old_registration); } -class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper { +// An instance client that breaks the Mojo connection upon receiving the +// Start() message. +class FailStartInstanceClient : public FakeEmbeddedWorkerInstanceClient { public: - FailToStartWorkerTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {} + FailStartInstanceClient(EmbeddedWorkerTestHelper* helper) + : FakeEmbeddedWorkerInstanceClient(helper) {} - void OnStartWorker( - int embedded_worker_id, - int64_t service_worker_version_id, - const GURL& scope, - const GURL& script_url, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) - override { - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtr instance_host_ptr; - instance_host_ptr.Bind(std::move(instance_host)); - instance_host_ptr->OnStopped(); - base::RunLoop().RunUntilIdle(); + void StartWorker(blink::mojom::EmbeddedWorkerStartParamsPtr params) override { + // Don't save the Mojo ptrs. The connection breaks. } }; TEST_F(ServiceWorkerJobTest, Register_FailToStartWorker) { - helper_.reset(new FailToStartWorkerTestHelper); + helper_->AddPendingInstanceClient( + std::make_unique<FailStartInstanceClient>(helper_.get())); blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = GURL("https://www.example.com/"); @@ -976,21 +949,49 @@ observed_registration_->RemoveListener(this); } + class UpdateJobEmbeddedWorkerInstanceClient + : public FakeEmbeddedWorkerInstanceClient { + public: + UpdateJobEmbeddedWorkerInstanceClient(UpdateJobTestHelper* helper) + : FakeEmbeddedWorkerInstanceClient(helper) {} + ~UpdateJobEmbeddedWorkerInstanceClient() override = default; + + void set_force_start_worker_failure(bool force_start_worker_failure) { + force_start_worker_failure_ = force_start_worker_failure; + } + + void ResumeAfterDownload() override { + if (force_start_worker_failure_) { + host()->OnScriptEvaluationStart(); + host()->OnStarted( + blink::mojom::ServiceWorkerStartStatus::kAbruptCompletion, + helper()->GetNextThreadId(), + blink::mojom::EmbeddedWorkerStartTiming::New()); + return; + } + FakeEmbeddedWorkerInstanceClient::ResumeAfterDownload(); + } + + private: + bool force_start_worker_failure_ = false; + }; + ServiceWorkerStorage* storage() { return context()->storage(); } ServiceWorkerJobCoordinator* job_coordinator() { return context()->job_coordinator(); } - void set_force_start_worker_failure(bool force_start_worker_failure) { - force_start_worker_failure_ = force_start_worker_failure; - } - scoped_refptr<ServiceWorkerRegistration> SetupInitialRegistration( const GURL& test_origin) { blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = test_origin.Resolve(kScope); scoped_refptr<ServiceWorkerRegistration> registration; bool called = false; + + auto client = std::make_unique<UpdateJobEmbeddedWorkerInstanceClient>(this); + initial_embedded_worker_instance_client_ = client.get(); + AddPendingInstanceClient(std::move(client)); + job_coordinator()->Register( test_origin.Resolve(kScript), options, SaveRegistration(blink::ServiceWorkerStatusCode::kOk, &called, @@ -1049,19 +1050,7 @@ std::move(callback).Run(); } - void OnResumeAfterDownload(int embedded_worker_id) override { - if (force_start_worker_failure_) { - SimulateScriptEvaluationStart(embedded_worker_id); - SimulateWorkerStarted( - embedded_worker_id, - blink::mojom::ServiceWorkerStartStatus::kAbruptCompletion, - GetNextThreadId()); - return; - } - EmbeddedWorkerTestHelper::OnResumeAfterDownload(embedded_worker_id); - } - - // ServiceWorkerContextCore::Observer overrides + // ServiceWorkerContextCoreObserver overrides void OnVersionStateChanged(int64_t version_id, const GURL& scope, ServiceWorkerVersion::Status status) override { @@ -1084,66 +1073,32 @@ } void OnRegistrationFailed(ServiceWorkerRegistration* registration) override { - NOTREACHED(); + registration_failed_ = true; } void OnUpdateFound(ServiceWorkerRegistration* registration) override { update_found_ = true; } + UpdateJobEmbeddedWorkerInstanceClient* + initial_embedded_worker_instance_client_ = nullptr; scoped_refptr<ServiceWorkerRegistration> observed_registration_; std::vector<AttributeChangeLogEntry> attribute_change_log_; std::vector<StateChangeLogEntry> state_change_log_; bool update_found_ = false; + bool registration_failed_ = false; bool force_start_worker_failure_ = false; base::Optional<bool> will_be_terminated_; base::WeakPtrFactory<UpdateJobTestHelper> weak_factory_; }; -// Helper class for update tests that evicts the active version when the update -// worker is about to be started. -class EvictIncumbentVersionHelper : public UpdateJobTestHelper { - public: - EvictIncumbentVersionHelper() {} - ~EvictIncumbentVersionHelper() override {} - - void OnStartWorker( - int embedded_worker_id, - int64_t version_id, - const GURL& scope, - const GURL& script, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) - override { - ServiceWorkerVersion* version = context()->GetLiveVersion(version_id); - ServiceWorkerRegistration* registration = - context()->GetLiveRegistration(version->registration_id()); - bool is_update = registration->active_version() && - version != registration->active_version(); - if (is_update) { - // Evict the incumbent worker. - ASSERT_FALSE(registration->waiting_version()); - registration->DeleteVersion( - base::WrapRefCounted(registration->active_version())); - } - UpdateJobTestHelper::OnStartWorker( - embedded_worker_id, version_id, scope, script, pause_after_download, - std::move(service_worker_request), std::move(controller_request), - std::move(instance_host), std::move(provider_info), - std::move(installed_scripts_info)); - } - - void OnRegistrationFailed(ServiceWorkerRegistration* registration) override { - registration_failed_ = true; - } - - bool registration_failed_ = false; -}; +void RequestTermination( + blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtr* host) { + // We can't wait for the callback since StopWorker() arrives before it which + // severs the Mojo connection. + (*host)->RequestTermination(base::DoNothing()); +} } // namespace @@ -1227,7 +1182,11 @@ // Run an update to a worker that loads successfully but fails to start up // (script evaluation failure). The check time should be updated. - update_helper->set_force_start_worker_failure(true); + auto* embedded_worker_instance_client = + update_helper->AddNewPendingInstanceClient< + UpdateJobTestHelper::UpdateJobEmbeddedWorkerInstanceClient>( + update_helper); + embedded_worker_instance_client->set_force_start_worker_failure(true); registration->set_last_update_check(kYesterday); registration->active_version()->StartUpdate(); base::RunLoop().RunUntilIdle(); @@ -1259,7 +1218,9 @@ scoped_refptr<ServiceWorkerVersion> new_version = registration->waiting_version(); EXPECT_EQ(2u, update_helper->attribute_change_log_.size()); - EXPECT_TRUE(RequestTermination(helper_.get(), first_version)); + UpdateJobTestHelper::UpdateJobEmbeddedWorkerInstanceClient* client = + update_helper->initial_embedded_worker_instance_client_; + RequestTermination(&client->host()); TestServiceWorkerObserver observer(helper_->context_wrapper()); observer.RunUntilActivated(new_version.get(), runner); @@ -1359,6 +1320,9 @@ // Create a registration with an active version. blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = GURL("https://www.example.com/one/"); + auto* initial_client = + helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( + helper_.get()); scoped_refptr<ServiceWorkerRegistration> registration = RunRegisterJob( GURL("https://www.example.com/service_worker.js"), options); auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); @@ -1388,8 +1352,7 @@ EXPECT_TRUE(waiting_version); EXPECT_NE(version.get(), waiting_version); - EXPECT_TRUE( - RequestTermination(helper_.get(), registration->active_version())); + RequestTermination(&initial_client->host()); TestServiceWorkerObserver observer(helper_->context_wrapper()); observer.RunUntilActivated(waiting_version, runner); } @@ -1404,18 +1367,27 @@ // Test that update succeeds if the incumbent worker was evicted // during the update job (this can happen on disk cache failure). TEST_F(ServiceWorkerJobTest, Update_EvictedIncumbent) { - EvictIncumbentVersionHelper* update_helper = new EvictIncumbentVersionHelper; + UpdateJobTestHelper* update_helper = new UpdateJobTestHelper; helper_.reset(update_helper); scoped_refptr<ServiceWorkerRegistration> registration = update_helper->SetupInitialRegistration(kNewVersionOrigin); ASSERT_TRUE(registration.get()); update_helper->state_change_log_.clear(); - // Run the update job. registration->AddListener(update_helper); scoped_refptr<ServiceWorkerVersion> first_version = registration->active_version(); + auto* instance_client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + + // Start the update job and make it block on the worker starting. + // Evict the incumbent during that time. first_version->StartUpdate(); + instance_client->RunUntilStartWorker(); + registration->DeleteVersion(first_version); + + // Finish the update job. + instance_client->UnblockStartWorker(); base::RunLoop().RunUntilIdle(); // Verify results. @@ -1467,6 +1439,9 @@ blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = GURL("https://www.example.com/one/"); + auto* initial_client = + helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( + helper_.get()); scoped_refptr<ServiceWorkerRegistration> registration = RunRegisterJob(script1, options); auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); @@ -1496,7 +1471,7 @@ // Make the old version eligible for eviction. old_version->RemoveControllee(host->client_uuid()); if (blink::ServiceWorkerUtils::IsServicificationEnabled()) - EXPECT_TRUE(RequestTermination(helper_.get(), old_version)); + RequestTermination(&initial_client->host()); // Wait for activated. TestServiceWorkerObserver observer(helper_->context_wrapper()); @@ -1568,6 +1543,9 @@ blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = GURL("https://www.example.com/one/"); + auto* initial_client = + helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( + helper_.get()); scoped_refptr<ServiceWorkerRegistration> registration = RunRegisterJob(script1, options); auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); @@ -1597,7 +1575,7 @@ old_version->RemoveControllee(host->client_uuid()); if (blink::ServiceWorkerUtils::IsServicificationEnabled()) - EXPECT_TRUE(RequestTermination(helper_.get(), old_version)); + RequestTermination(&initial_client->host()); // Wait for activated. TestServiceWorkerObserver observer(helper_->context_wrapper()); @@ -1619,6 +1597,9 @@ blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = GURL("https://www.example.com/one/"); + auto* initial_client = + helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( + helper_.get()); scoped_refptr<ServiceWorkerRegistration> registration = RunRegisterJob(script1, options); auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); @@ -1652,7 +1633,7 @@ first_version->RemoveControllee(host->client_uuid()); if (blink::ServiceWorkerUtils::IsServicificationEnabled()) - EXPECT_TRUE(RequestTermination(helper_.get(), first_version)); + RequestTermination(&initial_client->host()); // Wait for activated. TestServiceWorkerObserver observer(helper_->context_wrapper()); @@ -1868,11 +1849,12 @@ } class CheckPauseAfterDownloadEmbeddedWorkerInstanceClient - : public EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient { + : public FakeEmbeddedWorkerInstanceClient { public: explicit CheckPauseAfterDownloadEmbeddedWorkerInstanceClient( EmbeddedWorkerTestHelper* helper) - : EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient(helper) {} + : FakeEmbeddedWorkerInstanceClient(helper) {} + int num_of_startworker() const { return num_of_startworker_; } void set_next_pause_after_download(bool expectation) { next_pause_after_download_ = expectation; @@ -1883,8 +1865,7 @@ ASSERT_TRUE(next_pause_after_download_.has_value()); EXPECT_EQ(next_pause_after_download_.value(), params->pause_after_download); num_of_startworker_++; - EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::StartWorker( - std::move(params)); + FakeEmbeddedWorkerInstanceClient::StartWorker(std::move(params)); } private: @@ -1899,10 +1880,10 @@ std::vector<CheckPauseAfterDownloadEmbeddedWorkerInstanceClient*> clients; clients.push_back( - helper_->CreateAndRegisterMockInstanceClient< + helper_->AddNewPendingInstanceClient< CheckPauseAfterDownloadEmbeddedWorkerInstanceClient>(helper_.get())); clients.push_back( - helper_->CreateAndRegisterMockInstanceClient< + helper_->AddNewPendingInstanceClient< CheckPauseAfterDownloadEmbeddedWorkerInstanceClient>(helper_.get())); // The initial version should not pause after download. @@ -1928,6 +1909,9 @@ blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = GURL("https://www.example.com/"); + auto* initial_client = + helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( + helper_.get()); scoped_refptr<ServiceWorkerRegistration> registration = RunRegisterJob(script, options); auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); @@ -1964,7 +1948,7 @@ // S13nServiceWorker: Activating the new version won't happen until // RequestTermination() is called. EXPECT_EQ(first_version.get(), registration->active_version()); - EXPECT_TRUE(RequestTermination(update_helper, first_version)); + RequestTermination(&initial_client->host()); } TestServiceWorkerObserver observer(helper_->context_wrapper()); @@ -1975,7 +1959,11 @@ // Shutdown. update_helper->context()->wrapper()->Shutdown(); - update_helper->set_force_start_worker_failure(true); + auto* embedded_worker_instance_client = + update_helper->AddNewPendingInstanceClient< + UpdateJobTestHelper::UpdateJobEmbeddedWorkerInstanceClient>( + update_helper); + embedded_worker_instance_client->set_force_start_worker_failure(true); // Allow the activation to continue. It will fail, and the worker // should not be promoted to ACTIVATED because failure occur
diff --git a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc index d6709e1..425b53e 100644 --- a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc +++ b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
@@ -14,6 +14,8 @@ #include "base/test/scoped_feature_list.h" #include "content/browser/loader/navigation_loader_interceptor.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" +#include "content/browser/service_worker/fake_service_worker.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_test_utils.h" @@ -178,20 +180,24 @@ DISALLOW_COPY_AND_ASSIGN(NavigationPreloadLoaderClient); }; -// Helper simulates a service worker handling fetch events. The response can be +// Simulates a service worker handling fetch events. The response can be // customized via RespondWith* functions. -class Helper : public EmbeddedWorkerTestHelper { +class FetchEventServiceWorker : public FakeServiceWorker { public: - Helper() : EmbeddedWorkerTestHelper(base::FilePath()) {} - ~Helper() override = default; + FetchEventServiceWorker( + EmbeddedWorkerTestHelper* helper, + FakeEmbeddedWorkerInstanceClient* embedded_worker_instance_client) + : FakeServiceWorker(helper), + embedded_worker_instance_client_(embedded_worker_instance_client) {} + ~FetchEventServiceWorker() override = default; - // Tells this helper to respond to fetch events with the specified blob. + // Tells this worker to respond to fetch events with the specified blob. void RespondWithBlob(blink::mojom::SerializedBlobPtr blob) { response_mode_ = ResponseMode::kBlob; blob_body_ = std::move(blob); } - // Tells this helper to respond to fetch events with the specified stream. + // Tells this worker to respond to fetch events with the specified stream. void RespondWithStream( blink::mojom::ServiceWorkerStreamCallbackRequest callback_request, mojo::ScopedDataPipeConsumerHandle consumer_handle) { @@ -201,35 +207,35 @@ stream_handle_->stream = std::move(consumer_handle); } - // Tells this helper to respond to fetch events with network fallback. + // Tells this worker to respond to fetch events with network fallback. // i.e., simulate the service worker not calling respondWith(). void RespondWithFallback() { response_mode_ = ResponseMode::kFallbackResponse; } - // Tells this helper to respond to fetch events with an error response. + // Tells this worker to respond to fetch events with an error response. void RespondWithError() { response_mode_ = ResponseMode::kErrorResponse; } - // Tells this helper to respond to fetch events with + // Tells this worker to respond to fetch events with // FetchEvent#preloadResponse. See NavigationPreloadLoaderClient's // documentation for details. void RespondWithNavigationPreloadResponse() { response_mode_ = ResponseMode::kNavigationPreloadResponse; } - // Tells this helper to respond to fetch events with the redirect response. + // Tells this worker to respond to fetch events with the redirect response. void RespondWithRedirectResponse(const GURL& new_url) { response_mode_ = ResponseMode::kRedirect; redirected_url_ = new_url; } - // Tells this helper to simulate failure to dispatch the fetch event to the + // Tells this worker to simulate failure to dispatch the fetch event to the // service worker. void FailToDispatchFetchEvent() { response_mode_ = ResponseMode::kFailFetchEventDispatch; } - // Tells this helper to simulate "early response", where the respondWith() + // Tells this worker to simulate "early response", where the respondWith() // promise resolves before the waitUntil() promise. In this mode, the // helper sets the response mode to "early response", which simulates the // promise passed to respondWith() resolving before the waitUntil() promise @@ -243,7 +249,7 @@ base::RunLoop().RunUntilIdle(); } - // Tells this helper to wait for FinishRespondWith() to be called before + // Tells this worker to wait for FinishRespondWith() to be called before // providing the response to the fetch event. void DeferResponse() { response_mode_ = ResponseMode::kDeferredResponse; } void FinishRespondWith() { @@ -275,25 +281,23 @@ } protected: - void OnFetchEvent( - int embedded_worker_id, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::FetchEventPreloadHandlePtr preload_handle, + void DispatchFetchEvent( + blink::mojom::DispatchFetchEventParamsPtr params, blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback, blink::mojom::ServiceWorker::DispatchFetchEventCallback finish_callback) override { // Basic checks on DispatchFetchEvent parameters. - EXPECT_TRUE(request->is_main_resource_load); + EXPECT_TRUE(params->request->is_main_resource_load); has_received_fetch_event_ = true; - if (request->body) - request_body_ = request->body; + if (params->request->body) + request_body_ = params->request->body; switch (response_mode_) { case ResponseMode::kDefault: - EmbeddedWorkerTestHelper::OnFetchEvent( - embedded_worker_id, std::move(request), std::move(preload_handle), - std::move(response_callback), std::move(finish_callback)); + FakeServiceWorker::DispatchFetchEvent(std::move(params), + std::move(response_callback), + std::move(finish_callback)); break; case ResponseMode::kBlob: response_callback->OnResponse( @@ -324,7 +328,7 @@ break; case ResponseMode::kNavigationPreloadResponse: // Deletes itself when done. - new NavigationPreloadLoaderClient(std::move(preload_handle), + new NavigationPreloadLoaderClient(std::move(params->preload_handle), std::move(response_callback), std::move(finish_callback)); break; @@ -333,7 +337,8 @@ // This causes ServiceWorkerVersion::StartRequest() to call its error // callback, which triggers ServiceWorkerNavigationLoader's dispatch // failed behavior. - SimulateWorkerStopped(embedded_worker_id); + embedded_worker_instance_client_->host()->OnStopped(); + // Finish the event by calling |finish_callback|. // This is the Mojo callback for // blink::mojom::ServiceWorker::DispatchFetchEvent(). @@ -401,7 +406,9 @@ bool has_received_fetch_event_ = false; base::OnceClosure quit_closure_for_fetch_event_; - DISALLOW_COPY_AND_ASSIGN(Helper); + FakeEmbeddedWorkerInstanceClient* const embedded_worker_instance_client_; + + DISALLOW_COPY_AND_ASSIGN(FetchEventServiceWorker); }; // Returns typical response info for a resource load that went through a service @@ -443,7 +450,7 @@ void SetUp() override { feature_list_.InitAndEnableFeature(network::features::kNetworkService); - helper_ = std::make_unique<Helper>(); + helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath()); // Create an active service worker. storage()->LazyInitializeForTest(base::DoNothing()); @@ -474,6 +481,15 @@ CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); ASSERT_EQ(blink::ServiceWorkerStatusCode::kOk, status.value()); + + // Set up custom fakes to let tests customize how to respond to fetch + // events. + auto* client = + helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( + helper_.get()); + service_worker_ = + helper_->AddNewPendingServiceWorker<FetchEventServiceWorker>( + helper_.get(), client); } ServiceWorkerStorage* storage() { return helper_->context()->storage(); } @@ -591,9 +607,10 @@ // -------------------------------------------------------------------------- TestBrowserThreadBundle thread_bundle_; - std::unique_ptr<Helper> helper_; + std::unique_ptr<EmbeddedWorkerTestHelper> helper_; scoped_refptr<ServiceWorkerRegistration> registration_; scoped_refptr<ServiceWorkerVersion> version_; + FetchEventServiceWorker* service_worker_; storage::BlobStorageContext blob_context_; network::TestURLLoaderClient client_; bool was_main_resource_load_failed_called_ = false; @@ -673,7 +690,7 @@ // Verify that the request body was passed to the fetch event. std::string body; - helper_->ReadRequestBody(&body); + service_worker_->ReadRequestBody(&body); EXPECT_EQ(kData, body); } @@ -692,7 +709,7 @@ blob->size = blob_handle->size(); blink::mojom::BlobRequest request = mojo::MakeRequest(&blob->blob); storage::BlobImpl::Create(std::move(blob_handle), std::move(request)); - helper_->RespondWithBlob(std::move(blob)); + service_worker_->RespondWithBlob(std::move(blob)); // Perform the request. LoaderResult result = StartRequest(CreateRequest()); @@ -733,7 +750,7 @@ blob->uuid = kBrokenUUID; blink::mojom::BlobRequest request = mojo::MakeRequest(&blob->blob); storage::BlobImpl::Create(std::move(blob_handle), std::move(request)); - helper_->RespondWithBlob(std::move(blob)); + service_worker_->RespondWithBlob(std::move(blob)); // Perform the request. LoaderResult result = StartRequest(CreateRequest()); @@ -768,8 +785,8 @@ const char kResponseBody[] = "Here is sample text for the Stream."; blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback; mojo::DataPipe data_pipe; - helper_->RespondWithStream(mojo::MakeRequest(&stream_callback), - std::move(data_pipe.consumer_handle)); + service_worker_->RespondWithStream(mojo::MakeRequest(&stream_callback), + std::move(data_pipe.consumer_handle)); // Perform the request. LoaderResult result = StartRequest(CreateRequest()); @@ -816,8 +833,8 @@ const char kResponseBody[] = "Here is sample text for the Stream."; blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback; mojo::DataPipe data_pipe; - helper_->RespondWithStream(mojo::MakeRequest(&stream_callback), - std::move(data_pipe.consumer_handle)); + service_worker_->RespondWithStream(mojo::MakeRequest(&stream_callback), + std::move(data_pipe.consumer_handle)); // Perform the request. LoaderResult result = StartRequest(CreateRequest()); @@ -866,8 +883,8 @@ const char kResponseBody[] = "Here is sample text for the Stream."; blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback; mojo::DataPipe data_pipe; - helper_->RespondWithStream(mojo::MakeRequest(&stream_callback), - std::move(data_pipe.consumer_handle)); + service_worker_->RespondWithStream(mojo::MakeRequest(&stream_callback), + std::move(data_pipe.consumer_handle)); // Perform the request. LoaderResult result = StartRequest(CreateRequest()); @@ -919,7 +936,7 @@ // i.e., does not call respondWith(). TEST_F(ServiceWorkerNavigationLoaderTest, FallbackResponse) { base::HistogramTester histogram_tester; - helper_->RespondWithFallback(); + service_worker_->RespondWithFallback(); // Perform the request. LoaderResult result = StartRequest(CreateRequest()); @@ -946,7 +963,7 @@ // Test when the service worker rejects the FetchEvent. TEST_F(ServiceWorkerNavigationLoaderTest, ErrorResponse) { base::HistogramTester histogram_tester; - helper_->RespondWithError(); + service_worker_->RespondWithError(); // Perform the request. LoaderResult result = StartRequest(CreateRequest()); @@ -968,7 +985,7 @@ // Test when dispatching the fetch event to the service worker failed. TEST_F(ServiceWorkerNavigationLoaderTest, FailFetchDispatch) { base::HistogramTester histogram_tester; - helper_->FailToDispatchFetchEvent(); + service_worker_->FailToDispatchFetchEvent(); // Perform the request. LoaderResult result = StartRequest(CreateRequest()); @@ -992,7 +1009,7 @@ // Test when the respondWith() promise resolves before the waitUntil() promise // resolves. The response should be received before the event finishes. TEST_F(ServiceWorkerNavigationLoaderTest, EarlyResponse) { - helper_->RespondEarly(); + service_worker_->RespondEarly(); // Perform the request. LoaderResult result = StartRequest(CreateRequest()); @@ -1006,7 +1023,7 @@ // Although the response was already received, the event remains outstanding // until waitUntil() resolves. EXPECT_TRUE(HasWorkInBrowser(version_.get())); - helper_->FinishWaitUntil(); + service_worker_->FinishWaitUntil(); EXPECT_FALSE(HasWorkInBrowser(version_.get())); } @@ -1049,7 +1066,7 @@ // Test responding to the fetch event with the navigation preload response. TEST_F(ServiceWorkerNavigationLoaderTest, NavigationPreload) { registration_->EnableNavigationPreload(true); - helper_->RespondWithNavigationPreloadResponse(); + service_worker_->RespondWithNavigationPreloadResponse(); // Perform the request LoaderResult result = StartRequest(CreateRequest()); @@ -1076,7 +1093,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, Redirect) { base::HistogramTester histogram_tester; GURL new_url("https://example.com/redirected"); - helper_->RespondWithRedirectResponse(new_url); + service_worker_->RespondWithRedirectResponse(new_url); // Perform the request. LoaderResult result = StartRequest(CreateRequest()); @@ -1151,12 +1168,12 @@ } TEST_F(ServiceWorkerNavigationLoaderTest, ConnectionErrorDuringFetchEvent) { - helper_->DeferResponse(); + service_worker_->DeferResponse(); LoaderResult result = StartRequest(CreateRequest()); EXPECT_EQ(LoaderResult::kHandledRequest, result); // Wait for the fetch event to be dispatched. - helper_->RunUntilFetchEvent(); + service_worker_->RunUntilFetchEvent(); // Break the Mojo connection. The loader should return an aborted status. loader_ptr_.reset(); @@ -1165,7 +1182,8 @@ // The loader is still alive. Finish the fetch event. It shouldn't crash or // call any callbacks on |client_|, which would throw an error. - helper_->FinishRespondWith(); + service_worker_->FinishRespondWith(); + // There's no event to wait for, so just pump the message loop and the test // passes if there is no error or crash. base::RunLoop().RunUntilIdle();
diff --git a/content/browser/service_worker/service_worker_object_host_unittest.cc b/content/browser/service_worker/service_worker_object_host_unittest.cc index 25aeb8f..54c9c30 100644 --- a/content/browser/service_worker/service_worker_object_host_unittest.cc +++ b/content/browser/service_worker/service_worker_object_host_unittest.cc
@@ -12,6 +12,7 @@ #include "base/test/simple_test_tick_clock.h" #include "content/browser/service_worker/embedded_worker_registry.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_dispatcher_host.h" #include "content/browser/service_worker/service_worker_object_host.h" @@ -68,26 +69,15 @@ std::vector<blink::mojom::ExtendableMessageEventPtr> events_; }; -class FailToStartWorkerTestHelper : public ExtendableMessageEventTestHelper { +// An instance client that breaks the Mojo connection upon receiving the +// Start() message. +class FailStartInstanceClient : public FakeEmbeddedWorkerInstanceClient { public: - FailToStartWorkerTestHelper() : ExtendableMessageEventTestHelper() {} + FailStartInstanceClient(EmbeddedWorkerTestHelper* helper) + : FakeEmbeddedWorkerInstanceClient(helper) {} - void OnStartWorker( - int embedded_worker_id, - int64_t service_worker_version_id, - const GURL& scope, - const GURL& script_url, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) - override { - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtr instance_host_ptr; - instance_host_ptr.Bind(std::move(instance_host)); - instance_host_ptr->OnStopped(); - base::RunLoop().RunUntilIdle(); + void StartWorker(blink::mojom::EmbeddedWorkerStartParamsPtr params) override { + // Don't save the Mojo ptrs. The connection breaks. } }; @@ -380,7 +370,7 @@ const int64_t kProviderId = 99; const GURL scope("https://www.example.com/"); const GURL script_url("https://www.example.com/service_worker.js"); - Initialize(std::make_unique<FailToStartWorkerTestHelper>()); + Initialize(std::make_unique<ExtendableMessageEventTestHelper>()); SetUpRegistration(scope, script_url); // Prepare a ServiceWorkerProviderHost for a window client. A @@ -405,6 +395,10 @@ ServiceWorkerObjectHost* object_host = GetServiceWorkerObjectHost(provider_host.get(), version_->version_id()); + // Set up the service worker to fail to start. + helper_->AddPendingInstanceClient( + std::make_unique<FailStartInstanceClient>(helper_.get())); + // Try to dispatch ExtendableMessageEvent. This should fail to start the // worker and to dispatch the event. blink::TransferableMessage message;
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc index ac051996..00f439b 100644 --- a/content/browser/service_worker/service_worker_registration_unittest.cc +++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -16,15 +16,21 @@ #include "base/memory/weak_ptr.h" #include "base/run_loop.h" #include "base/test/simple_test_tick_clock.h" +#include "base/test/test_simple_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "content/browser/service_worker/embedded_worker_status.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" +#include "content/browser/service_worker/fake_service_worker.h" #include "content/browser/service_worker/service_worker_context_core.h" +#include "content/browser/service_worker/service_worker_context_core_observer.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_dispatcher_host.h" #include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_registration_object_host.h" #include "content/browser/service_worker/service_worker_test_utils.h" +#include "content/browser/service_worker/test_service_worker_observer.h" #include "content/common/service_worker/service_worker_utils.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/test/test_content_browser_client.h" @@ -41,10 +47,26 @@ // From service_worker_registration.cc. constexpr base::TimeDelta kMaxLameDuckTime = base::TimeDelta::FromMinutes(5); +// TODO(falken): Make this a common helper function. +void StartWorker(ServiceWorkerVersion* version, + ServiceWorkerMetrics::EventType purpose) { + base::RunLoop loop; + blink::ServiceWorkerStatusCode code; + version->StartWorker( + purpose, + base::BindOnce( + [](base::OnceClosure done, blink::ServiceWorkerStatusCode* out_code, + blink::ServiceWorkerStatusCode result_code) { + *out_code = result_code; + std::move(done).Run(); + }, + loop.QuitClosure(), &code)); + loop.Run(); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, code); +} + int CreateInflightRequest(ServiceWorkerVersion* version) { - version->StartWorker(ServiceWorkerMetrics::EventType::PUSH, - base::DoNothing()); - base::RunLoop().RunUntilIdle(); + StartWorker(version, ServiceWorkerMetrics::EventType::PUSH); return version->StartRequest(ServiceWorkerMetrics::EventType::PUSH, base::DoNothing()); } @@ -67,6 +89,29 @@ } }; +void RequestTermination( + blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtr* host) { + // We can't wait for the callback since Stop() arrives first which severs + // the connection. + (*host)->RequestTermination(base::DoNothing()); +} + +class ActivationTestServiceWorker : public FakeServiceWorker { + public: + explicit ActivationTestServiceWorker(EmbeddedWorkerTestHelper* helper) + : FakeServiceWorker(helper) {} + ~ActivationTestServiceWorker() override = default; + + bool is_zero_idle_timer_delay() const { return is_zero_idle_timer_delay_; } + + void SetIdleTimerDelayToZero() override { is_zero_idle_timer_delay_ = true; } + + private: + bool is_zero_idle_timer_delay_ = false; + + DISALLOW_COPY_AND_ASSIGN(ActivationTestServiceWorker); +}; + class MockServiceWorkerRegistrationObject : public blink::mojom::ServiceWorkerRegistrationObject { public: @@ -228,8 +273,8 @@ }; protected: - std::unique_ptr<RegistrationTestHelper> helper_; TestBrowserThreadBundle thread_bundle_; + std::unique_ptr<RegistrationTestHelper> helper_; }; TEST_F(ServiceWorkerRegistrationTest, SetAndUnsetVersions) { @@ -426,7 +471,16 @@ DCHECK(remote_endpoint_.host_ptr()->is_bound()); version_1->AddControllee(host_.get()); - // Give the active version an in-flight request. + // Setup the Mojo implementation fakes for the renderer-side service worker. + // These will be bound once the service worker starts. + version_1_client_ = + helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( + helper_.get()); + version_1_service_worker_ = + helper_->AddNewPendingServiceWorker<ActivationTestServiceWorker>( + helper_.get()); + + // Start the active version and give it an in-flight request. inflight_request_id_ = CreateInflightRequest(version_1.get()); // Create a waiting version. @@ -445,8 +499,18 @@ version_2->set_fetch_handler_existence( ServiceWorkerVersion::FetchHandlerExistence::EXISTS); registration_->SetWaitingVersion(version_2); - version_2->StartWorker(ServiceWorkerMetrics::EventType::INSTALL, - base::DoNothing()); + + // Setup the Mojo implementation fakes for the renderer-side service worker. + // These will be bound once the service worker starts. + version_2_client_ = + helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( + helper_.get()); + version_2_service_worker_ = + helper_->AddNewPendingServiceWorker<ActivationTestServiceWorker>( + helper_.get()); + + // Start the worker. + StartWorker(version_2.get(), ServiceWorkerMetrics::EventType::INSTALL); version_2->SetStatus(ServiceWorkerVersion::INSTALLED); // Set it to activate when ready. The original version should still be @@ -502,11 +566,34 @@ base::RunLoop().RunUntilIdle(); } + FakeEmbeddedWorkerInstanceClient* version_1_client() { + return version_1_client_; + } + FakeEmbeddedWorkerInstanceClient* version_2_client() { + return version_2_client_; + } + ActivationTestServiceWorker* version_1_service_worker() { + return version_1_service_worker_; + } + ActivationTestServiceWorker* version_2_service_worker() { + return version_2_service_worker_; + } + private: scoped_refptr<ServiceWorkerRegistration> registration_; + + // Mojo implementation fakes for the renderer-side service workers. Their + // lifetime is bound to the Mojo connection. + FakeEmbeddedWorkerInstanceClient* version_1_client_ = nullptr; + ActivationTestServiceWorker* version_1_service_worker_ = nullptr; + FakeEmbeddedWorkerInstanceClient* version_2_client_ = nullptr; + ActivationTestServiceWorker* version_2_service_worker_ = nullptr; + std::unique_ptr<ServiceWorkerProviderHost> host_; ServiceWorkerRemoteProviderEndpoint remote_endpoint_; int inflight_request_id_ = -1; + + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerActivationTest); }; // Test activation triggered by finishing all requests. @@ -514,6 +601,8 @@ scoped_refptr<ServiceWorkerRegistration> reg = registration(); scoped_refptr<ServiceWorkerVersion> version_1 = reg->active_version(); scoped_refptr<ServiceWorkerVersion> version_2 = reg->waiting_version(); + auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); + reg->SetTaskRunnerForTest(runner); // Remove the controllee. Since there is an in-flight request, // activation should not yet happen. @@ -523,20 +612,16 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(version_1.get(), reg->active_version()); if (blink::ServiceWorkerUtils::IsServicificationEnabled()) - EXPECT_TRUE(helper_->is_zero_idle_timer_delay()); + EXPECT_TRUE(version_1_service_worker()->is_zero_idle_timer_delay()); // Finish the request. Activation should happen. version_1->FinishRequest(inflight_request_id(), true /* was_handled */); - base::RunLoop().RunUntilIdle(); - if (blink::ServiceWorkerUtils::IsServicificationEnabled()) { EXPECT_EQ(version_1.get(), reg->active_version()); - helper_->RequestTermination( - version_1->embedded_worker()->embedded_worker_id()); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(helper_->will_be_terminated().value()); + RequestTermination(&version_1_client()->host()); } - + TestServiceWorkerObserver observer(helper_->context_wrapper()); + observer.RunUntilActivated(version_2.get(), runner); EXPECT_EQ(version_2.get(), reg->active_version()); } @@ -577,7 +662,7 @@ EXPECT_FALSE(result.has_value()); EXPECT_EQ(version_1.get(), reg->active_version()); if (blink::ServiceWorkerUtils::IsServicificationEnabled()) - EXPECT_TRUE(helper_->is_zero_idle_timer_delay()); + EXPECT_TRUE(version_1_service_worker()->is_zero_idle_timer_delay()); // Finish the request. // non-S13nServiceWorker: The service worker becomes idle. @@ -588,10 +673,7 @@ if (blink::ServiceWorkerUtils::IsServicificationEnabled()) { EXPECT_EQ(version_1.get(), reg->active_version()); - helper_->RequestTermination( - version_1->embedded_worker()->embedded_worker_id()); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(helper_->will_be_terminated().value()); + RequestTermination(&version_1_client()->host()); } // Wait until SkipWaiting resolves. @@ -624,13 +706,10 @@ skip_waiting_loop.QuitClosure()); if (blink::ServiceWorkerUtils::IsServicificationEnabled()) { - EXPECT_TRUE(helper_->is_zero_idle_timer_delay()); + EXPECT_TRUE(version_1_service_worker()->is_zero_idle_timer_delay()); EXPECT_FALSE(result.has_value()); EXPECT_EQ(version_1.get(), reg->active_version()); - helper_->RequestTermination( - version_1->embedded_worker()->embedded_worker_id()); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(helper_->will_be_terminated().value()); + RequestTermination(&version_1_client()->host()); } // Wait until SkipWaiting resolves.
diff --git a/content/browser/service_worker/service_worker_url_request_job.h b/content/browser/service_worker/service_worker_url_request_job.h index 6384c93..5f0ba12c 100644 --- a/content/browser/service_worker/service_worker_url_request_job.h +++ b/content/browser/service_worker/service_worker_url_request_job.h
@@ -65,6 +65,7 @@ } // namespace service_worker_controllee_request_handler_unittest namespace service_worker_url_request_job_unittest { +class ServiceWorkerURLRequestJobTest; class DelayHelper; } // namespace service_worker_url_request_job_unittest @@ -151,7 +152,8 @@ class NavigationPreloadMetrics; friend class service_worker_url_request_job_unittest::DelayHelper; - friend class ServiceWorkerURLRequestJobTest; + friend class service_worker_url_request_job_unittest:: + ServiceWorkerURLRequestJobTest; FRIEND_TEST_ALL_PREFIXES(service_worker_controllee_request_handler_unittest:: ServiceWorkerControlleeRequestHandlerTest, LostActiveVersion);
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc index 10abbb5..52a5f8a0 100644 --- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc +++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -26,6 +26,8 @@ #include "content/browser/resource_context_impl.h" #include "content/browser/service_worker/embedded_worker_registry.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" +#include "content/browser/service_worker/fake_service_worker.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_provider_host.h" @@ -419,6 +421,10 @@ } // --------------------------------------------------------------------------- + void CompleteNavigationPreload() { + handler()->job()->OnNavigationPreloadResponse(); + } + // |scoped_feature_list_| must be before |thread_bundle_|. // See comments in ServiceWorkerProviderHostTest. base::test::ScopedFeatureList scoped_feature_list_; @@ -470,93 +476,47 @@ EXPECT_EQ(std::string(), info->response_cache_storage_cache_name()); } -// Helper for controlling when to start a worker and respond to a fetch event. -class DelayHelper : public EmbeddedWorkerTestHelper { +// For controlling when to respond to a fetch event. +class DelayFetchWorker : public FakeServiceWorker { public: - DelayHelper(ServiceWorkerURLRequestJobTest* test) - : EmbeddedWorkerTestHelper(base::FilePath()), test_(test) {} - ~DelayHelper() override {} + explicit DelayFetchWorker(EmbeddedWorkerTestHelper* helper) + : FakeServiceWorker(std::move(helper)) {} + ~DelayFetchWorker() override = default; - void CompleteNavigationPreload() { - test_->handler()->job()->OnNavigationPreloadResponse(); - } - - void CompleteStartWorker() { - EmbeddedWorkerTestHelper::OnStartWorker( - embedded_worker_id_, service_worker_version_id_, scope_, script_url_, - pause_after_download_, std::move(start_worker_request_), - std::move(controller_request_), std::move(start_worker_instance_host_), - std::move(provider_info_), std::move(installed_scripts_info_)); + void DispatchFetchEvent( + blink::mojom::DispatchFetchEventParamsPtr params, + blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback, + DispatchFetchEventCallback callback) override { + params_ = std::move(params); + response_callback_ = std::move(response_callback); + callback_ = std::move(callback); + if (respond_immediately_) + Respond(); } void Respond() { - response_callback_->OnResponse( - MakeOkResponse(), blink::mojom::ServiceWorkerFetchEventTiming::New()); - std::move(finish_callback_) - .Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED); - } - - protected: - void OnStartWorker( - int embedded_worker_id, - int64_t service_worker_version_id, - const GURL& scope, - const GURL& script_url, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) - override { - embedded_worker_id_ = embedded_worker_id; - service_worker_version_id_ = service_worker_version_id; - scope_ = scope; - script_url_ = script_url; - pause_after_download_ = pause_after_download; - start_worker_request_ = std::move(service_worker_request); - controller_request_ = std::move(controller_request); - start_worker_instance_host_ = std::move(instance_host); - provider_info_ = std::move(provider_info); - installed_scripts_info_ = std::move(installed_scripts_info); - } - - void OnFetchEvent( - int embedded_worker_id, - blink::mojom::FetchAPIRequestPtr /* request */, - blink::mojom::FetchEventPreloadHandlePtr preload_handle, - blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback, - blink::mojom::ServiceWorker::DispatchFetchEventCallback finish_callback) - override { - embedded_worker_id_ = embedded_worker_id; - response_callback_ = std::move(response_callback); - finish_callback_ = std::move(finish_callback); - preload_handle_ = std::move(preload_handle); + if (!params_) { + respond_immediately_ = true; + return; + } + FakeServiceWorker::DispatchFetchEvent(std::move(params_), + std::move(response_callback_), + std::move(callback_)); } private: - int64_t service_worker_version_id_; - GURL scope_; - GURL script_url_; - bool pause_after_download_; - blink::mojom::ServiceWorkerRequest start_worker_request_; - blink::mojom::ControllerServiceWorkerRequest controller_request_; - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo - start_worker_instance_host_; - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info_; - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info_; - int embedded_worker_id_ = 0; + bool respond_immediately_ = false; + blink::mojom::DispatchFetchEventParamsPtr params_; blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_; - blink::mojom::FetchEventPreloadHandlePtr preload_handle_; - blink::mojom::ServiceWorker::DispatchFetchEventCallback finish_callback_; - ServiceWorkerURLRequestJobTest* test_; - DISALLOW_COPY_AND_ASSIGN(DelayHelper); + DispatchFetchEventCallback callback_; + DISALLOW_COPY_AND_ASSIGN(DelayFetchWorker); }; TEST_F(ServiceWorkerURLRequestJobTest, NavPreloadMetrics_WorkerAlreadyStarted_MainFrame) { - SetUpWithHelper(std::make_unique<DelayHelper>(this)); - DelayHelper* helper = static_cast<DelayHelper*>(helper_.get()); + SetUpWithHelper(std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath())); + auto* worker = + helper_->AddNewPendingServiceWorker<DelayFetchWorker>(helper_.get()); // Start the worker before the navigation. blink::ServiceWorkerStatusCode status = @@ -565,14 +525,12 @@ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, base::BindOnce(&SaveStatusCallback, &status)); base::RunLoop().RunUntilIdle(); - helper->CompleteStartWorker(); - base::RunLoop().RunUntilIdle(); EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status); // Do the navigation. SetUpNavigationPreloadTest(RESOURCE_TYPE_MAIN_FRAME); - helper->CompleteNavigationPreload(); - helper->Respond(); + CompleteNavigationPreload(); + worker->Respond(); base::RunLoop().RunUntilIdle(); histogram_tester.ExpectUniqueSample( @@ -590,16 +548,20 @@ TEST_F(ServiceWorkerURLRequestJobTest, NavPreloadMetrics_WorkerFirst_MainFrame) { - SetUpWithHelper(std::make_unique<DelayHelper>(this)); - DelayHelper* helper = static_cast<DelayHelper*>(helper_.get()); + SetUpWithHelper(std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath())); + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + auto* worker = + helper_->AddNewPendingServiceWorker<DelayFetchWorker>(helper_.get()); base::HistogramTester histogram_tester; SetUpNavigationPreloadTest(RESOURCE_TYPE_MAIN_FRAME); // Worker finishes first. - helper->CompleteStartWorker(); - helper->CompleteNavigationPreload(); - helper->Respond(); + client->UnblockStartWorker(); + base::RunLoop().RunUntilIdle(); + CompleteNavigationPreload(); + worker->Respond(); base::RunLoop().RunUntilIdle(); histogram_tester.ExpectUniqueSample( @@ -617,16 +579,19 @@ TEST_F(ServiceWorkerURLRequestJobTest, NavPreloadMetrics_NavPreloadFirst_MainFrame) { - SetUpWithHelper(std::make_unique<DelayHelper>(this)); - DelayHelper* helper = static_cast<DelayHelper*>(helper_.get()); + SetUpWithHelper(std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath())); + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + auto* worker = + helper_->AddNewPendingServiceWorker<DelayFetchWorker>(helper_.get()); base::HistogramTester histogram_tester; SetUpNavigationPreloadTest(RESOURCE_TYPE_MAIN_FRAME); // Nav preload finishes first. - helper->CompleteNavigationPreload(); - helper->CompleteStartWorker(); - helper->Respond(); + CompleteNavigationPreload(); + client->UnblockStartWorker(); + worker->Respond(); base::RunLoop().RunUntilIdle(); histogram_tester.ExpectUniqueSample( @@ -643,16 +608,20 @@ } TEST_F(ServiceWorkerURLRequestJobTest, NavPreloadMetrics_WorkerFirst_SubFrame) { - SetUpWithHelper(std::make_unique<DelayHelper>(this)); - DelayHelper* helper = static_cast<DelayHelper*>(helper_.get()); + SetUpWithHelper(std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath())); + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + auto* worker = + helper_->AddNewPendingServiceWorker<DelayFetchWorker>(helper_.get()); base::HistogramTester histogram_tester; SetUpNavigationPreloadTest(RESOURCE_TYPE_SUB_FRAME); // Worker finishes first. - helper->CompleteStartWorker(); - helper->CompleteNavigationPreload(); - helper->Respond(); + client->UnblockStartWorker(); + base::RunLoop().RunUntilIdle(); + CompleteNavigationPreload(); + worker->Respond(); base::RunLoop().RunUntilIdle(); histogram_tester.ExpectTotalCount( @@ -669,16 +638,19 @@ TEST_F(ServiceWorkerURLRequestJobTest, NavPreloadMetrics_NavPreloadFirst_SubFrame) { - SetUpWithHelper(std::make_unique<DelayHelper>(this)); - DelayHelper* helper = static_cast<DelayHelper*>(helper_.get()); + SetUpWithHelper(std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath())); + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + auto* worker = + helper_->AddNewPendingServiceWorker<DelayFetchWorker>(helper_.get()); base::HistogramTester histogram_tester; SetUpNavigationPreloadTest(RESOURCE_TYPE_SUB_FRAME); // Nav preload finishes first. - helper->CompleteNavigationPreload(); - helper->CompleteStartWorker(); - helper->Respond(); + CompleteNavigationPreload(); + client->UnblockStartWorker(); + worker->Respond(); base::RunLoop().RunUntilIdle(); histogram_tester.ExpectTotalCount( @@ -1255,32 +1227,38 @@ EXPECT_FALSE(info->service_worker_ready_time().is_null()); } -// Helper to simulate failing to dispatch a fetch event to a worker. -class FailFetchHelper : public EmbeddedWorkerTestHelper { +// Simulates failing to dispatch a fetch event to a worker. +class FailFetchWorker : public FakeServiceWorker { public: - FailFetchHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {} - ~FailFetchHelper() override {} + explicit FailFetchWorker(EmbeddedWorkerTestHelper* helper, + FakeEmbeddedWorkerInstanceClient* instance_client) + : FakeServiceWorker(helper), instance_client_(instance_client) {} + ~FailFetchWorker() override = default; protected: - void OnFetchEvent( - int embedded_worker_id, - blink::mojom::FetchAPIRequestPtr /* request */, - blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */, - blink::mojom:: - ServiceWorkerFetchResponseCallbackPtr /* response_callback */, - blink::mojom::ServiceWorker::DispatchFetchEventCallback finish_callback) - override { - SimulateWorkerStopped(embedded_worker_id); - std::move(finish_callback) - .Run(blink::mojom::ServiceWorkerEventStatus::ABORTED); + void DispatchFetchEvent( + blink::mojom::DispatchFetchEventParamsPtr params, + blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback, + DispatchFetchEventCallback callback) override { + instance_client_->host()->OnStopped(); + std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::ABORTED); } private: - DISALLOW_COPY_AND_ASSIGN(FailFetchHelper); + FakeEmbeddedWorkerInstanceClient* const instance_client_; + DISALLOW_COPY_AND_ASSIGN(FailFetchWorker); }; TEST_F(ServiceWorkerURLRequestJobTest, FailFetchDispatch) { - SetUpWithHelper(std::make_unique<FailFetchHelper>()); + SetUpWithHelper(std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath())); + + // Setup Mojo implementation fakes for the renderer-side service worker. + // These force dispatching the fetch event to fail. + auto* instance_client = + helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( + helper_.get()); + helper_->AddPendingServiceWorker( + std::make_unique<FailFetchWorker>(helper_.get(), instance_client)); version_->SetStatus(ServiceWorkerVersion::ACTIVATED); request_ = url_request_context_.CreateRequest( @@ -1403,8 +1381,11 @@ // Test cancelling the URLRequest while the fetch event is in flight. TEST_F(ServiceWorkerURLRequestJobTest, CancelRequest) { - SetUpWithHelper(std::make_unique<DelayHelper>(this)); - DelayHelper* helper = static_cast<DelayHelper*>(helper_.get()); + SetUpWithHelper(std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath())); + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + auto* worker = + helper_->AddNewPendingServiceWorker<DelayFetchWorker>(helper_.get()); // Start the URL request. The job will be waiting for the // worker to respond to the fetch event. @@ -1415,7 +1396,7 @@ request_->set_method("GET"); request_->Start(); base::RunLoop().RunUntilIdle(); - helper->CompleteStartWorker(); + client->UnblockStartWorker(); base::RunLoop().RunUntilIdle(); // Cancel the URL request. @@ -1424,7 +1405,7 @@ // Respond to the fetch event. EXPECT_FALSE(version_->HasNoWork()); - helper->Respond(); + worker->Respond(); base::RunLoop().RunUntilIdle(); // The fetch event request should no longer be in-flight.
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index aebb003..f3192c6 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -73,19 +73,13 @@ namespace service_worker_version_unittest { class ServiceWorkerVersionTest; -class ServiceWorkerRequestTimeoutTest; -class ServiceWorkerFailToStartTest; -FORWARD_DECLARE_TEST(ServiceWorkerFailToStartTest, Timeout); -FORWARD_DECLARE_TEST(ServiceWorkerRequestTimeoutTest, RequestTimeout); -FORWARD_DECLARE_TEST(ServiceWorkerStallInStoppingTest, DetachThenRestart); -FORWARD_DECLARE_TEST(ServiceWorkerStallInStoppingTest, - DetachThenRestartNoCrash); -FORWARD_DECLARE_TEST(ServiceWorkerStallInStoppingTest, DetachThenStart); +FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, FailToStart_Timeout); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, IdleTimeout); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, MixedRequestTimeouts); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, RegisterForeignFetchScopes); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, RequestCustomizedTimeout); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, RequestNowTimeout); +FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, RequestTimeout); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, RestartWorker); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, RequestNowTimeoutKill); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, SetDevToolsAttached); @@ -94,6 +88,9 @@ FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, StaleUpdate_NonActiveWorker); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, StaleUpdate_RunningWorker); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, StaleUpdate_StartWorker); +FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, + StallInStopping_DetachThenRestart); +FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, StallInStopping_DetachThenStart); FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, StartRequestWithNullContext); } // namespace service_worker_version_unittest @@ -576,29 +573,26 @@ service_worker_version_unittest::ServiceWorkerVersionTest, StartRequestWithNullContext); FRIEND_TEST_ALL_PREFIXES( - service_worker_version_unittest::ServiceWorkerRequestTimeoutTest, - RequestTimeout); - FRIEND_TEST_ALL_PREFIXES( - service_worker_version_unittest::ServiceWorkerFailToStartTest, - Timeout); + service_worker_version_unittest::ServiceWorkerVersionTest, + FailToStart_Timeout); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionBrowserTest, TimeoutStartingWorker); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionBrowserTest, TimeoutWorkerInEvent); FRIEND_TEST_ALL_PREFIXES( - service_worker_version_unittest::ServiceWorkerStallInStoppingTest, - DetachThenStart); + service_worker_version_unittest::ServiceWorkerVersionTest, + StallInStopping_DetachThenStart); FRIEND_TEST_ALL_PREFIXES( - service_worker_version_unittest::ServiceWorkerStallInStoppingTest, - DetachThenRestart); - FRIEND_TEST_ALL_PREFIXES( - service_worker_version_unittest::ServiceWorkerStallInStoppingTest, - DetachThenRestartNoCrash); + service_worker_version_unittest::ServiceWorkerVersionTest, + StallInStopping_DetachThenRestart); FRIEND_TEST_ALL_PREFIXES( service_worker_version_unittest::ServiceWorkerVersionTest, RequestNowTimeout); FRIEND_TEST_ALL_PREFIXES( service_worker_version_unittest::ServiceWorkerVersionTest, + RequestTimeout); + FRIEND_TEST_ALL_PREFIXES( + service_worker_version_unittest::ServiceWorkerVersionTest, RestartWorker); FRIEND_TEST_ALL_PREFIXES( service_worker_version_unittest::ServiceWorkerVersionTest,
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc index 76fa74a..99d4df35 100644 --- a/content/browser/service_worker/service_worker_version_unittest.cc +++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -21,6 +21,8 @@ #include "content/browser/service_worker/embedded_worker_registry.h" #include "content/browser/service_worker/embedded_worker_status.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/fake_embedded_worker_instance_client.h" +#include "content/browser/service_worker/fake_service_worker.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_dispatcher_host.h" #include "content/browser/service_worker/service_worker_ping_controller.h" @@ -43,24 +45,6 @@ namespace content { namespace service_worker_version_unittest { -class MessageReceiver : public EmbeddedWorkerTestHelper { - public: - MessageReceiver() : EmbeddedWorkerTestHelper(base::FilePath()) {} - ~MessageReceiver() override {} - - void SimulateSetCachedMetadata(int embedded_worker_id, - const GURL& url, - const std::vector<uint8_t>& data) { - GetServiceWorkerHost(embedded_worker_id)->SetCachedMetadata(url, data); - } - - void SimulateClearCachedMetadata(int embedded_worker_id, const GURL& url) { - GetServiceWorkerHost(embedded_worker_id)->ClearCachedMetadata(url); - } - - DISALLOW_COPY_AND_ASSIGN(MessageReceiver); -}; - void VerifyCalled(bool* called) { *called = true; } @@ -146,8 +130,7 @@ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} void SetUp() override { - helper_ = GetMessageReceiver(); - + helper_ = GetHelper(); helper_->context()->storage()->LazyInitializeForTest(base::DoNothing()); base::RunLoop().RunUntilIdle(); @@ -183,8 +166,8 @@ ASSERT_EQ(blink::ServiceWorkerStatusCode::kOk, status.value()); } - virtual std::unique_ptr<MessageReceiver> GetMessageReceiver() { - return std::make_unique<MessageReceiver>(); + virtual std::unique_ptr<EmbeddedWorkerTestHelper> GetHelper() { + return std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath()); } void TearDown() override { @@ -250,7 +233,7 @@ } TestBrowserThreadBundle thread_bundle_; - std::unique_ptr<MessageReceiver> helper_; + std::unique_ptr<EmbeddedWorkerTestHelper> helper_; scoped_refptr<ServiceWorkerRegistration> registration_; scoped_refptr<ServiceWorkerVersion> version_; GURL scope_; @@ -259,142 +242,19 @@ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersionTest); }; -class MessageReceiverDisallowStart : public MessageReceiver { +// An instance client that breaks the Mojo connection upon receiving the +// Start() message. +class FailStartInstanceClient : public FakeEmbeddedWorkerInstanceClient { public: - MessageReceiverDisallowStart() : MessageReceiver() {} - ~MessageReceiverDisallowStart() override {} + FailStartInstanceClient(EmbeddedWorkerTestHelper* helper) + : FakeEmbeddedWorkerInstanceClient(helper) {} - enum class StartMode { STALL, FAIL, SUCCEED }; - - void OnStartWorker( - int embedded_worker_id, - int64_t service_worker_version_id, - const GURL& scope, - const GURL& script_url, - bool pause_after_download, - blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, - blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, - blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, - blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) - override { - switch (mode_) { - case StartMode::STALL: - // Prepare for OnStopWorker(). - instance_host_ptr_map_[embedded_worker_id].Bind( - std::move(instance_host)); - // Just keep the connection alive. - service_worker_request_map_[embedded_worker_id] = - std::move(service_worker_request); - controller_request_map_[embedded_worker_id] = - std::move(controller_request); - break; - case StartMode::FAIL: - ASSERT_EQ(current_mock_instance_index_ + 1, - mock_instance_clients()->size()); - // Remove the connection by peer - mock_instance_clients()->at(current_mock_instance_index_).reset(); - break; - case StartMode::SUCCEED: - MessageReceiver::OnStartWorker( - embedded_worker_id, service_worker_version_id, scope, script_url, - pause_after_download, std::move(service_worker_request), - std::move(controller_request), std::move(instance_host), - std::move(provider_info), std::move(installed_scripts_info)); - break; - } - current_mock_instance_index_++; - } - - void OnStopWorker(int embedded_worker_id) override { - if (instance_host_ptr_map_[embedded_worker_id]) { - instance_host_ptr_map_[embedded_worker_id]->OnStopped(); - base::RunLoop().RunUntilIdle(); - return; - } - EmbeddedWorkerTestHelper::OnStopWorker(embedded_worker_id); - } - - void set_start_mode(StartMode mode) { mode_ = mode; } - - private: - uint32_t current_mock_instance_index_ = 0; - StartMode mode_ = StartMode::STALL; - - std::map<int /* embedded_worker_id */, - blink::mojom:: - EmbeddedWorkerInstanceHostAssociatedPtr /* instance_host_ptr */> - instance_host_ptr_map_; - std::map<int /* embedded_worker_id */, blink::mojom::ServiceWorkerRequest> - service_worker_request_map_; - std::map<int /* embedded_worker_id */, - blink::mojom::ControllerServiceWorkerRequest> - controller_request_map_; - DISALLOW_COPY_AND_ASSIGN(MessageReceiverDisallowStart); -}; - -class ServiceWorkerFailToStartTest : public ServiceWorkerVersionTest { - protected: - ServiceWorkerFailToStartTest() : ServiceWorkerVersionTest() {} - - void set_start_mode(MessageReceiverDisallowStart::StartMode mode) { - MessageReceiverDisallowStart* helper = - static_cast<MessageReceiverDisallowStart*>(helper_.get()); - helper->set_start_mode(mode); - } - - std::unique_ptr<MessageReceiver> GetMessageReceiver() override { - return std::make_unique<MessageReceiverDisallowStart>(); + void StartWorker(blink::mojom::EmbeddedWorkerStartParamsPtr params) override { + // Don't save the Mojo ptrs. The connection breaks. } private: - DISALLOW_COPY_AND_ASSIGN(ServiceWorkerFailToStartTest); -}; - -class NoOpStopWorkerEmbeddedWorkerInstanceClient - : public EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient { - public: - explicit NoOpStopWorkerEmbeddedWorkerInstanceClient( - EmbeddedWorkerTestHelper* helper) - : EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient(helper) {} - ~NoOpStopWorkerEmbeddedWorkerInstanceClient() override { - } - - protected: - void StopWorker() override { - // Do nothing. - } - - private: - DISALLOW_COPY_AND_ASSIGN(NoOpStopWorkerEmbeddedWorkerInstanceClient); -}; - -class MessageReceiverDisallowStop : public MessageReceiver { - public: - MessageReceiverDisallowStop() : MessageReceiver() { - CreateAndRegisterMockInstanceClient< - NoOpStopWorkerEmbeddedWorkerInstanceClient>(this); - } - ~MessageReceiverDisallowStop() override {} - - void OnStopWorker(int embedded_worker_id) override { - // Do nothing. - } - - private: - DISALLOW_COPY_AND_ASSIGN(MessageReceiverDisallowStop); -}; - -class ServiceWorkerStallInStoppingTest : public ServiceWorkerVersionTest { - protected: - ServiceWorkerStallInStoppingTest() : ServiceWorkerVersionTest() {} - - std::unique_ptr<MessageReceiver> GetMessageReceiver() override { - return std::make_unique<MessageReceiverDisallowStop>(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ServiceWorkerStallInStoppingTest); + DISALLOW_COPY_AND_ASSIGN(FailStartInstanceClient); }; TEST_F(ServiceWorkerVersionTest, ConcurrentStartAndStop) { @@ -861,21 +721,20 @@ CachedMetadataUpdateListener listener; version_->AddObserver(&listener); ASSERT_EQ(0, listener.updated_count); + auto* service_worker = + helper_->AddNewPendingServiceWorker<FakeServiceWorker>(helper_.get()); StartWorker(version_.get(), ServiceWorkerMetrics::EventType::UNKNOWN); + service_worker->RunUntilInitializeGlobalScope(); // Simulate requesting SetCachedMetadata from the service worker global scope. std::vector<uint8_t> data{1, 2, 3}; - helper_->SimulateSetCachedMetadata( - version_->embedded_worker()->embedded_worker_id(), version_->script_url(), - data); + service_worker->host()->SetCachedMetadata(version_->script_url(), data); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, listener.updated_count); // Simulate requesting ClearCachedMetadata from the service worker global // scope. - helper_->SimulateClearCachedMetadata( - version_->embedded_worker()->embedded_worker_id(), - version_->script_url()); + service_worker->host()->ClearCachedMetadata(version_->script_url()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(2, listener.updated_count); version_->RemoveObserver(&listener); @@ -912,76 +771,50 @@ version_->SetAllRequestExpirations(base::TimeTicks()); } -class MessageReceiverControlEvents : public MessageReceiver { +class DelayMessageWorker : public FakeServiceWorker { public: - MessageReceiverControlEvents() : MessageReceiver() {} - ~MessageReceiverControlEvents() override {} + explicit DelayMessageWorker(EmbeddedWorkerTestHelper* helper) + : FakeServiceWorker(helper) {} + ~DelayMessageWorker() override = default; - void OnExtendableMessageEvent( + void DispatchExtendableMessageEvent( blink::mojom::ExtendableMessageEventPtr event, - blink::mojom::ServiceWorker::DispatchExtendableMessageEventCallback - callback) override { - EXPECT_FALSE(extendable_message_event_callback_); - extendable_message_event_callback_ = std::move(callback); + DispatchExtendableMessageEventCallback callback) override { + event_ = std::move(event); + callback_ = std::move(callback); + if (quit_closure_) + std::move(quit_closure_).Run(); } - void OnStopWorker(int embedded_worker_id) override { - EXPECT_FALSE(stop_worker_callback_); - stop_worker_callback_ = - base::BindOnce(&MessageReceiverControlEvents::SimulateWorkerStopped, - base::Unretained(this), embedded_worker_id); + void AbortMessageEvent() { + std::move(callback_).Run(blink::mojom::ServiceWorkerEventStatus::ABORTED); } - bool has_extendable_message_event_callback() { - return !extendable_message_event_callback_.is_null(); - } - - blink::mojom::ServiceWorker::DispatchExtendableMessageEventCallback - TakeExtendableMessageEventCallback() { - return std::move(extendable_message_event_callback_); - } - - base::OnceClosure stop_worker_callback() { - return std::move(stop_worker_callback_); + void RunUntilDispatchMessageEvent() { + if (event_) + return; + base::RunLoop loop; + quit_closure_ = loop.QuitClosure(); + loop.Run(); } private: - blink::mojom::ServiceWorker::DispatchExtendableMessageEventCallback - extendable_message_event_callback_; - base::OnceClosure stop_worker_callback_; + blink::mojom::ExtendableMessageEventPtr event_; + DispatchExtendableMessageEventCallback callback_; + base::OnceClosure quit_closure_; + + DISALLOW_COPY_AND_ASSIGN(DelayMessageWorker); }; -class ServiceWorkerRequestTimeoutTest : public ServiceWorkerVersionTest { - protected: - ServiceWorkerRequestTimeoutTest() : ServiceWorkerVersionTest() {} +TEST_F(ServiceWorkerVersionTest, RequestTimeout) { + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + auto* worker = + helper_->AddNewPendingServiceWorker<DelayMessageWorker>(helper_.get()); - std::unique_ptr<MessageReceiver> GetMessageReceiver() override { - return std::make_unique<MessageReceiverControlEvents>(); - } - - bool has_extendable_message_event_callback() { - return static_cast<MessageReceiverControlEvents*>(helper_.get()) - ->has_extendable_message_event_callback(); - } - - blink::mojom::ServiceWorker::DispatchExtendableMessageEventCallback - TakeExtendableMessageEventCallback() { - return static_cast<MessageReceiverControlEvents*>(helper_.get()) - ->TakeExtendableMessageEventCallback(); - } - - base::OnceClosure stop_worker_callback() { - return static_cast<MessageReceiverControlEvents*>(helper_.get()) - ->stop_worker_callback(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRequestTimeoutTest); -}; - -TEST_F(ServiceWorkerRequestTimeoutTest, RequestTimeout) { base::Optional<blink::ServiceWorkerStatusCode> error_status; version_->SetStatus(ServiceWorkerVersion::ACTIVATED); + client->UnblockStartWorker(); StartWorker(version_.get(), ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME); @@ -990,31 +823,23 @@ version_->StartRequest(ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME, CreateReceiverOnCurrentThread(&error_status)); - // Dispatch a dummy event whose response will be received by SWVersion. - EXPECT_FALSE(has_extendable_message_event_callback()); + // Dispatch a dummy event. version_->endpoint()->DispatchExtendableMessageEvent( blink::mojom::ExtendableMessageEvent::New(), version_->CreateSimpleEventCallback(request_id)); + worker->RunUntilDispatchMessageEvent(); - base::RunLoop().RunUntilIdle(); - // The renderer should have received an ExtendableMessageEvent request. - EXPECT_TRUE(has_extendable_message_event_callback()); - - // Callback has not completed yet. + // Request callback has not completed yet. EXPECT_FALSE(error_status); - EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version_->running_status()); // Simulate timeout. - EXPECT_FALSE(stop_worker_callback()); EXPECT_TRUE(version_->timeout_timer_.IsRunning()); version_->SetAllRequestExpirations(base::TimeTicks::Now()); version_->timeout_timer_.user_task().Run(); - base::RunLoop().RunUntilIdle(); - - base::OnceClosure callback = stop_worker_callback(); // The renderer should have received a StopWorker request. - EXPECT_TRUE(callback); + client->RunUntilStopWorker(); + // The request should have timed out. EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorTimeout, error_status.value()); @@ -1023,12 +848,11 @@ // Simulate the renderer aborting the inflight event. // This should not crash: https://crbug.com/676984. - TakeExtendableMessageEventCallback().Run( - blink::mojom::ServiceWorkerEventStatus::ABORTED); + worker->AbortMessageEvent(); base::RunLoop().RunUntilIdle(); // Simulate the renderer stopping the worker. - std::move(callback).Run(); + client->UnblockStopWorker(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version_->running_status()); } @@ -1188,8 +1012,10 @@ EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version_->running_status()); } -TEST_F(ServiceWorkerFailToStartTest, RendererCrash) { +TEST_F(ServiceWorkerVersionTest, FailToStart_RendererCrash) { base::Optional<blink::ServiceWorkerStatusCode> status; + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); @@ -1200,7 +1026,7 @@ // Simulate renderer crash: break EmbeddedWorkerInstance's Mojo connection to // the renderer-side client. - helper_->mock_instance_clients()->clear(); + client->Disconnect(); base::RunLoop().RunUntilIdle(); // Callback completed. @@ -1209,10 +1035,13 @@ EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version_->running_status()); } -TEST_F(ServiceWorkerFailToStartTest, Timeout) { +TEST_F(ServiceWorkerVersionTest, FailToStart_Timeout) { base::Optional<blink::ServiceWorkerStatusCode> status; // Start starting the worker. + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + client->UnblockStopWorker(); version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); @@ -1234,8 +1063,11 @@ // Test that a service worker stalled in stopping will timeout and not get in a // sticky error state. -TEST_F(ServiceWorkerStallInStoppingTest, DetachThenStart) { +TEST_F(ServiceWorkerVersionTest, StallInStopping_DetachThenStart) { // Start a worker. + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + client->UnblockStartWorker(); StartWorker(version_.get(), ServiceWorkerMetrics::EventType::UNKNOWN); // Try to stop the worker. @@ -1269,8 +1101,11 @@ // Test that a service worker stalled in stopping with a start worker // request queued up will timeout and restart. -TEST_F(ServiceWorkerStallInStoppingTest, DetachThenRestart) { +TEST_F(ServiceWorkerVersionTest, StallInStopping_DetachThenRestart) { // Start a worker. + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + client->UnblockStartWorker(); StartWorker(version_.get(), ServiceWorkerMetrics::EventType::UNKNOWN); // Try to stop the worker. @@ -1296,27 +1131,32 @@ TEST_F(ServiceWorkerVersionTest, RendererCrashDuringEvent) { version_->SetStatus(ServiceWorkerVersion::ACTIVATED); + + auto* client = + helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( + helper_.get()); StartWorker(version_.get(), ServiceWorkerMetrics::EventType::SYNC); - base::Optional<blink::ServiceWorkerStatusCode> status; - int request_id = - version_->StartRequest(ServiceWorkerMetrics::EventType::SYNC, - CreateReceiverOnCurrentThread(&status)); - base::RunLoop().RunUntilIdle(); - - // Callback has not completed yet. - EXPECT_FALSE(status); + base::RunLoop loop; + blink::ServiceWorkerStatusCode status = blink::ServiceWorkerStatusCode::kOk; + int request_id = version_->StartRequest( + ServiceWorkerMetrics::EventType::SYNC, + base::BindOnce( + [](base::OnceClosure done, blink::ServiceWorkerStatusCode* out_status, + blink::ServiceWorkerStatusCode result_status) { + *out_status = result_status; + std::move(done).Run(); + }, + loop.QuitClosure(), &status)); // Simulate renderer crash: break EmbeddedWorkerInstance's Mojo connection to - // the renderer-side client. - helper_->mock_instance_clients()->clear(); - base::RunLoop().RunUntilIdle(); - - // Callback completed. - EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorFailed, status.value()); + // the renderer-side client. The request callback should be called. + client->Disconnect(); + loop.Run(); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorFailed, status); EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version_->running_status()); - // Request already failed, calling finsh should return false. + // Request already failed, calling finish should return false. EXPECT_FALSE(version_->FinishRequest(request_id, true /* was_handled */)); } @@ -1486,14 +1326,13 @@ helper_->mock_render_process_host()->foreground_service_worker_count()); } -TEST_F(ServiceWorkerFailToStartTest, FailingWorkerUsesNewRendererProcess) { +TEST_F(ServiceWorkerVersionTest, FailToStart_UseNewRendererProcess) { base::Optional<blink::ServiceWorkerStatusCode> status; ServiceWorkerContextCore* context = helper_->context(); int64_t id = version_->version_id(); version_->SetStatus(ServiceWorkerVersion::ACTIVATED); // Start once. It should choose the "existing process". - set_start_mode(MessageReceiverDisallowStart::StartMode::SUCCEED); version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); @@ -1505,7 +1344,8 @@ // Fail once. status.reset(); - set_start_mode(MessageReceiverDisallowStart::StartMode::FAIL); + helper_->AddPendingInstanceClient( + std::make_unique<FailStartInstanceClient>(helper_.get())); version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); @@ -1515,6 +1355,8 @@ // Fail again. status.reset(); + helper_->AddPendingInstanceClient( + std::make_unique<FailStartInstanceClient>(helper_.get())); version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); @@ -1524,7 +1366,6 @@ // Succeed. It should choose the "new process". status.reset(); - set_start_mode(MessageReceiverDisallowStart::StartMode::SUCCEED); version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); @@ -1548,20 +1389,21 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(ServiceWorkerFailToStartTest, RestartStalledWorker) { +TEST_F(ServiceWorkerVersionTest, FailToStart_RestartStalledWorker) { base::Optional<blink::ServiceWorkerStatusCode> status; + // Stall in starting. + auto* client = helper_->AddNewPendingInstanceClient< + DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()); + client->UnblockStopWorker(); version_->StartWorker(ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME, CreateReceiverOnCurrentThread(&status)); base::RunLoop().RunUntilIdle(); - // The default start mode is StartMode::STALL. So the callback of StartWorker - // is not called yet. EXPECT_FALSE(status); - // Set StartMode::SUCCEED. So the next start worker will be successful. - set_start_mode(MessageReceiverDisallowStart::StartMode::SUCCEED); - - // StartWorker message will be sent again because OnStopped is called before - // OnStarted. + // The restart logic is triggered because OnStopped is called before + // OnStarted. So the Start message is sent again. The delayed instance client + // was already consumed, so a default fake instance client will be created, + // which starts normally. bool has_stopped = false; version_->StopWorker(base::BindOnce(&VerifyCalled, &has_stopped)); base::RunLoop().RunUntilIdle();
diff --git a/content/browser/web_package/signed_exchange_envelope.cc b/content/browser/web_package/signed_exchange_envelope.cc index e503346..e74286b 100644 --- a/content/browser/web_package/signed_exchange_envelope.cc +++ b/content/browser/web_package/signed_exchange_envelope.cc
@@ -262,6 +262,13 @@ return false; } + found = out->response_headers().find("digest"); + if (found == out->response_headers().end()) { + signed_exchange_utils::ReportErrorAndTraceEvent( + devtools_proxy, "Signed exchange has no Digest: header"); + return false; + } + return true; }
diff --git a/content/browser/web_package/signed_exchange_envelope_unittest.cc b/content/browser/web_package/signed_exchange_envelope_unittest.cc index 49a0e3f..5065803 100644 --- a/content/browser/web_package/signed_exchange_envelope_unittest.cc +++ b/content/browser/web_package/signed_exchange_envelope_unittest.cc
@@ -111,11 +111,11 @@ TEST_P(SignedExchangeEnvelopeTest, ValidHeader) { auto header = GenerateHeaderAndParse( GetParam(), "https://test.example.org/test/", kSignatureString, - {{kStatusKey, "200"}, {"content-type", "text/html"}}); + {{kStatusKey, "200"}, {"content-type", "text/html"}, {"digest", "foo"}}); ASSERT_TRUE(header.has_value()); EXPECT_EQ(header->request_url().url, GURL("https://test.example.org/test/")); EXPECT_EQ(header->response_code(), static_cast<net::HttpStatusCode>(200u)); - EXPECT_EQ(header->response_headers().size(), 1u); + EXPECT_EQ(header->response_headers().size(), 2u); } TEST_P(SignedExchangeEnvelopeTest, InformationalResponseCode) { @@ -226,6 +226,7 @@ { {kStatusKey, "200"}, {"cache-control", "foo=\"300, no-store\""}, + {"digest", "foo"}, }); ASSERT_TRUE(header.has_value()); }
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc index a49cde4..68172c7 100644 --- a/content/browser/web_package/signed_exchange_handler.cc +++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -652,16 +652,8 @@ response_head.load_timing.receive_headers_end = now; std::string digest_header_value; - if (!response_head.headers->EnumerateHeader(nullptr, kDigestHeader, - &digest_header_value)) { - // TODO(https://crbug.com/803774): Detect this error in - // SignedExchangeEnvelope::Parse(). - signed_exchange_utils::ReportErrorAndTraceEvent( - devtools_proxy_.get(), "Signed exchange has no Digest: header"); - RunErrorCallback(SignedExchangeLoadResult::kHeaderParseError, - net::ERR_INVALID_SIGNED_EXCHANGE); - return; - } + response_head.headers->EnumerateHeader(nullptr, kDigestHeader, + &digest_header_value); auto mi_stream = std::make_unique<MerkleIntegritySourceStream>( digest_header_value, std::move(source_));
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc index a8f396c..a08976d 100644 --- a/content/browser/worker_host/worker_script_fetch_initiator.cc +++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -23,11 +23,13 @@ #include "content/browser/worker_host/worker_script_loader_factory.h" #include "content/common/content_constants_internal.h" #include "content/common/navigation_subresource_loader_params.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/resource_context.h" #include "content/public/browser/shared_cors_origin_access_list.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" @@ -62,6 +64,14 @@ resource_type == RESOURCE_TYPE_SHARED_WORKER) << resource_type; + BrowserContext* browser_context = storage_partition->browser_context(); + ResourceContext* resource_context = + browser_context ? browser_context->GetResourceContext() : nullptr; + if (!browser_context || !resource_context) { + // The browser is shutting down. Just drop this request. + return; + } + bool constructor_uses_file_url = request_initiator.scheme() == url::kFileScheme; @@ -88,12 +98,18 @@ resource_request->request_initiator = request_initiator; resource_request->resource_type = resource_type; - AddAdditionalRequestHeaders(resource_request.get(), - storage_partition->browser_context()); + AddAdditionalRequestHeaders(resource_request.get(), browser_context); } // Bounce to the IO thread to setup service worker and appcache support in // case the request for the worker script will need to be intercepted by them. + // + // This passes |resource_context| to the IO thread. |resource_context| will + // not be destroyed before the task runs, because the shutdown sequence is: + // 1. (UI thread) StoragePartitionImpl destructs. + // 2. (IO thread) ResourceContext destructs. + // Since |storage_partition| is alive, we must be before step 1, so this + // task we post to the IO thread must run before step 2. base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO}, base::BindOnce( @@ -101,7 +117,7 @@ std::move(resource_request), storage_partition->url_loader_factory_getter(), std::move(factory_bundle_for_browser), - std::move(subresource_loader_factories), + std::move(subresource_loader_factories), resource_context, std::move(service_worker_context), appcache_handle_core, blob_url_loader_factory ? blob_url_loader_factory->Clone() : nullptr, std::move(callback))); @@ -231,18 +247,21 @@ factory_bundle_for_browser_info, std::unique_ptr<blink::URLLoaderFactoryBundleInfo> subresource_loader_factories, - scoped_refptr<ServiceWorkerContextWrapper> context, + ResourceContext* resource_context, + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, AppCacheNavigationHandleCore* appcache_handle_core, std::unique_ptr<network::SharedURLLoaderFactoryInfo> blob_url_loader_factory_info, CompletionCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled()); + DCHECK(resource_context); // Set up for service worker. auto provider_info = blink::mojom::ServiceWorkerProviderInfoForWorker::New(); - base::WeakPtr<ServiceWorkerProviderHost> host = - context->PreCreateHostForSharedWorker(process_id, &provider_info); + base::WeakPtr<ServiceWorkerProviderHost> service_worker_host = + service_worker_context->PreCreateHostForSharedWorker(process_id, + &provider_info); // Create the URL loader factory for WorkerScriptLoaderFactory to use to load // the main script. @@ -289,13 +308,14 @@ base::BindRepeating([]() -> WebContents* { return nullptr; }); std::vector<std::unique_ptr<URLLoaderThrottle>> throttles = GetContentClient()->browser()->CreateURLLoaderThrottles( - *resource_request, context->resource_context(), wc_getter, + *resource_request, resource_context, wc_getter, nullptr /* navigation_ui_data */, -1 /* frame_tree_node_id */); WorkerScriptFetcher::CreateAndStart( std::make_unique<WorkerScriptLoaderFactory>( - process_id, host, std::move(appcache_host), - context->resource_context(), std::move(url_loader_factory)), + process_id, std::move(service_worker_host), + std::move(appcache_host), resource_context, + std::move(url_loader_factory)), std::move(throttles), std::move(resource_request), base::BindOnce(WorkerScriptFetchInitiator::DidCreateScriptLoaderOnIO, std::move(callback), std::move(provider_info), @@ -308,8 +328,8 @@ network::mojom::URLLoaderFactoryAssociatedPtrInfo main_script_loader_factory; mojo::MakeStrongAssociatedBinding( std::make_unique<WorkerScriptLoaderFactory>( - process_id, host->AsWeakPtr(), std::move(appcache_host), - context->resource_context(), std::move(url_loader_factory)), + process_id, std::move(service_worker_host), std::move(appcache_host), + resource_context, std::move(url_loader_factory)), mojo::MakeRequest(&main_script_loader_factory)); DidCreateScriptLoaderOnIO(std::move(callback), std::move(provider_info),
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.h b/content/browser/worker_host/worker_script_fetch_initiator.h index 8bf63d9..1d78977 100644 --- a/content/browser/worker_host/worker_script_fetch_initiator.h +++ b/content/browser/worker_host/worker_script_fetch_initiator.h
@@ -31,6 +31,7 @@ class AppCacheNavigationHandleCore; class BrowserContext; +class ResourceContext; class ServiceWorkerContextWrapper; class StoragePartitionImpl; class URLLoaderFactoryGetter; @@ -83,7 +84,8 @@ factory_bundle_for_browser_info, std::unique_ptr<blink::URLLoaderFactoryBundleInfo> subresource_loader_factories, - scoped_refptr<ServiceWorkerContextWrapper> context, + ResourceContext* resource_context, + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, AppCacheNavigationHandleCore* appcache_handle_core, std::unique_ptr<network::SharedURLLoaderFactoryInfo> blob_url_loader_factory_info,
diff --git a/content/browser/worker_host/worker_script_loader.cc b/content/browser/worker_host/worker_script_loader.cc index a5a14ff..2423559b 100644 --- a/content/browser/worker_host/worker_script_loader.cc +++ b/content/browser/worker_host/worker_script_loader.cc
@@ -239,7 +239,7 @@ void WorkerScriptLoader::OnComplete( const network::URLLoaderCompletionStatus& status) { - if (status.error_code == net::OK) + if (service_worker_provider_host_ && status.error_code == net::OK) service_worker_provider_host_->CompleteSharedWorkerPreparation(); client_->OnComplete(status); }
diff --git a/content/browser/worker_host/worker_script_loader.h b/content/browser/worker_host/worker_script_loader.h index affc0c5..0cf0badb 100644 --- a/content/browser/worker_host/worker_script_loader.h +++ b/content/browser/worker_host/worker_script_loader.h
@@ -123,7 +123,7 @@ network::ResourceRequest resource_request_; network::mojom::URLLoaderClientPtr client_; base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host_; - ResourceContext* resource_context_; + ResourceContext* const resource_context_; scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory_; net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
diff --git a/content/browser/worker_host/worker_script_loader_factory.cc b/content/browser/worker_host/worker_script_loader_factory.cc index c64846a..908379e8 100644 --- a/content/browser/worker_host/worker_script_loader_factory.cc +++ b/content/browser/worker_host/worker_script_loader_factory.cc
@@ -31,14 +31,18 @@ appcache_host_(std::move(appcache_host)), resource_context_(resource_context), loader_factory_(std::move(loader_factory)) { +#if DCHECK_IS_ON() DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled()); // In the current implementation, dedicated workers use // ServiceWorkerProviderHost w/ kForSharedWorker. // TODO(nhiroki): Rename it to kForWorker for both dedicated workers and // shared workers, or add kForDedicatedWorker (https://crbug.com/906991). - DCHECK_EQ(service_worker_provider_host_->provider_type(), - blink::mojom::ServiceWorkerProviderType::kForSharedWorker); + if (service_worker_provider_host_) { + DCHECK_EQ(service_worker_provider_host_->provider_type(), + blink::mojom::ServiceWorkerProviderType::kForSharedWorker); + } +#endif // DCHECK_IS_ON() } WorkerScriptLoaderFactory::~WorkerScriptLoaderFactory() { @@ -78,6 +82,12 @@ << resource_request.resource_type; DCHECK(!script_loader_); + // TODO(falken): There's no guarantee |resource_context_| is still valid here. + // WorkerScriptLoaderFactory needs access to an IO thread class that + // can tell it if shutdown has started (e.g., + // ServiceWorkerContextWrapper::resource_context(), though it's weird to + // depend on service worker infra for this. + // Create a WorkerScriptLoader to load the script. auto script_loader = std::make_unique<WorkerScriptLoader>( process_id_, routing_id, request_id, options, resource_request,
diff --git a/content/browser/worker_host/worker_script_loader_factory.h b/content/browser/worker_host/worker_script_loader_factory.h index 6500e3de..3344080 100644 --- a/content/browser/worker_host/worker_script_loader_factory.h +++ b/content/browser/worker_host/worker_script_loader_factory.h
@@ -29,7 +29,8 @@ // // This is created per one web worker. All functions of this class must be // called on the IO thread. -class WorkerScriptLoaderFactory : public network::mojom::URLLoaderFactory { +class CONTENT_EXPORT WorkerScriptLoaderFactory + : public network::mojom::URLLoaderFactory { public: // |loader_factory| is used to load the script if the load is not intercepted // by a feature like service worker. Typically it will load the script from @@ -37,7 +38,7 @@ // factories used for non-http(s) URLs, e.g., a chrome-extension:// URL. WorkerScriptLoaderFactory( int process_id, - base::WeakPtr<ServiceWorkerProviderHost> provider_host, + base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host, base::WeakPtr<AppCacheHost> appcache_host, ResourceContext* resource_context, scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
diff --git a/content/browser/worker_host/worker_script_loader_factory_unittest.cc b/content/browser/worker_host/worker_script_loader_factory_unittest.cc new file mode 100644 index 0000000..26c307a --- /dev/null +++ b/content/browser/worker_host/worker_script_loader_factory_unittest.cc
@@ -0,0 +1,180 @@ +// 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. + +#include "content/browser/worker_host/worker_script_loader_factory.h" + +#include "base/bind_helpers.h" +#include "base/run_loop.h" +#include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/service_worker_context_core.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "net/http/http_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_client.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { + +namespace { + +// A URLLoaderFactory that returns 200 OK with an empty javascript to any +// request. +// TODO(bashi): Avoid duplicated MockNetworkURLLoaderFactory. This is almost the +// same as EmbeddedWorkerTestHelper::MockNetworkURLLoaderFactory. +class MockNetworkURLLoaderFactory final + : public network::mojom::URLLoaderFactory { + public: + MockNetworkURLLoaderFactory() = default; + + // network::mojom::URLLoaderFactory implementation. + void CreateLoaderAndStart(network::mojom::URLLoaderRequest request, + int32_t routing_id, + int32_t request_id, + uint32_t options, + const network::ResourceRequest& url_request, + network::mojom::URLLoaderClientPtr client, + const net::MutableNetworkTrafficAnnotationTag& + traffic_annotation) override { + const std::string headers = + "HTTP/1.1 200 OK\n" + "Content-Type: application/javascript\n\n"; + net::HttpResponseInfo info; + info.headers = new net::HttpResponseHeaders( + net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + network::ResourceResponseHead response; + response.headers = info.headers; + response.headers->GetMimeType(&response.mime_type); + client->OnReceiveResponse(response); + + const std::string body = "/*this body came from the network*/"; + uint32_t bytes_written = body.size(); + mojo::DataPipe data_pipe; + data_pipe.producer_handle->WriteData(body.data(), &bytes_written, + MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); + client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle)); + + network::URLLoaderCompletionStatus status; + status.error_code = net::OK; + client->OnComplete(status); + } + + void Clone(network::mojom::URLLoaderFactoryRequest request) override { + bindings_.AddBinding(this, std::move(request)); + } + + private: + mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_; + DISALLOW_COPY_AND_ASSIGN(MockNetworkURLLoaderFactory); +}; + +} // namespace + +class WorkerScriptLoaderFactoryTest : public testing::Test { + public: + WorkerScriptLoaderFactoryTest() + : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} + ~WorkerScriptLoaderFactoryTest() override = default; + + void SetUp() override { + helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath()); + ServiceWorkerContextCore* context = helper_->context(); + context->storage()->LazyInitializeForTest(base::DoNothing()); + base::RunLoop().RunUntilIdle(); + + network_loader_factory_instance_ = + std::make_unique<MockNetworkURLLoaderFactory>(); + network::mojom::URLLoaderFactoryPtrInfo factory; + network_loader_factory_instance_->Clone(mojo::MakeRequest(&factory)); + auto info = std::make_unique<network::WrapperSharedURLLoaderFactoryInfo>( + std::move(factory)); + network_loader_factory_ = + network::SharedURLLoaderFactory::Create(std::move(info)); + } + + protected: + network::mojom::URLLoaderPtr CreateTestLoaderAndStart( + const GURL& url, + WorkerScriptLoaderFactory* factory, + network::TestURLLoaderClient* client) { + network::mojom::URLLoaderPtr loader; + network::ResourceRequest resource_request; + resource_request.url = url; + resource_request.resource_type = RESOURCE_TYPE_SHARED_WORKER; + factory->CreateLoaderAndStart( + mojo::MakeRequest(&loader), 0 /* routing_id */, 0 /* request_id */, + network::mojom::kURLLoadOptionNone, resource_request, + client->CreateInterfacePtr(), + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)); + return loader; + } + + TestBrowserThreadBundle browser_thread_bundle_; + std::unique_ptr<EmbeddedWorkerTestHelper> helper_; + std::unique_ptr<MockNetworkURLLoaderFactory> network_loader_factory_instance_; + scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory_; +}; + +TEST_F(WorkerScriptLoaderFactoryTest, ServiceWorkerProviderHost) { + // Make a service worker provider host for the shared worker. + auto service_worker_provider_info = + blink::mojom::ServiceWorkerProviderInfoForWorker::New(); + base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host = + ServiceWorkerProviderHost::PreCreateForSharedWorker( + helper_->context()->AsWeakPtr(), 1 /* process_id */, + &service_worker_provider_info); + + // Skip AppCache host as it's not worth testing. + base::WeakPtr<AppCacheHost> appcache_host; + + // Make the factory. + std::unique_ptr<WorkerScriptLoaderFactory> factory = + std::make_unique<WorkerScriptLoaderFactory>( + 1 /* process_id */, service_worker_provider_host, appcache_host, + nullptr /* resource_context */, network_loader_factory_); + + // Load the script. + GURL url("https://www.example.com/worker.js"); + network::TestURLLoaderClient client; + network::mojom::URLLoaderPtr loader = + CreateTestLoaderAndStart(url, factory.get(), &client); + client.RunUntilComplete(); + EXPECT_EQ(net::OK, client.completion_status().error_code); + + // The provider host should be set up. + EXPECT_TRUE(service_worker_provider_host->is_response_committed()); + EXPECT_TRUE(service_worker_provider_host->is_execution_ready()); + EXPECT_EQ(url, service_worker_provider_host->url()); +} + +// Test a null service worker provider host. This typically only happens during +// shutdown or after a fatal error occurred in the service worker system. +TEST_F(WorkerScriptLoaderFactoryTest, NullServiceWorkerProviderHost) { + // Use a null service worker provider host. + base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host; + + // Skip AppCache host as it's not worth testing. + base::WeakPtr<AppCacheHost> appcache_host; + + // Make the factory. + std::unique_ptr<WorkerScriptLoaderFactory> factory = + std::make_unique<WorkerScriptLoaderFactory>( + 1 /* process_id */, service_worker_provider_host, appcache_host, + nullptr /* resource_context */, network_loader_factory_); + + // Load the script. + GURL url("https://www.example.com/worker.js"); + network::TestURLLoaderClient client; + network::mojom::URLLoaderPtr loader = + CreateTestLoaderAndStart(url, factory.get(), &client); + client.RunUntilComplete(); + EXPECT_EQ(net::OK, client.completion_status().error_code); +} + +// TODO(falken): Add a test for a shared worker that's controlled by a service +// worker. + +} // namespace content
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 8b61441..9d9590e 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -484,6 +484,9 @@ WebRuntimeFeatures::EnableMimeHandlerViewInCrossProcessFrame( base::FeatureList::IsEnabled( features::kMimeHandlerViewInCrossProcessFrame)); + + if (base::FeatureList::IsEnabled(features::kUserAgentClientHint)) + WebRuntimeFeatures::EnableFeatureFromString("UserAgentClientHint", true); } } // namespace
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom index a9f2e5c..227e197 100644 --- a/content/common/renderer.mojom +++ b/content/common/renderer.mojom
@@ -15,6 +15,7 @@ import "third_party/blink/public/mojom/service_worker/embedded_worker.mojom"; import "third_party/blink/public/mojom/user_agent/user_agent_metadata.mojom"; import "ui/gfx/geometry/mojo/geometry.mojom"; +import "url/mojom/url.mojom"; struct CreateViewParams { // Renderer-wide preferences. @@ -256,7 +257,9 @@ // Tells the renderer process that it has been locked to a site (i.e., a // scheme plus eTLD+1, such as https://google.com), or to a more specific // origin. - SetIsLockedToSite(); + // TODO(nasko): Remove |lock_url| after we've gathered enough information to + // debug issues with browser-side security checks. https://crbug.com/931895. + SetIsLockedToSite(url.mojom.Url lock_url); // Tells the renderer to enable V8's memory saving mode when possible. // This is only used when site-per-process is enabled. If the process
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index e368e78..628baf4 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -150,6 +150,7 @@ "java/src/org/chromium/content/browser/SpeechRecognitionImpl.java", "java/src/org/chromium/content/browser/SyntheticGestureTarget.java", "java/src/org/chromium/content/browser/TracingControllerAndroidImpl.java", + "java/src/org/chromium/content/browser/UiConstants.java", "java/src/org/chromium/content/browser/UiThreadTaskTraitsImpl.java", "java/src/org/chromium/content/browser/ViewEventSinkImpl.java", "java/src/org/chromium/content/browser/WindowEventObserver.java", @@ -401,6 +402,7 @@ "java/src/org/chromium/content/browser/SyntheticGestureTarget.java", "java/src/org/chromium/content/browser/TracingControllerAndroidImpl.java", "java/src/org/chromium/content/browser/TtsPlatformImpl.java", + "java/src/org/chromium/content/browser/UiConstants.java", "java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityState.java", "java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java", "java/src/org/chromium/content/browser/accessibility/captioning/CaptioningController.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/UiConstants.java b/content/public/android/java/src/org/chromium/content/browser/UiConstants.java new file mode 100644 index 0000000..5234dcc --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/UiConstants.java
@@ -0,0 +1,81 @@ +// 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.content.browser; + +import org.chromium.base.Log; +import org.chromium.base.ThreadUtils; +import org.chromium.base.annotations.CalledByNative; + +/** + * Platform-provided UI constants. + */ +public class UiConstants { + private static final String TAG = "UiConstants"; + private static final String UI_CONSTANTS_INTERNAL = + "org.chromium.content.browser.UiConstantsInternal"; + private static UiConstants sInstance; + + private static UiConstants getInstance() { + ThreadUtils.assertOnUiThread(); + if (sInstance != null) return sInstance; + try { + sInstance = (UiConstants) Class.forName(UI_CONSTANTS_INTERNAL).newInstance(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException + | IllegalArgumentException e) { + Log.w(TAG, "Could not summon UiConstantsInternal", e); + sInstance = new UiConstants(); + } + return sInstance; + } + + @CalledByNative + private static boolean isFocusRingOutset() { + return getInstance().isFocusRingOutsetInternal(); + } + + @CalledByNative + private static boolean hasCustomFocusRingColor() { + return getInstance().hasCustomFocusRingColorInternal(); + } + + @CalledByNative + private static int getFocusRingColor() { + return getInstance().getFocusRingColorInternal(); + } + + @CalledByNative + private static boolean hasCustomMinimumStrokeWidthForFocusRing() { + return getInstance().hasCustomMinimumStrokeWidthForFocusRingInternal(); + } + + @CalledByNative + private static float getMinimumStrokeWidthForFocusRing() { + return getInstance().getMinimumStrokeWidthForFocusRingInternal(); + } + + protected UiConstants() {} + + protected boolean isFocusRingOutsetInternal() { + return false; + } + + protected boolean hasCustomFocusRingColorInternal() { + return false; + } + + protected int getFocusRingColorInternal() { + assert false; + return 0; + } + + protected boolean hasCustomMinimumStrokeWidthForFocusRingInternal() { + return false; + } + + protected float getMinimumStrokeWidthForFocusRingInternal() { + assert false; + return 1.0f; + } +}
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index 61b18ad..b1aa57b 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn
@@ -249,6 +249,8 @@ "render_widget_host_iterator.h", "render_widget_host_view.h", "render_widget_host_view_mac_delegate.h", + "renderer_preferences_util.cc", + "renderer_preferences_util.h", "replaced_navigation_entry_data.h", "resource_context.h", "resource_dispatcher_host.h",
diff --git a/content/public/browser/overlay_window.h b/content/public/browser/overlay_window.h index 64eadcaf..3ae666d 100644 --- a/content/public/browser/overlay_window.h +++ b/content/public/browser/overlay_window.h
@@ -61,6 +61,7 @@ virtual void SetAlwaysHidePlayPauseButton(bool is_visible) = 0; virtual void SetSkipAdButtonVisibility(bool is_visible) = 0; virtual void SetNextTrackButtonVisibility(bool is_visible) = 0; + virtual void SetPreviousTrackButtonVisibility(bool is_visible) = 0; // Retrieves the ui::Layers corresponding to the window and video. virtual ui::Layer* GetWindowBackgroundLayer() = 0;
diff --git a/content/public/browser/picture_in_picture_window_controller.h b/content/public/browser/picture_in_picture_window_controller.h index bd1595e5..ec7807fb 100644 --- a/content/public/browser/picture_in_picture_window_controller.h +++ b/content/public/browser/picture_in_picture_window_controller.h
@@ -73,6 +73,9 @@ // Called when the user interacts with the "Next Track" control. virtual void NextTrack() = 0; + // Called when the user interacts with the "Previous Track" control. + virtual void PreviousTrack() = 0; + // Commands. // Returns true if the player is active (i.e. currently playing) after this // call.
diff --git a/content/public/browser/renderer_preferences_util.cc b/content/public/browser/renderer_preferences_util.cc new file mode 100644 index 0000000..b7de4425 --- /dev/null +++ b/content/public/browser/renderer_preferences_util.cc
@@ -0,0 +1,51 @@ +// 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. + +#include "content/public/browser/renderer_preferences_util.h" + +#include "base/command_line.h" +#include "base/no_destructor.h" +#include "base/strings/string_number_conversions.h" +#include "build/build_config.h" +#include "content/public/common/content_switches.h" +#include "third_party/blink/public/mojom/renderer_preferences.mojom.h" +#include "ui/gfx/font_render_params.h" + +#if defined(OS_ANDROID) +#include "content/browser/android/android_ui_constants.h" +#endif + +namespace content { + +void UpdateFontRendererPreferencesFromSystemSettings( + blink::mojom::RendererPreferences* prefs) { + static const base::NoDestructor<gfx::FontRenderParams> params( + gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr)); + prefs->should_antialias_text = params->antialiasing; + prefs->use_subpixel_positioning = params->subpixel_positioning; + prefs->hinting = params->hinting; + prefs->use_autohinter = params->autohinter; + prefs->use_bitmaps = params->use_bitmaps; + prefs->subpixel_rendering = params->subpixel_rendering; +} + +void UpdateFocusRingPreferencesFromSystemSettings( + blink::mojom::RendererPreferences* prefs) { +#if defined(OS_ANDROID) + prefs->is_focus_ring_outset = AndroidUiConstants::IsFocusRingOutset(); + + base::Optional<float> stroke_width = + AndroidUiConstants::GetMinimumStrokeWidthForFocusRing(); + if (stroke_width) + prefs->minimum_stroke_width_for_focus_ring = *stroke_width; + + base::Optional<SkColor> color = AndroidUiConstants::GetFocusRingColor(); + if (color) { + prefs->use_custom_colors = true; + prefs->focus_ring_color = *color; + } +#endif +} + +} // namespace content
diff --git a/content/public/common/renderer_preferences_util.h b/content/public/browser/renderer_preferences_util.h similarity index 62% rename from content/public/common/renderer_preferences_util.h rename to content/public/browser/renderer_preferences_util.h index e1fbe6d9..bfd5be8 100644 --- a/content/public/common/renderer_preferences_util.h +++ b/content/public/browser/renderer_preferences_util.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_PUBLIC_COMMON_RENDERER_PREFERENCES_UTIL_H_ -#define CONTENT_PUBLIC_COMMON_RENDERER_PREFERENCES_UTIL_H_ +#ifndef CONTENT_PUBLIC_BROWSER_RENDERER_PREFERENCES_UTIL_H_ +#define CONTENT_PUBLIC_BROWSER_RENDERER_PREFERENCES_UTIL_H_ #include "content/common/content_export.h" @@ -19,6 +19,9 @@ CONTENT_EXPORT void UpdateFontRendererPreferencesFromSystemSettings( blink::mojom::RendererPreferences* prefs); +CONTENT_EXPORT void UpdateFocusRingPreferencesFromSystemSettings( + blink::mojom::RendererPreferences* prefs); + } // namespace content -#endif // CONTENT_PUBLIC_COMMON_RENDERER_PREFERENCES_UTIL_H_ +#endif // CONTENT_PUBLIC_BROWSER_RENDERER_PREFERENCES_UTIL_H_
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn index 1e89170e..22adef2 100644 --- a/content/public/common/BUILD.gn +++ b/content/public/common/BUILD.gn
@@ -184,8 +184,6 @@ "referrer.h", "referrer_type_converters.cc", "referrer_type_converters.h", - "renderer_preferences_util.cc", - "renderer_preferences_util.h", "resource_intercept_policy.h", "resource_request_body_android.cc", "resource_request_body_android.h",
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h index 37693ee..8db2b82 100644 --- a/content/public/common/common_param_traits_macros.h +++ b/content/public/common/common_param_traits_macros.h
@@ -305,6 +305,10 @@ IPC_STRUCT_TRAITS_MEMBER(subpixel_rendering) IPC_STRUCT_TRAITS_MEMBER(use_subpixel_positioning) IPC_STRUCT_TRAITS_MEMBER(focus_ring_color) +#if defined(OS_ANDROID) + IPC_STRUCT_TRAITS_MEMBER(minimum_stroke_width_for_focus_ring) + IPC_STRUCT_TRAITS_MEMBER(is_focus_ring_outset) +#endif IPC_STRUCT_TRAITS_MEMBER(active_selection_bg_color) IPC_STRUCT_TRAITS_MEMBER(active_selection_fg_color) IPC_STRUCT_TRAITS_MEMBER(inactive_selection_bg_color)
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 8f69d78..cb2213e 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -498,6 +498,11 @@ const base::Feature kUserActivationV2{"UserActivationV2", base::FEATURE_ENABLED_BY_DEFAULT}; +// An experimental replacement for the `User-Agent` header, defined in +// https://tools.ietf.org/html/draft-west-ua-client-hints. +const base::Feature kUserAgentClientHint{"UserAgentClientHint", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables V8's low memory mode for subframes. This is used only // in conjunction with the --site-per-process feature. const base::Feature kV8LowMemoryModeForSubframes{
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index b57a897..9a957af 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -120,6 +120,7 @@ CONTENT_EXPORT extern const base::Feature kTouchpadOverscrollHistoryNavigation; CONTENT_EXPORT extern const base::Feature kUserActivationSameOriginVisibility; CONTENT_EXPORT extern const base::Feature kUserActivationV2; +CONTENT_EXPORT extern const base::Feature kUserAgentClientHint; CONTENT_EXPORT extern const base::Feature kV8LowMemoryModeForSubframes; CONTENT_EXPORT extern const base::Feature kV8Orinoco; CONTENT_EXPORT extern const base::Feature kV8VmFuture;
diff --git a/content/public/common/renderer_preferences_util.cc b/content/public/common/renderer_preferences_util.cc deleted file mode 100644 index d4e4226..0000000 --- a/content/public/common/renderer_preferences_util.cc +++ /dev/null
@@ -1,25 +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. - -#include "content/public/common/renderer_preferences_util.h" - -#include "base/no_destructor.h" -#include "third_party/blink/public/mojom/renderer_preferences.mojom.h" -#include "ui/gfx/font_render_params.h" - -namespace content { - -void UpdateFontRendererPreferencesFromSystemSettings( - blink::mojom::RendererPreferences* prefs) { - static const base::NoDestructor<gfx::FontRenderParams> params( - gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr)); - prefs->should_antialias_text = params->antialiasing; - prefs->use_subpixel_positioning = params->subpixel_positioning; - prefs->hinting = params->hinting; - prefs->use_autohinter = params->autohinter; - prefs->use_bitmaps = params->use_bitmaps; - prefs->subpixel_rendering = params->subpixel_rendering; -} - -} // namespace content
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc index ef22a325..ec9e4e8 100644 --- a/content/renderer/loader/web_url_loader_impl.cc +++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -176,37 +176,6 @@ } } -// Extracts info from a data scheme URL |url| into |info| and |data|. Returns -// net::OK if successful. Returns a net error code otherwise. -int GetInfoFromDataURL(const GURL& url, - network::ResourceResponseInfo* info, - std::string* data) { - // Assure same time for all time fields of data: URLs. - Time now = Time::Now(); - info->load_timing.request_start = TimeTicks::Now(); - info->load_timing.request_start_time = now; - info->request_time = now; - info->response_time = now; - - std::string mime_type; - std::string charset; - scoped_refptr<net::HttpResponseHeaders> headers( - new net::HttpResponseHeaders(std::string())); - int result = net::URLRequestDataJob::BuildResponse( - url, &mime_type, &charset, data, headers.get()); - if (result != net::OK) - return result; - - info->headers = headers; - info->mime_type.swap(mime_type); - info->charset.swap(charset); - info->content_length = data->length(); - info->encoded_data_length = 0; - info->encoded_body_length = 0; - - return net::OK; -} - // Convert a net::SignedCertificateTimestampAndStatus object to a // blink::WebURLResponse::SignedCertificateTimestamp object. blink::WebURLResponse::SignedCertificateTimestamp NetSCTToBlinkSCT( @@ -451,7 +420,6 @@ void CancelBodyStreaming(); // We can optimize the handling of data URLs in most cases. bool CanHandleDataURLRequestLocally(const WebURLRequest& request) const; - void HandleDataURL(); void OnBodyAvailable(MojoResult, const mojo::HandleSignalsState&); void OnBodyHasBeenRead(uint32_t read_bytes); @@ -483,7 +451,7 @@ scoped_refptr<base::SingleThreadTaskRunner> task_runner_; std::unique_ptr<SharedMemoryDataConsumerHandle::Writer> body_stream_writer_; mojom::KeepAliveHandlePtr keep_alive_handle_; - enum DeferState {NOT_DEFERRING, SHOULD_DEFER, DEFERRED_DATA}; + enum DeferState { NOT_DEFERRING, SHOULD_DEFER }; DeferState defers_loading_; int request_id_; @@ -606,10 +574,6 @@ if (value && defers_loading_ == NOT_DEFERRING) { defers_loading_ = SHOULD_DEFER; } else if (!value && defers_loading_ != NOT_DEFERRING) { - if (defers_loading_ == DEFERRED_DATA) { - task_runner_->PostTask(FROM_HERE, - base::BindOnce(&Context::HandleDataURL, this)); - } defers_loading_ = NOT_DEFERRING; if (body_watcher_.IsWatching()) { @@ -644,19 +608,9 @@ report_raw_headers_ = request.ReportRawHeaders(); pass_response_pipe_to_client_ = request.PassResponsePipeToClient(); - if (CanHandleDataURLRequestLocally(request)) { - if (sync_load_response) { - // This is a sync load. Do the work now. - sync_load_response->url = url_; - sync_load_response->error_code = - GetInfoFromDataURL(sync_load_response->url, &sync_load_response->info, - &sync_load_response->data); - } else { - task_runner_->PostTask(FROM_HERE, - base::BindOnce(&Context::HandleDataURL, this)); - } - return; - } + // TODO(https://crbug.com/923779): Remove this once after we can confirm it's + // working well. + CHECK(!CanHandleDataURLRequestLocally(request)); std::unique_ptr<NavigationResponseOverrideParameters> response_override; if (request.GetExtraData()) { @@ -1034,31 +988,6 @@ return false; } -void WebURLLoaderImpl::Context::HandleDataURL() { - DCHECK_NE(defers_loading_, DEFERRED_DATA); - if (defers_loading_ == SHOULD_DEFER) { - defers_loading_ = DEFERRED_DATA; - return; - } - - network::ResourceResponseInfo info; - std::string data; - - int error_code = GetInfoFromDataURL(url_, &info, &data); - - if (error_code == net::OK) { - OnReceivedResponse(info); - auto size = data.size(); - if (size != 0) - OnReceivedData(std::make_unique<FixedReceivedData>(data.data(), size)); - } - - network::URLLoaderCompletionStatus status(error_code); - status.encoded_body_length = data.size(); - status.decoded_body_length = data.size(); - OnCompletedRequest(status); -} - void WebURLLoaderImpl::Context::OnBodyAvailable( MojoResult, const mojo::HandleSignalsState&) {
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc index be11f44..74b75758d 100644 --- a/content/renderer/loader/web_url_loader_impl_unittest.cc +++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -503,90 +503,6 @@ DoFailRequest(); } -TEST_P(WebURLLoaderImplTest, DeleteBeforeResponseDataURL) { - blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); - client()->loader()->LoadAsynchronously(request, client()); - client()->DeleteLoader(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(client()->did_receive_response()); -} - -// Data URL tests. - -TEST_P(WebURLLoaderImplTest, DataURL) { - blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); - client()->loader()->LoadAsynchronously(request, client()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ("blah!", client()->received_data()); - EXPECT_TRUE(client()->did_finish()); - EXPECT_FALSE(client()->error()); -} - -TEST_P(WebURLLoaderImplTest, DataURLDeleteOnReceiveResponse) { - blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); - client()->set_delete_on_receive_response(); - client()->loader()->LoadAsynchronously(request, client()); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(client()->did_receive_response()); - EXPECT_EQ("", client()->received_data()); - EXPECT_FALSE(client()->did_finish()); -} - -TEST_P(WebURLLoaderImplTest, DataURLDeleteOnReceiveData) { - blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); - client()->set_delete_on_receive_data(); - client()->loader()->LoadAsynchronously(request, client()); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(client()->did_receive_response()); - EXPECT_EQ("blah!", client()->received_data()); - EXPECT_FALSE(client()->did_finish()); -} - -TEST_P(WebURLLoaderImplTest, DataURLDeleteOnFinish) { - blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); - client()->set_delete_on_finish(); - client()->loader()->LoadAsynchronously(request, client()); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(client()->did_receive_response()); - EXPECT_EQ("blah!", client()->received_data()); - EXPECT_TRUE(client()->did_finish()); -} - -TEST_P(WebURLLoaderImplTest, DataURLDefersLoading) { - blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); - client()->loader()->LoadAsynchronously(request, client()); - - // setDefersLoading() might be called with either false or true in no - // specific order. The user of the API will not have sufficient information - // about the WebURLLoader's internal state, so the latter gracefully needs to - // handle calling setDefersLoading any number of times with any values from - // any point in time. - - client()->loader()->SetDefersLoading(false); - client()->loader()->SetDefersLoading(true); - client()->loader()->SetDefersLoading(true); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(client()->did_finish()); - - client()->loader()->SetDefersLoading(false); - client()->loader()->SetDefersLoading(true); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(client()->did_finish()); - - client()->loader()->SetDefersLoading(false); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(client()->did_finish()); - - client()->loader()->SetDefersLoading(true); - client()->loader()->SetDefersLoading(false); - client()->loader()->SetDefersLoading(false); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(client()->did_finish()); - - EXPECT_EQ("blah!", client()->received_data()); - EXPECT_FALSE(client()->error()); -} - TEST_P(WebURLLoaderImplTest, DefersLoadingBeforeStart) { client()->loader()->SetDefersLoading(true); EXPECT_FALSE(dispatcher()->defers_loading());
diff --git a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc index 534b792..6023862 100644 --- a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc +++ b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
@@ -572,12 +572,6 @@ void RemoveTextTrack(blink::WebInbandTextTrack*) override {} void MediaSourceOpened(blink::WebMediaSource*) override {} void RequestSeek(double) override {} - void RemoteRouteAvailabilityChanged( - blink::WebRemotePlaybackAvailability) override {} - void ConnectedToRemoteDevice() override {} - void DisconnectedFromRemoteDevice() override {} - void CancelledRemotePlaybackRequest() override {} - void RemotePlaybackStarted() override {} void RemotePlaybackCompatibilityChanged(const blink::WebURL& url, bool is_compatible) override {} void OnBecamePersistentVideo(bool) override {}
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 104e48a..79b954f 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -5948,15 +5948,38 @@ DCHECK(!(was_within_same_document && interface_params)); UpdateStateForCommit(item, commit_type, transition); + auto params = MakeDidCommitProvisionalLoadParams(commit_type, transition); + + // If this is a regular commit, not an error page, the URL that was just + // committed must match the process lock, if there is one. Verify it here, to + // get a stack trace for a bug where this seems to be occurring. + // TODO(nasko): Remove this check after we've gathered enough information to + // debug issues with browser-side security checks. https://crbug.com/931895. + RenderThreadImpl* render_thread = RenderThreadImpl::current(); + const GURL* lock_url = + render_thread ? render_thread->site_lock_url() : nullptr; + if (!params->url_is_unreachable && lock_url && + lock_url->scheme() == params->url.scheme() && + lock_url->SchemeIsHTTPOrHTTPS() && !params->url.HostIsIPAddress() && + !lock_url->HostIsIPAddress()) { + std::string lock_domain = + net::registry_controlled_domains::GetDomainAndRegistry( + lock_url->host(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); + std::string commit_domain = + net::registry_controlled_domains::GetDomainAndRegistry( + params->url.host(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); + CHECK_EQ(lock_domain, commit_domain); + } + // This invocation must precede any calls to allowScripts(), allowImages(), or // allowPlugins() for the new page. This ensures that when these functions // send ViewHostMsg_ContentBlocked messages, those arrive after the browser // process has already been informed of the provisional load committing. if (was_within_same_document) { - GetFrameHost()->DidCommitSameDocumentNavigation( - MakeDidCommitProvisionalLoadParams(commit_type, transition)); + GetFrameHost()->DidCommitSameDocumentNavigation(std::move(params)); } else { - auto params = MakeDidCommitProvisionalLoadParams(commit_type, transition); NavigationState* navigation_state = NavigationState::FromDocumentLoader(frame_->GetDocumentLoader()); if (navigation_state->uses_per_navigation_mojo_interface()) {
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index b5669f9..35759ddd 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -1722,9 +1722,10 @@ base::TimeDelta::FromMinutes(90)); } -void RenderThreadImpl::SetIsLockedToSite() { +void RenderThreadImpl::SetIsLockedToSite(const GURL& lock_url) { DCHECK(blink_platform_impl_); blink_platform_impl_->SetIsLockedToSite(); + site_lock_url_ = std::make_unique<GURL>(lock_url); } void RenderThreadImpl::EnableV8LowMemoryMode() {
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index 579131f..7b0b08e1 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h
@@ -510,6 +510,10 @@ video_frame_compositor_task_runner_ = task_runner; } + // TODO(nasko): Remove after we've gathered enough information to debug issues + // with browser-side security checks. https://crbug.com/931895. + const GURL* site_lock_url() { return site_lock_url_.get(); } + private: void OnProcessFinalRelease() override; // IPC::Listener @@ -565,7 +569,7 @@ void SetProcessBackgrounded(bool backgrounded) override; void SetSchedulerKeepActive(bool keep_active) override; void ProcessPurgeAndSuspend() override; - void SetIsLockedToSite() override; + void SetIsLockedToSite(const GURL& lock_url) override; void EnableV8LowMemoryMode() override; void OnMemoryPressure( @@ -767,6 +771,11 @@ mojo::Binding<viz::mojom::CompositingModeWatcher> compositing_mode_watcher_binding_; + // TODO(nasko): Temporary diagnostic member, holding the site URL this process + // is locked to. Remove after we've gathered enough information to + // debug issues with browser-side security checks. https://crbug.com/931895. + std::unique_ptr<GURL> site_lock_url_; + base::WeakPtrFactory<RenderThreadImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(RenderThreadImpl);
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 2d0908f..89983ab 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -1935,6 +1935,16 @@ } #endif // BUILDFLAG(USE_DEFAULT_RENDER_THEME) +#if defined(OS_ANDROID) + if (renderer_prefs.use_custom_colors) + blink::SetFocusRingColor(renderer_prefs.focus_ring_color); + + blink::SetMinimumStrokeWidthForFocusRing( + renderer_prefs.minimum_stroke_width_for_focus_ring); + + blink::SetIsFocusRingOutset(renderer_prefs.is_focus_ring_outset); +#endif + if (webview() && old_accept_languages != renderer_preferences_.accept_languages) { webview()->AcceptLanguagesChanged();
diff --git a/content/shell/browser/web_test/web_test_content_browser_client.cc b/content/shell/browser/web_test/web_test_content_browser_client.cc index 2c52e0e4..cb39a60 100644 --- a/content/shell/browser/web_test/web_test_content_browser_client.cc +++ b/content/shell/browser/web_test/web_test_content_browser_client.cc
@@ -79,6 +79,7 @@ void SetAlwaysHidePlayPauseButton(bool is_visible) override {} void SetSkipAdButtonVisibility(bool is_visible) override {} void SetNextTrackButtonVisibility(bool is_visible) override {} + void SetPreviousTrackButtonVisibility(bool is_visible) override {} ui::Layer* GetWindowBackgroundLayer() override { return nullptr; } ui::Layer* GetVideoLayer() override { return nullptr; } gfx::Rect GetVideoBounds() override { return gfx::Rect(); }
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 7e9da36..2ddd6a03 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1697,6 +1697,7 @@ "../browser/worker_host/shared_worker_host_unittest.cc", "../browser/worker_host/shared_worker_instance_unittest.cc", "../browser/worker_host/shared_worker_service_impl_unittest.cc", + "../browser/worker_host/worker_script_loader_factory_unittest.cc", "../child/blink_platform_impl_unittest.cc", "../child/dwrite_font_proxy/dwrite_font_proxy_win_unittest.cc", "../child/dwrite_font_proxy/font_fallback_win_unittest.cc",
diff --git a/content/test/test_background_sync_context.cc b/content/test/test_background_sync_context.cc index 8b8e56a5..82d4029 100644 --- a/content/test/test_background_sync_context.cc +++ b/content/test/test_background_sync_context.cc
@@ -4,7 +4,8 @@ #include "content/test/test_background_sync_context.h" -#include "base/memory/ptr_util.h" +#include <memory> + #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/public/browser/browser_thread.h" #include "content/test/test_background_sync_manager.h" @@ -16,9 +17,8 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(!background_sync_manager()); - TestBackgroundSyncManager* manager = new TestBackgroundSyncManager(context); set_background_sync_manager_for_testing( - base::WrapUnique<BackgroundSyncManager>(manager)); + std::make_unique<TestBackgroundSyncManager>(context)); } } // namespace content
diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc index 2403e178..64a3131 100644 --- a/fuchsia/engine/browser/frame_impl.cc +++ b/fuchsia/engine/browser/frame_impl.cc
@@ -16,8 +16,8 @@ #include "content/public/browser/message_port_provider.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_handle.h" +#include "content/public/browser/renderer_preferences_util.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/renderer_preferences_util.h" #include "content/public/common/was_activated_option.h" #include "fuchsia/base/mem_buffer_util.h" #include "fuchsia/engine/browser/context_impl.h"
diff --git a/google_apis/drive/files_list_request_runner.cc b/google_apis/drive/files_list_request_runner.cc index 3b7d9f2..8b25e1c 100644 --- a/google_apis/drive/files_list_request_runner.cc +++ b/google_apis/drive/files_list_request_runner.cc
@@ -33,8 +33,6 @@ const std::string& q, const std::string& fields, const FileListCallback& callback) { - UMA_HISTOGRAM_COUNTS_1000("Drive.FilesListRequestRunner.MaxResults", - max_results); base::Closure* const cancel_callback = new base::Closure; std::unique_ptr<drive::FilesListRequest> request = std::make_unique<drive::FilesListRequest>( @@ -74,8 +72,6 @@ if (!request_completed_callback_for_testing_.is_null()) request_completed_callback_for_testing_.Run(); - base::UmaHistogramSparse("Drive.FilesListRequestRunner.ApiErrorCode", error); - if (error == google_apis::DRIVE_RESPONSE_TOO_LARGE && max_results > 1) { CreateAndStartWithSizeBackoff(max_results / 2, corpora, team_drive_id, q, fields, callback);
diff --git a/google_apis/gaia/oauth2_token_service_delegate.h b/google_apis/gaia/oauth2_token_service_delegate.h index e49edad..a8c4135 100644 --- a/google_apis/gaia/oauth2_token_service_delegate.h +++ b/google_apis/gaia/oauth2_token_service_delegate.h
@@ -126,6 +126,12 @@ // and false otherwise. virtual bool FixRequestErrorIfPossible(); +#if defined(OS_IOS) + // Triggers platform specific implementation for IOS to add a given account + // to the token service from a system account. + virtual void AddAccountFromSystem(const std::string& account_id) {} +#endif + #if defined(OS_ANDROID) || defined(OS_IOS) // Triggers platform specific implementation for Android and IOS to reload // accounts from system.
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm index 23ceb76..f3c948d 100644 --- a/ios/chrome/browser/about_flags.mm +++ b/ios/chrome/browser/about_flags.mm
@@ -558,6 +558,9 @@ flag_descriptions::kBrowserContainerKeepsContentViewName, flag_descriptions::kBrowserContainerKeepsContentViewDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kBrowserContainerKeepsContentView)}, + {"web-clear-browsing-data", flag_descriptions::kWebClearBrowsingDataName, + flag_descriptions::kWebClearBrowsingDataDescription, flags_ui::kOsIos, + FEATURE_VALUE_TYPE(experimental_flags::kWebClearBrowsingData)}, }; // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/autofill/form_input_accessory_view_handler.mm b/ios/chrome/browser/autofill/form_input_accessory_view_handler.mm index 4781820..b8fce9c 100644 --- a/ios/chrome/browser/autofill/form_input_accessory_view_handler.mm +++ b/ios/chrome/browser/autofill/form_input_accessory_view_handler.mm
@@ -226,7 +226,7 @@ NSString* actionName = autofill::kFormSuggestionAssistButtonDone; BOOL performedAction = [self executeFormAssistAction:actionName]; - if (!performedAction) { + if (!performedAction && [_lastFocusFormActivityWebFrameID length]) { // We could not find the built-in form assist controls, so try to focus // the next or previous control using JavaScript. [_JSSuggestionManager
diff --git a/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm b/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm index 3287aa4e..3844849 100644 --- a/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm +++ b/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm
@@ -20,6 +20,7 @@ #import "ios/chrome/browser/ui/autofill/form_input_accessory_mediator.h" #include "ios/chrome/browser/ui/util/ui_util.h" #import "ios/web/public/navigation_manager.h" +#include "ios/web/public/test/fakes/fake_web_frame.h" #import "ios/web/public/test/fakes/test_web_state.h" #include "ios/web/public/test/test_web_thread_bundle.h" #import "ios/web/public/web_state/ui/crw_web_view_proxy.h" @@ -255,7 +256,9 @@ TEST_F(FormSuggestionControllerTest, PageLoadShouldRestoreKeyboardAccessoryViewAndInjectJavaScript) { SetUpController(@[ [TestSuggestionProvider providerWithSuggestions] ]); - test_web_state_.SetCurrentURL(GURL("http://foo.com")); + GURL url("http://foo.com"); + test_web_state_.SetCurrentURL(url); + web::FakeWebFrame main_frame("main_frame", /*is_main_frame=*/true, url); // Trigger form activity, which should set up the suggestions view. autofill::FormActivityParams params; @@ -265,8 +268,7 @@ params.type = "type"; params.value = "value"; params.input_missing = false; - test_form_activity_tab_helper_.FormActivityRegistered( - /*sender_frame*/ nullptr, params); + test_form_activity_tab_helper_.FormActivityRegistered(&main_frame, params); EXPECT_TRUE(received_suggestions_.count); // Trigger another page load. The suggestions should not be present. @@ -277,6 +279,9 @@ // Tests that "blur" events are ignored. TEST_F(FormSuggestionControllerTest, FormActivityBlurShouldBeIgnored) { SetUpController(@[ [TestSuggestionProvider providerWithSuggestions] ]); + GURL url("http://foo.com"); + test_web_state_.SetCurrentURL(url); + web::FakeWebFrame main_frame("main_frame", true, url); autofill::FormActivityParams params; params.form_name = "form"; @@ -285,8 +290,7 @@ params.type = "blur"; // blur! params.value = "value"; params.input_missing = false; - test_form_activity_tab_helper_.FormActivityRegistered( - /*sender_frame*/ nullptr, params); + test_form_activity_tab_helper_.FormActivityRegistered(&main_frame, params); EXPECT_FALSE(received_suggestions_.count); } @@ -295,7 +299,10 @@ FormActivityShouldRetrieveSuggestions_NoProvidersAvailable) { // Set up the controller without any providers. SetUpController(@[]); - test_web_state_.SetCurrentURL(GURL("http://foo.com")); + GURL url("http://foo.com"); + test_web_state_.SetCurrentURL(url); + web::FakeWebFrame main_frame("main_frame", true, url); + autofill::FormActivityParams params; params.form_name = "form"; params.field_identifier = "field_id"; @@ -303,8 +310,7 @@ params.type = "type"; params.value = "value"; params.input_missing = false; - test_form_activity_tab_helper_.FormActivityRegistered( - /*sender_frame*/ nullptr, params); + test_form_activity_tab_helper_.FormActivityRegistered(&main_frame, params); // The suggestions should be empty. EXPECT_TRUE(received_suggestions_); @@ -322,7 +328,9 @@ TestSuggestionProvider* provider2 = [[TestSuggestionProvider alloc] initWithSuggestions:@[]]; SetUpController(@[ provider1, provider2 ]); - test_web_state_.SetCurrentURL(GURL("http://foo.com")); + GURL url("http://foo.com"); + test_web_state_.SetCurrentURL(url); + web::FakeWebFrame main_frame("main_frame", true, url); autofill::FormActivityParams params; params.form_name = "form"; @@ -331,8 +339,7 @@ params.type = "type"; params.value = "value"; params.input_missing = false; - test_form_activity_tab_helper_.FormActivityRegistered( - /*sender_frame*/ nullptr, params); + test_form_activity_tab_helper_.FormActivityRegistered(&main_frame, params); // The providers should each be asked if they have suggestions for the // form in question. @@ -370,7 +377,9 @@ TestSuggestionProvider* provider2 = [[TestSuggestionProvider alloc] initWithSuggestions:@[]]; SetUpController(@[ provider1, provider2 ]); - test_web_state_.SetCurrentURL(GURL("http://foo.com")); + GURL url("http://foo.com"); + test_web_state_.SetCurrentURL(url); + web::FakeWebFrame main_frame("main_frame", true, url); autofill::FormActivityParams params; params.form_name = "form"; @@ -379,8 +388,7 @@ params.type = "type"; params.value = "value"; params.input_missing = false; - test_form_activity_tab_helper_.FormActivityRegistered( - /*sender_frame*/ nullptr, params); + test_form_activity_tab_helper_.FormActivityRegistered(&main_frame, params); // Since the first provider has suggestions available, it and only it // should have been asked. @@ -410,7 +418,10 @@ TestSuggestionProvider* provider = [[TestSuggestionProvider alloc] initWithSuggestions:suggestions]; SetUpController(@[ provider ]); - test_web_state_.SetCurrentURL(GURL("http://foo.com")); + GURL url("http://foo.com"); + test_web_state_.SetCurrentURL(url); + web::FakeWebFrame main_frame("main_frame", true, url); + autofill::FormActivityParams params; params.form_name = "form"; params.field_identifier = "field_id"; @@ -419,8 +430,7 @@ params.value = "value"; params.frame_id = "frame_id"; params.input_missing = false; - test_form_activity_tab_helper_.FormActivityRegistered( - /*sender_frame*/ nullptr, params); + test_form_activity_tab_helper_.FormActivityRegistered(&main_frame, params); // Selecting a suggestion should notify the delegate. [suggestion_controller_ didSelectSuggestion:suggestions[0]];
diff --git a/ios/chrome/browser/autofill/js_suggestion_manager_unittest.mm b/ios/chrome/browser/autofill/js_suggestion_manager_unittest.mm index 22457ba..d090d2b 100644 --- a/ios/chrome/browser/autofill/js_suggestion_manager_unittest.mm +++ b/ios/chrome/browser/autofill/js_suggestion_manager_unittest.mm
@@ -40,6 +40,13 @@ NSString* GetActiveElementName() { return ExecuteJavaScript(@"document.activeElement.name"); } + // Waits until the active element is |name|. + BOOL WaitUntilElementSelected(NSString* name) { + return base::test::ios::WaitUntilConditionOrTimeout( + base::test::ios::kWaitForJSCompletionTimeout, ^bool { + return [GetActiveElementName() isEqualToString:name]; + }); + } JsSuggestionManager* manager_; }; @@ -230,7 +237,7 @@ ExecuteJavaScript(@"document.getElementsByName('firstname')[0].focus()"); [manager_ selectNextElementInFrameWithID:GetFrameIdForMainFrame()]; - EXPECT_NSEQ(@"lastname", GetActiveElementName()); + EXPECT_TRUE(WaitUntilElementSelected(@"lastname")); __block BOOL block_was_called = NO; [manager_ fetchPreviousAndNextElementsPresenceInFrameWithID:GetFrameIdForMainFrame() @@ -245,9 +252,9 @@ return block_was_called; }); [manager_ selectNextElementInFrameWithID:GetFrameIdForMainFrame()]; - EXPECT_NSEQ(@"email", GetActiveElementName()); + EXPECT_TRUE(WaitUntilElementSelected(@"email")); [manager_ selectPreviousElementInFrameWithID:GetFrameIdForMainFrame()]; - EXPECT_NSEQ(@"lastname", GetActiveElementName()); + EXPECT_TRUE(WaitUntilElementSelected(@"lastname")); } void JsSuggestionManagerTest::SequentialNavigationSkipCheck(NSString* attribute, @@ -262,11 +269,10 @@ ExecuteJavaScript(@"document.getElementsByName('firstname')[0].focus()"); EXPECT_NSEQ(@"firstname", GetActiveElementName()); [manager_ selectNextElementInFrameWithID:GetFrameIdForMainFrame()]; - NSString* activeElementNameJS = GetActiveElementName(); if (shouldSkip) - EXPECT_NSEQ(@"lastname", activeElementNameJS); + EXPECT_TRUE(WaitUntilElementSelected(@"lastname")); else - EXPECT_NSEQ(@"middlename", activeElementNameJS); + EXPECT_TRUE(WaitUntilElementSelected(@"middlename")); } TEST_F(JsSuggestionManagerTest, SequentialNavigationNoSkipText) { @@ -360,6 +366,7 @@ GetFrameIdForMainFrame() completionHandler:completionHandler]; base::test::ios::WaitUntilCondition(^bool() { + base::RunLoop().RunUntilIdle(); return block_was_called; }); }
diff --git a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm index b8d71347..5011d77 100644 --- a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm +++ b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
@@ -42,6 +42,7 @@ #include "ios/chrome/browser/bookmarks/bookmark_remover_helper.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/browsing_data/browsing_data_remove_mask.h" +#include "ios/chrome/browser/experimental_flags.h" #include "ios/chrome/browser/history/history_service_factory.h" #include "ios/chrome/browser/history/web_history_service_factory.h" #include "ios/chrome/browser/ios_chrome_io_thread.h" @@ -57,6 +58,7 @@ #include "ios/chrome/browser/ui/external_file_remover_factory.h" #include "ios/chrome/browser/web_data_service_factory.h" #include "ios/net/http_cache_helper.h" +#import "ios/web/public/browsing_data_removing_util.h" #include "ios/web/public/web_task_traits.h" #include "ios/web/public/web_thread.h" #import "ios/web/public/web_view_creation_util.h" @@ -546,6 +548,38 @@ base::Time delete_begin, base::Time delete_end, BrowsingDataRemoveMask mask) { + if (base::FeatureList::IsEnabled(experimental_flags::kWebClearBrowsingData)) { + web::ClearBrowsingDataMask types = + web::ClearBrowsingDataMask::kRemoveNothing; + if (IsRemoveDataMaskSet(mask, BrowsingDataRemoveMask::REMOVE_APPCACHE)) { + types |= web::ClearBrowsingDataMask::kRemoveAppCache; + } + if (IsRemoveDataMaskSet(mask, BrowsingDataRemoveMask::REMOVE_COOKIES)) { + types |= web::ClearBrowsingDataMask::kRemoveCookies; + } + if (IsRemoveDataMaskSet(mask, BrowsingDataRemoveMask::REMOVE_INDEXEDDB)) { + types |= web::ClearBrowsingDataMask::kRemoveIndexedDB; + } + if (IsRemoveDataMaskSet(mask, + BrowsingDataRemoveMask::REMOVE_LOCAL_STORAGE)) { + types |= web::ClearBrowsingDataMask::kRemoveLocalStorage; + } + if (IsRemoveDataMaskSet(mask, BrowsingDataRemoveMask::REMOVE_WEBSQL)) { + types |= web::ClearBrowsingDataMask::kRemoveWebSQL; + } + if (IsRemoveDataMaskSet(mask, + BrowsingDataRemoveMask::REMOVE_CACHE_STORAGE)) { + types |= web::ClearBrowsingDataMask::kRemoveCacheStorage; + } + if (IsRemoveDataMaskSet(mask, + BrowsingDataRemoveMask::REMOVE_VISITED_LINKS)) { + types |= web::ClearBrowsingDataMask::kRemoveVisitedLinks; + } + + web::ClearBrowsingData(browser_state_, types); + return; + } + // Converts browsing data types from BrowsingDataRemoveMask to // WKWebsiteDataStore strings. NSMutableSet* data_types_to_remove = [[NSMutableSet alloc] init];
diff --git a/ios/chrome/browser/experimental_flags.h b/ios/chrome/browser/experimental_flags.h index 681bf39..85c9a7a 100644 --- a/ios/chrome/browser/experimental_flags.h +++ b/ios/chrome/browser/experimental_flags.h
@@ -18,6 +18,10 @@ // ExternalFileController. extern const base::Feature kExternalFilesLoadedInWebState; +// Feature to use the clear browsing data from web instead of the one from +// chrome. +extern const base::Feature kWebClearBrowsingData; + enum GaiaEnvironment { GAIA_ENVIRONMENT_PROD, GAIA_ENVIRONMENT_STAGING,
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm index e072e71..b2731f3 100644 --- a/ios/chrome/browser/experimental_flags.mm +++ b/ios/chrome/browser/experimental_flags.mm
@@ -50,6 +50,9 @@ const base::Feature kExternalFilesLoadedInWebState{ "ExternalFilesLoadedInWebState", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kWebClearBrowsingData{"WebClearBrowsingData", + base::FEATURE_DISABLED_BY_DEFAULT}; + bool AlwaysDisplayFirstRun() { return [[NSUserDefaults standardUserDefaults] boolForKey:kFirstRunForceEnabled];
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc index ca26dcd8..3d5e45e 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -415,6 +415,10 @@ const char kUseDdljsonApiDescription[] = "Enables the new ddljson API to fetch Doodles for the NTP."; +const char kWebClearBrowsingDataName[] = "Web-API for browsing data"; +const char kWebClearBrowsingDataDescription[] = + "When enabled the Clear Browsing Data feature is using the web API."; + const char kWebFrameMessagingName[] = "Web Frame Messaging"; const char kWebFrameMessagingDescription[] = "When enabled, API will be injected into webpages to allow sending messages"
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h index d532fc1..2f2a0aa 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -345,6 +345,11 @@ extern const char kUseDdljsonApiName[]; extern const char kUseDdljsonApiDescription[]; +// Title and description for the flag to use the Clear browsing data API from +// web. +extern const char kWebClearBrowsingDataName[]; +extern const char kWebClearBrowsingDataDescription[]; + // Title and description for the flag to enable web frame messaging. extern const char kWebFrameMessagingName[]; extern const char kWebFrameMessagingDescription[];
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm index e836f715..155716b6 100644 --- a/ios/chrome/browser/passwords/password_controller.mm +++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -101,6 +101,9 @@ COUNT }; +// Password is considered not generated when user edits it below 4 characters. +constexpr int kMinimumLengthForEditedPassword = 4; + // Duration for notify user auto-sign in dialog being displayed. constexpr int kNotifyAutoSigninDuration = 3; // seconds @@ -134,6 +137,9 @@ // The action sheet coordinator, if one is currently being shown. @property(nonatomic, strong) ActionSheetCoordinator* actionSheetCoordinator; +// Tracks if current password is generated. +@property(nonatomic, assign) BOOL isPasswordGenerated; + @end @interface PasswordController ()<FormSuggestionProvider, PasswordFormFiller> @@ -318,6 +324,7 @@ _passwordManagerClient.reset(); _credentialManager.reset(); _formGenerationData.clear(); + _isPasswordGenerated = NO; } #pragma mark - FormSuggestionProvider @@ -350,6 +357,22 @@ completion([fieldType isEqualToString:@"password"] || suggestionsAvailable); }]; + + if (self.isPasswordGenerated && + [self canGeneratePasswordForForm:formName + fieldIdentifier:fieldIdentifier + fieldType:fieldType]) { + if (typedValue.length < kMinimumLengthForEditedPassword) { + self.isPasswordGenerated = NO; + // TODO(crbug.com/886583): call + // passwordManager->OnPasswordNoLongerGenerated, but how to get + // PasswordForm? + } else { + [self injectGeneratedPasswordForFormName:formName + generatedPassword:typedValue + completionHandler:nil]; + } + } } - (void)retrieveSuggestionsForForm:(NSString*)formName @@ -722,29 +745,20 @@ IsIPadIdiom() ? UIAlertControllerStyleAlert : UIAlertControllerStyleActionSheet; - auto generatedPasswordInjected = ^(BOOL success) { - if (success) { - // TODO(crbug.com/886583) do not call presaved if username hasn't been - // filled in. - // TODO(crbug.com/886583) call _pM::OnPresaveGeneratedPassword once it has - // been refactored not to need a full form. - } - if (completionHandler) - completionHandler(YES); - }; - - auto injectGeneratedPassword = ^{ - [self.formHelper fillPasswordForm:formName - newPasswordIdentifier:newPasswordIdentifier - confirmPasswordIdentifier:confirmPasswordIdentifier - generatedPassword:displayPassword - completionHandler:generatedPasswordInjected]; - }; - + __weak PasswordController* weakSelf = self; // TODO(crbug.com/886583): i18n - [self.actionSheetCoordinator addItemWithTitle:@"Use Suggested Password" - action:injectGeneratedPassword - style:UIAlertActionStyleDefault]; + [self.actionSheetCoordinator + addItemWithTitle:@"Use Suggested Password" + action:^{ + [weakSelf + injectGeneratedPasswordForFormName:formName + newPasswordIdentifier:newPasswordIdentifier + confirmPasswordIdentifier: + confirmPasswordIdentifier + generatedPassword:displayPassword + completionHandler:completionHandler]; + } + style:UIAlertActionStyleDefault]; [self.actionSheetCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL) @@ -757,4 +771,44 @@ [self.actionSheetCoordinator start]; } +- (void)injectGeneratedPasswordForFormName:(NSString*)formName + generatedPassword:(NSString*)generatedPassword + completionHandler:(void (^)(BOOL))completionHandler { + if (![self hasFormForGenerationForFormName:formName]) + return; + const autofill::NewPasswordFormGenerationData form = + [self getFormForGenerationFromFormName:formName]; + NSString* newPasswordIdentifier = + SysUTF16ToNSString(form.new_password_element); + NSString* confirmPasswordIdentifier = + SysUTF16ToNSString(form.confirmation_password_element); + [self injectGeneratedPasswordForFormName:formName + newPasswordIdentifier:newPasswordIdentifier + confirmPasswordIdentifier:confirmPasswordIdentifier + generatedPassword:generatedPassword + completionHandler:completionHandler]; +} + +- (void)injectGeneratedPasswordForFormName:(NSString*)formName + newPasswordIdentifier:(NSString*)newPasswordIdentifier + confirmPasswordIdentifier:(NSString*)confirmPasswordIdentifier + generatedPassword:(NSString*)generatedPassword + completionHandler:(void (^)(BOOL))completionHandler { + auto generatedPasswordInjected = ^(BOOL success) { + if (success) { + // TODO(crbug.com/886583) call _pM::OnPresaveGeneratedPassword once it has + // been refactored not to need a full form. + self.isPasswordGenerated = YES; + } + if (completionHandler) + completionHandler(YES); + }; + + [self.formHelper fillPasswordForm:formName + newPasswordIdentifier:newPasswordIdentifier + confirmPasswordIdentifier:confirmPasswordIdentifier + generatedPassword:generatedPassword + completionHandler:generatedPasswordInjected]; +} + @end
diff --git a/ios/chrome/browser/passwords/password_controller_js_unittest.mm b/ios/chrome/browser/passwords/password_controller_js_unittest.mm index 51a17ea9..ed7b265 100644 --- a/ios/chrome/browser/passwords/password_controller_js_unittest.mm +++ b/ios/chrome/browser/passwords/password_controller_js_unittest.mm
@@ -513,7 +513,7 @@ // filled with the generated password and that new password field is untouched. TEST_F( PasswordControllerJsTest, - FillPasswordFormWithGeneratedPassword_SucceedsWhenOnlyConfirmPasswordFilled) { + FillPasswordFormWithGeneratedPassword_FailsWhenOnlyConfirmPasswordFilled) { LoadHtmlAndInject(@"<html>" " <body>" " <form name=\"foo\">" @@ -528,19 +528,16 @@ NSString* const password = @"abc"; NSString* const confirmPasswordIdentifier = @"ps2"; EXPECT_NSEQ( - @YES, - ExecuteJavaScriptWithFormat( - @"__gCrWeb.passwords." - @"fillPasswordFormWithGeneratedPassword('%@', '%@', '%@', '%@')", - formName, @"", confirmPasswordIdentifier, password)); + @NO, ExecuteJavaScriptWithFormat( + @"__gCrWeb.passwords." + @"fillPasswordFormWithGeneratedPassword('%@', '%@', '%@', '%@')", + formName, @"", confirmPasswordIdentifier, password)); EXPECT_NSEQ(@YES, ExecuteJavaScriptWithFormat( @"document.getElementById('ps1').value == '%@'", @"")); - EXPECT_NSEQ(@YES, - ExecuteJavaScriptWithFormat( - @"document.getElementById('ps2').value == '%@'", password)); - EXPECT_NSEQ(@NO, - ExecuteJavaScriptWithFormat( - @"document.getElementById('user').value == '%@'", password)); + EXPECT_NSEQ(@YES, ExecuteJavaScriptWithFormat( + @"document.getElementById('ps2').value == '%@'", @"")); + EXPECT_NSEQ(@YES, ExecuteJavaScriptWithFormat( + @"document.getElementById('user').value == '%@'", @"")); } // Check that unknown or null identifiers are handled gracefully.
diff --git a/ios/chrome/browser/signin/authentication_service.h b/ios/chrome/browser/signin/authentication_service.h index 7b2a7c649..82d0c0d 100644 --- a/ios/chrome/browser/signin/authentication_service.h +++ b/ios/chrome/browser/signin/authentication_service.h
@@ -14,31 +14,25 @@ #include "components/keyed_service/core/keyed_service.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/signin/core/browser/signin_metrics.h" -#include "google_apis/gaia/oauth2_token_service.h" #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" +#include "services/identity/public/cpp/identity_manager.h" namespace syncer { class SyncService; } -namespace identity { -class IdentityManager; -} - class AuthenticationServiceDelegate; @class ChromeIdentity; class PrefService; -class ProfileOAuth2TokenService; class SyncSetupService; // AuthenticationService is the Chrome interface to the iOS shared // authentication library. class AuthenticationService : public KeyedService, - public OAuth2TokenService::Observer, + public identity::IdentityManager::Observer, public ios::ChromeIdentityService::Observer { public: AuthenticationService(PrefService* pref_service, - ProfileOAuth2TokenService* token_service, SyncSetupService* sync_setup_service, identity::IdentityManager* identity_manager, syncer::SyncService* sync_service); @@ -180,8 +174,8 @@ // they were stored in the browser state prefs. void ComputeHaveAccountsChanged(); - // OAuth2TokenService::Observer implementation. - void OnEndBatchChanges() override; + // identity::IdentityManager::Observer implementation. + void OnEndBatchOfRefreshTokenStateChanges() override; // ChromeIdentityServiceObserver implementation. void OnIdentityListChanged() override; @@ -196,7 +190,6 @@ // Pointer to the KeyedServices used by AuthenticationService. PrefService* pref_service_ = nullptr; - ProfileOAuth2TokenService* token_service_ = nullptr; SyncSetupService* sync_setup_service_ = nullptr; identity::IdentityManager* identity_manager_ = nullptr; syncer::SyncService* sync_service_ = nullptr;
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm index 9df38f4..c422b02 100644 --- a/ios/chrome/browser/signin/authentication_service.mm +++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -16,8 +16,6 @@ #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" #include "components/signin/core/browser/account_info.h" -#include "components/signin/core/browser/profile_oauth2_token_service.h" -#include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h" #include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_user_settings.h" #include "google_apis/gaia/gaia_auth_util.h" @@ -31,7 +29,6 @@ #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" #import "ios/public/provider/chrome/browser/signin/chrome_identity.h" #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" -#import "services/identity/public/cpp/identity_manager.h" #import "services/identity/public/cpp/primary_account_mutator.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -74,12 +71,10 @@ AuthenticationService::AuthenticationService( PrefService* pref_service, - ProfileOAuth2TokenService* token_service, SyncSetupService* sync_setup_service, identity::IdentityManager* identity_manager, syncer::SyncService* sync_service) : pref_service_(pref_service), - token_service_(token_service), sync_setup_service_(sync_setup_service), identity_manager_(identity_manager), sync_service_(sync_service), @@ -89,7 +84,7 @@ DCHECK(sync_setup_service_); DCHECK(identity_manager_); DCHECK(sync_service_); - token_service_->AddObserver(this); + identity_manager_->AddObserver(this); } AuthenticationService::~AuthenticationService() { @@ -151,7 +146,7 @@ } void AuthenticationService::Shutdown() { - token_service_->RemoveObserver(this); + identity_manager_->RemoveObserver(this); NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; [center removeObserver:foreground_observer_]; @@ -196,13 +191,11 @@ // Clear signin errors on the accounts that had a specific MDM device status. // This will trigger services to fetch data for these accounts again. - ProfileOAuth2TokenServiceIOSDelegate* token_service_delegate = - static_cast<ProfileOAuth2TokenServiceIOSDelegate*>( - token_service_->GetDelegate()); std::map<std::string, NSDictionary*> cached_mdm_infos(cached_mdm_infos_); cached_mdm_infos_.clear(); for (const auto& cached_mdm_info : cached_mdm_infos) { - token_service_delegate->AddOrUpdateAccount(cached_mdm_info.first); + // TODO(crbug.com/930094): Eliminate this. + identity_manager_->LegacyAddAccountFromSystem(cached_mdm_info.first); } } @@ -358,10 +351,8 @@ // Reload all credentials to match the desktop model. Exclude all the // accounts ids that are the primary account ids on other profiles. - ProfileOAuth2TokenServiceIOSDelegate* tokenServiceDelegate = - static_cast<ProfileOAuth2TokenServiceIOSDelegate*>( - token_service_->GetDelegate()); - tokenServiceDelegate->ReloadCredentials(new_authenticated_account_id); + // TODO(crbug.com/930094): Eliminate this. + identity_manager_->LegacyReloadAccountsFromSystem(); StoreAccountsInPrefs(); // Kick-off sync: The authentication error UI (sign in infobar and warning @@ -413,7 +404,8 @@ return nil; } - if (!token_service_->RefreshTokenHasError(it->first)) { + if (!identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState( + it->first)) { // Account has no error, invalidate the cache. cached_mdm_infos_.erase(it); return nil; @@ -451,7 +443,7 @@ return weak_pointer_factory_.GetWeakPtr(); } -void AuthenticationService::OnEndBatchChanges() { +void AuthenticationService::OnEndBatchOfRefreshTokenStateChanges() { if (is_in_foreground_) { // Accounts maybe have been excluded or included from the current browser // state, without any change to the identity list. @@ -580,10 +572,8 @@ HandleForgottenIdentity(nil, should_prompt); if (GetAuthenticatedUserEmail()) { - ProfileOAuth2TokenServiceIOSDelegate* token_service_delegate = - static_cast<ProfileOAuth2TokenServiceIOSDelegate*>( - token_service_->GetDelegate()); - token_service_delegate->ReloadCredentials(); + // TODO(crbug.com/930094): Eliminate this. + identity_manager_->LegacyReloadAccountsFromSystem(); } }
diff --git a/ios/chrome/browser/signin/authentication_service_factory.mm b/ios/chrome/browser/signin/authentication_service_factory.mm index 810d24e5..a436d2b 100644 --- a/ios/chrome/browser/signin/authentication_service_factory.mm +++ b/ios/chrome/browser/signin/authentication_service_factory.mm
@@ -13,7 +13,6 @@ #import "ios/chrome/browser/signin/authentication_service.h" #import "ios/chrome/browser/signin/authentication_service_delegate.h" #include "ios/chrome/browser/signin/identity_manager_factory.h" -#include "ios/chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" #include "ios/chrome/browser/sync/sync_setup_service_factory.h" @@ -50,7 +49,6 @@ : BrowserStateKeyedServiceFactory( "AuthenticationService", BrowserStateDependencyManager::GetInstance()) { - DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance()); DependsOn(IdentityManagerFactory::GetInstance()); DependsOn(SyncSetupServiceFactory::GetInstance()); DependsOn(ProfileSyncServiceFactory::GetInstance()); @@ -65,7 +63,6 @@ ios::ChromeBrowserState::FromBrowserState(context); return std::make_unique<AuthenticationService>( browser_state->GetPrefs(), - ProfileOAuth2TokenServiceFactory::GetForBrowserState(browser_state), SyncSetupServiceFactory::GetForBrowserState(browser_state), IdentityManagerFactory::GetForBrowserState(browser_state), ProfileSyncServiceFactory::GetForBrowserState(browser_state));
diff --git a/ios/chrome/browser/signin/authentication_service_fake.h b/ios/chrome/browser/signin/authentication_service_fake.h index 3ae16b5..8cbdc80 100644 --- a/ios/chrome/browser/signin/authentication_service_fake.h +++ b/ios/chrome/browser/signin/authentication_service_fake.h
@@ -44,7 +44,6 @@ private: AuthenticationServiceFake(PrefService* pref_service, - ProfileOAuth2TokenService* token_service, SyncSetupService* sync_setup_service, identity::IdentityManager* identity_manager, syncer::SyncService* sync_service);
diff --git a/ios/chrome/browser/signin/authentication_service_fake.mm b/ios/chrome/browser/signin/authentication_service_fake.mm index 8dd076395..604bbc4 100644 --- a/ios/chrome/browser/signin/authentication_service_fake.mm +++ b/ios/chrome/browser/signin/authentication_service_fake.mm
@@ -11,7 +11,6 @@ #import "ios/chrome/browser/signin/authentication_service_delegate_fake.h" #import "ios/chrome/browser/signin/authentication_service_factory.h" #include "ios/chrome/browser/signin/identity_manager_factory.h" -#include "ios/chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" #include "ios/chrome/browser/sync/sync_setup_service_factory.h" #import "ios/public/provider/chrome/browser/signin/chrome_identity.h" @@ -22,12 +21,10 @@ AuthenticationServiceFake::AuthenticationServiceFake( PrefService* pref_service, - ProfileOAuth2TokenService* token_service, SyncSetupService* sync_setup_service, identity::IdentityManager* identity_manager, syncer::SyncService* sync_service) : AuthenticationService(pref_service, - token_service, sync_setup_service, identity_manager, sync_service), @@ -75,7 +72,6 @@ ios::ChromeBrowserState::FromBrowserState(context); auto service = base::WrapUnique(new AuthenticationServiceFake( browser_state->GetPrefs(), - ProfileOAuth2TokenServiceFactory::GetForBrowserState(browser_state), SyncSetupServiceFactory::GetForBrowserState(browser_state), IdentityManagerFactory::GetForBrowserState(browser_state), ProfileSyncServiceFactory::GetForBrowserState(browser_state)));
diff --git a/ios/chrome/browser/signin/authentication_service_unittest.mm b/ios/chrome/browser/signin/authentication_service_unittest.mm index bf43a4d..501b0b8 100644 --- a/ios/chrome/browser/signin/authentication_service_unittest.mm +++ b/ios/chrome/browser/signin/authentication_service_unittest.mm
@@ -10,9 +10,7 @@ #include "components/keyed_service/core/service_access_type.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_registry_simple.h" -#include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_pref_names.h" -#include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h" #include "components/sync_preferences/pref_service_mock_factory.h" #include "components/sync_preferences/pref_service_syncable.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" @@ -28,7 +26,6 @@ #import "ios/chrome/browser/signin/identity_manager_factory.h" #import "ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.h" #include "ios/chrome/browser/signin/ios_chrome_signin_client.h" -#include "ios/chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "ios/chrome/browser/signin/signin_client_factory.h" #include "ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" @@ -175,8 +172,6 @@ } authentication_service_ = std::make_unique<AuthenticationService>( browser_state_->GetPrefs(), - ProfileOAuth2TokenServiceFactory::GetForBrowserState( - browser_state_.get()), SyncSetupServiceFactory::GetForBrowserState(browser_state_.get()), IdentityManagerFactory::GetForBrowserState(browser_state_.get()), ProfileSyncServiceFactory::GetForBrowserState(browser_state_.get())); @@ -235,8 +230,11 @@ } identity::IdentityManager* identity_manager() { - return identity_test_environment_adaptor_->identity_test_env() - ->identity_manager(); + return identity_test_env()->identity_manager(); + } + + identity::IdentityTestEnvironment* identity_test_env() { + return identity_test_environment_adaptor_->identity_test_env(); } web::TestWebThreadBundle thread_bundle_; @@ -264,10 +262,6 @@ EXPECT_NSEQ(identity_, authentication_service_->GetAuthenticatedIdentity()); - ProfileOAuth2TokenService* token_service = - ProfileOAuth2TokenServiceFactory::GetForBrowserState( - browser_state_.get()); - std::string user_email = base::SysNSStringToUTF8([identity_ userEmail]); AccountInfo account_info = identity_manager() @@ -275,7 +269,8 @@ .value(); EXPECT_EQ(user_email, account_info.email); EXPECT_EQ(base::SysNSStringToUTF8([identity_ gaiaID]), account_info.gaia); - EXPECT_TRUE(token_service->RefreshTokenIsAvailable(account_info.account_id)); + EXPECT_TRUE( + identity_manager()->HasAccountWithRefreshToken(account_info.account_id)); } TEST_F(AuthenticationServiceTest, TestSetPromptForSignIn) { @@ -572,13 +567,8 @@ // AccountTrackerService::Initialize(), it fails because account ids are // updated with gaia ID from email at MigrateToGaiaId. As IdentityManager // needs refresh token to find account info, it reloads all credentials. - ProfileOAuth2TokenService* token_service = - ProfileOAuth2TokenServiceFactory::GetForBrowserState( - browser_state_.get()); - ProfileOAuth2TokenServiceIOSDelegate* token_service_delegate = - static_cast<ProfileOAuth2TokenServiceIOSDelegate*>( - token_service->GetDelegate()); - token_service_delegate->ReloadCredentials(); + // TODO(crbug.com/930094): Eliminate this. + identity_manager()->LegacyReloadAccountsFromSystem(); // Actually migrate the accounts in prefs. MigrateAccountsStoredInPrefsIfNeeded(); @@ -605,9 +595,8 @@ SetCachedMDMInfo(identity_, user_info); GoogleServiceAuthError error( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); - ProfileOAuth2TokenServiceFactory::GetForBrowserState(browser_state_.get()) - ->GetDelegate() - ->UpdateAuthError(base::SysNSStringToUTF8([identity_ gaiaID]), error); + identity_test_env()->UpdatePersistentErrorOfRefreshTokenForAccount( + base::SysNSStringToUTF8([identity_ gaiaID]), error); EXPECT_EQ(2, refresh_token_available_count_); // MDM error for |identity_| is being cleared, refresh token available @@ -646,9 +635,8 @@ authentication_service_->SignIn(identity_, std::string()); GoogleServiceAuthError error( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); - ProfileOAuth2TokenServiceFactory::GetForBrowserState(browser_state_.get()) - ->GetDelegate() - ->UpdateAuthError(base::SysNSStringToUTF8([identity_ gaiaID]), error); + identity_test_env()->UpdatePersistentErrorOfRefreshTokenForAccount( + base::SysNSStringToUTF8([identity_ gaiaID]), error); NSDictionary* user_info1 = @{ @"foo" : @1 }; ON_CALL(*identity_service_, GetMDMDeviceStatus(user_info1)) @@ -683,9 +671,8 @@ authentication_service_->SignIn(identity_, std::string()); GoogleServiceAuthError error( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); - ProfileOAuth2TokenServiceFactory::GetForBrowserState(browser_state_.get()) - ->GetDelegate() - ->UpdateAuthError(base::SysNSStringToUTF8([identity_ gaiaID]), error); + identity_test_env()->UpdatePersistentErrorOfRefreshTokenForAccount( + base::SysNSStringToUTF8([identity_ gaiaID]), error); NSDictionary* user_info1 = @{ @"foo" : @1 }; ON_CALL(*identity_service_, GetMDMDeviceStatus(user_info1)) @@ -742,9 +729,8 @@ authentication_service_->SignIn(identity_, std::string()); GoogleServiceAuthError error( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); - ProfileOAuth2TokenServiceFactory::GetForBrowserState(browser_state_.get()) - ->GetDelegate() - ->UpdateAuthError(base::SysNSStringToUTF8([identity_ gaiaID]), error); + identity_test_env()->UpdatePersistentErrorOfRefreshTokenForAccount( + base::SysNSStringToUTF8([identity_ gaiaID]), error); NSDictionary* user_info = [NSDictionary dictionary]; SetCachedMDMInfo(identity_, user_info);
diff --git a/ios/chrome/browser/ui/authentication/cells/account_control_item.h b/ios/chrome/browser/ui/authentication/cells/account_control_item.h index b5e71d7..2ec7c75 100644 --- a/ios/chrome/browser/ui/authentication/cells/account_control_item.h +++ b/ios/chrome/browser/ui/authentication/cells/account_control_item.h
@@ -22,7 +22,7 @@ // Cell for account settings view with a leading imageView, title text label, // and detail text label. The imageView is top-leading aligned. -@interface AccountControlCell : UITableViewCell +@interface AccountControlCell : TableViewCell @property(nonatomic, readonly, strong) UIImageView* imageView; @property(nonatomic, readonly, strong) UILabel* textLabel;
diff --git a/ios/chrome/browser/ui/authentication/cells/table_view_account_item.h b/ios/chrome/browser/ui/authentication/cells/table_view_account_item.h index 2bddb603..12fee1f 100644 --- a/ios/chrome/browser/ui/authentication/cells/table_view_account_item.h +++ b/ios/chrome/browser/ui/authentication/cells/table_view_account_item.h
@@ -29,7 +29,7 @@ // imageView. The imageView is vertical-centered and leading aligned. // If item/cell is disabled the image and text alpha will be set to 0.5 and // user interaction will be disabled. -@interface TableViewAccountCell : UITableViewCell +@interface TableViewAccountCell : TableViewCell // Rounded image used for the account user picture. @property(nonatomic, readonly, strong) UIImageView* imageView;
diff --git a/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.h b/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.h index d256e77..4fa8f95 100644 --- a/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.h +++ b/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.h
@@ -23,8 +23,8 @@ @property(nonatomic, readwrite, strong) NSString* text; @end -// UITableViewCell that contains a SignInPromoView. -@interface TableViewSigninPromoCell : UITableViewCell +// TableViewCell that contains a SignInPromoView. +@interface TableViewSigninPromoCell : TableViewCell // The SigninPromoView contained by this Cell. @property(nonatomic, strong) SigninPromoView* signinPromoView; @end
diff --git a/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.mm b/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.mm index e6f2e2f..39723f5 100644 --- a/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.mm +++ b/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.mm
@@ -30,7 +30,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)tableCell +- (void)configureCell:(TableViewCell*)tableCell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:tableCell withStyler:styler]; TableViewSigninPromoCell* cell =
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_cell.h b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_cell.h index 74520db..65d3105 100644 --- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_cell.h +++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_cell.h
@@ -7,10 +7,12 @@ #import <UIKit/UIKit.h> +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" + @class IdentityView; // Cell to display an user identity or the "Add Account…" button. -@interface IdentityChooserCell : UITableViewCell +@interface IdentityChooserCell : TableViewCell // Initializes IdentityChooserCell instance. - (instancetype)initWithStyle:(UITableViewCellStyle)style
diff --git a/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h b/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h index fc2d726..5e175cb 100644 --- a/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h +++ b/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h
@@ -46,9 +46,9 @@ @end -// AutofillEditCell implements an UITableViewCell subclass containing a label +// AutofillEditCell implements an TableViewCell subclass containing a label // and a text field. -@interface AutofillEditCell : UITableViewCell +@interface AutofillEditCell : TableViewCell // Label at the leading edge of the cell. It displays the item's textFieldName. @property(nonatomic, strong) UILabel* textLabel;
diff --git a/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.mm b/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.mm index 5e9595e..d16f5c3 100644 --- a/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.mm +++ b/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.mm
@@ -274,7 +274,7 @@ } } -#pragma mark UITableViewCell +#pragma mark - UITableViewCell - (void)prepareForReuse { [super prepareForReuse];
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/action_cell.h b/ios/chrome/browser/ui/autofill/manual_fill/action_cell.h index a3b26f4..3c30a59f 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/action_cell.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/action_cell.h
@@ -27,7 +27,7 @@ // A table view cell which contains a button and holds an action block, which // is called when the button is touched. -@interface ManualFillActionCell : UITableViewCell +@interface ManualFillActionCell : TableViewCell // Updates the cell with the passed title and action block. - (void)setUpWithTitle:(NSString*)title accessibilityID:(NSString*)accessibilityID
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_cell.h b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_cell.h index 1b6c4b1..ed81d4c 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_cell.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_cell.h
@@ -28,7 +28,7 @@ // Cell to display an Address into parts that are interactable // and sendable the data to the delegate. -@interface ManualFillAddressCell : UITableViewCell +@interface ManualFillAddressCell : TableViewCell // Updates the cell with address and the |delegate| to be notified. - (void)setUpWithAddress:(ManualFillAddress*)profile
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_card_cell.h b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_card_cell.h index 99d6a1d..74712039 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_card_cell.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_card_cell.h
@@ -28,7 +28,7 @@ // Cell to display a Card where the username and password are interactable // and send the data to the delegate. -@interface ManualFillCardCell : UITableViewCell +@interface ManualFillCardCell : TableViewCell // Updates the cell with credit card and the |delegate| to be notified. - (void)setUpWithCreditCard:(ManualFillCreditCard*)card
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_cell.h b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_cell.h index 5ecea917..cb6c71a1 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_cell.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_cell.h
@@ -27,7 +27,7 @@ // Cell to display a Credential where the username and password are interactable // and send the data to the delegate. -@interface ManualFillPasswordCell : UITableViewCell +@interface ManualFillPasswordCell : TableViewCell // Updates the cell with the |credential|. If the user iteracts with it, the // |delegate| will be notified.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm index 6096562..150f8998 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -1302,6 +1302,10 @@ [self setupContextBar]; } +- (BOOL)scrimIsVisible { + return self.scrimView.superview ? YES : NO; +} + #pragma mark - Loading and Empty States // Shows loading spinner background view. @@ -1693,8 +1697,8 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldReceiveTouch:(UITouch*)touch { - // Ignore long press in edit mode. - if (self.sharedState.currentlyInEditMode) { + // Ignore long press in edit mode or search mode. + if (self.sharedState.currentlyInEditMode || [self scrimIsVisible]) { return NO; } return YES;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm index 2eb93ff4..0cbcdcb 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -4236,6 +4236,43 @@ assertWithMatcher:grey_notNil()]; } +// Tests that long press on scrim while search box is enabled dismisses the +// search controller. +- (void)testSearchLongPressOnScrimCancelsSearchController { + [BookmarksTestCase setupStandardBookmarks]; + [BookmarksTestCase openBookmarks]; + [BookmarksTestCase openMobileBookmarks]; + + [[EarlGrey selectElementWithMatcher:SearchIconButton()] + performAction:grey_tap()]; + + // Try long press. + [[EarlGrey + selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"First URL")] + performAction:grey_longPress()]; + + // Verify context menu is not visible. + [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId( + IDS_IOS_BOOKMARK_CONTEXT_MENU_EDIT)] + assertWithMatcher:grey_nil()]; + + // Verify that scrim is not visible. + [[EarlGrey selectElementWithMatcher:grey_accessibilityID( + kBookmarkHomeSearchScrimIdentifier)] + assertWithMatcher:grey_nil()]; + + // Verifiy we went back to original folder content. + [[EarlGrey + selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"First URL")] + assertWithMatcher:grey_notNil()]; + [[EarlGrey + selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"Second URL")] + assertWithMatcher:grey_notNil()]; + [[EarlGrey + selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"French URL")] + assertWithMatcher:grey_notNil()]; +} + // Tests cancelling search restores the node's bookmarks. - (void)testSearchCancelRestoresNodeBookmarks { [BookmarksTestCase setupStandardBookmarks];
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.h b/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.h index d4315026..84894f2 100644 --- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.h +++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.h
@@ -43,7 +43,7 @@ // TableViewCell that displays BookmarkFolderItem data. @interface TableViewBookmarkFolderCell - : UITableViewCell<BookmarkTableCellTitleEditing> + : TableViewCell <BookmarkTableCellTitleEditing> // The leading constraint used to set the cell's leading indentation. The // default indentationLevel property doesn't affect any custom Cell subviews,
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.mm index 7d255d2..83cca1d 100644 --- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.mm +++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.mm
@@ -50,7 +50,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)cell +- (void)configureCell:(TableViewCell*)cell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:cell withStyler:styler]; TableViewBookmarkFolderCell* folderCell =
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.mm index 6fbb9994..a928daf 100644 --- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.mm +++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.mm
@@ -31,7 +31,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)cell +- (void)configureCell:(TableViewCell*)cell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:cell withStyler:styler]; if (_bookmarkNode->is_folder()) {
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.mm index 74d2552..77b8c02 100644 --- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.mm +++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.mm
@@ -28,7 +28,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)cell +- (void)configureCell:(TableViewCell*)cell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:cell withStyler:styler]; BookmarkTableSigninPromoCell* signinPromoCell =
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h index 2911634..25a7e01 100644 --- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h +++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h
@@ -18,7 +18,7 @@ @end // Cell class associated to BookmarkParentFolderItem. -@interface BookmarkParentFolderCell : UITableViewCell +@interface BookmarkParentFolderCell : TableViewCell // Label that displays the item's title. @property(nonatomic, readonly, strong) UILabel* parentFolderNameLabel;
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm index e57810b..1a211e0 100644 --- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm +++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm
@@ -36,7 +36,7 @@ #pragma mark TableViewItem -- (void)configureCell:(UITableViewCell*)tableCell +- (void)configureCell:(TableViewCell*)tableCell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:tableCell withStyler:styler]; BookmarkParentFolderCell* cell =
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_table_signin_promo_cell.h b/ios/chrome/browser/ui/bookmarks/cells/bookmark_table_signin_promo_cell.h index 0492503a..500a3bd 100644 --- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_table_signin_promo_cell.h +++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_table_signin_promo_cell.h
@@ -5,13 +5,15 @@ #ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_BOOKMARK_TABLE_SIGNIN_PROMO_CELL_H_ #define IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_BOOKMARK_TABLE_SIGNIN_PROMO_CELL_H_ -#import <UIKit/UIKit.h> +#import <Foundation/Foundation.h> + +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" @class SigninPromoView; // Sign-in promo cell based on SigninPromoView. This cell invites the user to // login without typing their password. -@interface BookmarkTableSigninPromoCell : UITableViewCell +@interface BookmarkTableSigninPromoCell : TableViewCell // Identifier for -[UITableView registerClass:forCellWithReuseIdentifier:]. + (NSString*)reuseIdentifier;
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h index 00feaee..87cae9ad 100644 --- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h +++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h
@@ -34,7 +34,7 @@ @end -@interface BookmarkTextFieldCell : UITableViewCell +@interface BookmarkTextFieldCell : TableViewCell // Label to display the type of content |self.textField| is displaying. @property(nonatomic, strong) UILabel* titleLabel;
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm index 5460e8a..d90fce9 100644 --- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm +++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm
@@ -35,7 +35,7 @@ #pragma mark TableViewItem -- (void)configureCell:(UITableViewCell*)tableCell +- (void)configureCell:(TableViewCell*)tableCell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:tableCell withStyler:styler];
diff --git a/ios/chrome/browser/ui/history/history_entries_status_item.h b/ios/chrome/browser/ui/history/history_entries_status_item.h index f98f0ab6..b4e8ae9 100644 --- a/ios/chrome/browser/ui/history/history_entries_status_item.h +++ b/ios/chrome/browser/ui/history/history_entries_status_item.h
@@ -13,7 +13,7 @@ @end // Cell that displays a HistoryEntriesStatusItem. -@interface HistoryEntriesStatusCell : UITableViewCell +@interface HistoryEntriesStatusCell : TableViewCell @end #endif // IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_ENTRIES_STATUS_ITEM_H_
diff --git a/ios/chrome/browser/ui/history/history_entry_item.mm b/ios/chrome/browser/ui/history/history_entry_item.mm index 2cfb06e..bc3d7ac 100644 --- a/ios/chrome/browser/ui/history/history_entry_item.mm +++ b/ios/chrome/browser/ui/history/history_entry_item.mm
@@ -46,7 +46,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)tableCell +- (void)configureCell:(TableViewCell*)tableCell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:tableCell withStyler:styler];
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.mm b/ios/chrome/browser/ui/history/history_table_view_controller.mm index 4e4e891f..3a7b187 100644 --- a/ios/chrome/browser/ui/history/history_table_view_controller.mm +++ b/ios/chrome/browser/ui/history/history_table_view_controller.mm
@@ -918,6 +918,10 @@ } } +- (BOOL)scrimIsVisible { + return self.scrimView.superview ? YES : NO; +} + #pragma mark Navigation Toolbar Configuration // Animates the view configuration after flipping the current status of |[self @@ -977,6 +981,10 @@ gestureRecognizer.state != UIGestureRecognizerStateBegan) { return; } + if ([self scrimIsVisible]) { + self.searchController.active = NO; + return; + } CGPoint touchLocation = [gestureRecognizer locationOfTouch:0 inView:self.tableView];
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm index 2a514023..5d9e900 100644 --- a/ios/chrome/browser/ui/history/history_ui_egtest.mm +++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -253,6 +253,38 @@ assertWithMatcher:grey_nil()]; } +// Tests that long press on scrim while search box is enabled dismisses the +// search controller. +- (void)testSearchLongPressOnScrimCancelsSearchController { + [self loadTestURLs]; + [self openHistoryPanel]; + [[EarlGrey selectElementWithMatcher:SearchIconButton()] + performAction:grey_tap()]; + + // Try long press. + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] + performAction:grey_longPress()]; + + // Verify context menu is not visible. + [[EarlGrey + selectElementWithMatcher:ButtonWithAccessibilityLabelId( + IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)] + assertWithMatcher:grey_nil()]; + + // Verify that scrim is not visible. + [[EarlGrey selectElementWithMatcher:grey_accessibilityID( + kHistorySearchScrimIdentifier)] + assertWithMatcher:grey_nil()]; + + // Verifiy we went back to original folder content. + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] + assertWithMatcher:grey_notNil()]; + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL2, kTitle2)] + assertWithMatcher:grey_notNil()]; + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL3, _URL3.GetContent())] + assertWithMatcher:grey_notNil()]; +} + // Tests deletion of history entries. - (void)testDeleteHistory { [self loadTestURLs];
diff --git a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_navigation_item.h b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_navigation_item.h index 6fd7a7b..539ea9bb 100644 --- a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_navigation_item.h +++ b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_navigation_item.h
@@ -23,7 +23,7 @@ @end // Associated cell for a PopupMenuNavigationItem. -@interface PopupMenuNavigationCell : UITableViewCell +@interface PopupMenuNavigationCell : TableViewCell - (void)setTitle:(NSString*)title; - (void)setFavicon:(UIImage*)favicon;
diff --git a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.h b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.h index 8be2b5d..af1646f0 100644 --- a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.h +++ b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.h
@@ -29,7 +29,7 @@ @end // Associated cell for the PopupMenuToolsItem. -@interface PopupMenuToolsCell : UITableViewCell +@interface PopupMenuToolsCell : TableViewCell // Image view to display the image. @property(nonatomic, strong, readonly) UIImageView* imageView;
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_item.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_item.mm index 4efc53c..582e51b 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_item.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_item.mm
@@ -81,7 +81,7 @@ #pragma mark - ListItem -- (void)configureCell:(UITableViewCell*)cell +- (void)configureCell:(TableViewCell*)cell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:cell withStyler:styler]; TableViewURLCell* URLCell = base::mac::ObjCCastStrict<TableViewURLCell>(cell);
diff --git a/ios/chrome/browser/ui/settings/cells/autofill_data_item.h b/ios/chrome/browser/ui/settings/cells/autofill_data_item.h index fd483878..d84d67ad 100644 --- a/ios/chrome/browser/ui/settings/cells/autofill_data_item.h +++ b/ios/chrome/browser/ui/settings/cells/autofill_data_item.h
@@ -27,7 +27,7 @@ // Cell for autofill data with two leading text labels and one trailing text // label. -@interface AutofillDataCell : UITableViewCell +@interface AutofillDataCell : TableViewCell @property(nonatomic, readonly, strong) UILabel* textLabel; @property(nonatomic, readonly, strong) UILabel* leadingDetailTextLabel;
diff --git a/ios/chrome/browser/ui/settings/cells/byo_textfield_item.h b/ios/chrome/browser/ui/settings/cells/byo_textfield_item.h index e3261dd..0db69e3 100644 --- a/ios/chrome/browser/ui/settings/cells/byo_textfield_item.h +++ b/ios/chrome/browser/ui/settings/cells/byo_textfield_item.h
@@ -24,7 +24,7 @@ @end // Cell class associated to BYOTextFieldItem. -@interface BYOTextFieldCell : UITableViewCell +@interface BYOTextFieldCell : TableViewCell @end #endif // IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_BYO_TEXTFIELD_ITEM_H_
diff --git a/ios/chrome/browser/ui/settings/cells/copied_to_chrome_item.h b/ios/chrome/browser/ui/settings/cells/copied_to_chrome_item.h index dce72b7..afefe960 100644 --- a/ios/chrome/browser/ui/settings/cells/copied_to_chrome_item.h +++ b/ios/chrome/browser/ui/settings/cells/copied_to_chrome_item.h
@@ -15,7 +15,7 @@ // A cell indicating that the credit card has been copied to Chrome. Includes a // button to clear the copy. -@interface CopiedToChromeCell : UITableViewCell +@interface CopiedToChromeCell : TableViewCell // Text label displaying the item's text. @property(nonatomic, readonly, strong) UILabel* textLabel;
diff --git a/ios/chrome/browser/ui/settings/cells/passphrase_error_item.h b/ios/chrome/browser/ui/settings/cells/passphrase_error_item.h index cf1806941..b95566a 100644 --- a/ios/chrome/browser/ui/settings/cells/passphrase_error_item.h +++ b/ios/chrome/browser/ui/settings/cells/passphrase_error_item.h
@@ -16,7 +16,7 @@ @end // Cell class associated to PassphraseErrorItem. -@interface PassphraseErrorCell : UITableViewCell +@interface PassphraseErrorCell : TableViewCell // Label for the error text. @property(nonatomic, readonly, strong) UILabel* textLabel;
diff --git a/ios/chrome/browser/ui/settings/cells/passphrase_error_item.mm b/ios/chrome/browser/ui/settings/cells/passphrase_error_item.mm index e164184..db9b230 100644 --- a/ios/chrome/browser/ui/settings/cells/passphrase_error_item.mm +++ b/ios/chrome/browser/ui/settings/cells/passphrase_error_item.mm
@@ -25,7 +25,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)cell +- (void)configureCell:(TableViewCell*)cell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:cell withStyler:styler]; cell.textLabel.text = self.text;
diff --git a/ios/chrome/browser/ui/settings/cells/settings_detail_item.h b/ios/chrome/browser/ui/settings/cells/settings_detail_item.h index 2318791..3d5fe5e 100644 --- a/ios/chrome/browser/ui/settings/cells/settings_detail_item.h +++ b/ios/chrome/browser/ui/settings/cells/settings_detail_item.h
@@ -26,11 +26,11 @@ @end -// SettingsDetailCell implements an UITableViewCell subclass containing an +// SettingsDetailCell implements an TableViewCell subclass containing an // optional leading icon and two text labels: a "main" label and a "detail" // label. The two labels are laid out side-by-side and fill the full width of // the cell. Labels are truncated as needed to fit in the cell. -@interface SettingsDetailCell : UITableViewCell +@interface SettingsDetailCell : TableViewCell // UILabels corresponding to |text| and |detailText| from the item. @property(nonatomic, readonly, strong) UILabel* textLabel;
diff --git a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_cell.h b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_cell.h index 275ac3a..507eaa6 100644 --- a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_cell.h +++ b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_cell.h
@@ -16,7 +16,7 @@ // | | | Optional multiline detail text | // | +-------+ | // +--------------------------------------------------+ -@interface SettingsImageDetailTextCell : UITableViewCell +@interface SettingsImageDetailTextCell : TableViewCell // Cell image. @property(nonatomic, strong) UIImage* image;
diff --git a/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h b/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h index 5f07090..c6529b6 100644 --- a/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h +++ b/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h
@@ -21,11 +21,11 @@ @end -// SettingsMultilineDetailCell implements an UITableViewCell +// SettingsMultilineDetailCell implements an TableViewCell // subclass containing two text labels: a "main" label and a "detail" label. // The two labels are laid out on top of each other and can span on multiple // lines. This is to be used with a SettingsMultilineDetailItem. -@interface SettingsMultilineDetailCell : UITableViewCell +@interface SettingsMultilineDetailCell : TableViewCell // UILabels corresponding to |text| and |detailText| from the item. @property(nonatomic, readonly, strong) UILabel* textLabel;
diff --git a/ios/chrome/browser/ui/settings/cells/settings_switch_cell.h b/ios/chrome/browser/ui/settings/cells/settings_switch_cell.h index 7df334a..3f3efe3c 100644 --- a/ios/chrome/browser/ui/settings/cells/settings_switch_cell.h +++ b/ios/chrome/browser/ui/settings/cells/settings_switch_cell.h
@@ -7,11 +7,13 @@ #import <UIKit/UIKit.h> -// SettingsSwitchCell implements a UITableViewCell subclass containing an icon, +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" + +// SettingsSwitchCell implements a TableViewCell subclass containing an icon, // a text label, a detail text and a switch. // If the preferred content size category is an accessibility category, the // switch is displayed below the label. Otherwise, it is on the trailing side. -@interface SettingsSwitchCell : UITableViewCell +@interface SettingsSwitchCell : TableViewCell // UILabel corresponding to |text| from the item. @property(nonatomic, readonly, strong) UILabel* textLabel;
diff --git a/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm b/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm index 1490fcb..40ffff90 100644 --- a/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm +++ b/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm
@@ -25,7 +25,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)tableCell +- (void)configureCell:(TableViewCell*)tableCell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:tableCell withStyler:styler]; TableViewTextCell* cell =
diff --git a/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm index 5c49556..40e5bb0 100644 --- a/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm
@@ -28,9 +28,6 @@ // Estimated height of the header/footer, used to speed the constraints. const CGFloat kEstimatedHeaderFooterHeight = 35; -// Color for the separator. -const int kSeparatorColor = 0xE8EAED; - enum SavedBarButtomItemPositionEnum { kUndefinedBarButtonItemPosition, kLeftBarButtonItemPosition, @@ -123,7 +120,7 @@ self.styler.tableViewSectionHeaderBlurEffect = nil; [super viewDidLoad]; if (base::FeatureList::IsEnabled(kSettingsRefresh)) { - self.tableView.separatorColor = UIColorFromRGB(kSeparatorColor); + self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; } self.styler.cellBackgroundColor = [UIColor whiteColor]; self.styler.cellTitleColor = [UIColor blackColor];
diff --git a/ios/chrome/browser/ui/table_view/cells/BUILD.gn b/ios/chrome/browser/ui/table_view/cells/BUILD.gn index 2ec7c81..30d47cb 100644 --- a/ios/chrome/browser/ui/table_view/cells/BUILD.gn +++ b/ios/chrome/browser/ui/table_view/cells/BUILD.gn
@@ -6,6 +6,8 @@ sources = [ "table_view_activity_indicator_header_footer_item.h", "table_view_activity_indicator_header_footer_item.mm", + "table_view_cell.h", + "table_view_cell.mm", "table_view_cells_constants.h", "table_view_cells_constants.mm", "table_view_detail_text_item.h",
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_cell.h b/ios/chrome/browser/ui/table_view/cells/table_view_cell.h new file mode 100644 index 0000000..ee7d077 --- /dev/null +++ b/ios/chrome/browser/ui/table_view/cells/table_view_cell.h
@@ -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. + +#ifndef IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_CELL_H_ +#define IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_CELL_H_ + +#import <UIKit/UIKit.h> + +// Base class for the TableViewCell used by the TableViewItems. +@interface TableViewCell : UITableViewCell + +// Whether custom separator should be used. The separator can replace the +// separator provided by UITableViewCell. It is a 0.5pt high line. +@property(nonatomic, assign) BOOL useCustomSeparator; + +// View displayed as custom separator. Use this property to set the leading +// anchor of the custom separator. Default is 16 points (priority high + 1). +@property(nonatomic, strong, readonly) UIView* customSeparator; + +@end + +#endif // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_CELL_H_
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_cell.mm b/ios/chrome/browser/ui/table_view/cells/table_view_cell.mm new file mode 100644 index 0000000..bdba2de --- /dev/null +++ b/ios/chrome/browser/ui/table_view/cells/table_view_cell.mm
@@ -0,0 +1,67 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" + +#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h" +#import "ios/chrome/browser/ui/util/ui_util.h" +#import "ios/chrome/browser/ui/util/uikit_ui_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { +const int kTableViewCustomSeparatorColor = 0xE8EAED; +const CGFloat kTableViewCustomSeparatorHeight = 0.5; +} // namespace + +@interface TableViewCell () +@end + +@implementation TableViewCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style + reuseIdentifier:(NSString*)reuseIdentifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + _customSeparator = [[UIView alloc] init]; + _customSeparator.translatesAutoresizingMaskIntoConstraints = NO; + _customSeparator.backgroundColor = + UIColorFromRGB(kTableViewCustomSeparatorColor); + [self addSubview:_customSeparator]; + + NSArray* constraints = @[ + [_customSeparator.trailingAnchor + constraintEqualToAnchor:self.trailingAnchor], + [_customSeparator.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], + [_customSeparator.heightAnchor + constraintEqualToConstant:AlignValueToPixel( + kTableViewCustomSeparatorHeight)], + [_customSeparator.leadingAnchor + constraintEqualToAnchor:self.leadingAnchor + constant:kTableViewHorizontalSpacing], + ]; + for (NSLayoutConstraint* constraint in constraints) { + // Have a priority higher than the default high but don't make it required + // to allow subclass to override it. + constraint.priority = UILayoutPriorityDefaultHigh + 1; + } + [NSLayoutConstraint activateConstraints:constraints]; + } + return self; +} + +- (void)setUseCustomSeparator:(BOOL)useCustomSeparator { + _useCustomSeparator = useCustomSeparator; + self.customSeparator.hidden = !useCustomSeparator; +} + +#pragma mark - UITableViewCell + +- (void)prepareForReuse { + [super prepareForReuse]; + self.useCustomSeparator = NO; +} +@end
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_detail_text_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_detail_text_item.h index 9d58a82..170e6e7e 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_detail_text_item.h +++ b/ios/chrome/browser/ui/table_view/cells/table_view_detail_text_item.h
@@ -7,6 +7,7 @@ #import <UIKit/UIKit.h> +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_item.h" // TableViewDetailTextItem contains the model data for a @@ -31,11 +32,11 @@ @end -// UITableViewCell that displays two text labels on top of each other. The text +// TableViewCell that displays two text labels on top of each other. The text // labels are displaying on one line if the preferred content size isn't an // Accessibility category. Otherwise they are displayed on an unlimited number // of lines. -@interface TableViewDetailTextCell : UITableViewCell +@interface TableViewDetailTextCell : TableViewCell // The text to display. @property(nonatomic, readonly, strong) UILabel* textLabel;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_image_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_image_item.h index cb16c58..dead71ea5 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_image_item.h +++ b/ios/chrome/browser/ui/table_view/cells/table_view_image_item.h
@@ -7,6 +7,7 @@ #import <UIKit/UIKit.h> +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_item.h" // TableViewImageItem contains the model data for a TableViewImageCell. @@ -26,7 +27,7 @@ @end // TableViewImageCell contains a favicon, a title, and an optional chevron. -@interface TableViewImageCell : UITableViewCell +@interface TableViewImageCell : TableViewCell // The cell favicon imageView. @property(nonatomic, readonly, strong) UIImageView* imageView;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_image_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_image_item.mm index 02b226b..fcfa04b 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_image_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_image_item.mm
@@ -32,7 +32,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)tableCell +- (void)configureCell:(TableViewCell*)tableCell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:tableCell withStyler:styler];
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_item.h index f20bfc3..5397e55b 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_item.h +++ b/ios/chrome/browser/ui/table_view/cells/table_view_item.h
@@ -8,6 +8,7 @@ #import <UIKit/UIKit.h> #import "ios/chrome/browser/ui/list_model/list_item.h" +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" @class ChromeTableViewStyler; @@ -17,13 +18,18 @@ // The accessory type to display on the trailing edge of the cell. @property(nonatomic, assign) UITableViewCellAccessoryType accessoryType; +// Whether custom separator should be used. The separator can replace the +// separator provided by UITableViewCell. It is a 0.5pt high line. Default is +// NO. +@property(nonatomic, assign) BOOL useCustomSeparator; + - (instancetype)initWithType:(NSInteger)type NS_DESIGNATED_INITIALIZER; // Configures the given cell with the item's information. Override this method // to specialize. At this level, only accessibility properties are ported from // the item to the cell. // The cell's class must match cellClass for the given instance. -- (void)configureCell:(UITableViewCell*)cell +- (void)configureCell:(TableViewCell*)cell withStyler:(ChromeTableViewStyler*)styler NS_REQUIRES_SUPER; @end
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_item.mm index 9ac5a8e0..73f74fe 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_item.mm
@@ -15,16 +15,20 @@ - (instancetype)initWithType:(NSInteger)type { if ((self = [super initWithType:type])) { - self.cellClass = [UITableViewCell class]; + _useCustomSeparator = NO; + + self.cellClass = [TableViewCell class]; } return self; } -- (void)configureCell:(UITableViewCell*)cell +- (void)configureCell:(TableViewCell*)cell withStyler:(ChromeTableViewStyler*)styler { DCHECK(styler); DCHECK([cell class] == self.cellClass); + DCHECK([cell isKindOfClass:[TableViewCell class]]); cell.accessoryType = self.accessoryType; + cell.useCustomSeparator = self.useCustomSeparator; cell.accessibilityTraits = self.accessibilityTraits; cell.accessibilityIdentifier = self.accessibilityIdentifier; if (!cell.backgroundView) {
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_item_unittest.mm b/ios/chrome/browser/ui/table_view/cells/table_view_item_unittest.mm index 2dbc3e06..59d081c 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_item_unittest.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_item_unittest.mm
@@ -21,8 +21,8 @@ TableViewItem* item = [[TableViewItem alloc] initWithType:0]; item.accessibilityIdentifier = @"test_identifier"; item.accessibilityTraits = UIAccessibilityTraitButton; - UITableViewCell* cell = [[[item cellClass] alloc] init]; - EXPECT_TRUE([cell isMemberOfClass:[UITableViewCell class]]); + TableViewCell* cell = [[[item cellClass] alloc] init]; + EXPECT_TRUE([cell isMemberOfClass:[TableViewCell class]]); EXPECT_EQ(UIAccessibilityTraitNone, [cell accessibilityTraits]); EXPECT_FALSE([cell accessibilityIdentifier]); @@ -34,8 +34,8 @@ TEST_F(TableViewItemTest, ConfigureCellWithStyler) { TableViewItem* item = [[TableViewItem alloc] initWithType:0]; - UITableViewCell* cell = [[[item cellClass] alloc] init]; - ASSERT_TRUE([cell isMemberOfClass:[UITableViewCell class]]); + TableViewCell* cell = [[[item cellClass] alloc] init]; + ASSERT_TRUE([cell isMemberOfClass:[TableViewCell class]]); ChromeTableViewStyler* styler = [[ChromeTableViewStyler alloc] init]; UIColor* testColor = [UIColor redColor]; @@ -46,8 +46,8 @@ TEST_F(TableViewItemTest, NoBackgroundColorIfBackgroundViewIsPresent) { TableViewItem* item = [[TableViewItem alloc] initWithType:0]; - UITableViewCell* cell = [[[item cellClass] alloc] init]; - ASSERT_TRUE([cell isMemberOfClass:[UITableViewCell class]]); + TableViewCell* cell = [[[item cellClass] alloc] init]; + ASSERT_TRUE([cell isMemberOfClass:[TableViewCell class]]); // If a background view is present on the cell, the styler's background color // should be ignored.
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.h index 1c57af3..78d81bd52 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.h +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.h
@@ -5,6 +5,7 @@ #ifndef IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_TEXT_BUTTON_ITEM_H_ #define IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_TEXT_BUTTON_ITEM_H_ +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_item.h" // TableViewTextButtonItem contains the model for @@ -26,7 +27,7 @@ // TableViewTextButtonCell contains a textLabel and a UIbutton // laid out vertically and centered. -@interface TableViewTextButtonCell : UITableViewCell +@interface TableViewTextButtonCell : TableViewCell // Cell text information. @property(nonatomic, strong) UILabel* textLabel;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.mm index 702a95b..8e40c89d 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.mm
@@ -46,7 +46,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)tableCell +- (void)configureCell:(TableViewCell*)tableCell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:tableCell withStyler:styler]; TableViewTextButtonCell* cell =
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_text_item.h index a26c511..140deb9 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_item.h +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_item.h
@@ -7,6 +7,7 @@ #import <UIKit/UIKit.h> +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_item.h" // TableViewTextItem contains the model data for a TableViewTextCell. @@ -31,8 +32,8 @@ @end -// UITableViewCell that displays a text label. -@interface TableViewTextCell : UITableViewCell +// TableViewCell that displays a text label. +@interface TableViewTextCell : TableViewCell // The text to display. @property(nonatomic, readonly, strong) UILabel* textLabel;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_item.mm index caec2cb..59b74fa 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_item.mm
@@ -33,7 +33,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)tableCell +- (void)configureCell:(TableViewCell*)tableCell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:tableCell withStyler:styler]; TableViewTextCell* cell =
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h index d3993c83..ff48e03 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h
@@ -7,6 +7,7 @@ #import <UIKit/UIKit.h> +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_item.h" class GURL; @@ -27,8 +28,8 @@ @property(nonatomic, assign) GURL linkURL; @end -// UITableViewCell that displays a text label that might contain a link. -@interface TableViewTextLinkCell : UITableViewCell +// TableViewCell that displays a text label that might contain a link. +@interface TableViewTextLinkCell : TableViewCell // The text to display. @property(nonatomic, readonly, strong) UILabel* textLabel; // Delegate for the TableViewTextLinkCell. Is notified when a link is
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm index 6bf4c9b1..2b10243 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm
@@ -35,7 +35,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)tableCell +- (void)configureCell:(TableViewCell*)tableCell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:tableCell withStyler:styler]; TableViewTextLinkCell* cell =
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_url_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_url_item.h index d44e41a53..4cada52 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_url_item.h +++ b/ios/chrome/browser/ui/table_view/cells/table_view_url_item.h
@@ -7,6 +7,7 @@ #import <UIKit/UIKit.h> +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_item.h" class GURL; @@ -37,7 +38,7 @@ // contains a favicon, a title, a URL, and optionally some metadata such as a // timestamp or a file size. After configuring the cell, make sure to call // configureUILayout:. -@interface TableViewURLCell : UITableViewCell +@interface TableViewURLCell : TableViewCell // The imageview that is displayed on the leading edge of the cell. This // contains a favicon composited on top of an off-white background.
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm index 00d82a514..93f7c44 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm
@@ -51,7 +51,7 @@ return self; } -- (void)configureCell:(UITableViewCell*)tableCell +- (void)configureCell:(TableViewCell*)tableCell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:tableCell withStyler:styler];
diff --git a/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm b/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm index 6401926..00dfc5a44 100644 --- a/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm +++ b/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm
@@ -5,8 +5,10 @@ #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h" #include "base/logging.h" +#include "base/mac/foundation_util.h" #import "ios/chrome/browser/ui/material_components/chrome_app_bar_view_controller.h" #import "ios/chrome/browser/ui/material_components/utils.h" +#import "ios/chrome/browser/ui/table_view/cells/table_view_cell.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_item.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" @@ -195,7 +197,9 @@ // |cell| may be nil if the row is not currently on screen. if (cell) { - [item configureCell:cell withStyler:self.styler]; + TableViewCell* tableViewCell = + base::mac::ObjCCastStrict<TableViewCell>(cell); + [item configureCell:tableViewCell withStyler:self.styler]; } } } @@ -226,7 +230,8 @@ UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath]; - [item configureCell:cell withStyler:self.styler]; + TableViewCell* tableViewCell = base::mac::ObjCCastStrict<TableViewCell>(cell); + [item configureCell:tableViewCell withStyler:self.styler]; return cell; }
diff --git a/ios/chrome/browser/ui/table_view/chrome_table_view_controller_unittest.mm b/ios/chrome/browser/ui/table_view/chrome_table_view_controller_unittest.mm index 6a5c571..61879f3 100644 --- a/ios/chrome/browser/ui/table_view/chrome_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/table_view/chrome_table_view_controller_unittest.mm
@@ -24,7 +24,7 @@ @synthesize configureCellCalled = _configureCellCalled; -- (void)configureCell:(UITableViewCell*)cell +- (void)configureCell:(TableViewCell*)cell withStyler:(ChromeTableViewStyler*)styler { self.configureCellCalled = YES; [super configureCell:cell withStyler:styler];
diff --git a/ios/chrome/browser/ui/translate/cells/translate_popup_menu_item.h b/ios/chrome/browser/ui/translate/cells/translate_popup_menu_item.h index 0714d26d..a8e1825 100644 --- a/ios/chrome/browser/ui/translate/cells/translate_popup_menu_item.h +++ b/ios/chrome/browser/ui/translate/cells/translate_popup_menu_item.h
@@ -22,7 +22,7 @@ @end // Associated cell for a TranslatePopupMenuItem. -@interface TranslatePopupMenuCell : UITableViewCell +@interface TranslatePopupMenuCell : TableViewCell - (void)setTitle:(NSString*)title;
diff --git a/ios/chrome/browser/ui/util/ui_util.mm b/ios/chrome/browser/ui/util/ui_util.mm index 202ffe1..9444b19 100644 --- a/ios/chrome/browser/ui/util/ui_util.mm +++ b/ios/chrome/browser/ui/util/ui_util.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ios/chrome/browser/ui/util/ui_util.h" +#import "ios/chrome/browser/ui/util/ui_util.h" #import <UIKit/UIKit.h> #include <limits>
diff --git a/ios/chrome/browser/web/error_page_egtest.mm b/ios/chrome/browser/web/error_page_egtest.mm index 3af4c02..6fad78c 100644 --- a/ios/chrome/browser/web/error_page_egtest.mm +++ b/ios/chrome/browser/web/error_page_egtest.mm
@@ -44,9 +44,6 @@ &net::test_server::HandlePrefixedRequest, "/echo-query", base::BindRepeating(&testing::HandleEchoQueryOrCloseSocket, base::ConstRef(_serverRespondsWithContent)))); - self.testServer->RegisterRequestHandler( - base::BindRepeating(&net::test_server::HandlePrefixedRequest, "/iframe", - base::BindRepeating(&testing::HandleIFrame))); GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); }
diff --git a/ios/chrome/browser/web/visible_url_egtest.mm b/ios/chrome/browser/web/visible_url_egtest.mm index c3103456..991bdba 100644 --- a/ios/chrome/browser/web/visible_url_egtest.mm +++ b/ios/chrome/browser/web/visible_url_egtest.mm
@@ -605,18 +605,10 @@ // Make server respond so URL1 becomes committed. [self setServerPaused:NO]; - if (base::FeatureList::IsEnabled(web::features::kWebFrameMessaging)) { - // With frame messaging, only one back is executed. This is the expected - // behavior. - [ChromeEarlGrey waitForWebViewContainingText:kTestPage2]; - [[EarlGrey selectElementWithMatcher:OmniboxText(_testURL2.GetContent())] - assertWithMatcher:grey_notNil()]; - } else { - // TODO(crbug.com/866406): fix the test to have documented behavior. - [ChromeEarlGrey waitForWebViewContainingText:kTestPage1]; - [[EarlGrey selectElementWithMatcher:OmniboxText(_testURL1.GetContent())] - assertWithMatcher:grey_notNil()]; - } + // TODO(crbug.com/866406): fix the test to have documented behavior. + [ChromeEarlGrey waitForWebViewContainingText:kTestPage1]; + [[EarlGrey selectElementWithMatcher:OmniboxText(_testURL1.GetContent())] + assertWithMatcher:grey_notNil()]; } #pragma mark -
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn index 4b8d812f..4f4bf51 100644 --- a/ios/web/BUILD.gn +++ b/ios/web/BUILD.gn
@@ -174,6 +174,7 @@ ":ios_web_web_state_unittests", ":ios_web_webui_unittests", "//ios/testing:http_server_bundle_data", + "//ios/web/browsing_data:browsing_data_unittests", "//ios/web/download:download_unittests", "//ios/web/interstitials:interstitials_unittests", ]
diff --git a/ios/web/browsing_data/BUILD.gn b/ios/web/browsing_data/BUILD.gn new file mode 100644 index 0000000..b187e9e --- /dev/null +++ b/ios/web/browsing_data/BUILD.gn
@@ -0,0 +1,32 @@ +# 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. + +source_set("browsing_data") { + sources = [ + "browsing_data_remover.h", + "browsing_data_remover.mm", + "browsing_data_remover_observer.h", + "browsing_data_removing_util.mm", + ] + + deps = [ + "//ios/web/public", + ] + + configs += [ "//build/config/compiler:enable_arc" ] +} + +source_set("browsing_data_unittests") { + configs += [ "//build/config/compiler:enable_arc" ] + testonly = true + deps = [ + ":browsing_data", + "//ios/web/public/test/fakes", + "//testing/gtest", + ] + + sources = [ + "browsing_data_remover_unittest.mm", + ] +}
diff --git a/ios/web/browsing_data/browsing_data_remover.h b/ios/web/browsing_data/browsing_data_remover.h new file mode 100644 index 0000000..1f51abf --- /dev/null +++ b/ios/web/browsing_data/browsing_data_remover.h
@@ -0,0 +1,44 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_WEB_BROWSING_DATA_BROWSING_DATA_REMOVER_H_ +#define IOS_WEB_BROWSING_DATA_BROWSING_DATA_REMOVER_H_ + +#import <Foundation/Foundation.h> + +#include "base/supports_user_data.h" +#import "ios/web/public/browsing_data_removing_util.h" + +@protocol BrowsingDataRemoverObserver; + +namespace web { + +class BrowserState; + +// Class used to removes the browsing data stored by the WebKit data store. +class BrowsingDataRemover : public base::SupportsUserData::Data { + public: + explicit BrowsingDataRemover(web::BrowserState* browser_state); + ~BrowsingDataRemover() override; + + // Returns the BrowsingDataRemover associated with |browser_state.| + // Lazily creates one if an BrowsingDataRemover is not already associated with + // the |browser_state|. |browser_state| cannot be a nullptr. + static BrowsingDataRemover* FromBrowserState(BrowserState* browser_state); + + // Clears the browsing data. + void ClearBrowsingData(ClearBrowsingDataMask types); + + void AddObserver(id<BrowsingDataRemoverObserver> observer); + void RemoveObserver(id<BrowsingDataRemoverObserver> observer); + + private: + web::BrowserState* browser_state_; // weak, owns this object. + // The list of observers. Holds weak references. + NSHashTable<id<BrowsingDataRemoverObserver>>* observers_list_; +}; + +} // namespace web + +#endif // IOS_WEB_BROWSING_DATA_BROWSING_DATA_REMOVER_H_
diff --git a/ios/web/browsing_data/browsing_data_remover.mm b/ios/web/browsing_data/browsing_data_remover.mm new file mode 100644 index 0000000..4d73ebd --- /dev/null +++ b/ios/web/browsing_data/browsing_data_remover.mm
@@ -0,0 +1,59 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/web/browsing_data/browsing_data_remover.h" + +#import "ios/web/browsing_data/browsing_data_remover_observer.h" +#import "ios/web/public/browser_state.h" +#import "ios/web/public/web_thread.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { +const char kWebBrowsingDataRemoverKeyName[] = "web_browsing_data_remover"; +} // namespace + +namespace web { + +BrowsingDataRemover::BrowsingDataRemover(web::BrowserState* browser_state) + : browser_state_(browser_state) { + DCHECK(browser_state_); + observers_list_ = [NSHashTable weakObjectsHashTable]; +} + +BrowsingDataRemover::~BrowsingDataRemover() {} + +// static +BrowsingDataRemover* BrowsingDataRemover::FromBrowserState( + BrowserState* browser_state) { + DCHECK(browser_state); + + BrowsingDataRemover* browsing_data_remover = + static_cast<BrowsingDataRemover*>( + browser_state->GetUserData(kWebBrowsingDataRemoverKeyName)); + if (!browsing_data_remover) { + browsing_data_remover = new BrowsingDataRemover(browser_state); + browser_state->SetUserData(kWebBrowsingDataRemoverKeyName, + base::WrapUnique(browsing_data_remover)); + } + return browsing_data_remover; +} + +void BrowsingDataRemover::ClearBrowsingData(ClearBrowsingDataMask types) { + // TODO(crbug.com/619783):implement this. +} + +void BrowsingDataRemover::AddObserver( + id<BrowsingDataRemoverObserver> observer) { + [observers_list_ addObject:observer]; +} + +void BrowsingDataRemover::RemoveObserver( + id<BrowsingDataRemoverObserver> observer) { + [observers_list_ removeObject:observer]; +} + +} // namespace web
diff --git a/ios/web/browsing_data/browsing_data_remover_observer.h b/ios/web/browsing_data/browsing_data_remover_observer.h new file mode 100644 index 0000000..60fef80e --- /dev/null +++ b/ios/web/browsing_data/browsing_data_remover_observer.h
@@ -0,0 +1,15 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_WEB_BROWSING_DATA_BROWSING_DATA_REMOVER_OBSERVER_H_ +#define IOS_WEB_BROWSING_DATA_BROWSING_DATA_REMOVER_OBSERVER_H_ + +#import <Foundation/Foundation.h> + +// Protocol used to observe the BrowsingDataRemover. +@protocol BrowsingDataRemoverObserver + +@end + +#endif // IOS_WEB_BROWSING_DATA_BROWSING_DATA_REMOVER_OBSERVER_H_
diff --git a/ios/web/browsing_data/browsing_data_remover_unittest.mm b/ios/web/browsing_data/browsing_data_remover_unittest.mm new file mode 100644 index 0000000..031e5d0 --- /dev/null +++ b/ios/web/browsing_data/browsing_data_remover_unittest.mm
@@ -0,0 +1,40 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/web/browsing_data/browsing_data_remover.h" + +#include "ios/web/public/test/fakes/test_browser_state.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace web { + +class BrowsingDataRemoverTest : public PlatformTest { + protected: + BrowsingDataRemover* GetRemover() { + return BrowsingDataRemover::FromBrowserState(&browser_state_); + } + TestBrowserState browser_state_; +}; + +TEST_F(BrowsingDataRemoverTest, DifferentRemoverForDifferentBrowserState) { + TestBrowserState browser_state_1; + TestBrowserState browser_state_2; + + BrowsingDataRemover* remover_1 = + BrowsingDataRemover::FromBrowserState(&browser_state_1); + BrowsingDataRemover* remover_2 = + BrowsingDataRemover::FromBrowserState(&browser_state_2); + + EXPECT_NE(remover_1, remover_2); + + BrowsingDataRemover* remover_1_again = + BrowsingDataRemover::FromBrowserState(&browser_state_1); + EXPECT_EQ(remover_1_again, remover_1); +} + +} // namespace web
diff --git a/ios/web/browsing_data/browsing_data_removing_util.mm b/ios/web/browsing_data/browsing_data_removing_util.mm new file mode 100644 index 0000000..912e0d6 --- /dev/null +++ b/ios/web/browsing_data/browsing_data_removing_util.mm
@@ -0,0 +1,22 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/web/public/browsing_data_removing_util.h" + +#import "ios/web/browsing_data/browsing_data_remover.h" +#import "ios/web/public/browser_state.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace web { + +void ClearBrowsingData(BrowserState* browser_state, + ClearBrowsingDataMask types) { + BrowsingDataRemover::FromBrowserState(browser_state) + ->ClearBrowsingData(types); +} + +} // namespace web
diff --git a/ios/web/features.mm b/ios/web/features.mm index 8c9e0223..6f55e193 100644 --- a/ios/web/features.mm +++ b/ios/web/features.mm
@@ -11,7 +11,7 @@ "IgnoresViewportScaleLimits", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kWebFrameMessaging{"WebFrameMessaging", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kSlimNavigationManager{"SlimNavigationManager", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/web/public/BUILD.gn b/ios/web/public/BUILD.gn index 9b64373..1c60fae 100644 --- a/ios/web/public/BUILD.gn +++ b/ios/web/public/BUILD.gn
@@ -21,6 +21,7 @@ "block_types.h", "browser_state.h", "browser_url_rewriter.h", + "browsing_data_removing_util.h", "cert_policy.h", "certificate_policy_cache.h", "crw_navigation_item_storage.h",
diff --git a/ios/web/public/browsing_data_removing_util.h b/ios/web/public/browsing_data_removing_util.h new file mode 100644 index 0000000..a1c156e --- /dev/null +++ b/ios/web/public/browsing_data_removing_util.h
@@ -0,0 +1,70 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_WEB_PUBLIC_BROWSING_DATA_REMOVING_UTIL_H_ +#define IOS_WEB_PUBLIC_BROWSING_DATA_REMOVING_UTIL_H_ + +#include <type_traits> + +namespace web { + +class BrowserState; + +// Mask used to control which data to remove when clearing browsing +// data. +enum class ClearBrowsingDataMask { + kRemoveNothing = 0, + + kRemoveAppCache = 1 << 0, + kRemoveCookies = 1 << 1, + kRemoveIndexedDB = 1 << 2, + kRemoveLocalStorage = 1 << 3, + kRemoveWebSQL = 1 << 4, + kRemoveCacheStorage = 1 << 5, + kRemoveVisitedLinks = 1 << 6, + +}; + +// Clears the browsing data store in the Web layer. +void ClearBrowsingData(BrowserState* browser_state, + ClearBrowsingDataMask types); + +// Implementation of bitwise "or", "and" operators and the corresponding +// assignment operators too (as those are not automatically defined for +// "class enum"). +constexpr ClearBrowsingDataMask operator|(ClearBrowsingDataMask lhs, + ClearBrowsingDataMask rhs) { + return static_cast<ClearBrowsingDataMask>( + static_cast<std::underlying_type<ClearBrowsingDataMask>::type>(lhs) | + static_cast<std::underlying_type<ClearBrowsingDataMask>::type>(rhs)); +} + +constexpr ClearBrowsingDataMask operator&(ClearBrowsingDataMask lhs, + ClearBrowsingDataMask rhs) { + return static_cast<ClearBrowsingDataMask>( + static_cast<std::underlying_type<ClearBrowsingDataMask>::type>(lhs) & + static_cast<std::underlying_type<ClearBrowsingDataMask>::type>(rhs)); +} + +inline ClearBrowsingDataMask& operator|=(ClearBrowsingDataMask& lhs, + ClearBrowsingDataMask rhs) { + lhs = lhs | rhs; + return lhs; +} + +inline ClearBrowsingDataMask& operator&=(ClearBrowsingDataMask& lhs, + ClearBrowsingDataMask rhs) { + lhs = lhs & rhs; + return lhs; +} + +// Returns whether the |flag| is set in |mask|. +constexpr bool IsRemoveDataMaskSet(ClearBrowsingDataMask mask, + ClearBrowsingDataMask flag) { + return (mask & flag) == flag; +} + +} // namespace web + +#endif // IOS_WEB_PUBLIC_BROWSING_DATA_REMOVING_UTIL_H_
diff --git a/ios/web/web_state/ui/BUILD.gn b/ios/web/web_state/ui/BUILD.gn index e204894..30341c0 100644 --- a/ios/web/web_state/ui/BUILD.gn +++ b/ios/web/web_state/ui/BUILD.gn
@@ -14,6 +14,7 @@ "//base", "//ios/net", "//ios/web:core", + "//ios/web/browsing_data", "//ios/web/find_in_page", "//ios/web/interstitials", "//ios/web/navigation",
diff --git a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm index 3dd274c5..3ff5a8f1 100644 --- a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm +++ b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
@@ -13,15 +13,7 @@ #include "base/test/bind_test_util.h" #include "components/browser_sync/profile_sync_service_mock.h" #include "components/browser_sync/profile_sync_test_util.h" -#include "components/signin/core/browser/account_tracker_service.h" -#include "components/signin/core/browser/fake_account_fetcher_service.h" -#include "components/signin/core/browser/fake_profile_oauth2_token_service.h" -#include "components/signin/core/browser/fake_signin_manager.h" #include "components/signin/core/browser/signin_error_controller.h" -#include "components/signin/core/browser/test_signin_client.h" -#include "components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h" -#include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h" -#include "components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h" #include "components/sync/driver/sync_service_observer.h" #include "google_apis/gaia/google_service_auth_error.h" #import "ios/web/public/test/fakes/test_web_state.h" @@ -32,6 +24,7 @@ #import "ios/web_view/public/cwv_sync_controller_data_source.h" #import "ios/web_view/public/cwv_sync_controller_delegate.h" #include "services/identity/public/cpp/identity_test_environment.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #import "testing/gtest_mac.h" @@ -55,24 +48,6 @@ protected: CWVSyncControllerTest() : browser_state_(/*off_the_record=*/false), - signin_client_(browser_state_.GetPrefs()), - token_service_delegate_(new ProfileOAuth2TokenServiceIOSDelegate( - &signin_client_, - std::make_unique<FakeProfileOAuth2TokenServiceIOSProvider>(), - &account_tracker_service_)), - token_service_(browser_state_.GetPrefs(), - std::unique_ptr<ProfileOAuth2TokenServiceIOSDelegate>( - token_service_delegate_)), - gaia_cookie_manager_service_(&token_service_, &signin_client_), - signin_manager_(&signin_client_, - &token_service_, - &account_tracker_service_, - &gaia_cookie_manager_service_), - identity_test_env_(&account_tracker_service_, - &account_fetcher_service_, - &token_service_, - &signin_manager_, - &gaia_cookie_manager_service_), signin_error_controller_( SigninErrorController::AccountMode::ANY_ACCOUNT, identity_test_env_.identity_manager()) { @@ -89,14 +64,6 @@ std::make_unique<browser_sync::ProfileSyncServiceMock>( std::move(init_params)); - account_tracker_service_.Initialize(browser_state_.GetPrefs(), - base::FilePath()); - account_fetcher_service_.Initialize(&signin_client_, &token_service_, - &account_tracker_service_, - std::make_unique<TestImageDecoder>()); - signin_manager_.Initialize( - ApplicationContext::GetInstance()->GetLocalState()); - EXPECT_CALL(*profile_sync_service_, AddObserver(_)) .WillOnce(Invoke(this, &CWVSyncControllerTest::AddObserver)); @@ -108,8 +75,6 @@ ~CWVSyncControllerTest() override { EXPECT_CALL(*profile_sync_service_, RemoveObserver(_)); - account_fetcher_service_.Shutdown(); - account_tracker_service_.Shutdown(); } void AddObserver(syncer::SyncServiceObserver* observer) { @@ -125,17 +90,6 @@ ios_web_view::WebViewBrowserState browser_state_; web::TestWebState web_state_; browser_sync::ProfileSyncServiceBundle profile_sync_service_bundle_; - AccountTrackerService account_tracker_service_; - FakeAccountFetcherService account_fetcher_service_; - TestSigninClient signin_client_; - - // Weak, owned by the token service. - ProfileOAuth2TokenServiceIOSDelegate* token_service_delegate_; - - FakeProfileOAuth2TokenService token_service_; - - GaiaCookieManagerService gaia_cookie_manager_service_; - FakeSigninManager signin_manager_; identity::IdentityTestEnvironment identity_test_env_; SigninErrorController signin_error_controller_; std::unique_ptr<browser_sync::ProfileSyncServiceMock> profile_sync_service_; @@ -199,10 +153,14 @@ // Create authentication error. GoogleServiceAuthError auth_error( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); - std::string account_id = account_tracker_service_.SeedAccountInfo( - "gaia_id", "email@example.com"); - token_service_delegate_->AddOrUpdateAccount(account_id); - token_service_delegate_->UpdateAuthError(account_id, auth_error); + std::string account_id = + identity_test_env_.MakePrimaryAccountAvailable("email@example.com") + .account_id; + // TODO(crbug.com/930094): Eliminate this. + identity_test_env_.identity_manager()->LegacyAddAccountFromSystem( + account_id); + identity_test_env_.UpdatePersistentErrorOfRefreshTokenForAccount( + account_id, auth_error); [[delegate expect] syncController:sync_controller_ didStopSyncWithReason:CWVStopSyncReasonServer];
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc index 9b0b81f..e46686b 100644 --- a/media/blink/webmediaplayer_impl_unittest.cc +++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -129,12 +129,6 @@ MOCK_METHOD1(RemoveTextTrack, void(blink::WebInbandTextTrack*)); MOCK_METHOD1(MediaSourceOpened, void(blink::WebMediaSource*)); MOCK_METHOD1(RequestSeek, void(double)); - MOCK_METHOD1(RemoteRouteAvailabilityChanged, - void(blink::WebRemotePlaybackAvailability)); - MOCK_METHOD0(ConnectedToRemoteDevice, void()); - MOCK_METHOD0(DisconnectedFromRemoteDevice, void()); - MOCK_METHOD0(CancelledRemotePlaybackRequest, void()); - MOCK_METHOD0(RemotePlaybackStarted, void()); MOCK_METHOD2(RemotePlaybackCompatibilityChanged, void(const blink::WebURL&, bool)); MOCK_METHOD1(OnBecamePersistentVideo, void(bool));
diff --git a/net/base/url_util.cc b/net/base/url_util.cc index 57d180e..3fe45e9c 100644 --- a/net/base/url_util.cc +++ b/net/base/url_util.cc
@@ -21,6 +21,7 @@ #include "url/gurl.h" #include "url/url_canon.h" #include "url/url_canon_ip.h" +#include "url/url_constants.h" namespace net { @@ -372,6 +373,14 @@ return url.ReplaceComponents(replacements); } +GURL ChangeWebSocketSchemeToHttpScheme(const GURL& url) { + DCHECK(url.SchemeIsWSOrWSS()); + GURL::Replacements replace_scheme; + replace_scheme.SetSchemeStr(url.SchemeIs(url::kWssScheme) ? url::kHttpsScheme + : url::kHttpScheme); + return url.ReplaceComponents(replace_scheme); +} + void GetIdentityFromURL(const GURL& url, base::string16* username, base::string16* password) {
diff --git a/net/base/url_util.h b/net/base/url_util.h index 0b820a70..c21c96e 100644 --- a/net/base/url_util.h +++ b/net/base/url_util.h
@@ -156,6 +156,12 @@ // - reference section NET_EXPORT GURL SimplifyUrlForRequest(const GURL& url); +// Changes scheme "ws" to "http" and "wss" to "https". This is useful for origin +// checks and authentication, where WebSocket URLs are treated as if they were +// HTTP. It is an error to call this function with a url with a scheme other +// than "ws" or "wss". +NET_EXPORT GURL ChangeWebSocketSchemeToHttpScheme(const GURL& url); + // Extracts the unescaped username/password from |url|, saving the results // into |*username| and |*password|. NET_EXPORT_PRIVATE void GetIdentityFromURL(const GURL& url,
diff --git a/net/base/url_util_unittest.cc b/net/base/url_util_unittest.cc index 2aa0f184..f57d89ef 100644 --- a/net/base/url_util_unittest.cc +++ b/net/base/url_util_unittest.cc
@@ -479,6 +479,21 @@ } } +TEST(UrlUtilTest, ChangeWebSocketSchemeToHttpScheme) { + struct { + const char* const input_url; + const char* const expected_output_url; + } tests[] = { + {"ws://google.com:78/path?query=1", "http://google.com:78/path?query=1"}, + {"wss://google.com:441/path?q=1", "https://google.com:441/path?q=1"}}; + for (const auto& test : tests) { + GURL input_url(test.input_url); + GURL expected_output_url(test.expected_output_url); + EXPECT_EQ(expected_output_url, + ChangeWebSocketSchemeToHttpScheme(input_url)); + } +} + TEST(UrlUtilTest, GetIdentityFromURL) { struct { const char* const input_url;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index b87afc1..397f54b 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -1868,15 +1868,7 @@ } case HttpAuth::AUTH_SERVER: if (ForWebSocketHandshake()) { - const GURL& url = request_->url; - url::Replacements<char> ws_to_http; - if (url.SchemeIs("ws")) { - ws_to_http.SetScheme("http", url::Component(0, 4)); - } else { - DCHECK(url.SchemeIs("wss")); - ws_to_http.SetScheme("https", url::Component(0, 5)); - } - return url.ReplaceComponents(ws_to_http); + return net::ChangeWebSocketSchemeToHttpScheme(request_->url); } return request_->url; default:
diff --git a/services/identity/DEPS b/services/identity/DEPS index e875947..8a5277bb 100644 --- a/services/identity/DEPS +++ b/services/identity/DEPS
@@ -1,6 +1,8 @@ include_rules = [ + "+components/prefs/pref_service.h", "+components/signin/core/browser/account_info.h", "+components/signin/core/browser/account_tracker_service.h", + "+components/signin/core/browser/device_id_helper.h", "+components/signin/core/browser/fake_profile_oauth2_token_service.h", "+components/signin/core/browser/fake_signin_manager.h", "+components/signin/core/browser/profile_oauth2_token_service.h",
diff --git a/services/identity/public/cpp/BUILD.gn b/services/identity/public/cpp/BUILD.gn index 2d4266a..ceb24d15 100644 --- a/services/identity/public/cpp/BUILD.gn +++ b/services/identity/public/cpp/BUILD.gn
@@ -44,6 +44,10 @@ "//services/identity/public/cpp:cpp_types", "//services/network/public/cpp", ] + + deps = [ + "//components/prefs:prefs", + ] } # A source_set for types which the public interfaces depend on for typemapping. @@ -97,6 +101,7 @@ "//base", "//base/test:test_support", "//components/signin/core/browser:internals_test_support", + "//components/sync_preferences:test_support", "//services/network:test_support", "//testing/gtest", ]
diff --git a/services/identity/public/cpp/DEPS b/services/identity/public/cpp/DEPS index 93030af..547d0d50 100644 --- a/services/identity/public/cpp/DEPS +++ b/services/identity/public/cpp/DEPS
@@ -30,12 +30,12 @@ "+services/network/test/test_url_loader_factory.h", "+services/network/test/test_utils.h", ], + "accounts_mutator_unittest.cc": [ + "+services/network/test/test_url_loader_factory.h", + ], "identity_manager_unittest.cc": [ "+google_apis/gaia/oauth2_token_service_delegate.h", "+services/network/test/test_cookie_manager.h", "+services/network/test/test_url_loader_factory.h", ], - "accounts_mutator_impl_unittest.cc": [ - "+components/image_fetcher" - ] }
diff --git a/services/identity/public/cpp/accounts_cookie_mutator_unittest.cc b/services/identity/public/cpp/accounts_cookie_mutator_unittest.cc index 1339b5c..1279cdf 100644 --- a/services/identity/public/cpp/accounts_cookie_mutator_unittest.cc +++ b/services/identity/public/cpp/accounts_cookie_mutator_unittest.cc
@@ -19,6 +19,7 @@ #include "services/identity/public/cpp/accounts_in_cookie_jar_info.h" #include "services/identity/public/cpp/identity_manager.h" #include "services/identity/public/cpp/identity_test_environment.h" +#include "services/identity/public/cpp/test_identity_manager_observer.h" #include "services/network/test/test_url_loader_factory.h" #include "services/network/test/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -51,56 +52,6 @@ kTriggerCookieJarUpdateOneAccount, }; -// Class that observes updates from identity::IdentityManager. -class TestIdentityManagerObserver : public identity::IdentityManager::Observer { - public: - explicit TestIdentityManagerObserver( - identity::IdentityManager* identity_manager) - : identity_manager_(identity_manager) { - identity_manager_->AddObserver(this); - } - ~TestIdentityManagerObserver() override { - identity_manager_->RemoveObserver(this); - } - - void set_on_accounts_in_cookie_updated_callback( - base::OnceCallback<void(const identity::AccountsInCookieJarInfo&, - const GoogleServiceAuthError&)> callback) { - on_accounts_in_cookie_updated_callback_ = std::move(callback); - } - - void set_on_add_account_to_cookie_completed_callback( - base::OnceCallback<void(const std::string&, - const GoogleServiceAuthError&)> callback) { - on_add_account_to_cookie_completed_callback_ = std::move(callback); - } - - private: - // identity::IdentityManager::Observer: - void OnAccountsInCookieUpdated( - const identity::AccountsInCookieJarInfo& accounts_in_cookie_jar_info, - const GoogleServiceAuthError& error) override { - if (on_accounts_in_cookie_updated_callback_) - std::move(on_accounts_in_cookie_updated_callback_) - .Run(accounts_in_cookie_jar_info, error); - } - - void OnAddAccountToCookieCompleted( - const std::string& account_id, - const GoogleServiceAuthError& error) override { - if (on_add_account_to_cookie_completed_callback_) - std::move(on_add_account_to_cookie_completed_callback_) - .Run(account_id, error); - } - - identity::IdentityManager* identity_manager_; - base::OnceCallback<void(const identity::AccountsInCookieJarInfo&, - const GoogleServiceAuthError&)> - on_accounts_in_cookie_updated_callback_; - base::OnceCallback<void(const std::string&, const GoogleServiceAuthError&)> - on_add_account_to_cookie_completed_callback_; -}; - } // namespace namespace identity { @@ -190,22 +141,19 @@ // results in an error due to such account not being available. TEST_F(AccountsCookieMutatorTest, AddAccountToCookie_NonExistingAccount) { base::RunLoop run_loop; - identity_manager_observer()->set_on_add_account_to_cookie_completed_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id, - const GoogleServiceAuthError& error) { - EXPECT_EQ(account_id, kTestUnavailableAccountId); - // The account was not previously available and no access token was - // provided when adding it to the cookie jar: expect an error. - EXPECT_EQ(error.state(), - GoogleServiceAuthError::USER_NOT_SIGNED_UP); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); - + identity_manager_observer()->SetOnAddAccountToCookieCompletedCallback( + run_loop.QuitClosure()); accounts_cookie_mutator()->AddAccountToCookie(kTestUnavailableAccountId, gaia::GaiaSource::kChrome); run_loop.Run(); + + EXPECT_EQ(identity_manager_observer() + ->AccountFromAddAccountToCookieCompletedCallback(), + kTestUnavailableAccountId); + EXPECT_EQ(identity_manager_observer() + ->ErrorFromAddAccountToCookieCompletedCallback() + .state(), + GoogleServiceAuthError::USER_NOT_SIGNED_UP); } // Test that adding an already available account without providing an access @@ -216,26 +164,22 @@ std::string account_id = AddAcountWithRefreshToken(kTestAccountEmail); base::RunLoop run_loop; - identity_manager_observer()->set_on_add_account_to_cookie_completed_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, - const std::string& expected_account_id, - const std::string& account_id, - const GoogleServiceAuthError& error) { - EXPECT_EQ(account_id, expected_account_id); - // The account was previously available: expect success. - EXPECT_EQ(error.state(), GoogleServiceAuthError::NONE); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure(), account_id)); - + identity_manager_observer()->SetOnAddAccountToCookieCompletedCallback( + run_loop.QuitClosure()); accounts_cookie_mutator()->AddAccountToCookie(account_id, gaia::GaiaSource::kChrome); identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( account_id, kTestAccessToken, base::Time::Now() + base::TimeDelta::FromHours(1)); - run_loop.Run(); + + EXPECT_EQ(identity_manager_observer() + ->AccountFromAddAccountToCookieCompletedCallback(), + account_id); + EXPECT_EQ(identity_manager_observer() + ->ErrorFromAddAccountToCookieCompletedCallback() + .state(), + GoogleServiceAuthError::NONE); } // Test that adding a non existing account along with an access token, results @@ -246,21 +190,19 @@ AccountsCookiesMutatorAction::kAddAccountToCookie); base::RunLoop run_loop; - identity_manager_observer()->set_on_add_account_to_cookie_completed_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id, - const GoogleServiceAuthError& error) { - EXPECT_EQ(account_id, kTestUnavailableAccountId); - // Trying to add an non-available account with a valid token to the - // cookie jar should result in the account being merged. - EXPECT_EQ(error.state(), GoogleServiceAuthError::NONE); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); - + identity_manager_observer()->SetOnAddAccountToCookieCompletedCallback( + run_loop.QuitClosure()); accounts_cookie_mutator()->AddAccountToCookieWithToken( kTestUnavailableAccountId, kTestAccessToken, gaia::GaiaSource::kChrome); run_loop.Run(); + + EXPECT_EQ(identity_manager_observer() + ->AccountFromAddAccountToCookieCompletedCallback(), + kTestUnavailableAccountId); + EXPECT_EQ(identity_manager_observer() + ->ErrorFromAddAccountToCookieCompletedCallback() + .state(), + GoogleServiceAuthError::NONE); } // Test that adding an already available account along with an access token, @@ -272,24 +214,20 @@ std::string account_id = AddAcountWithRefreshToken(kTestAccountEmail); base::RunLoop run_loop; - identity_manager_observer()->set_on_add_account_to_cookie_completed_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, - const std::string& expected_account_id, - const std::string& account_id, - const GoogleServiceAuthError& error) { - EXPECT_EQ(account_id, expected_account_id); - // Trying to add a previously available account with a valid token - // to the cookie jar should also result in the account being merged. - EXPECT_EQ(error.state(), GoogleServiceAuthError::NONE); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure(), account_id)); - + identity_manager_observer()->SetOnAddAccountToCookieCompletedCallback( + run_loop.QuitClosure()); accounts_cookie_mutator()->AddAccountToCookieWithToken( account_id, kTestAccessToken, gaia::GaiaSource::kChrome); run_loop.Run(); + + EXPECT_EQ(identity_manager_observer() + ->AccountFromAddAccountToCookieCompletedCallback(), + account_id); + EXPECT_EQ(identity_manager_observer() + ->ErrorFromAddAccountToCookieCompletedCallback() + .state(), + GoogleServiceAuthError::NONE); } // Test that trying to set a list of accounts in the cookie jar where none of @@ -376,21 +314,22 @@ AccountsCookiesMutatorAction::kTriggerCookieJarUpdateNoAccounts); base::RunLoop run_loop; - identity_manager_observer()->set_on_accounts_in_cookie_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, - const identity::AccountsInCookieJarInfo& accounts_in_jar_info, - const GoogleServiceAuthError& error) { - EXPECT_EQ(accounts_in_jar_info.signed_in_accounts.size(), 0U); - EXPECT_EQ(accounts_in_jar_info.signed_out_accounts.size(), 0U); - EXPECT_TRUE(accounts_in_jar_info.accounts_are_fresh); - EXPECT_EQ(error.state(), GoogleServiceAuthError::NONE); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); - + identity_manager_observer()->SetOnAccountsInCookieUpdatedCallback( + run_loop.QuitClosure()); accounts_cookie_mutator()->TriggerCookieJarUpdate(); run_loop.Run(); + + const AccountsInCookieJarInfo& accounts_in_jar_info = + identity_manager_observer() + ->AccountsInfoFromAccountsInCookieUpdatedCallback(); + EXPECT_EQ(accounts_in_jar_info.signed_in_accounts.size(), 0U); + EXPECT_EQ(accounts_in_jar_info.signed_out_accounts.size(), 0U); + EXPECT_TRUE(accounts_in_jar_info.accounts_are_fresh); + + EXPECT_EQ(identity_manager_observer() + ->ErrorFromAddAccountToCookieCompletedCallback() + .state(), + GoogleServiceAuthError::NONE); } // Test triggering the update of a cookie jar with one accounts works and that @@ -400,46 +339,47 @@ AccountsCookiesMutatorAction::kTriggerCookieJarUpdateOneAccount); base::RunLoop run_loop; - identity_manager_observer()->set_on_accounts_in_cookie_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, - const identity::AccountsInCookieJarInfo& accounts_in_jar_info, - const GoogleServiceAuthError& error) { - EXPECT_EQ(accounts_in_jar_info.signed_in_accounts.size(), 1U); - EXPECT_EQ(accounts_in_jar_info.signed_in_accounts[0].gaia_id, - kTestAccountGaiaId); - EXPECT_EQ(accounts_in_jar_info.signed_in_accounts[0].email, - kTestAccountEmail); - - EXPECT_EQ(accounts_in_jar_info.signed_out_accounts.size(), 0U); - EXPECT_TRUE(accounts_in_jar_info.accounts_are_fresh); - EXPECT_EQ(error.state(), GoogleServiceAuthError::NONE); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); - + identity_manager_observer()->SetOnAccountsInCookieUpdatedCallback( + run_loop.QuitClosure()); accounts_cookie_mutator()->TriggerCookieJarUpdate(); run_loop.Run(); + + const AccountsInCookieJarInfo& accounts_in_jar_info = + identity_manager_observer() + ->AccountsInfoFromAccountsInCookieUpdatedCallback(); + EXPECT_EQ(accounts_in_jar_info.signed_in_accounts.size(), 1U); + EXPECT_EQ(accounts_in_jar_info.signed_in_accounts[0].gaia_id, + kTestAccountGaiaId); + EXPECT_EQ(accounts_in_jar_info.signed_in_accounts[0].email, + kTestAccountEmail); + + EXPECT_EQ(accounts_in_jar_info.signed_out_accounts.size(), 0U); + EXPECT_TRUE(accounts_in_jar_info.accounts_are_fresh); + + EXPECT_EQ(identity_manager_observer() + ->ErrorFromAddAccountToCookieCompletedCallback() + .state(), + GoogleServiceAuthError::NONE); } // Test that calling ForceTriggerOnAddAccountToCookieCompleted() with an account // ID and a valid error runs the callback with that data passed through. TEST_F(AccountsCookieMutatorTest, ForceTriggerOnAddAccountToCookieCompleted) { base::RunLoop run_loop; - identity_manager_observer()->set_on_add_account_to_cookie_completed_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id, - const GoogleServiceAuthError& error) { - EXPECT_EQ(account_id, kTestUnavailableAccountId); - EXPECT_EQ(error.state(), GoogleServiceAuthError::TWO_FACTOR); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); - + identity_manager_observer()->SetOnAddAccountToCookieCompletedCallback( + run_loop.QuitClosure()); accounts_cookie_mutator()->ForceTriggerOnAddAccountToCookieCompleted( kTestUnavailableAccountId, GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR)); run_loop.Run(); + + EXPECT_EQ(identity_manager_observer() + ->AccountFromAddAccountToCookieCompletedCallback(), + kTestUnavailableAccountId); + EXPECT_EQ(identity_manager_observer() + ->ErrorFromAddAccountToCookieCompletedCallback() + .state(), + GoogleServiceAuthError::TWO_FACTOR); } } // namespace identity
diff --git a/services/identity/public/cpp/accounts_mutator.h b/services/identity/public/cpp/accounts_mutator.h index 414e143c..047b4e58 100644 --- a/services/identity/public/cpp/accounts_mutator.h +++ b/services/identity/public/cpp/accounts_mutator.h
@@ -56,7 +56,9 @@ // Removes the credentials associated to account_id from the internal storage, // and moves them to |target|. The credentials are not revoked on the server, // but the IdentityManager::Observer::OnRefreshTokenRemovedForAccount() - // notification is sent to the observers. + // notification is sent to the observers. Also recreates a new device ID for + // this mutator. The device ID of the current mutator is not moved to the + // target mutator. virtual void MoveAccount(AccountsMutator* target, const std::string& account_id) = 0; #endif
diff --git a/services/identity/public/cpp/accounts_mutator_impl.cc b/services/identity/public/cpp/accounts_mutator_impl.cc index b5808ad..5ededbc 100644 --- a/services/identity/public/cpp/accounts_mutator_impl.cc +++ b/services/identity/public/cpp/accounts_mutator_impl.cc
@@ -7,8 +7,10 @@ #include <string> #include "base/logging.h" +#include "components/prefs/pref_service.h" #include "components/signin/core/browser/account_info.h" #include "components/signin/core/browser/account_tracker_service.h" +#include "components/signin/core/browser/device_id_helper.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_manager_base.h" @@ -17,13 +19,19 @@ AccountsMutatorImpl::AccountsMutatorImpl( ProfileOAuth2TokenService* token_service, AccountTrackerService* account_tracker_service, - SigninManagerBase* signin_manager) + SigninManagerBase* signin_manager, + PrefService* pref_service) : token_service_(token_service), account_tracker_service_(account_tracker_service), signin_manager_(signin_manager) { DCHECK(token_service_); DCHECK(account_tracker_service_); DCHECK(signin_manager_); +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + // TODO(myid.shin): Ensure a non-null PrefService is passed in tests and add + // DCHECK here. + pref_service_ = pref_service; +#endif } AccountsMutatorImpl::~AccountsMutatorImpl() {} @@ -89,6 +97,13 @@ auto* target_impl = static_cast<AccountsMutatorImpl*>(target); target_impl->account_tracker_service_->SeedAccountInfo(account_info); token_service_->ExtractCredentials(target_impl->token_service_, account_id); + + DCHECK(pref_service_); + // Reset the device ID from the source mutator: the exported token is linked + // to the device ID of the current mutator on the server. Reset the device ID + // of the current mutator to avoid tying it with the new mutator. See + // https://crbug.com/813928#c16 + signin::RecreateSigninScopedDeviceId(pref_service_); } #endif
diff --git a/services/identity/public/cpp/accounts_mutator_impl.h b/services/identity/public/cpp/accounts_mutator_impl.h index 728f1a18..4ba626fc 100644 --- a/services/identity/public/cpp/accounts_mutator_impl.h +++ b/services/identity/public/cpp/accounts_mutator_impl.h
@@ -8,10 +8,13 @@ #include <string> #include "base/macros.h" +#include "build/buildflag.h" +#include "components/signin/core/browser/signin_buildflags.h" #include "components/signin/core/browser/signin_metrics.h" #include "services/identity/public/cpp/accounts_mutator.h" class AccountTrackerService; +class PrefService; class ProfileOAuth2TokenService; class SigninManagerBase; @@ -22,7 +25,8 @@ public: explicit AccountsMutatorImpl(ProfileOAuth2TokenService* token_service, AccountTrackerService* account_tracker_service, - SigninManagerBase* signin_manager); + SigninManagerBase* signin_manager, + PrefService* pref_service); ~AccountsMutatorImpl() override; // AccountsMutator: @@ -56,7 +60,9 @@ ProfileOAuth2TokenService* token_service_; AccountTrackerService* account_tracker_service_; SigninManagerBase* signin_manager_; - +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + PrefService* pref_service_; +#endif DISALLOW_COPY_AND_ASSIGN(AccountsMutatorImpl); };
diff --git a/services/identity/public/cpp/accounts_mutator_unittest.cc b/services/identity/public/cpp/accounts_mutator_unittest.cc index dea93819..fd5b9983 100644 --- a/services/identity/public/cpp/accounts_mutator_unittest.cc +++ b/services/identity/public/cpp/accounts_mutator_unittest.cc
@@ -8,11 +8,15 @@ #include "base/message_loop/message_loop.h" #include "base/optional.h" #include "base/test/gtest_util.h" +#include "components/signin/core/browser/device_id_helper.h" #include "components/signin/core/browser/signin_metrics.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" #include "services/identity/public/cpp/accounts_mutator_impl.h" #include "services/identity/public/cpp/identity_manager.h" #include "services/identity/public/cpp/identity_test_environment.h" #include "services/identity/public/cpp/identity_test_utils.h" +#include "services/identity/public/cpp/test_identity_manager_observer.h" +#include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -25,49 +29,6 @@ const char kRefreshToken2[] = "refresh_token_2"; const char kSupervisedUserPseudoEmail[] = "managed_user@localhost"; -// Class that observes updates from identity::IdentityManager. -class TestIdentityManagerObserver : public identity::IdentityManager::Observer { - public: - explicit TestIdentityManagerObserver( - identity::IdentityManager* identity_manager) - : identity_manager_(identity_manager) { - identity_manager_->AddObserver(this); - } - ~TestIdentityManagerObserver() override { - identity_manager_->RemoveObserver(this); - } - - void set_on_refresh_token_updated_callback( - base::OnceCallback<void(const std::string&)> callback) { - on_refresh_token_updated_callback_ = std::move(callback); - } - - void set_on_refresh_token_removed_callback( - base::OnceCallback<void(const std::string&)> callback) { - on_refresh_token_removed_callback_ = std::move(callback); - } - - private: - // identity::IdentityManager::Observer: - void OnRefreshTokenUpdatedForAccount( - const CoreAccountInfo& account_info) override { - if (on_refresh_token_updated_callback_) - std::move(on_refresh_token_updated_callback_) - .Run(account_info.account_id); - } - - void OnRefreshTokenRemovedForAccount(const std::string& account_id) override { - if (on_refresh_token_removed_callback_) - std::move(on_refresh_token_removed_callback_).Run(account_id); - } - - identity::IdentityManager* identity_manager_; - base::OnceCallback<void(const std::string&)> - on_refresh_token_updated_callback_; - base::OnceCallback<void(const std::string&)> - on_refresh_token_removed_callback_; -}; - // Class that observes diagnostics updates from identity::IdentityManager. class TestIdentityManagerDiagnosticsObserver : public identity::IdentityManager::DiagnosticsObserver { @@ -125,11 +86,14 @@ class AccountsMutatorTest : public testing::Test { public: AccountsMutatorTest() - : identity_manager_observer_(identity_manager()), + : identity_test_env_(&test_url_loader_factory_, &prefs_), + identity_manager_observer_(identity_manager()), identity_manager_diagnostics_observer_(identity_manager()) {} ~AccountsMutatorTest() override {} + PrefService* pref_service() { return &prefs_; } + identity::IdentityManager* identity_manager() { return identity_test_env_.identity_manager(); } @@ -149,6 +113,8 @@ private: base::MessageLoop message_loop_; + sync_preferences::TestingPrefServiceSyncable prefs_; + network::TestURLLoaderFactory test_url_loader_factory_; identity::IdentityTestEnvironment identity_test_env_; TestIdentityManagerObserver identity_manager_observer_; TestIdentityManagerDiagnosticsObserver identity_manager_diagnostics_observer_; @@ -169,12 +135,8 @@ return; base::RunLoop run_loop; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id) { - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop.QuitClosure()); std::string account_id = accounts_mutator()->AddOrUpdateAccount( kTestGaiaId, kTestEmail, kRefreshToken, @@ -206,12 +168,8 @@ // First of all add the account to the account tracker service. base::RunLoop run_loop; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id) { - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop.QuitClosure()); std::string account_id = accounts_mutator()->AddOrUpdateAccount( kTestGaiaId, kTestEmail, kRefreshToken, @@ -234,15 +192,8 @@ // Now try adding the account again with the same account id but with // different information, and check that the account gets updated. base::RunLoop run_loop2; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, - const std::string& expected_account_id, - const std::string& added_account_id) { - EXPECT_EQ(added_account_id, expected_account_id); - std::move(quit_closure).Run(); - }, - run_loop2.QuitClosure(), account_id)); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop2.QuitClosure()); // The internals of IdentityService is migrating from email to gaia id // as the account id. Detect whether the current plaform has completed @@ -261,6 +212,11 @@ signin_metrics::SourceForRefreshTokenOperation::kUnknown); run_loop2.Run(); + EXPECT_EQ(identity_manager_observer() + ->AccountFromRefreshTokenUpdatedCallback() + .account_id, + account_id); + // No new accounts should be created, just the information should be updated. EXPECT_EQ(identity_manager()->GetAccountsWithRefreshTokens().size(), 1U); AccountInfo updated_account_info = @@ -286,12 +242,8 @@ // First of all add the account to the account tracker service. base::RunLoop run_loop; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id) { - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop.QuitClosure()); std::string account_id = accounts_mutator()->AddOrUpdateAccount( kTestGaiaId, kTestEmail, kRefreshToken, @@ -379,20 +331,17 @@ // Now try invalidating the primary account, and check that it gets updated. base::RunLoop run_loop; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, - const std::string& expected_account_id, - const std::string& added_or_updated_account_id) { - EXPECT_EQ(added_or_updated_account_id, expected_account_id); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure(), primary_account_info.account_id)); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop.QuitClosure()); accounts_mutator()->InvalidateRefreshTokenForPrimaryAccount( signin_metrics::SourceForRefreshTokenOperation::kUnknown); run_loop.Run(); + EXPECT_EQ(identity_manager_observer() + ->AccountFromRefreshTokenUpdatedCallback() + .account_id, + primary_account_info.account_id); EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken( primary_account_info.account_id)); EXPECT_TRUE( @@ -420,12 +369,8 @@ // Next, add a secondary account. base::RunLoop run_loop; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id) { - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop.QuitClosure()); std::string account_id = accounts_mutator()->AddOrUpdateAccount( kTestGaiaId, kTestEmail, kRefreshToken, @@ -441,20 +386,18 @@ // Now try invalidating the primary account, and check that it gets updated. base::RunLoop run_loop2; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, - const std::string& expected_account_id, - const std::string& added_or_updated_account_id) { - EXPECT_EQ(added_or_updated_account_id, expected_account_id); - std::move(quit_closure).Run(); - }, - run_loop2.QuitClosure(), primary_account_info.account_id)); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop2.QuitClosure()); accounts_mutator()->InvalidateRefreshTokenForPrimaryAccount( signin_metrics::SourceForRefreshTokenOperation::kUnknown); run_loop2.Run(); + EXPECT_EQ(identity_manager_observer() + ->AccountFromRefreshTokenUpdatedCallback() + .account_id, + primary_account_info.account_id); + // Check whether the primary account refresh token got invalidated. EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken( primary_account_info.account_id)); @@ -503,8 +446,8 @@ return; base::RunLoop run_loop; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce([](const std::string& account_id) { + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + base::BindOnce([]() { // This callback should not be invoked now. EXPECT_TRUE(false); })); @@ -529,12 +472,8 @@ // First of all add the account to the account tracker service. base::RunLoop run_loop; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id) { - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop.QuitClosure()); std::string account_id = accounts_mutator()->AddOrUpdateAccount( kTestGaiaId, kTestEmail, kRefreshToken, @@ -550,20 +489,17 @@ // Now remove the account that we just added. base::RunLoop run_loop2; - identity_manager_observer()->set_on_refresh_token_removed_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, - const std::string& expected_account_id, - const std::string& removed_account_id) { - EXPECT_EQ(removed_account_id, expected_account_id); - std::move(quit_closure).Run(); - }, - run_loop2.QuitClosure(), account_id)); + identity_manager_observer()->SetOnRefreshTokenRemovedCallback( + run_loop2.QuitClosure()); accounts_mutator()->RemoveAccount( account_id, signin_metrics::SourceForRefreshTokenOperation::kUnknown); run_loop2.Run(); + EXPECT_EQ( + identity_manager_observer()->AccountIdFromRefreshTokenRemovedCallback(), + account_id); + EXPECT_FALSE(identity_manager()->HasAccountWithRefreshToken(account_id)); EXPECT_FALSE( identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( @@ -580,12 +516,8 @@ // First of all the first account to the account tracker service. base::RunLoop run_loop; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id) { - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop.QuitClosure()); std::string account_id = accounts_mutator()->AddOrUpdateAccount( kTestGaiaId, kTestEmail, kRefreshToken, @@ -601,12 +533,8 @@ // Now add the second account. base::RunLoop run_loop2; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id) { - std::move(quit_closure).Run(); - }, - run_loop2.QuitClosure())); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop2.QuitClosure()); std::string account_id2 = accounts_mutator()->AddOrUpdateAccount( kTestGaiaId2, kTestEmail2, kRefreshToken2, @@ -650,10 +578,19 @@ auto* other_accounts_mutator = other_identity_test_env.identity_manager()->GetAccountsMutator(); + std::string device_id_1 = signin::GetOrCreateScopedDeviceId(pref_service()); + EXPECT_FALSE(device_id_1.empty()); + accounts_mutator()->MoveAccount(other_accounts_mutator, account_info.account_id); EXPECT_EQ(0U, identity_manager()->GetAccountsWithRefreshTokens().size()); + std::string device_id_2 = signin::GetOrCreateScopedDeviceId(pref_service()); + EXPECT_FALSE(device_id_2.empty()); + // |device_id_1| and |device_id_2| should be different as the divice ID is + // recreated in MoveAccount(). + EXPECT_NE(device_id_1, device_id_2); + auto other_accounts_with_refresh_token = other_identity_test_env.identity_manager() ->GetAccountsWithRefreshTokens(); @@ -675,12 +612,8 @@ EXPECT_EQ(identity_manager()->GetAccountsWithRefreshTokens().size(), 0U); base::RunLoop run_loop; - identity_manager_observer()->set_on_refresh_token_updated_callback( - base::BindOnce( - [](base::OnceClosure quit_closure, const std::string& account_id) { - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + identity_manager_observer()->SetOnRefreshTokenUpdatedCallback( + run_loop.QuitClosure()); accounts_mutator()->LegacySetRefreshTokenForSupervisedUser(kRefreshToken); run_loop.Run();
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc index af9fff8..5de99d4 100644 --- a/services/identity/public/cpp/identity_manager.cc +++ b/services/identity/public/cpp/identity_manager.cc
@@ -285,6 +285,11 @@ void IdentityManager::ForceTriggerOnCookieChange() { gaia_cookie_manager_service_->ForceOnCookieChangeProcessing(); } + +void IdentityManager::LegacyAddAccountFromSystem( + const std::string& account_id) { + token_service_->GetDelegate()->AddAccountFromSystem(account_id); +} #endif #if defined(OS_ANDROID) || defined(OS_IOS)
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h index 3f43070..f7b097b5 100644 --- a/services/identity/public/cpp/identity_manager.h +++ b/services/identity/public/cpp/identity_manager.h
@@ -398,6 +398,13 @@ // TODO(https://crbug.com/930582) : Remove the need to expose this method // or move it to the network::CookieManager. void ForceTriggerOnCookieChange(); + + // Adds a given account to the token service from a system account. This + // API calls OAuth2TokenServiceDelegate::AddAccountFromSystem and it + // triggers platform specific implementation for IOS. + // NOTE: In normal usage, this method SHOULD NOT be called. + // TODO(https://crbug.com/930094): Eliminate the need to expose this. + void LegacyAddAccountFromSystem(const std::string& account_id); #endif #if defined(OS_ANDROID) || defined(OS_IOS)
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc index ca6caa8..f05f497 100644 --- a/services/identity/public/cpp/identity_manager_unittest.cc +++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -131,24 +131,28 @@ on_google_signed_out_callback_ = std::move(callback); } - const AccountInfo& primary_account_from_signin_callback() const { + const CoreAccountInfo& primary_account_from_signin_callback() const { return primary_account_from_signin_callback_; } - const AccountInfo& primary_account_from_signout_callback() const { + const CoreAccountInfo& primary_account_from_signout_callback() const { return primary_account_from_signout_callback_; } private: // SigninManager::Observer: - void GoogleSigninSucceeded(const AccountInfo& account_info) override { - ASSERT_TRUE(identity_manager_); + void GoogleSigninSucceeded(const AccountInfo&) override { + // Fetch the primary account from IdentityManager. The goal is to check + // that the account from IdentityManager has correct values even if other + // SigninManager::Observer are notified. primary_account_from_signin_callback_ = identity_manager_->GetPrimaryAccountInfo(); if (on_google_signin_succeeded_callback_) std::move(on_google_signin_succeeded_callback_).Run(); } - void GoogleSignedOut(const AccountInfo& account_info) override { - ASSERT_TRUE(identity_manager_); + void GoogleSignedOut(const AccountInfo&) override { + // Fetch the primary account from IdentityManager. The goal is to check + // that the account from IdentityManager has correct values even if other + // SigninManager::Observer are notified. primary_account_from_signout_callback_ = identity_manager_->GetPrimaryAccountInfo(); if (on_google_signed_out_callback_) @@ -160,8 +164,8 @@ base::OnceClosure on_google_signin_succeeded_callback_; base::OnceClosure on_google_signin_failed_callback_; base::OnceClosure on_google_signed_out_callback_; - AccountInfo primary_account_from_signin_callback_; - AccountInfo primary_account_from_signout_callback_; + CoreAccountInfo primary_account_from_signin_callback_; + CoreAccountInfo primary_account_from_signout_callback_; }; // Class that observes updates from ProfileOAuth2TokenService and and verifies @@ -436,7 +440,7 @@ // Test that IdentityManager starts off with the information in SigninManager. TEST_F(IdentityManagerTest, PrimaryAccountInfoAtStartup) { - AccountInfo primary_account_info = + CoreAccountInfo primary_account_info = identity_manager()->GetPrimaryAccountInfo(); EXPECT_EQ(kTestGaiaId, primary_account_info.gaia); EXPECT_EQ(kTestEmail, primary_account_info.email); @@ -462,7 +466,7 @@ EXPECT_EQ(kTestGaiaId, primary_account_from_set_callback.gaia); EXPECT_EQ(kTestEmail, primary_account_from_set_callback.email); - AccountInfo primary_account_info = + CoreAccountInfo primary_account_info = identity_manager()->GetPrimaryAccountInfo(); EXPECT_EQ(kTestGaiaId, primary_account_info.gaia); EXPECT_EQ(kTestEmail, primary_account_info.email); @@ -498,7 +502,7 @@ EXPECT_EQ(kTestGaiaId, primary_account_from_cleared_callback.gaia); EXPECT_EQ(kTestEmail, primary_account_from_cleared_callback.email); - AccountInfo primary_account_info = + CoreAccountInfo primary_account_info = identity_manager()->GetPrimaryAccountInfo(); EXPECT_EQ("", primary_account_info.gaia); EXPECT_EQ("", primary_account_info.email); @@ -525,7 +529,7 @@ // the IdentityManager is still storing the primary account's ID. account_tracker()->RemoveAccount(kTestGaiaId); - AccountInfo primary_account_info = + CoreAccountInfo primary_account_info = identity_manager()->GetPrimaryAccountInfo(); EXPECT_EQ("", primary_account_info.gaia); EXPECT_EQ("", primary_account_info.email); @@ -595,7 +599,7 @@ TEST_F(IdentityManagerTest, QueryingOfRefreshTokensInteractionWithPrimaryAccount) { - AccountInfo account_info = identity_manager()->GetPrimaryAccountInfo(); + CoreAccountInfo account_info = identity_manager()->GetPrimaryAccountInfo(); std::string account_id = account_info.account_id; // Should not have a refresh token for the primary account at initialization. @@ -658,7 +662,7 @@ TEST_F(IdentityManagerTest, QueryingOfRefreshTokensReflectsNonemptyInitialState) { - AccountInfo account_info = identity_manager()->GetPrimaryAccountInfo(); + CoreAccountInfo account_info = identity_manager()->GetPrimaryAccountInfo(); std::string account_id = account_info.account_id; EXPECT_FALSE( @@ -901,7 +905,7 @@ TEST_F( IdentityManagerTest, HasAccountWithRefreshTokenInteractionBetweenPrimaryAndSecondaryAccounts) { - AccountInfo primary_account_info = + CoreAccountInfo primary_account_info = identity_manager()->GetPrimaryAccountInfo(); std::string primary_account_id = primary_account_info.account_id; @@ -943,7 +947,7 @@ TEST_F(IdentityManagerTest, CallbackSentOnUpdateToErrorStateOfRefreshTokenForAccount) { - AccountInfo primary_account_info = + CoreAccountInfo primary_account_info = identity_manager()->GetPrimaryAccountInfo(); std::string primary_account_id = primary_account_info.account_id; SetRefreshTokenForPrimaryAccount(identity_manager()); @@ -997,7 +1001,7 @@ } TEST_F(IdentityManagerTest, GetErrorStateOfRefreshTokenForAccount) { - AccountInfo primary_account_info = + CoreAccountInfo primary_account_info = identity_manager()->GetPrimaryAccountInfo(); std::string primary_account_id = primary_account_info.account_id; @@ -1338,7 +1342,7 @@ signin_manager()->SignIn(kTestGaiaId, kTestEmail); run_loop.Run(); - AccountInfo primary_account_from_signin_callback = + CoreAccountInfo primary_account_from_signin_callback = signin_manager_observer.primary_account_from_signin_callback(); EXPECT_EQ(kTestGaiaId, primary_account_from_signin_callback.gaia); EXPECT_EQ(kTestEmail, primary_account_from_signin_callback.email); @@ -1363,7 +1367,7 @@ signin_manager()->ForceSignOut(); run_loop.Run(); - AccountInfo primary_account_from_signout_callback = + CoreAccountInfo primary_account_from_signout_callback = signin_manager_observer.primary_account_from_signout_callback(); EXPECT_EQ(std::string(), primary_account_from_signout_callback.gaia); EXPECT_EQ(std::string(), primary_account_from_signout_callback.email); @@ -1380,7 +1384,7 @@ // IdentityManager correctly reflects the updated version. See crbug.com/842041 // and crbug.com/842670 for further details. TEST_F(IdentityManagerTest, IdentityManagerReflectsUpdatedEmailAddress) { - AccountInfo primary_account_info = + CoreAccountInfo primary_account_info = identity_manager()->GetPrimaryAccountInfo(); EXPECT_EQ(kTestGaiaId, primary_account_info.gaia); EXPECT_EQ(kTestEmail, primary_account_info.email); @@ -1433,7 +1437,7 @@ EXPECT_EQ( account_id, - identity_manager_observer()->AccountFromRefreshTokenRemovedCallback()); + identity_manager_observer()->AccountIdFromRefreshTokenRemovedCallback()); } TEST_F(IdentityManagerTest, @@ -1475,7 +1479,7 @@ EXPECT_EQ( expected_account_info.account_id, - identity_manager_observer()->AccountFromRefreshTokenRemovedCallback()); + identity_manager_observer()->AccountIdFromRefreshTokenRemovedCallback()); } #if !defined(OS_CHROMEOS) @@ -1539,7 +1543,7 @@ EXPECT_EQ( expected_account_info.account_id, - identity_manager_observer()->AccountFromRefreshTokenRemovedCallback()); + identity_manager_observer()->AccountIdFromRefreshTokenRemovedCallback()); } #endif @@ -1559,7 +1563,7 @@ EXPECT_EQ( dummy_account_id, - identity_manager_observer()->AccountFromRefreshTokenRemovedCallback()); + identity_manager_observer()->AccountIdFromRefreshTokenRemovedCallback()); } TEST_F(
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc index 040bb85..914295c 100644 --- a/services/identity/public/cpp/identity_test_environment.cc +++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -263,8 +263,12 @@ #endif #if !defined(OS_ANDROID) && !defined(OS_IOS) + // TODO(https://crbug.com/928677): Once there is no more usage of ctors + // that allows tests to pass backing object, |dependencies_owner_| null + // pointer condition is not neccessary. accounts_mutator = std::make_unique<AccountsMutatorImpl>( - token_service_, account_tracker_service_, signin_manager_); + token_service_, account_tracker_service_, signin_manager_, + dependencies_owner_ ? dependencies_owner_->pref_service() : nullptr); #endif std::unique_ptr<AccountsCookieMutator> accounts_cookie_mutator =
diff --git a/services/identity/public/cpp/test_identity_manager_observer.cc b/services/identity/public/cpp/test_identity_manager_observer.cc index b7e170d..c76d493 100644 --- a/services/identity/public/cpp/test_identity_manager_observer.cc +++ b/services/identity/public/cpp/test_identity_manager_observer.cc
@@ -75,15 +75,13 @@ return error_from_error_state_of_refresh_token_updated_callback_; } -// This method uses a RepeatingCallback to simplify verification of multiple -// removed tokens. void TestIdentityManagerObserver::SetOnRefreshTokenRemovedCallback( - base::RepeatingCallback<void(const std::string&)> callback) { + base::OnceClosure callback) { on_refresh_token_removed_callback_ = std::move(callback); } const std::string& -TestIdentityManagerObserver::AccountFromRefreshTokenRemovedCallback() { +TestIdentityManagerObserver::AccountIdFromRefreshTokenRemovedCallback() { return account_from_refresh_token_removed_callback_; } @@ -186,7 +184,7 @@ batch_change_records_.rbegin()->emplace_back(account_id); account_from_refresh_token_removed_callback_ = account_id; if (on_refresh_token_removed_callback_) - on_refresh_token_removed_callback_.Run(account_id); + std::move(on_refresh_token_removed_callback_).Run(); } void TestIdentityManagerObserver::OnErrorStateOfRefreshTokenUpdatedForAccount(
diff --git a/services/identity/public/cpp/test_identity_manager_observer.h b/services/identity/public/cpp/test_identity_manager_observer.h index 65639c6..7fccd33 100644 --- a/services/identity/public/cpp/test_identity_manager_observer.h +++ b/services/identity/public/cpp/test_identity_manager_observer.h
@@ -41,11 +41,8 @@ const GoogleServiceAuthError& ErrorFromErrorStateOfRefreshTokenUpdatedCallback() const; - // This method uses a RepeatingCallback to simplify verification of multiple - // removed tokens. - void SetOnRefreshTokenRemovedCallback( - base::RepeatingCallback<void(const std::string&)> callback); - const std::string& AccountFromRefreshTokenRemovedCallback(); + void SetOnRefreshTokenRemovedCallback(base::OnceClosure callback); + const std::string& AccountIdFromRefreshTokenRemovedCallback(); void SetOnRefreshTokensLoadedCallback(base::OnceClosure callback); @@ -118,8 +115,7 @@ GoogleServiceAuthError error_from_error_state_of_refresh_token_updated_callback_; - base::RepeatingCallback<void(const std::string&)> - on_refresh_token_removed_callback_; + base::OnceClosure on_refresh_token_removed_callback_; std::string account_from_refresh_token_removed_callback_; base::OnceClosure on_refresh_tokens_loaded_callback_;
diff --git a/services/network/public/cpp/cors/cors.cc b/services/network/public/cpp/cors/cors.cc index 29d5ec5..c84c25b3 100644 --- a/services/network/public/cpp/cors/cors.cc +++ b/services/network/public/cpp/cors/cors.cc
@@ -359,21 +359,38 @@ // Treat 'Intervention' as a CORS-safelisted header, since it is added by // Chrome when an intervention is (or may be) applied. static const char* const safe_names[] = { - "accept", "accept-language", "content-language", "intervention", - "content-type", "save-data", + "accept", + "accept-language", + "content-language", + "intervention", + "content-type", + "save-data", // The Device Memory header field is a number that indicates the client’s // device memory i.e. approximate amount of ram in GiB. The header value // must satisfy ABNF 1*DIGIT [ "." 1*DIGIT ] // See // https://w3c.github.io/device-memory/#sec-device-memory-client-hint-header // for more details. - "device-memory", "dpr", "width", "viewport-width", + "device-memory", + "dpr", + "width", + "viewport-width", // The `Sec-CH-Lang` header field is a proposed replacement for // `Accept-Language`, using the Client Hints infrastructure. // // https://tools.ietf.org/html/draft-west-lang-client-hint - "sec-ch-lang"}; + "sec-ch-lang", + + // The `Sec-CH-UA-*` header fields are proposed replacements for + // `User-Agent`, using the Client Hints infrastructure. + // + // https://tools.ietf.org/html/draft-west-ua-client-hints + "sec-ch-ua", + "sec-ch-ua-platform", + "sec-ch-ua-arch", + "sec-ch-ua-model", + }; const std::string lower_name = base::ToLowerASCII(name); if (std::find(std::begin(safe_names), std::end(safe_names), lower_name) == std::end(safe_names))
diff --git a/services/network/public/cpp/cors/cors_unittest.cc b/services/network/public/cpp/cors/cors_unittest.cc index 2a24891..2fdda5d2 100644 --- a/services/network/public/cpp/cors/cors_unittest.cc +++ b/services/network/public/cpp/cors/cors_unittest.cc
@@ -386,6 +386,16 @@ // https://crbug.com/924969 } +TEST_F(CorsTest, SafelistedSecCHUA) { + EXPECT_TRUE(IsCorsSafelistedHeader("Sec-CH-UA", "\"User Agent!\"")); + EXPECT_TRUE(IsCorsSafelistedHeader("Sec-CH-UA-Platform", "\"Platform!\"")); + EXPECT_TRUE(IsCorsSafelistedHeader("Sec-CH-UA-Arch", "\"Architecture!\"")); + EXPECT_TRUE(IsCorsSafelistedHeader("Sec-CH-UA-Model", "\"Model!\"")); + + // TODO(mkwst): Validate that `Sec-CH-UA-*` is a structured header. + // https://crbug.com/924969 +} + TEST_F(CorsTest, SafelistedContentLanguage) { EXPECT_TRUE(IsCorsSafelistedHeader("content-language", "en,ja")); EXPECT_TRUE(IsCorsSafelistedHeader("cONTent-LANguaGe", "en,ja"));
diff --git a/services/network/websocket_factory.cc b/services/network/websocket_factory.cc index a61bb29..a933adf 100644 --- a/services/network/websocket_factory.cc +++ b/services/network/websocket_factory.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/memory/weak_ptr.h" #include "mojo/public/cpp/bindings/strong_binding.h" +#include "net/base/url_util.h" #include "services/network/network_context.h" #include "services/network/network_service.h" #include "services/network/public/mojom/network_service.mojom.h" @@ -63,10 +64,7 @@ bool CanReadRawCookies(const GURL& url) override { DCHECK(url.SchemeIsWSOrWSS()); - GURL::Replacements replace_scheme; - replace_scheme.SetSchemeStr( - url.SchemeIs(url::kWssScheme) ? url::kHttpsScheme : url::kHttpScheme); - GURL url_to_check = url.ReplaceComponents(replace_scheme); + GURL url_to_check = net::ChangeWebSocketSchemeToHttpScheme(url); return factory_->context_->network_service()->HasRawHeadersAccess( process_id_, url_to_check); }
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn index d40378c4..f00fd1e 100644 --- a/storage/browser/BUILD.gn +++ b/storage/browser/BUILD.gn
@@ -87,6 +87,8 @@ "fileapi/file_system_context.h", "fileapi/file_system_dir_url_request_job.cc", "fileapi/file_system_dir_url_request_job.h", + "fileapi/file_system_features.cc", + "fileapi/file_system_features.h", "fileapi/file_system_file_stream_reader.cc", "fileapi/file_system_file_stream_reader.h", "fileapi/file_system_file_util.cc", @@ -125,14 +127,21 @@ "fileapi/local_file_stream_writer.h", "fileapi/local_file_util.cc", "fileapi/local_file_util.h", + "fileapi/memory_file_stream_reader.cc", + "fileapi/memory_file_stream_reader.h", + "fileapi/memory_file_stream_writer.cc", + "fileapi/memory_file_stream_writer.h", "fileapi/mount_points.cc", "fileapi/mount_points.h", "fileapi/native_file_util.cc", "fileapi/native_file_util.h", "fileapi/obfuscated_file_util.cc", "fileapi/obfuscated_file_util.h", + "fileapi/obfuscated_file_util_delegate.h", "fileapi/obfuscated_file_util_disk_delegate.cc", "fileapi/obfuscated_file_util_disk_delegate.h", + "fileapi/obfuscated_file_util_memory_delegate.cc", + "fileapi/obfuscated_file_util_memory_delegate.h", "fileapi/open_file_system_mode.h", "fileapi/plugin_private_file_system_backend.cc", "fileapi/plugin_private_file_system_backend.h",
diff --git a/storage/browser/fileapi/file_stream_reader.h b/storage/browser/fileapi/file_stream_reader.h index 1aeaf0e..d5bd883 100644 --- a/storage/browser/fileapi/file_stream_reader.h +++ b/storage/browser/fileapi/file_stream_reader.h
@@ -10,6 +10,7 @@ #include "base/compiler_specific.h" #include "base/component_export.h" #include "base/files/file.h" +#include "base/memory/weak_ptr.h" #include "net/base/completion_once_callback.h" namespace base { @@ -25,6 +26,7 @@ namespace storage { class FileSystemContext; class FileSystemURL; +class ObfuscatedFileUtilMemoryDelegate; } namespace storage { @@ -48,6 +50,22 @@ int64_t initial_offset, const base::Time& expected_modification_time); + // Creates a new FileReader for a memory file |file_path|. + // |initial_offset| specifies the offset in the file where the first read + // should start. If the given offset is out of the file range any + // read operation may error out with net::ERR_REQUEST_RANGE_NOT_SATISFIABLE. + // |expected_modification_time| specifies the expected last modification + // If the value is non-null, the reader will check the underlying file's + // actual modification time to see if the file has been modified, and if + // it does any succeeding read operations should fail with + // ERR_UPLOAD_FILE_CHANGED error. + COMPONENT_EXPORT(STORAGE_BROWSER) + static FileStreamReader* CreateForMemoryFile( + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util, + const base::FilePath& file_path, + int64_t initial_offset, + const base::Time& expected_modification_time); + // Creates a new reader for a filesystem URL |url| form |initial_offset|. // |expected_modification_time| specifies the expected last modification if // the value is non-null, the reader will check the underlying file's actual
diff --git a/storage/browser/fileapi/file_stream_writer.h b/storage/browser/fileapi/file_stream_writer.h index 0d899c0..921e1837 100644 --- a/storage/browser/fileapi/file_stream_writer.h +++ b/storage/browser/fileapi/file_stream_writer.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include "base/component_export.h" +#include "base/memory/weak_ptr.h" #include "net/base/completion_once_callback.h" namespace base { @@ -20,6 +21,10 @@ } namespace storage { +class ObfuscatedFileUtilMemoryDelegate; +} + +namespace storage { // A generic interface for writing to a file-like object. class FileStreamWriter { @@ -34,6 +39,15 @@ int64_t initial_offset, OpenOrCreate open_or_create); + // Creates a writer for the existing memory file in the path |file_path| + // starting from |initial_offset|. + COMPONENT_EXPORT(STORAGE_BROWSER) + static FileStreamWriter* CreateForMemoryFile( + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util, + const base::FilePath& file_path, + int64_t initial_offset, + OpenOrCreate open_or_create); + // Closes the file. If there's an in-flight operation, it is canceled (i.e., // the callback function associated with the operation is not called). virtual ~FileStreamWriter() {}
diff --git a/storage/browser/fileapi/file_system_context.h b/storage/browser/fileapi/file_system_context.h index 9e4c99f..ab494b9 100644 --- a/storage/browser/fileapi/file_system_context.h +++ b/storage/browser/fileapi/file_system_context.h
@@ -308,6 +308,8 @@ OpenFileSystemMode mode, StatusCallback callback); + bool is_incognito() { return is_incognito_; } + private: // For CreateFileSystemOperation. friend class FileSystemOperationRunner;
diff --git a/storage/browser/fileapi/file_system_features.cc b/storage/browser/fileapi/file_system_features.cc new file mode 100644 index 0000000..b573b76d --- /dev/null +++ b/storage/browser/fileapi/file_system_features.cc
@@ -0,0 +1,16 @@ +// 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. + +#include "storage/browser/fileapi/file_system_features.h" + +namespace storage { + +namespace features { + +// Enables Filesystem API in incognito mode. +const base::Feature kEnableFilesystemInIncognito{ + "EnableFilesystemInIncognito", base::FEATURE_DISABLED_BY_DEFAULT}; +} // namespace features + +} // namespace storage
diff --git a/storage/browser/fileapi/file_system_features.h b/storage/browser/fileapi/file_system_features.h new file mode 100644 index 0000000..7c5861b3 --- /dev/null +++ b/storage/browser/fileapi/file_system_features.h
@@ -0,0 +1,22 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_FEATURES_H_ +#define STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_FEATURES_H_ + +#include "base/component_export.h" +#include "base/feature_list.h" + +namespace storage { + +namespace features { + +COMPONENT_EXPORT(STORAGE_BROWSER) +extern const base::Feature kEnableFilesystemInIncognito; + +} // namespace features + +} // namespace storage + +#endif // STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_FEATURES_H_ \ No newline at end of file
diff --git a/storage/browser/fileapi/file_system_file_stream_reader.cc b/storage/browser/fileapi/file_system_file_stream_reader.cc index 8511e21..0d0bd7b 100644 --- a/storage/browser/fileapi/file_system_file_stream_reader.cc +++ b/storage/browser/fileapi/file_system_file_stream_reader.cc
@@ -13,6 +13,7 @@ #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "storage/browser/fileapi/file_system_context.h" +#include "storage/browser/fileapi/file_system_features.h" #include "storage/browser/fileapi/file_system_operation_runner.h" using storage::FileStreamReader; @@ -49,8 +50,8 @@ int FileSystemFileStreamReader::Read(net::IOBuffer* buf, int buf_len, net::CompletionOnceCallback callback) { - if (local_file_reader_) - return local_file_reader_->Read(buf, buf_len, std::move(callback)); + if (file_reader_) + return file_reader_->Read(buf, buf_len, std::move(callback)); read_buf_ = buf; read_buf_len_ = buf_len; @@ -60,8 +61,8 @@ int64_t FileSystemFileStreamReader::GetLength( net::Int64CompletionOnceCallback callback) { - if (local_file_reader_) - return local_file_reader_->GetLength(std::move(callback)); + if (file_reader_) + return file_reader_->GetLength(std::move(callback)); get_length_callback_ = std::move(callback); return CreateSnapshot(); @@ -82,7 +83,7 @@ const base::FilePath& platform_path, scoped_refptr<storage::ShareableFileReference> file_ref) { DCHECK(has_pending_create_snapshot_); - DCHECK(!local_file_reader_.get()); + DCHECK(!file_reader_.get()); has_pending_create_snapshot_ = false; if (file_error != base::File::FILE_OK) { @@ -98,9 +99,16 @@ // Keep the reference (if it's non-null) so that the file won't go away. snapshot_ref_ = std::move(file_ref); - local_file_reader_.reset(FileStreamReader::CreateForLocalFile( - file_system_context_->default_file_task_runner(), platform_path, - initial_offset_, expected_modification_time_)); + if (file_system_context_->is_incognito() && + base::FeatureList::IsEnabled(features::kEnableFilesystemInIncognito)) { + file_reader_.reset(FileStreamReader::CreateForMemoryFile( + file_system_context_->sandbox_delegate()->memory_file_util_delegate(), + platform_path, initial_offset_, expected_modification_time_)); + } else { + file_reader_.reset(FileStreamReader::CreateForLocalFile( + file_system_context_->default_file_task_runner(), platform_path, + initial_offset_, expected_modification_time_)); + } if (read_callback_) { DCHECK(!get_length_callback_); @@ -112,7 +120,7 @@ return; } - int rv = local_file_reader_->GetLength(base::BindOnce( + int rv = file_reader_->GetLength(base::BindOnce( &FileSystemFileStreamReader::OnGetLength, weak_factory_.GetWeakPtr())); if (rv != net::ERR_IO_PENDING) std::move(get_length_callback_).Run(rv);
diff --git a/storage/browser/fileapi/file_system_file_stream_reader.h b/storage/browser/fileapi/file_system_file_stream_reader.h index 7bba41a..8239c76 100644 --- a/storage/browser/fileapi/file_system_file_stream_reader.h +++ b/storage/browser/fileapi/file_system_file_stream_reader.h
@@ -74,7 +74,7 @@ FileSystemURL url_; const int64_t initial_offset_; const base::Time expected_modification_time_; - std::unique_ptr<storage::FileStreamReader> local_file_reader_; + std::unique_ptr<storage::FileStreamReader> file_reader_; scoped_refptr<storage::ShareableFileReference> snapshot_ref_; bool has_pending_create_snapshot_; base::WeakPtrFactory<FileSystemFileStreamReader> weak_factory_;
diff --git a/storage/browser/fileapi/memory_file_stream_reader.cc b/storage/browser/fileapi/memory_file_stream_reader.cc new file mode 100644 index 0000000..ada3541 --- /dev/null +++ b/storage/browser/fileapi/memory_file_stream_reader.cc
@@ -0,0 +1,43 @@ +// 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. + +#include "storage/browser/fileapi/memory_file_stream_reader.h" + +namespace storage { + +FileStreamReader* FileStreamReader::CreateForMemoryFile( + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util, + const base::FilePath& file_path, + int64_t initial_offset, + const base::Time& expected_modification_time) { + return new MemoryFileStreamReader(std::move(memory_file_util), file_path, + initial_offset, expected_modification_time); +} + +MemoryFileStreamReader::~MemoryFileStreamReader() = default; + +int MemoryFileStreamReader::Read(net::IOBuffer* buf, + int buf_len, + net::CompletionOnceCallback callback) { + // TODO(https://crbug.com/93417): Implement! + NOTIMPLEMENTED(); + return 0; +} + +int64_t MemoryFileStreamReader::GetLength( + net::Int64CompletionOnceCallback callback) { + NOTIMPLEMENTED(); + return 0; +} + +MemoryFileStreamReader::MemoryFileStreamReader( + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util, + const base::FilePath& file_path, + int64_t initial_offset, + const base::Time& expected_modification_time) + : memory_file_util_(std::move(memory_file_util)) { + DCHECK(memory_file_util_); +} + +} // namespace storage
diff --git a/storage/browser/fileapi/memory_file_stream_reader.h b/storage/browser/fileapi/memory_file_stream_reader.h new file mode 100644 index 0000000..660ea5c --- /dev/null +++ b/storage/browser/fileapi/memory_file_stream_reader.h
@@ -0,0 +1,47 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_FILEAPI_MEMORY_FILE_STREAM_READER_H_ +#define STORAGE_BROWSER_FILEAPI_MEMORY_FILE_STREAM_READER_H_ + +#include "base/component_export.h" +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "net/base/completion_once_callback.h" +#include "storage/browser/fileapi/file_stream_reader.h" +#include "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h" + +namespace storage { + +// A stream reader for memory files. +class COMPONENT_EXPORT(STORAGE_BROWSER) MemoryFileStreamReader + : public FileStreamReader { + public: + ~MemoryFileStreamReader() override; + + // FileStreamReader overrides. + int Read(net::IOBuffer* buf, + int buf_len, + net::CompletionOnceCallback callback) override; + int64_t GetLength(net::Int64CompletionOnceCallback callback) override; + + private: + friend class FileStreamReader; + + MemoryFileStreamReader( + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util, + const base::FilePath& file_path, + int64_t initial_offset, + const base::Time& expected_modification_time); + + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_; + + DISALLOW_COPY_AND_ASSIGN(MemoryFileStreamReader); +}; + +} // namespace storage + +#endif // STORAGE_BROWSER_FILEAPI_MEMORY_FILE_STREAM_READER_H_
diff --git a/storage/browser/fileapi/memory_file_stream_writer.cc b/storage/browser/fileapi/memory_file_stream_writer.cc new file mode 100644 index 0000000..7089e371 --- /dev/null +++ b/storage/browser/fileapi/memory_file_stream_writer.cc
@@ -0,0 +1,47 @@ +// 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. + +#include "storage/browser/fileapi/memory_file_stream_writer.h" + +namespace storage { + +FileStreamWriter* FileStreamWriter::CreateForMemoryFile( + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util, + const base::FilePath& file_path, + int64_t initial_offset, + OpenOrCreate open_or_create) { + return new MemoryFileStreamWriter(std::move(memory_file_util), file_path, + initial_offset, open_or_create); +} + +MemoryFileStreamWriter::~MemoryFileStreamWriter() = default; + +int MemoryFileStreamWriter::Write(net::IOBuffer* buf, + int buf_len, + net::CompletionOnceCallback callback) { + // TODO(https://crbug.com/93417): Implement! + NOTIMPLEMENTED(); + return 0; +} + +int MemoryFileStreamWriter::Cancel(net::CompletionOnceCallback callback) { + NOTIMPLEMENTED(); + return 0; +} + +int MemoryFileStreamWriter::Flush(net::CompletionOnceCallback callback) { + NOTIMPLEMENTED(); + + return 0; +} + +MemoryFileStreamWriter::MemoryFileStreamWriter( + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util, + const base::FilePath& file_path, + int64_t initial_offset, + OpenOrCreate open_or_create) + : memory_file_util_(std::move(memory_file_util)) { + DCHECK(memory_file_util_); +} +} // namespace storage
diff --git a/storage/browser/fileapi/memory_file_stream_writer.h b/storage/browser/fileapi/memory_file_stream_writer.h new file mode 100644 index 0000000..de6b39f --- /dev/null +++ b/storage/browser/fileapi/memory_file_stream_writer.h
@@ -0,0 +1,44 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_FILEAPI_MEMORY_FILE_STREAM_WRITER_H_ +#define STORAGE_BROWSER_FILEAPI_MEMORY_FILE_STREAM_WRITER_H_ + +#include "base/callback.h" +#include "base/component_export.h" +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "storage/browser/fileapi/file_stream_writer.h" + +namespace storage { + +// This is a stream writer for in-memory files. +class COMPONENT_EXPORT(STORAGE_BROWSER) MemoryFileStreamWriter + : public FileStreamWriter { + public: + ~MemoryFileStreamWriter() override; + + // FileStreamWriter overrides. + int Write(net::IOBuffer* buf, + int buf_len, + net::CompletionOnceCallback callback) override; + int Cancel(net::CompletionOnceCallback callback) override; + int Flush(net::CompletionOnceCallback callback) override; + + private: + friend class FileStreamWriter; + MemoryFileStreamWriter( + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util, + const base::FilePath& file_path, + int64_t initial_offset, + OpenOrCreate open_or_create); + + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_; + + DISALLOW_COPY_AND_ASSIGN(MemoryFileStreamWriter); +}; + +} // namespace storage + +#endif // STORAGE_BROWSER_FILEAPI_MEMORY_FILE_STREAM_WRITER_H_
diff --git a/storage/browser/fileapi/obfuscated_file_util.cc b/storage/browser/fileapi/obfuscated_file_util.cc index 300432e..a6e973e 100644 --- a/storage/browser/fileapi/obfuscated_file_util.cc +++ b/storage/browser/fileapi/obfuscated_file_util.cc
@@ -24,7 +24,10 @@ #include "base/time/time.h" #include "storage/browser/fileapi/file_observers.h" #include "storage/browser/fileapi/file_system_context.h" +#include "storage/browser/fileapi/file_system_features.h" #include "storage/browser/fileapi/file_system_operation_context.h" +#include "storage/browser/fileapi/obfuscated_file_util_disk_delegate.h" +#include "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h" #include "storage/browser/fileapi/sandbox_file_system_backend.h" #include "storage/browser/fileapi/sandbox_isolated_origin_database.h" #include "storage/browser/fileapi/sandbox_origin_database.h" @@ -262,17 +265,22 @@ : special_storage_policy_(special_storage_policy), file_system_directory_(file_system_directory), env_override_(env_override), + is_incognito_(is_incognito), db_flush_delay_seconds_(10 * 60), // 10 mins. get_type_string_for_url_(std::move(get_type_string_for_url)), known_type_strings_(known_type_strings), - sandbox_delegate_(sandbox_delegate), - delegate_(std::make_unique<ObfuscatedFileUtilDiskDelegate>()) { - // TODO(https://crbug.com/93417): |delegate_| to be initialized with an - // instance of |ObfuscatedFileUtilMemoryDelegate| if |is_incognito| is true. + sandbox_delegate_(sandbox_delegate) { DCHECK(!get_type_string_for_url_.is_null()); DETACH_FROM_SEQUENCE(sequence_checker_); - DCHECK(!is_incognito || + DCHECK(!is_incognito_ || (env_override && leveldb_chrome::IsMemEnv(env_override))); + + if (is_incognito_ && + base::FeatureList::IsEnabled(features::kEnableFilesystemInIncognito)) { + delegate_ = std::make_unique<ObfuscatedFileUtilMemoryDelegate>(); + } else { + delegate_ = std::make_unique<ObfuscatedFileUtilDiskDelegate>(); + } } ObfuscatedFileUtil::~ObfuscatedFileUtil() {
diff --git a/storage/browser/fileapi/obfuscated_file_util.h b/storage/browser/fileapi/obfuscated_file_util.h index 1c9b3ae..e80c1d6b 100644 --- a/storage/browser/fileapi/obfuscated_file_util.h +++ b/storage/browser/fileapi/obfuscated_file_util.h
@@ -23,9 +23,7 @@ #include "storage/browser/blob/shareable_file_reference.h" #include "storage/browser/fileapi/file_system_file_util.h" #include "storage/browser/fileapi/file_system_url.h" -// TODO(https://crbug.com/93417): To be replaced with -// obfuscated_file_util_delegate.h -#include "storage/browser/fileapi/obfuscated_file_util_disk_delegate.h" +#include "storage/browser/fileapi/obfuscated_file_util_delegate.h" #include "storage/browser/fileapi/sandbox_directory_database.h" #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h" #include "storage/common/fileapi/file_system_types.h" @@ -215,6 +213,10 @@ // This will rewrite the databases to remove traces of deleted data from disk. void RewriteDatabases(); + bool is_incognito() { return is_incognito_; } + + ObfuscatedFileUtilDelegate* delegate() { return delegate_.get(); } + private: using FileId = SandboxDirectoryDatabase::FileId; using FileInfo = SandboxDirectoryDatabase::FileInfo; @@ -330,6 +332,7 @@ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_; base::FilePath file_system_directory_; leveldb::Env* env_override_; + bool is_incognito_; // Used to delete database after a certain period of inactivity. int64_t db_flush_delay_seconds_; @@ -342,9 +345,7 @@ // Not owned. SandboxFileSystemBackendDelegate* sandbox_delegate_; - // TODO(https://crbug.com/93417): To be replaced with - // ObfuscatedFileUtilDelegate. - std::unique_ptr<ObfuscatedFileUtilDiskDelegate> delegate_; + std::unique_ptr<ObfuscatedFileUtilDelegate> delegate_; DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtil); };
diff --git a/storage/browser/fileapi/obfuscated_file_util_delegate.h b/storage/browser/fileapi/obfuscated_file_util_delegate.h new file mode 100644 index 0000000..6a63cdf --- /dev/null +++ b/storage/browser/fileapi/obfuscated_file_util_delegate.h
@@ -0,0 +1,58 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_DELEGATE_H_ +#define STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_DELEGATE_H_ + +#include "base/component_export.h" +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "storage/browser/fileapi/native_file_util.h" + +namespace storage { + +// This delegate performs all ObfuscatedFileUtil tasks that actually touch disk. + +class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilDelegate { + public: + ObfuscatedFileUtilDelegate() = default; + virtual ~ObfuscatedFileUtilDelegate() = default; + + virtual bool DirectoryExists(const base::FilePath& path) = 0; + virtual bool DeleteFileOrDirectory(const base::FilePath& path, + bool recursive) = 0; + virtual bool IsLink(const base::FilePath& file_path) = 0; + virtual bool PathExists(const base::FilePath& path) = 0; + + virtual NativeFileUtil::CopyOrMoveMode CopyOrMoveModeForDestination( + const FileSystemURL& dest_url, + bool copy) = 0; + virtual base::File CreateOrOpen(const base::FilePath& path, + int file_flags) = 0; + virtual base::File::Error EnsureFileExists(const base::FilePath& path, + bool* created) = 0; + virtual base::File::Error CreateDirectory(const base::FilePath& path, + bool exclusive, + bool recursive) = 0; + virtual base::File::Error GetFileInfo(const base::FilePath& path, + base::File::Info* file_info) = 0; + virtual base::File::Error Touch(const base::FilePath& path, + const base::Time& last_access_time, + const base::Time& last_modified_time) = 0; + virtual base::File::Error Truncate(const base::FilePath& path, + int64_t length) = 0; + virtual base::File::Error CopyOrMoveFile( + const base::FilePath& src_path, + const base::FilePath& dest_path, + FileSystemOperation::CopyOrMoveOption option, + NativeFileUtil::CopyOrMoveMode mode) = 0; + virtual base::File::Error DeleteFile(const base::FilePath& path) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilDelegate); +}; + +} // namespace storage + +#endif // STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_DELEGATE_H_
diff --git a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc index 7d2acb3..36d34aa 100644 --- a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc +++ b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc
@@ -11,6 +11,8 @@ ObfuscatedFileUtilDiskDelegate::ObfuscatedFileUtilDiskDelegate() {} +ObfuscatedFileUtilDiskDelegate::~ObfuscatedFileUtilDiskDelegate() {} + bool ObfuscatedFileUtilDiskDelegate::DirectoryExists( const base::FilePath& path) { return base::DirectoryExists(path);
diff --git a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h index 612ebb42..50373442 100644 --- a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h +++ b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h
@@ -9,42 +9,46 @@ #include "base/files/file.h" #include "base/files/file_path.h" #include "storage/browser/fileapi/native_file_util.h" +#include "storage/browser/fileapi/obfuscated_file_util_delegate.h" namespace storage { // This delegate performs all ObfuscatedFileUtil tasks that actually touch disk. -// TODO(https://crbug.com/93417): To be driven from abstract class -// |ObfuscatedFileUtilDelegate|. -class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilDiskDelegate { +class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilDiskDelegate + : public ObfuscatedFileUtilDelegate { public: ObfuscatedFileUtilDiskDelegate(); - ~ObfuscatedFileUtilDiskDelegate() = default; + ~ObfuscatedFileUtilDiskDelegate() override; - bool DirectoryExists(const base::FilePath& path); - bool DeleteFileOrDirectory(const base::FilePath& path, bool recursive); - bool IsLink(const base::FilePath& file_path); - bool PathExists(const base::FilePath& path); + bool DirectoryExists(const base::FilePath& path) override; + bool DeleteFileOrDirectory(const base::FilePath& path, + bool recursive) override; + bool IsLink(const base::FilePath& file_path) override; + bool PathExists(const base::FilePath& path) override; NativeFileUtil::CopyOrMoveMode CopyOrMoveModeForDestination( const FileSystemURL& dest_url, - bool copy); - base::File CreateOrOpen(const base::FilePath& path, int file_flags); - base::File::Error EnsureFileExists(const base::FilePath& path, bool* created); + bool copy) override; + base::File CreateOrOpen(const base::FilePath& path, int file_flags) override; + base::File::Error EnsureFileExists(const base::FilePath& path, + bool* created) override; base::File::Error CreateDirectory(const base::FilePath& path, bool exclusive, - bool recursive); + bool recursive) override; base::File::Error GetFileInfo(const base::FilePath& path, - base::File::Info* file_info); + base::File::Info* file_info) override; base::File::Error Touch(const base::FilePath& path, const base::Time& last_access_time, - const base::Time& last_modified_time); - base::File::Error Truncate(const base::FilePath& path, int64_t length); - base::File::Error CopyOrMoveFile(const base::FilePath& src_path, - const base::FilePath& dest_path, - FileSystemOperation::CopyOrMoveOption option, - NativeFileUtil::CopyOrMoveMode mode); - base::File::Error DeleteFile(const base::FilePath& path); + const base::Time& last_modified_time) override; + base::File::Error Truncate(const base::FilePath& path, + int64_t length) override; + base::File::Error CopyOrMoveFile( + const base::FilePath& src_path, + const base::FilePath& dest_path, + FileSystemOperation::CopyOrMoveOption option, + NativeFileUtil::CopyOrMoveMode mode) override; + base::File::Error DeleteFile(const base::FilePath& path) override; DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilDiskDelegate); };
diff --git a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc new file mode 100644 index 0000000..d7ee8f55 --- /dev/null +++ b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc
@@ -0,0 +1,115 @@ +// 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. + +#include "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h" + +namespace storage { + +ObfuscatedFileUtilMemoryDelegate::ObfuscatedFileUtilMemoryDelegate() + : weak_factory_(this) {} +ObfuscatedFileUtilMemoryDelegate::~ObfuscatedFileUtilMemoryDelegate() = default; + +bool ObfuscatedFileUtilMemoryDelegate::DirectoryExists( + const base::FilePath& path) { + NOTIMPLEMENTED(); + // return base::DirectoryExists(path); + return false; +} + +bool ObfuscatedFileUtilMemoryDelegate::DeleteFileOrDirectory( + const base::FilePath& path, + bool recursive) { + NOTIMPLEMENTED(); + // return base::DeleteFile(path, recursive); + return false; +} + +bool ObfuscatedFileUtilMemoryDelegate::IsLink(const base::FilePath& file_path) { + NOTIMPLEMENTED(); + // return base::IsLink(file_path); + return false; +} + +bool ObfuscatedFileUtilMemoryDelegate::PathExists(const base::FilePath& path) { + NOTIMPLEMENTED(); + // return base::PathExists(path); + return false; +} + +NativeFileUtil::CopyOrMoveMode +ObfuscatedFileUtilMemoryDelegate::CopyOrMoveModeForDestination( + const FileSystemURL& dest_url, + bool copy) { + NOTIMPLEMENTED(); + // return NativeFileUtil::CopyOrMoveModeForDestination(dest_url, copy); + return NativeFileUtil::CopyOrMoveMode::MOVE; +} + +base::File ObfuscatedFileUtilMemoryDelegate::CreateOrOpen( + const base::FilePath& path, + int file_flags) { + NOTIMPLEMENTED(); + // return NativeFileUtil::CreateOrOpen(path, file_flags); + return base::File(); +} + +base::File::Error ObfuscatedFileUtilMemoryDelegate::EnsureFileExists( + const base::FilePath& path, + bool* created) { + NOTIMPLEMENTED(); + // return NativeFileUtil::EnsureFileExists(path, created); + return base::File::FILE_ERROR_FAILED; +} +base::File::Error ObfuscatedFileUtilMemoryDelegate::CreateDirectory( + const base::FilePath& path, + bool exclusive, + bool recursive) { + NOTIMPLEMENTED(); + // return NativeFileUtil::CreateDirectory(path, exclusive, recursive); + return base::File::FILE_ERROR_FAILED; +} + +base::File::Error ObfuscatedFileUtilMemoryDelegate::GetFileInfo( + const base::FilePath& path, + base::File::Info* file_info) { + NOTIMPLEMENTED(); + // return NativeFileUtil::GetFileInfo(path, file_info); + return base::File::FILE_ERROR_FAILED; +} + +base::File::Error ObfuscatedFileUtilMemoryDelegate::Touch( + const base::FilePath& path, + const base::Time& last_access_time, + const base::Time& last_modified_time) { + NOTIMPLEMENTED(); + // return NativeFileUtil::Touch(path, last_access_time, last_modified_time); + return base::File::FILE_ERROR_FAILED; +} + +base::File::Error ObfuscatedFileUtilMemoryDelegate::Truncate( + const base::FilePath& path, + int64_t length) { + NOTIMPLEMENTED(); + // return NativeFileUtil::Truncate(path, length); + return base::File::FILE_ERROR_FAILED; +} + +base::File::Error ObfuscatedFileUtilMemoryDelegate::CopyOrMoveFile( + const base::FilePath& src_path, + const base::FilePath& dest_path, + FileSystemOperation::CopyOrMoveOption option, + NativeFileUtil::CopyOrMoveMode mode) { + NOTIMPLEMENTED(); + // return NativeFileUtil::CopyOrMoveFile(src_path, dest_path, option, mode); + return base::File::FILE_ERROR_FAILED; +} + +base::File::Error ObfuscatedFileUtilMemoryDelegate::DeleteFile( + const base::FilePath& path) { + NOTIMPLEMENTED(); + // return NativeFileUtil::DeleteFile(path); + return base::File::FILE_ERROR_FAILED; +} + +} // namespace storage
diff --git a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h new file mode 100644 index 0000000..c218924 --- /dev/null +++ b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h
@@ -0,0 +1,66 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_MEMORY_DELEGATE_H_ +#define STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_MEMORY_DELEGATE_H_ + +#include "base/component_export.h" +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "storage/browser/fileapi/native_file_util.h" +#include "storage/browser/fileapi/obfuscated_file_util_delegate.h" + +namespace storage { + +// This delegate performs all ObfuscatedFileUtil tasks that require touching +// disk and peforms them in memory. + +class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilMemoryDelegate + : public ObfuscatedFileUtilDelegate { + public: + ObfuscatedFileUtilMemoryDelegate(); + ~ObfuscatedFileUtilMemoryDelegate() override; + + bool DirectoryExists(const base::FilePath& path) override; + bool DeleteFileOrDirectory(const base::FilePath& path, + bool recursive) override; + bool IsLink(const base::FilePath& file_path) override; + bool PathExists(const base::FilePath& path) override; + + NativeFileUtil::CopyOrMoveMode CopyOrMoveModeForDestination( + const FileSystemURL& dest_url, + bool copy) override; + base::File CreateOrOpen(const base::FilePath& path, int file_flags) override; + base::File::Error EnsureFileExists(const base::FilePath& path, + bool* created) override; + base::File::Error CreateDirectory(const base::FilePath& path, + bool exclusive, + bool recursive) override; + base::File::Error GetFileInfo(const base::FilePath& path, + base::File::Info* file_info) override; + base::File::Error Touch(const base::FilePath& path, + const base::Time& last_access_time, + const base::Time& last_modified_time) override; + base::File::Error Truncate(const base::FilePath& path, + int64_t length) override; + base::File::Error CopyOrMoveFile( + const base::FilePath& src_path, + const base::FilePath& dest_path, + FileSystemOperation::CopyOrMoveOption option, + NativeFileUtil::CopyOrMoveMode mode) override; + base::File::Error DeleteFile(const base::FilePath& path) override; + + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + + private: + base::WeakPtrFactory<ObfuscatedFileUtilMemoryDelegate> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilMemoryDelegate); +}; + +} // namespace storage + +#endif // STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_MEMORY_DELEGATE_H_
diff --git a/storage/browser/fileapi/obfuscated_file_util_unittest.cc b/storage/browser/fileapi/obfuscated_file_util_unittest.cc index 6bfce69..5c83919 100644 --- a/storage/browser/fileapi/obfuscated_file_util_unittest.cc +++ b/storage/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -43,6 +43,7 @@ #include "storage/browser/test/test_file_system_context.h" #include "storage/common/database/database_identifier.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/leveldatabase/leveldb_chrome.h" using content::AsyncFileTestHelper; using storage::FileSystemContext; @@ -151,11 +152,14 @@ // could theoretically be shared. It would basically be a FSFU interface // compliance test, and only the subclass-specific bits that look into the // implementation would need to be written per-subclass. -class ObfuscatedFileUtilTest : public testing::Test { +class ObfuscatedFileUtilTest : public testing::Test, + public ::testing::WithParamInterface<bool> { public: ObfuscatedFileUtilTest() - : scoped_task_environment_( + : is_incognito_(GetParam()), + scoped_task_environment_( base::test::ScopedTaskEnvironment::MainThreadType::IO), + origin_(GURL("http://www.example.com")), type_(storage::kFileSystemTypeTemporary), sandbox_file_system_(origin_, type_), @@ -169,7 +173,7 @@ storage_policy_ = new MockSpecialStoragePolicy(); quota_manager_ = new storage::QuotaManager( - false /* is_incognito */, data_dir_.GetPath(), + is_incognito_, data_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get(), storage::GetQuotaSettingsFunc()); storage::QuotaSettings settings; @@ -190,6 +194,9 @@ change_observers_ = storage::MockFileChangeObserver::CreateList(&change_observer_); + + if (is_incognito_) + incognito_leveldb_environment_ = leveldb_chrome::NewMemEnv("FileSystem"); } void TearDown() override { @@ -247,11 +254,11 @@ std::unique_ptr<ObfuscatedFileUtil> CreateObfuscatedFileUtil( storage::SpecialStoragePolicy* storage_policy) { - // TODO(https://crbug.com/93417): Add support for incognito tests. return std::unique_ptr<ObfuscatedFileUtil>( - ObfuscatedFileUtil::CreateForTesting(storage_policy, data_dir_path(), - /*env_override=*/nullptr, - /*is_incognito=*/false)); + ObfuscatedFileUtil::CreateForTesting( + storage_policy, data_dir_path(), + is_incognito_ ? incognito_leveldb_environment_.get() : nullptr, + is_incognito_)); } ObfuscatedFileUtil* ofu() { @@ -680,6 +687,10 @@ } void MaybeDropDatabasesAliveCaseTestBody() { + // TODO(https://crbug.com/43417): Enable test after finishing incognito + // implementation. + if (is_incognito_) + return; std::unique_ptr<ObfuscatedFileUtil> file_util = CreateObfuscatedFileUtil(nullptr); file_util->InitOriginDatabase(GURL(), true /*create*/); @@ -710,6 +721,10 @@ } void DestroyDirectoryDatabase_IsolatedTestBody() { + // TODO(https://crbug.com/43417): Enable test after finishing incognito + // implementation. + if (is_incognito_) + return; storage_policy_->AddIsolated(origin_); std::unique_ptr<ObfuscatedFileUtil> file_util = CreateObfuscatedFileUtil(storage_policy_.get()); @@ -729,6 +744,10 @@ } void GetDirectoryDatabase_IsolatedTestBody() { + // TODO(https://crbug.com/43417): Enable test after finishing incognito + // implementation. + if (is_incognito_) + return; storage_policy_->AddIsolated(origin_); std::unique_ptr<ObfuscatedFileUtil> file_util = CreateObfuscatedFileUtil(storage_policy_.get()); @@ -763,6 +782,8 @@ const base::FilePath& data_dir_path() const { return data_dir_.GetPath(); } protected: + bool is_incognito_; + std::unique_ptr<leveldb::Env> incognito_leveldb_environment_; base::test::ScopedTaskEnvironment scoped_task_environment_; base::ScopedTempDir data_dir_; scoped_refptr<MockSpecialStoragePolicy> storage_policy_; @@ -781,7 +802,9 @@ DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilTest); }; -TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) { +INSTANTIATE_TEST_CASE_P(, ObfuscatedFileUtilTest, ::testing::Bool()); + +TEST_P(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) { FileSystemURL url = CreateURLFromUTF8("fake/file"); std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); int file_flags = base::File::FLAG_CREATE | base::File::FLAG_WRITE; @@ -866,7 +889,7 @@ EXPECT_TRUE(change_observer()->HasNoChange()); } -TEST_F(ObfuscatedFileUtilTest, TestTruncate) { +TEST_P(ObfuscatedFileUtilTest, TestTruncate) { bool created = false; FileSystemURL url = CreateURLFromUTF8("file"); std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); @@ -903,7 +926,7 @@ EXPECT_TRUE(change_observer()->HasNoChange()); } -TEST_F(ObfuscatedFileUtilTest, TestQuotaOnTruncation) { +TEST_P(ObfuscatedFileUtilTest, TestQuotaOnTruncation) { bool created = false; FileSystemURL url = CreateURLFromUTF8("file"); @@ -958,7 +981,7 @@ ASSERT_EQ(0, ComputeTotalFileSize()); } -TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) { +TEST_P(ObfuscatedFileUtilTest, TestEnsureFileExists) { FileSystemURL url = CreateURLFromUTF8("fake/file"); bool created = false; std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); @@ -1013,7 +1036,7 @@ EXPECT_TRUE(change_observer()->HasNoChange()); } -TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) { +TEST_P(ObfuscatedFileUtilTest, TestDirectoryOps) { std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); bool exclusive = false; @@ -1155,7 +1178,7 @@ EXPECT_TRUE(change_observer()->HasNoChange()); } -TEST_F(ObfuscatedFileUtilTest, TestReadDirectory) { +TEST_P(ObfuscatedFileUtilTest, TestReadDirectory) { std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); bool exclusive = true; bool recursive = true; @@ -1165,15 +1188,15 @@ TestReadDirectoryHelper(url); } -TEST_F(ObfuscatedFileUtilTest, TestReadRootWithSlash) { +TEST_P(ObfuscatedFileUtilTest, TestReadRootWithSlash) { TestReadDirectoryHelper(CreateURLFromUTF8(std::string())); } -TEST_F(ObfuscatedFileUtilTest, TestReadRootWithEmptyString) { +TEST_P(ObfuscatedFileUtilTest, TestReadRootWithEmptyString) { TestReadDirectoryHelper(CreateURLFromUTF8("/")); } -TEST_F(ObfuscatedFileUtilTest, TestReadDirectoryOnFile) { +TEST_P(ObfuscatedFileUtilTest, TestReadDirectoryOnFile) { FileSystemURL url = CreateURLFromUTF8("file"); std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); @@ -1190,7 +1213,7 @@ EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), url)); } -TEST_F(ObfuscatedFileUtilTest, TestTouch) { +TEST_P(ObfuscatedFileUtilTest, TestTouch) { FileSystemURL url = CreateURLFromUTF8("file"); std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); @@ -1220,7 +1243,7 @@ TestTouchHelper(url, false); } -TEST_F(ObfuscatedFileUtilTest, TestPathQuotas) { +TEST_P(ObfuscatedFileUtilTest, TestPathQuotas) { FileSystemURL url = CreateURLFromUTF8("fake/file"); std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); @@ -1255,7 +1278,7 @@ EXPECT_EQ(1024 - path_cost, context->allowed_bytes_growth()); } -TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileNotFound) { +TEST_P(ObfuscatedFileUtilTest, TestCopyOrMoveFileNotFound) { FileSystemURL source_url = CreateURLFromUTF8("path0.txt"); FileSystemURL dest_url = CreateURLFromUTF8("path1.txt"); std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); @@ -1297,7 +1320,7 @@ EXPECT_TRUE(change_observer()->HasNoChange()); } -TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) { +TEST_P(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) { const int64_t kSourceLength = 5; const int64_t kDestLength = 50; @@ -1386,7 +1409,7 @@ } } -TEST_F(ObfuscatedFileUtilTest, TestCopyPathQuotas) { +TEST_P(ObfuscatedFileUtilTest, TestCopyPathQuotas) { FileSystemURL src_url = CreateURLFromUTF8("src path"); FileSystemURL dest_url = CreateURLFromUTF8("destination path"); std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); @@ -1416,7 +1439,7 @@ FileSystemOperation::OPTION_NONE, is_copy)); } -TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithRename) { +TEST_P(ObfuscatedFileUtilTest, TestMovePathQuotasWithRename) { FileSystemURL src_url = CreateURLFromUTF8("src path"); FileSystemURL dest_url = CreateURLFromUTF8("destination path"); std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); @@ -1453,7 +1476,7 @@ FileSystemOperation::OPTION_NONE, is_copy)); } -TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithoutRename) { +TEST_P(ObfuscatedFileUtilTest, TestMovePathQuotasWithoutRename) { FileSystemURL src_url = CreateURLFromUTF8("src path"); std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); bool created = false; @@ -1496,12 +1519,12 @@ context->allowed_bytes_growth()); } -TEST_F(ObfuscatedFileUtilTest, TestCopyInForeignFile) { +TEST_P(ObfuscatedFileUtilTest, TestCopyInForeignFile) { TestCopyInForeignFileHelper(false /* overwrite */); TestCopyInForeignFileHelper(true /* overwrite */); } -TEST_F(ObfuscatedFileUtilTest, TestEnumerator) { +TEST_P(ObfuscatedFileUtilTest, TestEnumerator) { std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); FileSystemURL src_url = CreateURLFromUTF8("source dir"); bool exclusive = true; @@ -1531,7 +1554,7 @@ EXPECT_FALSE(DirectoryExists(dest_url)); } -TEST_F(ObfuscatedFileUtilTest, TestOriginEnumerator) { +TEST_P(ObfuscatedFileUtilTest, TestOriginEnumerator) { std::unique_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enumerator( ofu()->CreateOriginEnumerator()); // The test helper starts out with a single filesystem. @@ -1617,7 +1640,7 @@ EXPECT_TRUE(diff.empty()); } -TEST_F(ObfuscatedFileUtilTest, TestRevokeUsageCache) { +TEST_P(ObfuscatedFileUtilTest, TestRevokeUsageCache) { std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); int64_t expected_quota = 0; @@ -1663,7 +1686,7 @@ EXPECT_EQ(expected_quota, usage()); } -TEST_F(ObfuscatedFileUtilTest, TestInconsistency) { +TEST_P(ObfuscatedFileUtilTest, TestInconsistency) { const FileSystemURL kPath1 = CreateURLFromUTF8("hoge"); const FileSystemURL kPath2 = CreateURLFromUTF8("fuga"); @@ -1738,7 +1761,7 @@ EXPECT_EQ(0, file_info.size); } -TEST_F(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) { +TEST_P(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) { const FileSystemURL kPath[] = { CreateURLFromUTF8("foo"), CreateURLFromUTF8("bar"), @@ -1773,7 +1796,7 @@ EXPECT_EQ(base::size(kPath) - 1, entries.size()); } -TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForCreation) { +TEST_P(ObfuscatedFileUtilTest, TestDirectoryTimestampForCreation) { std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); const FileSystemURL dir_url = CreateURLFromUTF8("foo_dir"); @@ -1898,7 +1921,7 @@ EXPECT_NE(base::Time(), GetModifiedTime(dir_url)); } -TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForDeletion) { +TEST_P(ObfuscatedFileUtilTest, TestDirectoryTimestampForDeletion) { std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr)); const FileSystemURL dir_url = CreateURLFromUTF8("foo_dir"); @@ -1957,7 +1980,7 @@ EXPECT_NE(base::Time(), GetModifiedTime(dir_url)); } -TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForCopyAndMove) { +TEST_P(ObfuscatedFileUtilTest, TestDirectoryTimestampForCopyAndMove) { TestDirectoryTimestampHelper( CreateURLFromUTF8("copy overwrite"), true, true); TestDirectoryTimestampHelper( @@ -1968,7 +1991,7 @@ CreateURLFromUTF8("move non-overwrite"), false, false); } -TEST_F(ObfuscatedFileUtilTest, TestFileEnumeratorTimestamp) { +TEST_P(ObfuscatedFileUtilTest, TestFileEnumeratorTimestamp) { FileSystemURL dir = CreateURLFromUTF8("foo"); FileSystemURL url1 = FileSystemURLAppendUTF8(dir, "bar"); FileSystemURL url2 = FileSystemURLAppendUTF8(dir, "baz"); @@ -2030,7 +2053,7 @@ #else #define MAYBE_TestQuotaOnCopyFile TestQuotaOnCopyFile #endif -TEST_F(ObfuscatedFileUtilTest, MAYBE_TestQuotaOnCopyFile) { +TEST_P(ObfuscatedFileUtilTest, MAYBE_TestQuotaOnCopyFile) { FileSystemURL from_file(CreateURLFromUTF8("fromfile")); FileSystemURL obstacle_file(CreateURLFromUTF8("obstaclefile")); FileSystemURL to_file1(CreateURLFromUTF8("tofile1")); @@ -2128,7 +2151,7 @@ } } -TEST_F(ObfuscatedFileUtilTest, TestQuotaOnMoveFile) { +TEST_P(ObfuscatedFileUtilTest, TestQuotaOnMoveFile) { FileSystemURL from_file(CreateURLFromUTF8("fromfile")); FileSystemURL obstacle_file(CreateURLFromUTF8("obstaclefile")); FileSystemURL to_file(CreateURLFromUTF8("tofile")); @@ -2234,7 +2257,7 @@ context.reset(); } -TEST_F(ObfuscatedFileUtilTest, TestQuotaOnRemove) { +TEST_P(ObfuscatedFileUtilTest, TestQuotaOnRemove) { FileSystemURL dir(CreateURLFromUTF8("dir")); FileSystemURL file(CreateURLFromUTF8("file")); FileSystemURL dfile1(CreateURLFromUTF8("dir/dfile1")); @@ -2298,7 +2321,7 @@ ASSERT_EQ(0, ComputeTotalFileSize()); } -TEST_F(ObfuscatedFileUtilTest, TestQuotaOnOpen) { +TEST_P(ObfuscatedFileUtilTest, TestQuotaOnOpen) { FileSystemURL url(CreateURLFromUTF8("file")); bool created; @@ -2347,23 +2370,23 @@ file.Close(); } -TEST_F(ObfuscatedFileUtilTest, MaybeDropDatabasesAliveCase) { +TEST_P(ObfuscatedFileUtilTest, MaybeDropDatabasesAliveCase) { MaybeDropDatabasesAliveCaseTestBody(); } -TEST_F(ObfuscatedFileUtilTest, MaybeDropDatabasesAlreadyDeletedCase) { +TEST_P(ObfuscatedFileUtilTest, MaybeDropDatabasesAlreadyDeletedCase) { MaybeDropDatabasesAlreadyDeletedCaseTestBody(); } -TEST_F(ObfuscatedFileUtilTest, DestroyDirectoryDatabase_Isolated) { +TEST_P(ObfuscatedFileUtilTest, DestroyDirectoryDatabase_Isolated) { DestroyDirectoryDatabase_IsolatedTestBody(); } -TEST_F(ObfuscatedFileUtilTest, GetDirectoryDatabase_Isolated) { +TEST_P(ObfuscatedFileUtilTest, GetDirectoryDatabase_Isolated) { GetDirectoryDatabase_IsolatedTestBody(); } -TEST_F(ObfuscatedFileUtilTest, OpenPathInNonDirectory) { +TEST_P(ObfuscatedFileUtilTest, OpenPathInNonDirectory) { FileSystemURL url(CreateURLFromUTF8("file")); FileSystemURL path_in_file(CreateURLFromUTF8("file/file")); bool created; @@ -2385,7 +2408,7 @@ false /* recursive */)); } -TEST_F(ObfuscatedFileUtilTest, CreateDirectory_NotADirectoryInRecursive) { +TEST_P(ObfuscatedFileUtilTest, CreateDirectory_NotADirectoryInRecursive) { FileSystemURL file(CreateURLFromUTF8("file")); FileSystemURL path_in_file(CreateURLFromUTF8("file/child")); FileSystemURL path_in_file_in_file( @@ -2408,7 +2431,7 @@ true /* recursive */)); } -TEST_F(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType) { +TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType) { const GURL origin1("http://www.example.com:12"); const GURL origin2("http://www.example.com:1234"); const GURL origin3("http://nope.example.com"); @@ -2486,7 +2509,7 @@ origin3, GetTypeString(kFileSystemTypePersistent))); } -TEST_F(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType_DeleteAll) { +TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType_DeleteAll) { const GURL origin1("http://www.example.com:12"); const GURL origin2("http://www.example.com:1234");
diff --git a/storage/browser/fileapi/sandbox_file_stream_writer.cc b/storage/browser/fileapi/sandbox_file_stream_writer.cc index 7418c64a..857d307 100644 --- a/storage/browser/fileapi/sandbox_file_stream_writer.cc +++ b/storage/browser/fileapi/sandbox_file_stream_writer.cc
@@ -18,6 +18,7 @@ #include "storage/browser/fileapi/file_observers.h" #include "storage/browser/fileapi/file_stream_reader.h" #include "storage/browser/fileapi/file_system_context.h" +#include "storage/browser/fileapi/file_system_features.h" #include "storage/browser/fileapi/file_system_operation_runner.h" #include "storage/browser/quota/quota_manager_proxy.h" #include "storage/common/fileapi/file_system_util.h" @@ -70,7 +71,7 @@ DCHECK(!write_callback_); has_pending_operation_ = true; write_callback_ = std::move(callback); - if (local_file_writer_) + if (file_writer_) return WriteInternal(buf, buf_len); net::CompletionOnceCallback write_task = base::BindOnce( @@ -104,11 +105,11 @@ if (buf_len > allowed_bytes_to_write_ - total_bytes_written_) buf_len = allowed_bytes_to_write_ - total_bytes_written_; - DCHECK(local_file_writer_.get()); - const int result = local_file_writer_->Write( - buf, buf_len, - base::BindOnce(&SandboxFileStreamWriter::DidWrite, - weak_factory_.GetWeakPtr())); + DCHECK(file_writer_.get()); + const int result = + file_writer_->Write(buf, buf_len, + base::BindOnce(&SandboxFileStreamWriter::DidWrite, + weak_factory_.GetWeakPtr())); if (result != net::ERR_IO_PENDING) has_pending_operation_ = false; return result; @@ -140,13 +141,18 @@ NOTREACHED(); initial_offset_ = file_size_; } - DCHECK(!local_file_writer_.get()); - local_file_writer_.reset(FileStreamWriter::CreateForLocalFile( - file_system_context_->default_file_task_runner(), - platform_path, - initial_offset_, - FileStreamWriter::OPEN_EXISTING_FILE)); + DCHECK(!file_writer_.get()); + if (file_system_context_->is_incognito() && + base::FeatureList::IsEnabled(features::kEnableFilesystemInIncognito)) { + file_writer_.reset(FileStreamWriter::CreateForMemoryFile( + file_system_context_->sandbox_delegate()->memory_file_util_delegate(), + platform_path, initial_offset_, FileStreamWriter::OPEN_EXISTING_FILE)); + } else { + file_writer_.reset(FileStreamWriter::CreateForLocalFile( + file_system_context_->default_file_task_runner(), platform_path, + initial_offset_, FileStreamWriter::OPEN_EXISTING_FILE)); + } storage::QuotaManagerProxy* quota_manager_proxy = file_system_context_->quota_manager_proxy(); if (!quota_manager_proxy) { @@ -247,10 +253,10 @@ DCHECK(cancel_callback_.is_null()); // Write() is not called yet, so there's nothing to flush. - if (!local_file_writer_) + if (!file_writer_) return net::OK; - return local_file_writer_->Flush(std::move(callback)); + return file_writer_->Flush(std::move(callback)); } } // namespace storage
diff --git a/storage/browser/fileapi/sandbox_file_stream_writer.h b/storage/browser/fileapi/sandbox_file_stream_writer.h index 308f370..e8cb6f7 100644 --- a/storage/browser/fileapi/sandbox_file_stream_writer.h +++ b/storage/browser/fileapi/sandbox_file_stream_writer.h
@@ -46,7 +46,7 @@ void set_default_quota(int64_t quota) { default_quota_ = quota; } private: - // Performs quota calculation and calls local_file_writer_->Write(). + // Performs quota calculation and calls file_writer_->Write(). int WriteInternal(net::IOBuffer* buf, int buf_len); // Callbacks that are chained for the first write. This eventually calls @@ -72,7 +72,7 @@ scoped_refptr<FileSystemContext> file_system_context_; FileSystemURL url_; int64_t initial_offset_; - std::unique_ptr<FileStreamWriter> local_file_writer_; + std::unique_ptr<FileStreamWriter> file_writer_; net::CompletionOnceCallback write_callback_; net::CompletionOnceCallback cancel_callback_;
diff --git a/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc b/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc index 89afce7..d50a6e83 100644 --- a/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc +++ b/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc
@@ -26,6 +26,7 @@ #include "storage/browser/fileapi/file_system_url.h" #include "storage/browser/fileapi/file_system_usage_cache.h" #include "storage/browser/fileapi/obfuscated_file_util.h" +#include "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h" #include "storage/browser/fileapi/quota/quota_backend_impl.h" #include "storage/browser/fileapi/quota/quota_reservation.h" #include "storage/browser/fileapi/quota/quota_reservation_manager.h" @@ -712,6 +713,14 @@ return static_cast<ObfuscatedFileUtil*>(sync_file_util()); } +base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> +SandboxFileSystemBackendDelegate::memory_file_util_delegate() { + DCHECK(obfuscated_file_util()->is_incognito()); + return static_cast<ObfuscatedFileUtilMemoryDelegate*>( + obfuscated_file_util()->delegate()) + ->GetWeakPtr(); +} + // Declared in obfuscated_file_util.h. // static ObfuscatedFileUtil* ObfuscatedFileUtil::CreateForTesting(
diff --git a/storage/browser/fileapi/sandbox_file_system_backend_delegate.h b/storage/browser/fileapi/sandbox_file_system_backend_delegate.h index 96ae2a5..93c5b01f 100644 --- a/storage/browser/fileapi/sandbox_file_system_backend_delegate.h +++ b/storage/browser/fileapi/sandbox_file_system_backend_delegate.h
@@ -56,6 +56,7 @@ class FileSystemURL; class FileSystemUsageCache; class ObfuscatedFileUtil; +class ObfuscatedFileUtilMemoryDelegate; class QuotaReservationManager; class SandboxQuotaObserver; @@ -206,6 +207,8 @@ FileSystemFileUtil* sync_file_util(); + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_delegate(); + private: friend class QuotaBackendImpl; friend class SandboxQuotaObserver;
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc index 62830e0d..fe150e8 100644 --- a/storage/browser/quota/quota_manager.cc +++ b/storage/browser/quota/quota_manager.cc
@@ -559,10 +559,14 @@ remaining_clients_ = manager()->clients_.size(); for (auto* client : manager()->clients_) { if (quota_client_mask_ & client->id()) { + static int tracing_id = 0; + TRACE_EVENT_ASYNC_BEGIN2( + "browsing_data", "QuotaManager::OriginDataDeleter", ++tracing_id, + "client_id", client->id(), "origin", origin_.Serialize()); client->DeleteOriginData( origin_, type_, base::BindOnce(&OriginDataDeleter::DidDeleteOriginData, - weak_factory_.GetWeakPtr())); + weak_factory_.GetWeakPtr(), tracing_id)); } else { ++skipped_clients_; if (--remaining_clients_ == 0) @@ -596,8 +600,11 @@ } private: - void DidDeleteOriginData(blink::mojom::QuotaStatusCode status) { + void DidDeleteOriginData(int tracing_id, + blink::mojom::QuotaStatusCode status) { DCHECK_GT(remaining_clients_, 0); + TRACE_EVENT_ASYNC_END0("browsing_data", "QuotaManager::OriginDataDeleter", + tracing_id); if (status != blink::mojom::QuotaStatusCode::kOk) ++error_count_;
diff --git a/third_party/blink/common/client_hints/client_hints.cc b/third_party/blink/common/client_hints/client_hints.cc index 5777f6cc..d6a2568 100644 --- a/third_party/blink/common/client_hints/client_hints.cc +++ b/third_party/blink/common/client_hints/client_hints.cc
@@ -10,12 +10,24 @@ namespace blink { const char* const kClientHintsNameMapping[] = { - "device-memory", "dpr", "width", "viewport-width", - "rtt", "downlink", "ect", "lang"}; + "device-memory", "dpr", "width", "viewport-width", "rtt", "downlink", + "ect", "lang", "ua", "arch", "platform", "model", +}; const char* const kClientHintsHeaderMapping[] = { - "device-memory", "dpr", "width", "viewport-width", - "rtt", "downlink", "ect", "sec-ch-lang"}; + "device-memory", + "dpr", + "width", + "viewport-width", + "rtt", + "downlink", + "ect", + "sec-ch-lang", + "sec-ch-ua", + "sec-ch-ua-arch", + "sec-ch-ua-platform", + "sec-ch-ua-model", +}; const size_t kClientHintsMappingsCount = base::size(kClientHintsNameMapping);
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 3b668afe..c54fa31 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -93,6 +93,11 @@ // Enable Portals. https://crbug.com/865123. const base::Feature kPortals{"Portals", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enable limiting previews loading hints to specific resource types. +const base::Feature kPreviewsResourceLoadingHintsSpecificResourceTypes{ + "PreviewsResourceLoadingHintsSpecificResourceTypes", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Enable Implicit Root Scroller. https://crbug.com/903260. const base::Feature kImplicitRootScroller{"ImplicitRootScroller", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn index f9299d7..e068fe33 100644 --- a/third_party/blink/public/BUILD.gn +++ b/third_party/blink/public/BUILD.gn
@@ -72,7 +72,6 @@ java_cpp_enum("blink_headers_java_enums_srcjar") { sources = [ "./common/manifest/web_display_mode.h", - "./platform/modules/remoteplayback/web_remote_playback_availability.h", "./platform/web_focus_type.h", "./platform/web_input_event.h", "./platform/web_text_input_mode.h", @@ -163,7 +162,6 @@ "platform/modules/push_messaging/web_push_provider.h", "platform/modules/push_messaging/web_push_subscription.h", "platform/modules/push_messaging/web_push_subscription_options.h", - "platform/modules/remoteplayback/web_remote_playback_availability.h", "platform/modules/remoteplayback/web_remote_playback_client.h", "platform/modules/remoteplayback/web_remote_playback_state.h", "platform/modules/service_worker/web_service_worker_clients_info.h",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 5acf74f..11c8319 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -34,6 +34,8 @@ BLINK_COMMON_EXPORT extern const base::Feature kOnionSoupDOMStorage; BLINK_COMMON_EXPORT extern const base::Feature kPlzDedicatedWorker; BLINK_COMMON_EXPORT extern const base::Feature kPortals; +BLINK_COMMON_EXPORT extern const base::Feature + kPreviewsResourceLoadingHintsSpecificResourceTypes; BLINK_COMMON_EXPORT extern const base::Feature kRTCGetDisplayMedia; BLINK_COMMON_EXPORT extern const base::Feature kRTCUnifiedPlanByDefault; BLINK_COMMON_EXPORT extern const base::Feature kRTCOfferExtmapAllowMixed;
diff --git a/third_party/blink/public/mojom/renderer_preferences.mojom b/third_party/blink/public/mojom/renderer_preferences.mojom index 8fcd4502..e15295c 100644 --- a/third_party/blink/public/mojom/renderer_preferences.mojom +++ b/third_party/blink/public/mojom/renderer_preferences.mojom
@@ -40,8 +40,11 @@ // positions for glyphs. Currently only used by Linux. bool use_subpixel_positioning = false; - // The color of the focus ring. Currently only used on Linux. uint32 focus_ring_color = 0xFFE59700; + [EnableIf=is_android] + float minimum_stroke_width_for_focus_ring = 1.0; + [EnableIf=is_android] + bool is_focus_ring_outset = false; // The colors used in selection text. Currently only used on Linux and Ash. uint32 active_selection_bg_color = 0xFF1E90FF;
diff --git a/third_party/blink/public/mojom/service_worker/embedded_worker.mojom b/third_party/blink/public/mojom/service_worker/embedded_worker.mojom index 2b941c1..5c12d7a 100644 --- a/third_party/blink/public/mojom/service_worker/embedded_worker.mojom +++ b/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
@@ -27,10 +27,6 @@ // Parameters to launch a service worker. This is passed from the browser to the // renderer at mojom::EmbeddedWorkerInstanceClient::StartWorker(). struct EmbeddedWorkerStartParams { - // DEPRECATED: This is only used in unit tests. - // TODO(https://crbug.com/927651): Remove this. - int32 embedded_worker_id; - // The id of the service worker being started. This remains fixed even if the // worker is stopped and restarted, or even if the browser restarts. int64 service_worker_version_id;
diff --git a/third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h b/third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h deleted file mode 100644 index f0697b0..0000000 --- a/third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_REMOTEPLAYBACK_WEB_REMOTE_PLAYBACK_AVAILABILITY_H_ -#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_REMOTEPLAYBACK_WEB_REMOTE_PLAYBACK_AVAILABILITY_H_ - -namespace blink { - -// GENERATED_JAVA_ENUM_PACKAGE: ( -// org.chromium.blink_public.platform.modules.remoteplayback) -// Various states for the remote playback availability. -enum class WebRemotePlaybackAvailability { - // The availability is unknown. - kUnknown, - - // The media source is compatible with some supported device types but - // no devices were found. - kDeviceNotAvailable, - - // There're available devices but the current media source is not compatible - // with any of those. - kSourceNotCompatible, - - // There're available remote playback devices and the media source is - // compatible with at least one of them. - kDeviceAvailable, - - kLast = kDeviceAvailable -}; - -} // namespace blink - -#endif // WebRemotePlaybackState_h
diff --git a/third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h b/third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h index 588fccf0..10ec2d3a 100644 --- a/third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h +++ b/third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h
@@ -7,7 +7,6 @@ namespace blink { -enum class WebRemotePlaybackAvailability; enum class WebRemotePlaybackState; class WebURL; class WebString; @@ -18,15 +17,6 @@ public: virtual ~WebRemotePlaybackClient() = default; - // Notifies the client that the media element state has changed. - virtual void StateChanged(WebRemotePlaybackState) = 0; - - // Notifies the client of the remote playback device availability change. - virtual void AvailabilityChanged(WebRemotePlaybackAvailability) = 0; - - // Notifies the client that the user cancelled the prompt shown via the API. - virtual void PromptCancelled() = 0; - // Returns if the remote playback available for this media element. virtual bool RemotePlaybackAvailable() const = 0;
diff --git a/third_party/blink/public/platform/web_client_hints_types.mojom b/third_party/blink/public/platform/web_client_hints_types.mojom index 3a41a1c..4f9a2b13 100644 --- a/third_party/blink/public/platform/web_client_hints_types.mojom +++ b/third_party/blink/public/platform/web_client_hints_types.mojom
@@ -24,6 +24,10 @@ kDownlink = 5, kEct = 6, kLang = 7, + kUA = 8, + kUAArch = 9, + kUAPlatform = 10, + kUAModel = 11, // Warning: Before adding a new client hint, read the warning at the top. };
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom index d4cb9fd..cc6c1d5b 100644 --- a/third_party/blink/public/platform/web_feature.mojom +++ b/third_party/blink/public/platform/web_feature.mojom
@@ -2225,6 +2225,10 @@ kV8UserActivation_IsActive_AttributeGetter = 2786, kTextEncoderEncodeInto = 2787, kInvalidBasicCardMethodData = 2788, + kClientHintsUA = 2789, + kClientHintsUAArch = 2790, + kClientHintsUAPlatform = 2791, + kClientHintsUAModel = 2792, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/web_media_player_client.h b/third_party/blink/public/platform/web_media_player_client.h index e4cab565..571e6da4 100644 --- a/third_party/blink/public/platform/web_media_player_client.h +++ b/third_party/blink/public/platform/web_media_player_client.h
@@ -46,8 +46,6 @@ class WebMediaSource; class WebRemotePlaybackClient; -enum class WebRemotePlaybackAvailability; - class BLINK_PLATFORM_EXPORT WebMediaPlayerClient { public: enum VideoTrackKind { @@ -93,12 +91,6 @@ virtual void RemoveTextTrack(WebInbandTextTrack*) = 0; virtual void MediaSourceOpened(WebMediaSource*) = 0; virtual void RequestSeek(double) = 0; - virtual void RemoteRouteAvailabilityChanged( - WebRemotePlaybackAvailability) = 0; - virtual void ConnectedToRemoteDevice() = 0; - virtual void DisconnectedFromRemoteDevice() = 0; - virtual void CancelledRemotePlaybackRequest() = 0; - virtual void RemotePlaybackStarted() = 0; virtual void RemotePlaybackCompatibilityChanged(const WebURL&, bool is_compatible) = 0;
diff --git a/third_party/blink/public/web/web_render_theme.h b/third_party/blink/public/web/web_render_theme.h index 7a1e0af..210239f0 100644 --- a/third_party/blink/public/web/web_render_theme.h +++ b/third_party/blink/public/web/web_render_theme.h
@@ -42,6 +42,10 @@ BLINK_EXPORT void SetFocusRingColor(SkColor); +BLINK_EXPORT void SetMinimumStrokeWidthForFocusRing(float); + +BLINK_EXPORT void SetIsFocusRingOutset(bool); + } // namespace blink #endif
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc index c345ace..ef4641f 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -66,6 +66,7 @@ #include "third_party/blink/renderer/platform/bindings/v8_private_property.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h" #include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h"
diff --git a/third_party/blink/renderer/core/animation/non_interpolable_value.h b/third_party/blink/renderer/core/animation/non_interpolable_value.h index 271eee8c..a570f8aa8 100644 --- a/third_party/blink/renderer/core/animation/non_interpolable_value.h +++ b/third_party/blink/renderer/core/animation/non_interpolable_value.h
@@ -29,12 +29,11 @@ #define DEFINE_NON_INTERPOLABLE_VALUE_TYPE(T) \ NonInterpolableValue::Type T::static_type_ = &T::static_type_ -#define DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(T) \ - inline bool Is##T(const NonInterpolableValue* value) { \ - return !value || value->GetType() == T::static_type_; \ - } \ - DEFINE_TYPE_CASTS(T, NonInterpolableValue, value, Is##T(value), \ - Is##T(&value)); +#define DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(T) \ + inline bool Is##T(const NonInterpolableValue* value) { \ + return !value || value->GetType() == T::static_type_; \ + } \ + DEFINE_TYPE_CASTS(T, NonInterpolableValue, value, Is##T(value), Is##T(&value)) } // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc b/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc index 058dfd6d..142e2b9 100644 --- a/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc +++ b/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc
@@ -318,7 +318,7 @@ float scaled_value = document_->GetPage()->GetChromeClient().WindowToViewportScalar( result.GetFloatValue()); - result.SetValue(scaled_value); + result = Length::Fixed(scaled_value); } return result; }
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator_behavior.h b/third_party/blink/renderer/core/editing/iterators/text_iterator_behavior.h index 59eb8df..ce189732 100644 --- a/third_party/blink/renderer/core/editing/iterators/text_iterator_behavior.h +++ b/third_party/blink/renderer/core/editing/iterators/text_iterator_behavior.h
@@ -7,10 +7,13 @@ #include "base/macros.h" #include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" namespace blink { class CORE_EXPORT TextIteratorBehavior final { + DISALLOW_NEW(); + public: class CORE_EXPORT Builder; @@ -103,6 +106,8 @@ }; class CORE_EXPORT TextIteratorBehavior::Builder final { + STACK_ALLOCATED(); + public: explicit Builder(const TextIteratorBehavior&); Builder();
diff --git a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h index 1e6cdf1..071f02f 100644 --- a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h +++ b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/editing/finder/find_options.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/text/string_view.h" #include "third_party/blink/renderer/platform/wtf/text/unicode.h" @@ -21,6 +22,8 @@ }; class CORE_EXPORT TextSearcherICU { + DISALLOW_NEW(); + public: TextSearcherICU(); ~TextSearcherICU();
diff --git a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc index 2de2f8a..660986c1 100644 --- a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc +++ b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
@@ -66,8 +66,8 @@ } // https://w3c.github.io/DOM-Parsing/#dfn-recording-the-namespace-information - void RecordNamespaceInformation(const Element& element) { - local_default_namespace_ = AtomicString(); + AtomicString RecordNamespaceInformation(const Element& element) { + AtomicString local_default_namespace; // 2. For each attribute attr in element's attributes, in the order they are // specified in the element's attribute list: for (const auto& attr : element.Attributes()) { @@ -79,11 +79,13 @@ // declaration. Set the default namespace attr value to attr's value // and stop running these steps, returning to Main to visit the next // attribute. - local_default_namespace_ = attr.Value(); + local_default_namespace = attr.Value(); } else if (attr.Prefix() == g_xmlns_atom) { Add(attr.Prefix() ? attr.LocalName() : g_empty_atom, attr.Value()); } } + // 3. Return the value of default namespace attr value. + return local_default_namespace; } AtomicString LookupNamespaceURI(const AtomicString& prefix) const { @@ -95,16 +97,13 @@ context_namespace_ = context_ns; } - const AtomicString& LocalDefaultNamespace() const { - return local_default_namespace_; - } - - void InheritLocalDefaultNamespace() { - if (!local_default_namespace_) + void InheritLocalDefaultNamespace( + const AtomicString& local_default_namespace) { + if (!local_default_namespace) return; - SetContextNamespace(local_default_namespace_.IsEmpty() + SetContextNamespace(local_default_namespace.IsEmpty() ? g_null_atom - : local_default_namespace_); + : local_default_namespace); } const Vector<AtomicString> PrefixList(const AtomicString& ns) const { @@ -122,9 +121,18 @@ // https://w3c.github.io/DOM-Parsing/#dfn-context-namespace AtomicString context_namespace_; +}; - // https://w3c.github.io/DOM-Parsing/#dfn-local-default-namespace - AtomicString local_default_namespace_; +// This stores values used to serialize an element. The values are not +// inherited to child node serialization. +class MarkupAccumulator::ElementSerializationData final { + STACK_ALLOCATED(); + + public: + // https://w3c.github.io/DOM-Parsing/#dfn-ignore-namespace-definition-attribute + bool ignore_namespace_definition_attribute_ = false; + + AtomicString serialized_prefix_; }; MarkupAccumulator::MarkupAccumulator(EAbsoluteURLs resolve_urls_method, @@ -174,10 +182,10 @@ } AtomicString MarkupAccumulator::AppendElement(const Element& element) { - AtomicString prefix = element.prefix(); + const ElementSerializationData data = AppendStartTagOpen(element); if (SerializeAsHTMLDocument(element)) { // https://html.spec.whatwg.org/C/#html-fragment-serialisation-algorithm - AppendStartTagOpen(element); + AttributeCollection attributes = element.Attributes(); // 3.2. Element: If current node's is value is not null, and the // element does not have an is attribute in its attribute list, ... @@ -191,13 +199,9 @@ } } else { // https://w3c.github.io/DOM-Parsing/#xml-serializing-an-element-node - namespace_stack_.back().RecordNamespaceInformation(element); - auto pair = AppendStartTagOpen(element); - const bool ignore_namespace_definition_attribute = pair.first; - prefix = pair.second; for (const auto& attribute : element.Attributes()) { - if (ignore_namespace_definition_attribute && + if (data.ignore_namespace_definition_attribute_ && attribute.NamespaceURI() == xmlns_names::kNamespaceURI && attribute.Prefix().IsEmpty()) continue; @@ -210,14 +214,16 @@ AppendCustomAttributes(element); AppendStartTagClose(element); - return prefix; + return data.serialized_prefix_; } -std::pair<bool, AtomicString> MarkupAccumulator::AppendStartTagOpen( - const Element& element) { +MarkupAccumulator::ElementSerializationData +MarkupAccumulator::AppendStartTagOpen(const Element& element) { + ElementSerializationData data; + data.serialized_prefix_ = element.prefix(); if (SerializeAsHTMLDocument(element)) { formatter_.AppendStartTagOpen(markup_, element); - return std::make_pair(false, element.prefix()); + return data; } // https://w3c.github.io/DOM-Parsing/#xml-serializing-an-element-node @@ -226,11 +232,11 @@ // 5. Let ignore namespace definition attribute be a boolean flag with value // false. - bool ignore_namespace_definition_attribute = false; + data.ignore_namespace_definition_attribute_ = false; // 8. Let local default namespace be the result of recording the namespace // information for node given map and local prefixes map. AtomicString local_default_namespace = - namespace_stack_.back().LocalDefaultNamespace(); + namespace_context.RecordNamespaceInformation(element); // 9. Let inherited ns be a copy of namespace. AtomicString inherited_ns = namespace_context.ContextNamespace(); // 10. Let ns be the value of node's namespaceURI attribute. @@ -240,13 +246,15 @@ if (inherited_ns == ns) { // 11.1. If local default namespace is not null, then set ignore namespace // definition attribute to true. - ignore_namespace_definition_attribute = !local_default_namespace.IsNull(); + data.ignore_namespace_definition_attribute_ = + !local_default_namespace.IsNull(); // 11.3. Otherwise, append to qualified name the value of node's // localName. The node's prefix if it exists, is dropped. // 11.4. Append the value of qualified name to markup. formatter_.AppendStartTagOpen(markup_, g_null_atom, element.localName()); - return std::make_pair(ignore_namespace_definition_attribute, g_null_atom); + data.serialized_prefix_ = g_null_atom; + return data; } // 12. Otherwise, inherited ns is not equal to ns (the node's own namespace is @@ -267,6 +275,7 @@ // 12.4.3. Append the value of qualified name to markup. formatter_.AppendStartTagOpen(markup_, candidate_prefix, element.localName()); + data.serialized_prefix_ = candidate_prefix; // 12.4.2. If the local default namespace is not null (there exists a // locally-defined default namespace declaration attribute) and its value is // not the XML namespace, then let inherited ns get the value of local @@ -274,10 +283,8 @@ // in which case let it get null (the context namespace is changed to the // declared default, rather than this node's own namespace). if (local_default_namespace != xml_names::kNamespaceURI) - namespace_context.InheritLocalDefaultNamespace(); - - return std::make_pair(ignore_namespace_definition_attribute, - candidate_prefix); + namespace_context.InheritLocalDefaultNamespace(local_default_namespace); + return data; } // 12.5. Otherwise, if prefix is not null, then: @@ -295,21 +302,22 @@ // COLON), and node's localName. // 12.5.4. Append the value of qualified name to markup. formatter_.AppendStartTagOpen(markup_, prefix, element.localName()); + data.serialized_prefix_ = prefix; // 12.5.5. Append the following to markup, in the order listed: MarkupFormatter::AppendAttribute(markup_, g_xmlns_atom, prefix, ns, false); // 12.5.5.7. If local default namespace is not null (there exists a // locally-defined default namespace declaration attribute), then let // inherited ns get the value of local default namespace unless the local // default namespace is the empty string in which case let it get null. - namespace_context.InheritLocalDefaultNamespace(); - return std::make_pair(ignore_namespace_definition_attribute, prefix); + namespace_context.InheritLocalDefaultNamespace(local_default_namespace); + return data; } // 12.6. Otherwise, if local default namespace is null, or local default // namespace is not null and its value is not equal to ns, then: if (local_default_namespace.IsNull() || local_default_namespace != ns) { // 12.6.1. Set the ignore namespace definition attribute flag to true. - ignore_namespace_definition_attribute = true; + data.ignore_namespace_definition_attribute_ = true; // 12.6.3. Let the value of inherited ns be ns. namespace_context.SetContextNamespace(ns); // 12.6.4. Append the value of qualified name to markup. @@ -317,7 +325,7 @@ // 12.6.5. Append the following to markup, in the order listed: MarkupFormatter::AppendAttribute(markup_, g_null_atom, g_xmlns_atom, ns, false); - return std::make_pair(ignore_namespace_definition_attribute, g_null_atom); + return data; } // 12.7. Otherwise, the node has a local default namespace that matches @@ -326,7 +334,7 @@ DCHECK_EQ(local_default_namespace, ns); namespace_context.SetContextNamespace(ns); formatter_.AppendStartTagOpen(markup_, element); - return std::make_pair(ignore_namespace_definition_attribute, g_null_atom); + return data; } void MarkupAccumulator::AppendStartTagClose(const Element& element) {
diff --git a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.h b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.h index ebd2895..0294f54 100644 --- a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.h +++ b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.h
@@ -68,11 +68,13 @@ void AppendString(const String&); // Serialize a Node, without its children and its end tag. void AppendStartMarkup(const Node&); - // Returns the pair of 'ignore namespace definition attribute' flag and the - // serialized prefix. + + class ElementSerializationData; + // Returns 'ignore namespace definition attribute' flag and the serialized + // prefix. // If the flag is true, we should not serialize xmlns="..." on the element. // The prefix should be used in end tag serialization. - std::pair<bool, AtomicString> AppendStartTagOpen(const Element&); + ElementSerializationData AppendStartTagOpen(const Element&); void AppendStartTagClose(const Element&); void AppendNamespace(const AtomicString& prefix, const AtomicString& namespace_uri);
diff --git a/third_party/blink/renderer/core/events/current_input_event.h b/third_party/blink/renderer/core/events/current_input_event.h index 149b6a43..3820049 100644 --- a/third_party/blink/renderer/core/events/current_input_event.h +++ b/third_party/blink/renderer/core/events/current_input_event.h
@@ -6,12 +6,15 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_CURRENT_INPUT_EVENT_H_ #include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" namespace blink { class WebInputEvent; class CORE_EXPORT CurrentInputEvent { + STATIC_ONLY(CurrentInputEvent); + public: // Gets the "current" input event - event that is currently being processed by // either blink::WebViewImpl::HandleInputEventInternal or by
diff --git a/third_party/blink/renderer/core/events/message_event.h b/third_party/blink/renderer/core/events/message_event.h index 40db582..6d88a50 100644 --- a/third_party/blink/renderer/core/events/message_event.h +++ b/third_party/blink/renderer/core/events/message_event.h
@@ -39,6 +39,7 @@ #include "third_party/blink/renderer/core/fileapi/blob.h" #include "third_party/blink/renderer/core/messaging/message_port.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/compiler.h" namespace blink { @@ -209,6 +210,8 @@ private: class V8GCAwareString final { + DISALLOW_NEW(); + public: V8GCAwareString() = default; V8GCAwareString(const String&);
diff --git a/third_party/blink/renderer/core/exported/web_render_theme.cc b/third_party/blink/renderer/core/exported/web_render_theme.cc index 4213986..dff6608 100644 --- a/third_party/blink/renderer/core/exported/web_render_theme.cc +++ b/third_party/blink/renderer/core/exported/web_render_theme.cc
@@ -44,4 +44,12 @@ LayoutTheme::GetTheme().SetCustomFocusRingColor(color); } +void SetMinimumStrokeWidthForFocusRing(float stroke_width) { + LayoutTheme::GetTheme().SetMinimumStrokeWidthForFocusRing(stroke_width); +} + +void SetIsFocusRingOutset(bool is_outset) { + LayoutTheme::GetTheme().SetIsFocusRingOutset(is_outset); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.h b/third_party/blink/renderer/core/frame/frame_test_helpers.h index 7d0abe63..1eb3209 100644 --- a/third_party/blink/renderer/core/frame/frame_test_helpers.h +++ b/third_party/blink/renderer/core/frame/frame_test_helpers.h
@@ -60,6 +60,7 @@ #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h" #include "third_party/blink/renderer/core/testing/use_mock_scrollbar_settings.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/vector.h" #define EXPECT_FLOAT_POINT_EQ(expected, actual) \ @@ -176,6 +177,8 @@ // A class that constructs and owns a LayerTreeView for blink // unit tests. class LayerTreeViewFactory { + DISALLOW_NEW(); + public: // Use this to make a LayerTreeView with a stub delegate. content::LayerTreeView* Initialize(); @@ -255,6 +258,8 @@ // Convenience class for handling the lifetime of a WebView and its associated // mainframe in tests. class WebViewHelper { + USING_FAST_MALLOC(WebViewHelper); + public: WebViewHelper(); ~WebViewHelper();
diff --git a/third_party/blink/renderer/core/frame/fullscreen_controller.h b/third_party/blink/renderer/core/frame/fullscreen_controller.h index ab6676c1..3bffc9a7 100644 --- a/third_party/blink/renderer/core/frame/fullscreen_controller.h +++ b/third_party/blink/renderer/core/frame/fullscreen_controller.h
@@ -39,6 +39,7 @@ #include "third_party/blink/renderer/platform/geometry/int_size.h" #include "third_party/blink/renderer/platform/graphics/color.h" #include "third_party/blink/renderer/platform/heap/persistent.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" namespace blink { @@ -50,6 +51,8 @@ // and out of fullscreen, including restoring scroll offset and scale after // exiting fullscreen. It is (indirectly) used by the Fullscreen class. class CORE_EXPORT FullscreenController { + USING_FAST_MALLOC(FullscreenController); + public: static std::unique_ptr<FullscreenController> Create(WebViewImpl*);
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h index 2d3be7e..a8145cdb 100644 --- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LOCAL_FRAME_UKM_AGGREGATOR_H_ #include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/time.h" @@ -172,6 +173,8 @@ // aggregator that created the scoped timer. It will also record an event // into the histogram counter. class CORE_EXPORT ScopedUkmHierarchicalTimer { + STACK_ALLOCATED(); + public: ScopedUkmHierarchicalTimer(ScopedUkmHierarchicalTimer&&); ~ScopedUkmHierarchicalTimer();
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index 7cf80d8b..4eac4650 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -47,6 +47,7 @@ #include "third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h" #include "third_party/blink/renderer/platform/graphics/subtree_paint_property_update_reason.h" #include "third_party/blink/renderer/platform/timer.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/skia/include/core/SkColor.h" namespace cc { @@ -724,6 +725,8 @@ private: #if DCHECK_IS_ON() class DisallowLayoutInvalidationScope { + STACK_ALLOCATED(); + public: DisallowLayoutInvalidationScope(LocalFrameView* view) : local_frame_view_(view) {
diff --git a/third_party/blink/renderer/core/frame/navigator.h b/third_party/blink/renderer/core/frame/navigator.h index 3c049fc..16ed6e3 100644 --- a/third_party/blink/renderer/core/frame/navigator.h +++ b/third_party/blink/renderer/core/frame/navigator.h
@@ -71,8 +71,12 @@ String GetAcceptLanguages() override; UserAgentMetadata GetUserAgentMetadata() const override; + void SetUserAgentMetadataForTesting(UserAgentMetadata); void Trace(blink::Visitor*) override; + + private: + UserAgentMetadata metadata_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/opened_frame_tracker.h b/third_party/blink/renderer/core/frame/opened_frame_tracker.h index b89c6069..60c44d6c 100644 --- a/third_party/blink/renderer/core/frame/opened_frame_tracker.h +++ b/third_party/blink/renderer/core/frame/opened_frame_tracker.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_OPENED_FRAME_TRACKER_H_ #include "base/macros.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" namespace blink { @@ -16,6 +17,8 @@ // Due to layering restrictions, we need to hide the implementation, since // public/web/ cannot depend on wtf/. class OpenedFrameTracker { + USING_FAST_MALLOC(OpenedFrameTracker); + public: OpenedFrameTracker(); ~OpenedFrameTracker();
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc index eecab41..7eed8bec 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.cc +++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -33,7 +33,6 @@ #include "base/debug/crash_logging.h" #include "base/memory/ptr_util.h" #include "media/base/logging_override_if_enabled.h" -#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h" #include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h" #include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_state.h" #include "third_party/blink/public/platform/platform.h" @@ -505,7 +504,6 @@ should_perform_automatic_track_selection_(true), tracks_are_ready_(true), processing_preference_change_(false), - playing_remotely_(false), mostly_filling_viewport_(false), was_always_muted_(true), audio_tracks_(AudioTrackList::Create(*this)), @@ -2519,21 +2517,6 @@ UpdatePlayState(); } -void HTMLMediaElement::RequestRemotePlayback() { - if (GetWebMediaPlayer()) - GetWebMediaPlayer()->RequestRemotePlayback(); -} - -void HTMLMediaElement::RequestRemotePlaybackControl() { - if (GetWebMediaPlayer()) - GetWebMediaPlayer()->RequestRemotePlaybackControl(); -} - -void HTMLMediaElement::RequestRemotePlaybackStop() { - if (GetWebMediaPlayer()) - GetWebMediaPlayer()->RequestRemotePlaybackStop(); -} - void HTMLMediaElement::FlingingStarted() { if (GetWebMediaPlayer()) GetWebMediaPlayer()->FlingingStarted(); @@ -3299,48 +3282,12 @@ setCurrentTime(time); } -void HTMLMediaElement::RemoteRouteAvailabilityChanged( - WebRemotePlaybackAvailability availability) { - // The new remote playback pipeline is using the Presentation API for - // remote playback device availability monitoring. - // This code is left as is because many tests depend on this path for the - // moment, but it will be cleaned up. - // TODO(https://crbug.com/927099): Clean up old discovery paths. - // TODO(https://crubg.com/927451): Remove test depencencies on - // RemoteRouteAvailabilityChanged - - if (RemotePlaybackClient()) - RemotePlaybackClient()->AvailabilityChanged(availability); -} - bool HTMLMediaElement::HasRemoteRoutes() const { // TODO(mlamouri): used by MediaControlsPainter; should be refactored out. return RemotePlaybackClient() && RemotePlaybackClient()->RemotePlaybackAvailable(); } -void HTMLMediaElement::ConnectedToRemoteDevice() { - playing_remotely_ = true; - if (RemotePlaybackClient()) - RemotePlaybackClient()->StateChanged(WebRemotePlaybackState::kConnecting); -} - -void HTMLMediaElement::DisconnectedFromRemoteDevice() { - playing_remotely_ = false; - if (RemotePlaybackClient()) - RemotePlaybackClient()->StateChanged(WebRemotePlaybackState::kDisconnected); -} - -void HTMLMediaElement::CancelledRemotePlaybackRequest() { - if (RemotePlaybackClient()) - RemotePlaybackClient()->PromptCancelled(); -} - -void HTMLMediaElement::RemotePlaybackStarted() { - if (RemotePlaybackClient()) - RemotePlaybackClient()->StateChanged(WebRemotePlaybackState::kConnected); -} - void HTMLMediaElement::RemotePlaybackCompatibilityChanged(const WebURL& url, bool is_compatible) { if (RemotePlaybackClient()) @@ -3549,10 +3496,6 @@ pending_action_flags_ = 0; load_state_ = kWaitingForSource; - // We can't cast if we don't have a media player. - playing_remotely_ = false; - RemoteRouteAvailabilityChanged(WebRemotePlaybackAvailability::kUnknown); - if (GetLayoutObject()) GetLayoutObject()->SetShouldDoFullPaintInvalidation(); } @@ -3907,10 +3850,6 @@ ClearMediaPlayerAndAudioSourceProviderClientWithoutLocking(); } - // We haven't yet found out if any remote routes are available. - playing_remotely_ = false; - RemoteRouteAvailabilityChanged(WebRemotePlaybackAvailability::kUnknown); - if (audio_source_node_) GetAudioSourceProvider().SetClient(audio_source_node_); }
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.h b/third_party/blink/renderer/core/html/media/html_media_element.h index 68807403..b785d9e 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.h +++ b/third_party/blink/renderer/core/html/media/html_media_element.h
@@ -136,7 +136,6 @@ void ScheduleTextTrackResourceLoad(); bool HasRemoteRoutes() const; - bool IsPlayingRemotely() const { return playing_remotely_; } // error state MediaError* error() const; @@ -197,9 +196,6 @@ ScriptPromise playForBindings(ScriptState*); base::Optional<DOMExceptionCode> Play(); void pause(); - void RequestRemotePlayback(); - void RequestRemotePlaybackControl(); - void RequestRemotePlaybackStop(); void FlingingStarted(); void FlingingStopped(); @@ -423,11 +419,6 @@ void RemoveTextTrack(WebInbandTextTrack*) final; void MediaSourceOpened(WebMediaSource*) final; void RequestSeek(double) final; - void RemoteRouteAvailabilityChanged(WebRemotePlaybackAvailability) final; - void ConnectedToRemoteDevice() final; - void DisconnectedFromRemoteDevice() final; - void CancelledRemotePlaybackRequest() final; - void RemotePlaybackStarted() final; void RemotePlaybackCompatibilityChanged(const WebURL&, bool is_compatible) final; void OnBecamePersistentVideo(bool) override {} @@ -672,7 +663,6 @@ bool tracks_are_ready_ : 1; bool processing_preference_change_ : 1; - bool playing_remotely_ : 1; // The following is always false unless viewport intersection monitoring is // turned on via ActivateViewportIntersectionMonitoring().
diff --git a/third_party/blink/renderer/core/html/media/remote_playback_controller.h b/third_party/blink/renderer/core/html/media/remote_playback_controller.h index 88a9dc31..5bd208e 100644 --- a/third_party/blink/renderer/core/html/media/remote_playback_controller.h +++ b/third_party/blink/renderer/core/html/media/remote_playback_controller.h
@@ -26,6 +26,10 @@ virtual void AddObserver(RemotePlaybackObserver*) = 0; virtual void RemoveObserver(RemotePlaybackObserver*) = 0; + // Exposes simplified internal methods for testing purposes. + virtual void AvailabilityChangedForTesting(bool screen_is_available) = 0; + virtual void StateChangedForTesting(bool is_connected) = 0; + void Trace(Visitor*) override; protected:
diff --git a/third_party/blink/renderer/core/html/media/remote_playback_observer.h b/third_party/blink/renderer/core/html/media/remote_playback_observer.h index e9e7cc8..591eecc 100644 --- a/third_party/blink/renderer/core/html/media/remote_playback_observer.h +++ b/third_party/blink/renderer/core/html/media/remote_playback_observer.h
@@ -7,7 +7,6 @@ namespace blink { -enum class WebRemotePlaybackAvailability; enum class WebRemotePlaybackState; // Interface to be implemented by objects that intend to be notified by remote @@ -18,11 +17,6 @@ // Called when the remote playback state is changed. The state is related to // the connection to a remote device. virtual void OnRemotePlaybackStateChanged(WebRemotePlaybackState) = 0; - - // Called when the remote playback availability is changed. The availabality - // is realted to the presence of a compatible remote device on the network. - virtual void OnRemotePlaybackAvailabilityChanged( - WebRemotePlaybackAvailability) = 0; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/html/media/video_wake_lock.cc b/third_party/blink/renderer/core/html/media/video_wake_lock.cc index d5dfeb9..a9e5da87 100644 --- a/third_party/blink/renderer/core/html/media/video_wake_lock.cc +++ b/third_party/blink/renderer/core/html/media/video_wake_lock.cc
@@ -60,9 +60,6 @@ Update(); } -void VideoWakeLock::OnRemotePlaybackAvailabilityChanged( - WebRemotePlaybackAvailability) {} - void VideoWakeLock::Update() { bool should_be_active = ShouldBeActive(); if (should_be_active == active_)
diff --git a/third_party/blink/renderer/core/html/media/video_wake_lock.h b/third_party/blink/renderer/core/html/media/video_wake_lock.h index ee4ec11..bbe5b499 100644 --- a/third_party/blink/renderer/core/html/media/video_wake_lock.h +++ b/third_party/blink/renderer/core/html/media/video_wake_lock.h
@@ -40,7 +40,6 @@ // RemotePlaybackObserver implementation. void OnRemotePlaybackStateChanged(WebRemotePlaybackState) final; - void OnRemotePlaybackAvailabilityChanged(WebRemotePlaybackAvailability) final; bool active_for_tests() const { return active_; }
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.cc b/third_party/blink/renderer/core/inspector/devtools_session.cc index 3eb4292..a44df36 100644 --- a/third_party/blink/renderer/core/inspector/devtools_session.cc +++ b/third_party/blink/renderer/core/inspector/devtools_session.cc
@@ -43,11 +43,16 @@ } mojom::blink::DevToolsMessagePtr WrapMessage( - const protocol::ProtocolMessage& message) { + protocol::ProtocolMessage message) { auto result = mojom::blink::DevToolsMessage::New(); - WTF::StringUTF8Adaptor adaptor(message.json); - result->data = mojo_base::BigBuffer(base::make_span( - reinterpret_cast<const uint8_t*>(adaptor.Data()), adaptor.length())); + + if (message.json.IsEmpty()) { + result->data = std::move(message.binary); + } else { + WTF::StringUTF8Adaptor adaptor(message.json); + result->data = mojo_base::BigBuffer(base::make_span( + reinterpret_cast<const uint8_t*>(adaptor.Data()), adaptor.length())); + } return result; } @@ -129,7 +134,8 @@ inspector_backend_dispatcher_(new protocol::UberDispatcher(this)), session_state_(std::move(reattach_session_state)), v8_session_state_(kV8StateKey), - v8_session_state_json_(&v8_session_state_, /*default_value=*/String()) { + v8_session_state_json_(&v8_session_state_, /*default_value=*/String()), + uses_binary_protocol_(&v8_session_state_, false) { io_session_ = new IOSession(agent_->io_task_runner_, agent_->inspector_task_runner_, WrapCrossThreadWeakPersistent(this), std::move(io_request)); @@ -203,7 +209,7 @@ std::vector<uint8_t> data) { bool binary_protocol = data.size() && data[0] == 0xD8; if (binary_protocol) - uses_binary_protocol_ = true; + uses_binary_protocol_.Set(true); // IOSession does not provide ordering guarantees relative to // Session, so a command may come to IOSession after Session is detached, @@ -267,7 +273,8 @@ void DevToolsSession::sendProtocolResponse( int call_id, std::unique_ptr<protocol::Serializable> message) { - SendProtocolResponse(call_id, message->serialize(uses_binary_protocol_)); + SendProtocolResponse(call_id, + message->serialize(uses_binary_protocol_.Get())); } void DevToolsSession::fallThrough(int call_id, @@ -283,8 +290,8 @@ // We can potentially avoid copies if WebString would convert to utf8 right // from StringView, but it uses StringImpl itself, so we don't create any // extra copies here. - SendProtocolResponse( - call_id, ToProtocolMessage(std::move(message), uses_binary_protocol_)); + SendProtocolResponse(call_id, ToProtocolMessage(std::move(message), + uses_binary_protocol_.Get())); } void DevToolsSession::SendProtocolResponse( @@ -333,7 +340,7 @@ serialized = ToProtocolMessage(std::move(v8_notification_), binary); v8_notification_.reset(); } - return WrapMessage(serialized); + return WrapMessage(std::move(serialized)); } private: @@ -367,9 +374,10 @@ if (v8_session_) v8_session_state_json_.Set(ToCoreString(v8_session_->stateJSON())); for (wtf_size_t i = 0; i < notification_queue_.size(); ++i) { - host_ptr_->DispatchProtocolNotification( - notification_queue_[i]->Serialize(uses_binary_protocol_), - session_state_.TakeUpdates()); + auto serialized = + notification_queue_[i]->Serialize(uses_binary_protocol_.Get()); + host_ptr_->DispatchProtocolNotification(std::move(serialized), + session_state_.TakeUpdates()); } notification_queue_.clear(); }
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.h b/third_party/blink/renderer/core/inspector/devtools_session.h index efd265c..388f64676 100644 --- a/third_party/blink/renderer/core/inspector/devtools_session.h +++ b/third_party/blink/renderer/core/inspector/devtools_session.h
@@ -97,7 +97,7 @@ Vector<std::unique_ptr<Notification>> notification_queue_; InspectorAgentState v8_session_state_; InspectorAgentState::String v8_session_state_json_; - bool uses_binary_protocol_ = false; + InspectorAgentState::Boolean uses_binary_protocol_; DISALLOW_COPY_AND_ASSIGN(DevToolsSession); };
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc index c6579ce..62e6b14 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
@@ -223,10 +223,10 @@ root_(root), thresholds_(thresholds), delay_(delay), - top_margin_(kFixed), - right_margin_(kFixed), - bottom_margin_(kFixed), - left_margin_(kFixed), + top_margin_(Length::Fixed(0)), + right_margin_(Length::Fixed(0)), + bottom_margin_(Length::Fixed(0)), + left_margin_(Length::Fixed(0)), root_is_implicit_(root ? 0 : 1), track_visibility_(track_visibility ? 1 : 0), track_fraction_of_root_(semantics == kFractionOfRoot),
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 69022e8..4c08a81 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -3101,9 +3101,9 @@ // will think we're wider than we actually are and calculate line sizes // wrong. See also https://drafts.csswg.org/css-flexbox/#auto-margins if (margin_start_length.IsAuto()) - margin_start_length.SetValue(0); + margin_start_length = Length::Fixed(0); if (margin_end_length.IsAuto()) - margin_end_length.SetValue(0); + margin_end_length = Length::Fixed(0); } LayoutUnit margin_start_width = @@ -4100,9 +4100,9 @@ // them (depending on the direction) is simply "0". if (parent->IsLayoutGrid() && parent == child->ContainingBlock()) { if (parent_direction == TextDirection::kLtr) - logical_left.SetValue(kFixed, 0); + logical_left = Length::Fixed(0); else - logical_right.SetValue(kFixed, 0); + logical_right = Length::Fixed(0); return; } @@ -4138,7 +4138,7 @@ } } } - logical_left.SetValue(kFixed, static_position); + logical_left = Length::Fixed(static_position); } else { LayoutBox* enclosing_box = child->Parent()->EnclosingBox(); LayoutUnit static_position = child->Layer()->StaticInlinePosition() + @@ -4176,7 +4176,7 @@ if (curr == container_block) break; } - logical_right.SetValue(kFixed, static_position); + logical_right = Length::Fixed(static_position); } } @@ -4602,7 +4602,7 @@ static_logical_top -= ToLayoutBox(container_block)->LogicalTopScrollbarHeight(); } - logical_top.SetValue(kFixed, static_logical_top); + logical_top = Length::Fixed(static_logical_top); } void LayoutBox::ComputePositionedLogicalHeight(
diff --git a/third_party/blink/renderer/core/layout/layout_replaced.cc b/third_party/blink/renderer/core/layout/layout_replaced.cc index 0cbb932..9436cbdf 100644 --- a/third_party/blink/renderer/core/layout/layout_replaced.cc +++ b/third_party/blink/renderer/core/layout/layout_replaced.cc
@@ -272,9 +272,9 @@ // --------------------------------------------------------------------------- if (logical_left.IsAuto() || logical_right.IsAuto()) { if (margin_logical_left.IsAuto()) - margin_logical_left.SetValue(kFixed, 0); + margin_logical_left = Length::Fixed(0); if (margin_logical_right.IsAuto()) - margin_logical_right.SetValue(kFixed, 0); + margin_logical_right = Length::Fixed(0); } // --------------------------------------------------------------------------- @@ -481,9 +481,9 @@ // auto, but if only top is auto, this makes step 4 impossible. if (logical_top.IsAuto() || logical_bottom.IsAuto()) { if (margin_before.IsAuto()) - margin_before.SetValue(kFixed, 0); + margin_before = Length::Fixed(0); if (margin_after.IsAuto()) - margin_after.SetValue(kFixed, 0); + margin_after = Length::Fixed(0); } // ---------------------------------------------------------------------------
diff --git a/third_party/blink/renderer/core/layout/layout_theme.cc b/third_party/blink/renderer/core/layout/layout_theme.cc index d7df2dfe..6202634a 100644 --- a/third_party/blink/renderer/core/layout/layout_theme.cc +++ b/third_party/blink/renderer/core/layout/layout_theme.cc
@@ -838,6 +838,22 @@ has_custom_focus_ring_color_ = true; } +bool LayoutTheme::IsFocusRingOutset() const { + return is_focus_ring_outset_; +} + +void LayoutTheme::SetIsFocusRingOutset(bool is_outset) { + is_focus_ring_outset_ = is_outset; +} + +float LayoutTheme::MinimumStrokeWidthForFocusRing() const { + return minimum_width_for_focus_ring_; +} + +void LayoutTheme::SetMinimumStrokeWidthForFocusRing(float stroke_width) { + minimum_width_for_focus_ring_ = stroke_width; +} + Color LayoutTheme::FocusRingColor() const { return has_custom_focus_ring_color_ ? custom_focus_ring_color_ : GetTheme().PlatformFocusRingColor();
diff --git a/third_party/blink/renderer/core/layout/layout_theme.h b/third_party/blink/renderer/core/layout/layout_theme.h index 4137b78..98fd6b9 100644 --- a/third_party/blink/renderer/core/layout/layout_theme.h +++ b/third_party/blink/renderer/core/layout/layout_theme.h
@@ -153,6 +153,10 @@ Color PlatformTextSearchHighlightColor(bool active_match) const; Color PlatformTextSearchColor(bool active_match) const; + bool IsFocusRingOutset() const; + void SetIsFocusRingOutset(bool is_outset); + float MinimumStrokeWidthForFocusRing() const; + void SetMinimumStrokeWidthForFocusRing(float stroke_width); Color FocusRingColor() const; virtual Color PlatformFocusRingColor() const { return Color(0, 0, 0); } void SetCustomFocusRingColor(const Color&); @@ -300,6 +304,8 @@ // implementation to hand back the appropriate platform theme. static LayoutTheme& NativeTheme(); + bool is_focus_ring_outset_ = false; + float minimum_width_for_focus_ring_ = 1.0f; Color custom_focus_ring_color_; bool has_custom_focus_ring_color_; TimeDelta caret_blink_interval_ = TimeDelta::FromMilliseconds(500);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h index c74ae29..b6fcf9e0 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
@@ -80,9 +80,7 @@ NGInlineItemType Type() const { return static_cast<NGInlineItemType>(type_); } const char* NGInlineItemTypeToString(int val) const; - scoped_refptr<const ShapeResult> TextShapeResult() const { - return shape_result_; - } + const ShapeResult* TextShapeResult() const { return shape_result_.get(); } NGLayoutInlineShapeOptions ShapeOptions() const { return static_cast<NGLayoutInlineShapeOptions>(shape_options_); }
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc index 102310bc..9612baa 100644 --- a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc +++ b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
@@ -89,9 +89,9 @@ if (cell_logical_width.IsCalculated()) cell_logical_width = Length(); // Make it Auto if (cell_logical_width.Value() > kCCellMaxWidth) - cell_logical_width.SetValue(kCCellMaxWidth); + cell_logical_width = Length::Fixed(kCCellMaxWidth); if (cell_logical_width.IsNegative()) - cell_logical_width.SetValue(0); + cell_logical_width = Length::Fixed(0); switch (cell_logical_width.GetType()) { case kFixed: // ignore width=0 @@ -106,11 +106,11 @@ if ((logical_width > column_layout.logical_width.Value()) || ((column_layout.logical_width.Value() == logical_width) && (max_contributor == cell))) { - column_layout.logical_width.SetValue(kFixed, logical_width); + column_layout.logical_width = Length::Fixed(logical_width); fixed_contributor = cell; } } else { - column_layout.logical_width.SetValue(kFixed, logical_width); + column_layout.logical_width = Length::Fixed(logical_width); fixed_contributor = cell; } } @@ -478,11 +478,8 @@ total_width -= layout_struct_[pos].ClampedEffectiveMaxLogicalWidth(); percent_missing -= percent; - if (percent > 0) - layout_struct_[pos].effective_logical_width.SetValue(kPercent, - percent); - else - layout_struct_[pos].effective_logical_width = Length(); + layout_struct_[pos].effective_logical_width = + percent > 0 ? Length::Percent(percent) : Length(); } } }
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc b/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc index ab6ccb2..16ba913 100644 --- a/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc +++ b/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
@@ -160,7 +160,7 @@ fixed_border_box_logical_width = cell->AdjustBorderBoxLogicalWidthForBoxSizing(logical_width.Value()) .ToInt(); - logical_width.SetValue(fixed_border_box_logical_width); + logical_width = Length::Fixed(fixed_border_box_logical_width); } unsigned used_span = 0;
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc index 3082f4d..4d814a0 100644 --- a/third_party/blink/renderer/core/loader/base_fetch_context.cc +++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -391,7 +391,7 @@ // Loading of a subresource may be blocked by previews resource loading hints. if (GetPreviewsResourceLoadingHints() && !GetPreviewsResourceLoadingHints()->AllowLoad( - url, resource_request.Priority())) { + type, url, resource_request.Priority())) { return ResourceRequestBlockedReason::kOther; }
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc index 7269fca..812e49a 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc +++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -106,6 +106,7 @@ #include "third_party/blink/renderer/platform/network/network_state_notifier.h" #include "third_party/blink/renderer/platform/network/network_utils.h" #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" +#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { @@ -180,6 +181,7 @@ const ClientHintsPreferences& client_hints_preferences, float device_pixel_ratio, const String& user_agent, + const UserAgentMetadata& user_agent_metadata, bool is_svg_image_chrome_client) : url(url), parent_security_origin(std::move(parent_security_origin)), @@ -189,6 +191,7 @@ client_hints_preferences(client_hints_preferences), device_pixel_ratio(device_pixel_ratio), user_agent(user_agent), + user_agent_metadata(user_agent_metadata), is_svg_image_chrome_client(is_svg_image_chrome_client) {} const KURL url; @@ -199,6 +202,7 @@ const ClientHintsPreferences client_hints_preferences; const float device_pixel_ratio; const String user_agent; + const UserAgentMetadata user_agent_metadata; const bool is_svg_image_chrome_client; void Trace(blink::Visitor* visitor) { @@ -723,6 +727,33 @@ if (!AllowScriptFromSourceWithoutNotifying(request.Url())) return; + // Sec-CH-UA is special: we always send the header to all origins that are + // eligible for client hints (e.g. secure transport, JavaScript enabled). We + // alter the header's value based on whether or not the site has opted into + // additional detail. + // + // https://github.com/WICG/ua-client-hints + blink::UserAgentMetadata ua = GetUserAgentMetadata(); + if (RuntimeEnabledFeatures::UserAgentClientHintEnabled()) { + StringBuilder result; + result.Append(ua.brand.data()); + if (!ua.version.empty()) { + result.Append(' '); + if (ShouldSendClientHint(mojom::WebClientHintsType::kUA, + hints_preferences, enabled_hints)) { + result.Append(ua.version.data()); + } else { + // TODO(mkwst): This should only send the major version, but we haven't + // piped that through yet. + result.Append(ua.version.data()); + } + } + request.AddHTTPHeaderField( + blink::kClientHintsHeaderMapping[static_cast<size_t>( + mojom::WebClientHintsType::kUA)], + result.ToAtomicString()); + } + bool is_1p_origin = IsFirstPartyOrigin(request.Url()); if (!base::FeatureList::IsEnabled(kAllowClientHintsToThirdParty) && @@ -830,6 +861,30 @@ ->navigator() ->SerializeLanguagesForClientHintHeader()); } + + if (ShouldSendClientHint(mojom::WebClientHintsType::kUAArch, + hints_preferences, enabled_hints)) { + request.AddHTTPHeaderField( + blink::kClientHintsHeaderMapping[static_cast<size_t>( + mojom::WebClientHintsType::kUAArch)], + AtomicString(ua.architecture.data())); + } + + if (ShouldSendClientHint(mojom::WebClientHintsType::kUAPlatform, + hints_preferences, enabled_hints)) { + request.AddHTTPHeaderField( + blink::kClientHintsHeaderMapping[static_cast<size_t>( + mojom::WebClientHintsType::kUAPlatform)], + AtomicString(ua.platform.data())); + } + + if (ShouldSendClientHint(mojom::WebClientHintsType::kUAModel, + hints_preferences, enabled_hints)) { + request.AddHTTPHeaderField( + blink::kClientHintsHeaderMapping[static_cast<size_t>( + mojom::WebClientHintsType::kUAModel)], + AtomicString(ua.model.data())); + } } void FrameFetchContext::PopulateResourceRequest( @@ -1072,6 +1127,12 @@ return GetFrame()->Loader().UserAgent(); } +UserAgentMetadata FrameFetchContext::GetUserAgentMetadata() const { + if (GetResourceFetcherProperties().IsDetached()) + return frozen_state_->user_agent_metadata; + return GetLocalFrameClient()->UserAgentMetadata(); +} + const ClientHintsPreferences FrameFetchContext::GetClientHintsPreferences() const { if (GetResourceFetcherProperties().IsDetached()) @@ -1114,13 +1175,15 @@ frozen_state_ = MakeGarbageCollected<FrozenState>( Url(), GetParentSecurityOrigin(), GetContentSecurityPolicy(), GetSiteForCookies(), GetTopFrameOrigin(), GetClientHintsPreferences(), - GetDevicePixelRatio(), GetUserAgent(), IsSVGImageChromeClient()); + GetDevicePixelRatio(), GetUserAgent(), GetUserAgentMetadata(), + IsSVGImageChromeClient()); } else { // Some getters are unavailable in this case. frozen_state_ = MakeGarbageCollected<FrozenState>( NullURL(), GetParentSecurityOrigin(), GetContentSecurityPolicy(), GetSiteForCookies(), GetTopFrameOrigin(), GetClientHintsPreferences(), - GetDevicePixelRatio(), GetUserAgent(), IsSVGImageChromeClient()); + GetDevicePixelRatio(), GetUserAgent(), GetUserAgentMetadata(), + IsSVGImageChromeClient()); } frame_or_imported_document_ = nullptr;
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.h b/third_party/blink/renderer/core/loader/frame_fetch_context.h index b7563821..6f9d676 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context.h +++ b/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -60,6 +60,7 @@ class ResourceResponse; class Settings; class WebContentSettingsClient; +struct UserAgentMetadata; struct WebEnabledClientHints; class CORE_EXPORT FrameFetchContext final : public BaseFetchContext { @@ -204,6 +205,7 @@ WebContentSettingsClient* GetContentSettingsClient() const; Settings* GetSettings() const; String GetUserAgent() const; + UserAgentMetadata GetUserAgentMetadata() const; const ClientHintsPreferences GetClientHintsPreferences() const; float GetDevicePixelRatio() const; bool ShouldSendClientHint(mojom::WebClientHintsType,
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc index b2f9d7d..bb44e2e 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc +++ b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -643,6 +643,7 @@ bool is_present, const char* header_value, float width = 0) { + SCOPED_TRACE(testing::Message() << header_name); ClientHintsPreferences hints_preferences; FetchParameters::ResourceWidth resource_width; @@ -822,6 +823,69 @@ ExpectHeader("http://www.example.com/1.gif", "Sec-CH-Lang", false, ""); } +TEST_F(FrameFetchContextHintsTest, MonitorUAHints) { + // `Sec-CH-UA` is always sent for secure requests + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA", true, ""); + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA", false, ""); + + // `Sec-CH-UA-*` requires opt-in. + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Arch", false, ""); + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Arch", false, ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Platform", false, + ""); + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Platform", false, ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Model", false, ""); + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Model", false, ""); + + { + ClientHintsPreferences preferences; + preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kUAArch); + document->GetFrame()->GetClientHintsPreferences().UpdateFrom(preferences); + + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Arch", true, ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Platform", false, + ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Model", false, ""); + + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Arch", false, ""); + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Platform", false, + ""); + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Model", false, ""); + } + + { + ClientHintsPreferences preferences; + preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kUAPlatform); + document->GetFrame()->GetClientHintsPreferences().UpdateFrom(preferences); + + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Arch", false, ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Platform", true, + ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Model", false, ""); + + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Arch", false, ""); + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Platform", false, + ""); + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Model", false, ""); + } + + { + ClientHintsPreferences preferences; + preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kUAModel); + document->GetFrame()->GetClientHintsPreferences().UpdateFrom(preferences); + + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Arch", false, ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Platform", false, + ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Model", true, ""); + + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Arch", false, ""); + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Platform", false, + ""); + ExpectHeader("http://www.example.com/1.gif", "Sec-CH-UA-Model", false, ""); + } +} + TEST_F(FrameFetchContextHintsTest, MonitorAllHints) { ExpectHeader("https://www.example.com/1.gif", "Device-Memory", false, ""); ExpectHeader("https://www.example.com/1.gif", "DPR", false, ""); @@ -831,6 +895,13 @@ ExpectHeader("https://www.example.com/1.gif", "downlink", false, ""); ExpectHeader("https://www.example.com/1.gif", "ect", false, ""); ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", false, ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Arch", false, ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Platform", false, + ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Model", false, ""); + + // `Sec-CH-UA` is special. + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA", true, ""); ClientHintsPreferences preferences; preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kDeviceMemory); @@ -843,6 +914,10 @@ preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kDownlink); preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kEct); preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kLang); + preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kUA); + preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kUAArch); + preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kUAPlatform); + preferences.SetShouldSendForTesting(mojom::WebClientHintsType::kUAModel); ApproximatedDeviceMemory::SetPhysicalMemoryMBForTesting(4096); document->GetFrame()->GetClientHintsPreferences().UpdateFrom(preferences); ExpectHeader("https://www.example.com/1.gif", "Device-Memory", true, "4"); @@ -854,6 +929,11 @@ ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", true, "\"en\", \"de\", \"fr\""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA", true, ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Arch", true, ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Platform", true, ""); + ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Model", true, ""); + // Value of network quality client hints may vary, so only check if the // header is present and the values are non-negative/non-empty. bool conversion_ok = false;
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc b/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc index a8ff441..68c172e 100644 --- a/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc +++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc
@@ -4,9 +4,11 @@ #include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h" +#include "base/metrics/field_trial_params.h" #include "base/metrics/histogram_macros.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_recorder.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/inspector/console_message.h" @@ -14,6 +16,7 @@ #include "third_party/blink/renderer/core/loader/document_loader.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -48,16 +51,44 @@ subresource_patterns_to_block_usage_.assign( subresource_patterns_to_block.size(), false); blocked_resource_load_priority_counts_.fill(0); + + // Populate which specific resource types are eligible for blocking. + // Certain resource types are blocked by default since their blocking + // is currently verified by the server verification pipeline. Note that + // the blocking of these resource types can be overridden using field trial. + block_resource_type_[static_cast<int>(ResourceType::kCSSStyleSheet)] = true; + block_resource_type_[static_cast<int>(ResourceType::kScript)] = true; + block_resource_type_[static_cast<int>(ResourceType::kRaw)] = true; + for (int i = 0; i < static_cast<int>(ResourceType::kLast) + 1; ++i) { + // Parameter names are of format: "block_resource_type_%d". The value + // should be either "true" or "false". + block_resource_type_[i] = base::GetFieldTrialParamByFeatureAsBool( + features::kPreviewsResourceLoadingHintsSpecificResourceTypes, + String::Format("block_resource_type_%d", i).Ascii().data(), + block_resource_type_[i]); + } + + // Ensure that the ResourceType enums have not changed. These should not be + // changed since the resource type integer values are used as field trial + // params. + static_assert(static_cast<int>(ResourceType::kImage) == 1 && + static_cast<int>(ResourceType::kCSSStyleSheet) == 2 && + static_cast<int>(ResourceType::kScript) == 3, + "ResourceType enums can't be changed"); } PreviewsResourceLoadingHints::~PreviewsResourceLoadingHints() = default; bool PreviewsResourceLoadingHints::AllowLoad( + ResourceType type, const KURL& resource_url, ResourceLoadPriority resource_load_priority) const { if (!resource_url.ProtocolIsInHTTPFamily()) return true; + if (!block_resource_type_[static_cast<int>(type)]) + return true; + WTF::String resource_url_string = resource_url.GetString(); resource_url_string = resource_url_string.Left(resource_url.PathEnd()); bool allow_load = true;
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h b/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h index 2ad7cc2..db3febb 100644 --- a/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h +++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h
@@ -7,9 +7,11 @@ #include <vector> +#include "base/feature_list.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -38,9 +40,11 @@ const std::vector<WTF::String>& subresource_patterns_to_block); ~PreviewsResourceLoadingHints(); - // Returns true if load of resource with URL |resource_url| and priority - // |resource_load_priority| is allowed as per resource loading hints. - bool AllowLoad(const KURL& resource_url, + // Returns true if load of resource with type |type|, URL |resource_url| + // and priority |resource_load_priority| is allowed as per resource loading + // hints. + bool AllowLoad(ResourceType type, + const KURL& resource_url, ResourceLoadPriority resource_load_priority) const; virtual void Trace(blink::Visitor*); @@ -64,6 +68,10 @@ // be blocked. const std::vector<WTF::String> subresource_patterns_to_block_; + // True if resource blocking hints should apply to resource of a given type. + bool block_resource_type_[static_cast<int>(ResourceType::kLast) + 1] = { + false}; + // |subresource_patterns_to_block_usage_| records whether the pattern located // at the same index in |subresource_patterns_to_block_| was ever blocked. mutable std::vector<bool> subresource_patterns_to_block_usage_;
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc index 4d5a001a..03869ad 100644 --- a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc +++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc
@@ -8,15 +8,18 @@ #include <vector> #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "components/ukm/test_ukm_recorder.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_recorder.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/loader/frame_loader.h" #include "third_party/blink/renderer/core/testing/dummy_page_holder.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/platform/geometry/int_size.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h" #include "third_party/blink/renderer/platform/testing/url_test_helpers.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" @@ -42,7 +45,8 @@ PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create( dummy_page_holder_->GetDocument(), ukm::UkmRecorder::GetNewSourceID(), subresources_to_block); - EXPECT_TRUE(hints->AllowLoad(KURL("https://www.example.com/"), + EXPECT_TRUE(hints->AllowLoad(ResourceType::kScript, + KURL("https://www.example.com/"), ResourceLoadPriority::kHighest)); } @@ -72,16 +76,24 @@ for (const auto& test : tests) { base::HistogramTester histogram_tester; + // By default, resource blocking hints do not apply to images. + EXPECT_TRUE(hints->AllowLoad(ResourceType::kImage, test.url, + ResourceLoadPriority::kHighest)); + // By default, resource blocking hints apply to CSS and Scripts. EXPECT_EQ(test.allow_load_expected, - hints->AllowLoad(test.url, ResourceLoadPriority::kHighest)); + hints->AllowLoad(ResourceType::kCSSStyleSheet, test.url, + ResourceLoadPriority::kHighest)); + EXPECT_EQ(test.allow_load_expected, + hints->AllowLoad(ResourceType::kScript, test.url, + ResourceLoadPriority::kHighest)); histogram_tester.ExpectUniqueSample( "ResourceLoadingHints.ResourceLoadingBlocked", - !test.allow_load_expected, 1); + !test.allow_load_expected, 2); if (!test.allow_load_expected) { histogram_tester.ExpectUniqueSample( "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority." "Blocked", - ResourceLoadPriority::kHighest, 1); + ResourceLoadPriority::kHighest, 2); histogram_tester.ExpectTotalCount( "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority." "Allowed", @@ -94,7 +106,7 @@ histogram_tester.ExpectUniqueSample( "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority." "Allowed", - ResourceLoadPriority::kHighest, 1); + ResourceLoadPriority::kHighest, 2); } } } @@ -128,7 +140,8 @@ for (const auto& test : tests) { EXPECT_EQ(test.allow_load_expected, - hints->AllowLoad(test.url, ResourceLoadPriority::kHighest)); + hints->AllowLoad(ResourceType::kScript, test.url, + ResourceLoadPriority::kHighest)); } } @@ -158,7 +171,8 @@ for (const auto& test : tests) { base::HistogramTester histogram_tester; EXPECT_EQ(test.allow_load_expected, - hints->AllowLoad(test.url, test.resource_load_priority)); + hints->AllowLoad(ResourceType::kScript, test.url, + test.resource_load_priority)); histogram_tester.ExpectUniqueSample( "ResourceLoadingHints.ResourceLoadingBlocked", !test.allow_load_expected, 1); @@ -235,7 +249,7 @@ }; for (const auto& resource_to_load : resources_to_load) { - hints->AllowLoad(resource_to_load.url, + hints->AllowLoad(ResourceType::kScript, resource_to_load.url, resource_to_load.resource_load_priority); } @@ -262,6 +276,122 @@ entry, UkmEntry::kblocked_very_high_priorityName, 1); } +// Test class that overrides field trial so that resource blocking hints apply +// to images as well. +class PreviewsResourceLoadingHintsTestBlockImages + : public PreviewsResourceLoadingHintsTest { + public: + PreviewsResourceLoadingHintsTestBlockImages() = default; + + void SetUp() override { + std::map<std::string, std::string> feature_parameters; + feature_parameters["block_resource_type_1"] = "true"; + + scoped_feature_list_.InitAndEnableFeatureWithParameters( + blink::features::kPreviewsResourceLoadingHintsSpecificResourceTypes, + feature_parameters); + } + + protected: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +TEST_F(PreviewsResourceLoadingHintsTestBlockImages, + OnePatternWithResourceSubtype) { + std::vector<WTF::String> subresources_to_block; + subresources_to_block.push_back("foo.jpg"); + + PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create( + dummy_page_holder_->GetDocument(), ukm::UkmRecorder::GetNewSourceID(), + subresources_to_block); + + const struct { + KURL url; + bool allow_load_expected; + } tests[] = { + {KURL("https://www.example.com/"), true}, + {KURL("https://www.example.com/foo.js"), true}, + {KURL("https://www.example.com/foo.jpg"), false}, + {KURL("https://www.example.com/pages/foo.jpg"), false}, + {KURL("https://www.example.com/foobar.jpg"), true}, + {KURL("https://www.example.com/barfoo.jpg"), false}, + {KURL("http://www.example.com/foo.jpg"), false}, + {KURL("http://www.example.com/foo.jpg?q=alpha"), false}, + {KURL("http://www.example.com/bar.jpg?q=foo.jpg"), true}, + {KURL("http://www.example.com/bar.jpg?q=foo.jpg#foo.jpg"), true}, + }; + + for (const auto& test : tests) { + // By default, resource blocking hints do not apply to fonts. + EXPECT_TRUE(hints->AllowLoad(ResourceType::kFont, test.url, + ResourceLoadPriority::kHighest)); + // Feature override should cause resource blocking hints to apply to images. + EXPECT_EQ(test.allow_load_expected, + hints->AllowLoad(ResourceType::kImage, test.url, + ResourceLoadPriority::kHighest)); + EXPECT_EQ(test.allow_load_expected, + hints->AllowLoad(ResourceType::kScript, test.url, + ResourceLoadPriority::kHighest)); + } +} + +// Test class that overrides field trial so that resource blocking hints do not +// apply to CSS. +class PreviewsResourceLoadingHintsTestAllowCSS + : public PreviewsResourceLoadingHintsTestBlockImages { + public: + PreviewsResourceLoadingHintsTestAllowCSS() = default; + + void SetUp() override { + std::map<std::string, std::string> feature_parameters; + feature_parameters["block_resource_type_2"] = "false"; + + scoped_feature_list_.InitAndEnableFeatureWithParameters( + blink::features::kPreviewsResourceLoadingHintsSpecificResourceTypes, + feature_parameters); + } +}; + +TEST_F(PreviewsResourceLoadingHintsTestAllowCSS, + OnePatternWithResourceSubtype) { + std::vector<WTF::String> subresources_to_block; + subresources_to_block.push_back("foo.jpg"); + + PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create( + dummy_page_holder_->GetDocument(), ukm::UkmRecorder::GetNewSourceID(), + subresources_to_block); + + const struct { + KURL url; + bool allow_load_expected; + } tests[] = { + {KURL("https://www.example.com/"), true}, + {KURL("https://www.example.com/foo.js"), true}, + {KURL("https://www.example.com/foo.jpg"), false}, + {KURL("https://www.example.com/pages/foo.jpg"), false}, + {KURL("https://www.example.com/foobar.jpg"), true}, + {KURL("https://www.example.com/barfoo.jpg"), false}, + {KURL("http://www.example.com/foo.jpg"), false}, + {KURL("http://www.example.com/foo.jpg?q=alpha"), false}, + {KURL("http://www.example.com/bar.jpg?q=foo.jpg"), true}, + {KURL("http://www.example.com/bar.jpg?q=foo.jpg#foo.jpg"), true}, + }; + + for (const auto& test : tests) { + // Feature override should cause resource blocking hints to apply to only + // scripts. + EXPECT_TRUE(hints->AllowLoad(ResourceType::kFont, test.url, + ResourceLoadPriority::kHighest)); + EXPECT_TRUE(hints->AllowLoad(ResourceType::kImage, test.url, + ResourceLoadPriority::kHighest)); + EXPECT_TRUE(hints->AllowLoad(ResourceType::kCSSStyleSheet, test.url, + ResourceLoadPriority::kHighest)); + EXPECT_EQ(test.allow_load_expected, + hints->AllowLoad(ResourceType::kScript, test.url, + ResourceLoadPriority::kHighest)); + } +} + } // namespace } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc b/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc index 480d0344..0216216 100644 --- a/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc +++ b/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc
@@ -22,6 +22,10 @@ WebFeature::kClientHintsDownlink, WebFeature::kClientHintsEct, WebFeature::kClientHintsLang, + WebFeature::kClientHintsUA, + WebFeature::kClientHintsUAArch, + WebFeature::kClientHintsUAPlatform, + WebFeature::kClientHintsUAModel, }; static_assert(static_cast<int>(mojom::WebClientHintsType::kMaxValue) + 1 ==
diff --git a/third_party/blink/renderer/core/paint/object_painter_base.cc b/third_party/blink/renderer/core/paint/object_painter_base.cc index 929c97bc..78bfba6 100644 --- a/third_party/blink/renderer/core/paint/object_painter_base.cc +++ b/third_party/blink/renderer/core/paint/object_painter_base.cc
@@ -499,9 +499,10 @@ Color color = style.VisitedDependentColor(GetCSSPropertyOutlineColor()); if (style.OutlineStyleIsAuto()) { - paint_info.context.DrawFocusRing(pixel_snapped_outline_rects, - style.GetOutlineStrokeWidthForFocusRing(), - style.OutlineOffset(), color); + paint_info.context.DrawFocusRing( + pixel_snapped_outline_rects, style.GetOutlineStrokeWidthForFocusRing(), + style.OutlineOffset(), color, + LayoutTheme::GetTheme().IsFocusRingOutset()); return; }
diff --git a/third_party/blink/renderer/core/script/classic_script.cc b/third_party/blink/renderer/core/script/classic_script.cc index 82eba9b..67f6888d 100644 --- a/third_party/blink/renderer/core/script/classic_script.cc +++ b/third_party/blink/renderer/core/script/classic_script.cc
@@ -15,7 +15,7 @@ } void ClassicScript::RunScript(LocalFrame* frame, - const SecurityOrigin* security_origin) const { + const SecurityOrigin* security_origin) { frame->GetScriptController().ExecuteScriptInMainWorld( GetScriptSourceCode(), BaseURL(), sanitize_script_errors_, FetchOptions());
diff --git a/third_party/blink/renderer/core/script/classic_script.h b/third_party/blink/renderer/core/script/classic_script.h index 25e5e43..41f3ed1e 100644 --- a/third_party/blink/renderer/core/script/classic_script.h +++ b/third_party/blink/renderer/core/script/classic_script.h
@@ -42,7 +42,7 @@ mojom::ScriptType GetScriptType() const override { return mojom::ScriptType::kClassic; } - void RunScript(LocalFrame*, const SecurityOrigin*) const override; + void RunScript(LocalFrame*, const SecurityOrigin*) override; String InlineSourceTextForCSP() const override { return script_source_code_.Source().ToString(); }
diff --git a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc index 9e3e01c..0f3c85f 100644 --- a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc +++ b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
@@ -87,7 +87,7 @@ fetch_tree_was_called_ = true; } - ScriptValue ExecuteModule(const ModuleScript* module_script, + ScriptValue ExecuteModule(ModuleScript* module_script, CaptureEvalErrorFlag capture_error) final { EXPECT_EQ(CaptureEvalErrorFlag::kCapture, capture_error);
diff --git a/third_party/blink/renderer/core/script/modulator.h b/third_party/blink/renderer/core/script/modulator.h index 41f650a..2172280 100644 --- a/third_party/blink/renderer/core/script/modulator.h +++ b/third_party/blink/renderer/core/script/modulator.h
@@ -198,8 +198,7 @@ // and the caller should rethrow the returned exception. - When "rethrow // errors" is not to be set, use kReport. EvaluateModule() "report the error" // inside it (if any), and always returns null ScriptValue(). - virtual ScriptValue ExecuteModule(const ModuleScript*, - CaptureEvalErrorFlag) = 0; + virtual ScriptValue ExecuteModule(ModuleScript*, CaptureEvalErrorFlag) = 0; virtual ModuleScriptFetcher* CreateModuleScriptFetcher( ModuleScriptCustomFetchType) = 0;
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.cc b/third_party/blink/renderer/core/script/modulator_impl_base.cc index ad130f7..b49b7a9 100644 --- a/third_party/blink/renderer/core/script/modulator_impl_base.cc +++ b/third_party/blink/renderer/core/script/modulator_impl_base.cc
@@ -261,7 +261,7 @@ // <specdef href="https://html.spec.whatwg.org/C/#run-a-module-script"> ScriptValue ModulatorImplBase::ExecuteModule( - const ModuleScript* module_script, + ModuleScript* module_script, CaptureEvalErrorFlag capture_error) { // <spec step="1">If rethrow errors is not given, let it be false.</spec>
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.h b/third_party/blink/renderer/core/script/modulator_impl_base.h index fb4b174..8916dce 100644 --- a/third_party/blink/renderer/core/script/modulator_impl_base.h +++ b/third_party/blink/renderer/core/script/modulator_impl_base.h
@@ -80,7 +80,7 @@ ModuleImportMeta HostGetImportMetaProperties(ScriptModule) const override; ScriptValue InstantiateModule(ScriptModule) override; Vector<ModuleRequest> ModuleRequestsFromScriptModule(ScriptModule) override; - ScriptValue ExecuteModule(const ModuleScript*, CaptureEvalErrorFlag) override; + ScriptValue ExecuteModule(ModuleScript*, CaptureEvalErrorFlag) override; // Populates |reason| and returns true if the dynamic import is disallowed on // the associated execution context. In that case, a caller of this function
diff --git a/third_party/blink/renderer/core/script/module_script.cc b/third_party/blink/renderer/core/script/module_script.cc index 0c2d2fd9..da03e43 100644 --- a/third_party/blink/renderer/core/script/module_script.cc +++ b/third_party/blink/renderer/core/script/module_script.cc
@@ -226,7 +226,7 @@ Script::Trace(visitor); } -void ModuleScript::RunScript(LocalFrame* frame, const SecurityOrigin*) const { +void ModuleScript::RunScript(LocalFrame* frame, const SecurityOrigin*) { DVLOG(1) << *this << "::RunScript()"; settings_object_->ExecuteModule(this, Modulator::CaptureEvalErrorFlag::kReport);
diff --git a/third_party/blink/renderer/core/script/module_script.h b/third_party/blink/renderer/core/script/module_script.h index 305035f..473de68aa 100644 --- a/third_party/blink/renderer/core/script/module_script.h +++ b/third_party/blink/renderer/core/script/module_script.h
@@ -89,7 +89,7 @@ mojom::ScriptType GetScriptType() const override { return mojom::ScriptType::kModule; } - void RunScript(LocalFrame*, const SecurityOrigin*) const override; + void RunScript(LocalFrame*, const SecurityOrigin*) override; String InlineSourceTextForCSP() const override; friend class ModulatorImplBase;
diff --git a/third_party/blink/renderer/core/script/script.h b/third_party/blink/renderer/core/script/script.h index 70e4aff..0e5e9cf0 100644 --- a/third_party/blink/renderer/core/script/script.h +++ b/third_party/blink/renderer/core/script/script.h
@@ -30,7 +30,7 @@ // or // https://html.spec.whatwg.org/C/#run-a-module-script, // depending on the script type. - virtual void RunScript(LocalFrame*, const SecurityOrigin*) const = 0; + virtual void RunScript(LocalFrame*, const SecurityOrigin*) = 0; // For CSP check for inline scripts. virtual String InlineSourceTextForCSP() const = 0;
diff --git a/third_party/blink/renderer/core/script/script_runner.cc b/third_party/blink/renderer/core/script/script_runner.cc index 95d55e5..9c50f4c 100644 --- a/third_party/blink/renderer/core/script/script_runner.cc +++ b/third_party/blink/renderer/core/script/script_runner.cc
@@ -32,6 +32,7 @@ #include "third_party/blink/renderer/core/script/script_loader.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h" #include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h" @@ -235,6 +236,12 @@ } void ScriptRunner::ExecuteTask() { + // This method is triggered by ScriptRunner::PostTask, and runs directly from + // the scheduler. So, the call stack is safe to reenter. + scheduler::CooperativeSchedulingManager::WhitelistedStackScope + whitelisted_stack_scope( + scheduler::CooperativeSchedulingManager::Instance()); + if (is_suspended_) return;
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index 44f00c3..b93f8a6 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -2069,7 +2069,8 @@ return 0; if (OutlineStyleIsAuto()) { return GraphicsContext::FocusRingOutsetExtent( - OutlineOffset(), std::ceil(GetOutlineStrokeWidthForFocusRing())); + OutlineOffset(), std::ceil(GetOutlineStrokeWidthForFocusRing()), + LayoutTheme::GetTheme().IsFocusRingOutset()); } return ClampAdd(OutlineWidth(), OutlineOffset()).Max(0); } @@ -2079,8 +2080,9 @@ return OutlineWidth(); #else // Draw an outline with thickness in proportion to the zoom level, but never - // less than 1 pixel so that it remains visible. - return std::max(EffectiveZoom(), 1.f); + // so narrow that it becomes invisible. + return std::max(EffectiveZoom(), + LayoutTheme::GetTheme().MinimumStrokeWidthForFocusRing()); #endif }
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc index 32bf625..b3060da 100644 --- a/third_party/blink/renderer/core/style/computed_style_test.cc +++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -77,6 +77,26 @@ #endif } +TEST(ComputedStyleTest, FocusRingCustomizedOutset) { + float old_minimum_stroke_width_for_focus_ring = + LayoutTheme::GetTheme().MinimumStrokeWidthForFocusRing(); + bool old_is_focus_ring_outset = LayoutTheme::GetTheme().IsFocusRingOutset(); + LayoutTheme::GetTheme().SetMinimumStrokeWidthForFocusRing(4.0); + LayoutTheme::GetTheme().SetIsFocusRingOutset(true); + scoped_refptr<ComputedStyle> style = ComputedStyle::Create(); + style->SetOutlineStyle(EBorderStyle::kSolid); + style->SetOutlineStyleIsAuto(static_cast<bool>(OutlineIsAuto::kOn)); + style->SetEffectiveZoom(4.75); +#if defined(OS_MACOSX) + EXPECT_EQ(4, style->OutlineOutsetExtent()); +#else + EXPECT_EQ(5, style->OutlineOutsetExtent()); +#endif + LayoutTheme::GetTheme().SetMinimumStrokeWidthForFocusRing( + old_minimum_stroke_width_for_focus_ring); + LayoutTheme::GetTheme().SetIsFocusRingOutset(old_is_focus_ring_outset); +} + TEST(ComputedStyleTest, SVGStackingContext) { scoped_refptr<ComputedStyle> style = ComputedStyle::Create(); style->UpdateIsStackingContext(false, false, true);
diff --git a/third_party/blink/renderer/core/style/style_reflection.h b/third_party/blink/renderer/core/style/style_reflection.h index 68dcb1c..d2db3af6 100644 --- a/third_party/blink/renderer/core/style/style_reflection.h +++ b/third_party/blink/renderer/core/style/style_reflection.h
@@ -55,7 +55,7 @@ private: StyleReflection() : direction_(kReflectionBelow), - offset_(0, kFixed), + offset_(Length::Fixed(0)), mask_(NinePieceImage::MaskDefaults()) {} CSSReflectionDirection direction_;
diff --git a/third_party/blink/renderer/core/testing/dummy_modulator.cc b/third_party/blink/renderer/core/testing/dummy_modulator.cc index dce4fe1..1a9b6eb 100644 --- a/third_party/blink/renderer/core/testing/dummy_modulator.cc +++ b/third_party/blink/renderer/core/testing/dummy_modulator.cc
@@ -140,8 +140,7 @@ return Vector<ModuleRequest>(); } -ScriptValue DummyModulator::ExecuteModule(const ModuleScript*, - CaptureEvalErrorFlag) { +ScriptValue DummyModulator::ExecuteModule(ModuleScript*, CaptureEvalErrorFlag) { NOTREACHED(); return ScriptValue(); }
diff --git a/third_party/blink/renderer/core/testing/dummy_modulator.h b/third_party/blink/renderer/core/testing/dummy_modulator.h index 2f4a0bd..63d30fe 100644 --- a/third_party/blink/renderer/core/testing/dummy_modulator.h +++ b/third_party/blink/renderer/core/testing/dummy_modulator.h
@@ -62,7 +62,7 @@ ModuleImportMeta HostGetImportMetaProperties(ScriptModule) const override; ScriptValue InstantiateModule(ScriptModule) override; Vector<ModuleRequest> ModuleRequestsFromScriptModule(ScriptModule) override; - ScriptValue ExecuteModule(const ModuleScript*, CaptureEvalErrorFlag) override; + ScriptValue ExecuteModule(ModuleScript*, CaptureEvalErrorFlag) override; ModuleScriptFetcher* CreateModuleScriptFetcher( ModuleScriptCustomFetchType) override;
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc index b38b302..992d12c 100644 --- a/third_party/blink/renderer/core/testing/internals.cc +++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -33,8 +33,6 @@ #include "base/optional.h" #include "cc/layers/picture_layer.h" #include "gpu/command_buffer/client/gles2_interface.h" -#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h" -#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h" #include "third_party/blink/renderer/bindings/core/v8/script_function.h" @@ -100,6 +98,7 @@ #include "third_party/blink/renderer/core/html/html_image_element.h" #include "third_party/blink/renderer/core/html/media/html_media_element.h" #include "third_party/blink/renderer/core/html/media/html_video_element.h" +#include "third_party/blink/renderer/core/html/media/remote_playback_controller.h" #include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h" #include "third_party/blink/renderer/core/html_names.h" #include "third_party/blink/renderer/core/input/event_handler.h" @@ -2500,20 +2499,18 @@ HTMLMediaElement* media_element, bool available) { DCHECK(media_element); - DCHECK(media_element->remote_playback_client_); - media_element->remote_playback_client_->AvailabilityChanged( - available ? WebRemotePlaybackAvailability::kDeviceAvailable - : WebRemotePlaybackAvailability::kDeviceNotAvailable); + + RemotePlaybackController::From(*media_element) + ->AvailabilityChangedForTesting(available); } void Internals::mediaPlayerPlayingRemotelyChanged( HTMLMediaElement* media_element, bool remote) { DCHECK(media_element); - if (remote) - media_element->ConnectedToRemoteDevice(); - else - media_element->DisconnectedFromRemoteDevice(); + + RemotePlaybackController::From(*media_element) + ->StateChangedForTesting(remote); } void Internals::setPersistent(HTMLVideoElement* video_element,
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.cc b/third_party/blink/renderer/core/workers/dedicated_worker.cc index be9ba2f..1c98d4a 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker.cc +++ b/third_party/blink/renderer/core/workers/dedicated_worker.cc
@@ -154,7 +154,9 @@ script_request_url_(script_request_url), options_(options), context_proxy_( - MakeGarbageCollected<DedicatedWorkerMessagingProxy>(context, this)) { + MakeGarbageCollected<DedicatedWorkerMessagingProxy>(context, this)), + v8_stack_trace_id_(ThreadDebugger::From(context->GetIsolate()) + ->StoreCurrentStackTrace("Worker Created")) { DCHECK(context->IsContextThread()); DCHECK(script_request_url_.IsValid()); DCHECK(context_proxy_); @@ -213,10 +215,6 @@ void DedicatedWorker::Start() { DCHECK(GetExecutionContext()->IsContextThread()); - v8_inspector::V8StackTraceId stack_id = - ThreadDebugger::From(GetExecutionContext()->GetIsolate()) - ->StoreCurrentStackTrace("Worker Created"); - if (auto* scope = DynamicTo<WorkerGlobalScope>(*GetExecutionContext())) scope->EnsureFetcher(); if (blink::features::IsPlzDedicatedWorkerEnabled()) { @@ -243,18 +241,9 @@ options_->type() == "module") { // Specify empty source code here because scripts will be fetched on the // worker thread. - auto* outside_settings_object = - MakeGarbageCollected<FetchClientSettingsObjectSnapshot>( - GetExecutionContext() - ->Fetcher() - ->GetProperties() - .GetFetchClientSettingsObject()); - context_proxy_->StartWorkerGlobalScope( - CreateGlobalScopeCreationParams( - script_request_url_, OffMainThreadWorkerScriptFetchOption::kEnabled, - network::mojom::ReferrerPolicy::kDefault), - options_, script_request_url_, *outside_settings_object, stack_id, - String() /* source_code */); + ContinueStart( + script_request_url_, OffMainThreadWorkerScriptFetchOption::kEnabled, + network::mojom::ReferrerPolicy::kDefault, String() /* source_code */); return; } if (options_->type() == "classic") { @@ -269,8 +258,7 @@ network::mojom::FetchCredentialsMode::kSameOrigin, GetExecutionContext()->GetSecurityContext().AddressSpace(), WTF::Bind(&DedicatedWorker::OnResponse, WrapPersistent(this)), - WTF::Bind(&DedicatedWorker::OnFinished, WrapPersistent(this), - stack_id)); + WTF::Bind(&DedicatedWorker::OnFinished, WrapPersistent(this))); return; } NOTREACHED() << "Invalid type: " << options_->type(); @@ -329,7 +317,11 @@ void DedicatedWorker::OnScriptLoaded() { DCHECK(features::IsPlzDedicatedWorkerEnabled()); - // TODO(nhiroki): Continue worker start. + // Specify empty source code here because scripts will be fetched on the + // worker thread. + ContinueStart( + script_request_url_, OffMainThreadWorkerScriptFetchOption::kEnabled, + network::mojom::ReferrerPolicy::kDefault, String() /* source_code */); } void DedicatedWorker::OnScriptLoadFailed() { @@ -377,7 +369,7 @@ classic_script_loader_->Identifier()); } -void DedicatedWorker::OnFinished(const v8_inspector::V8StackTraceId& stack_id) { +void DedicatedWorker::OnFinished() { DCHECK(GetExecutionContext()->IsContextThread()); if (classic_script_loader_->Canceled()) { // Do nothing. @@ -398,18 +390,9 @@ DCHECK(script_request_url_ == script_response_url || SecurityOrigin::AreSameSchemeHostPort(script_request_url_, script_response_url)); - auto* outside_settings_object = - MakeGarbageCollected<FetchClientSettingsObjectSnapshot>( - GetExecutionContext() - ->Fetcher() - ->GetProperties() - .GetFetchClientSettingsObject()); - context_proxy_->StartWorkerGlobalScope( - CreateGlobalScopeCreationParams( - script_response_url, - OffMainThreadWorkerScriptFetchOption::kDisabled, referrer_policy), - options_, script_response_url, *outside_settings_object, stack_id, - classic_script_loader_->SourceText()); + ContinueStart(script_response_url, + OffMainThreadWorkerScriptFetchOption::kDisabled, + referrer_policy, classic_script_loader_->SourceText()); probe::scriptImported(GetExecutionContext(), classic_script_loader_->Identifier(), classic_script_loader_->SourceText()); @@ -417,6 +400,24 @@ classic_script_loader_ = nullptr; } +void DedicatedWorker::ContinueStart( + const KURL& script_url, + OffMainThreadWorkerScriptFetchOption off_main_thread_fetch_option, + network::mojom::ReferrerPolicy referrer_policy, + const String& source_code) { + auto* outside_settings_object = + MakeGarbageCollected<FetchClientSettingsObjectSnapshot>( + GetExecutionContext() + ->Fetcher() + ->GetProperties() + .GetFetchClientSettingsObject()); + context_proxy_->StartWorkerGlobalScope( + CreateGlobalScopeCreationParams(script_url, off_main_thread_fetch_option, + referrer_policy), + options_, script_url, *outside_settings_object, v8_stack_trace_id_, + source_code); +} + std::unique_ptr<GlobalScopeCreationParams> DedicatedWorker::CreateGlobalScopeCreationParams( const KURL& script_url, @@ -440,6 +441,8 @@ ? mojom::ScriptType::kClassic : mojom::ScriptType::kModule; + // TODO(nhiroki): Create WebWorkerFetchContext using |factory_client_| when + // PlzDedicatedWorker is enabled (https://crbug.com/906991). scoped_refptr<WebWorkerFetchContext> web_worker_fetch_context; if (auto* document = DynamicTo<Document>(GetExecutionContext())) { LocalFrame* frame = document->GetFrame();
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.h b/third_party/blink/renderer/core/workers/dedicated_worker.h index 90e9745..e087647a 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker.h +++ b/third_party/blink/renderer/core/workers/dedicated_worker.h
@@ -20,10 +20,7 @@ #include "third_party/blink/renderer/platform/graphics/begin_frame_provider.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/forward.h" - -namespace v8_inspector { -struct V8StackTraceId; -} // namespace v8_inspector +#include "v8/include/v8-inspector.h" namespace blink { @@ -42,6 +39,30 @@ // called DedicatedWorker. This lives on the thread that created the worker (the // thread that called `new Worker()`), i.e., the main thread if a document // created the worker or a worker thread in the case of nested workers. +// +// We have been rearchitecting the worker startup sequence, and now there are +// 3 paths as follows. The path is chosen based on runtime flags: +// +// A) Legacy on-the-main-thread worker script loading (default) +// - DedicatedWorker::Start() +// - (Async script loading on the main thread) +// - DedicatedWorker::OnFinished() +// - DedicatedWorker::ContinueStart() +// +// B) Off-the-main-thread worker script loading +// (kOffMainThreadDedicatedWorkerScriptFetch) +// - DedicatedWorker::Start() +// - DedicatedWorker::ContinueStart() +// - (Async script loading on the worker thread) +// +// C) Off-the-main-thread worker script loading w/ PlzDedicatedWorker +// (kOffMainThreadDedicatedWorkerScriptFetch + kPlzDedicatedWorker + +// kNetworkService) +// - DedicatedWorker::Start() +// - (Start script loading in the browser) +// - DedicatedWorker::OnScriptLoaded() +// - DedicatedWorker::ContinueStart() +// - (Async script loading on the worker thread) class CORE_EXPORT DedicatedWorker final : public AbstractWorker, public ActiveScriptWrappable<DedicatedWorker>, @@ -100,7 +121,10 @@ private: // Starts the worker. void Start(); - + void ContinueStart(const KURL& script_url, + OffMainThreadWorkerScriptFetchOption, + network::mojom::ReferrerPolicy, + const String& source_code); std::unique_ptr<GlobalScopeCreationParams> CreateGlobalScopeCreationParams( const KURL& script_url, OffMainThreadWorkerScriptFetchOption, @@ -110,7 +134,7 @@ // Callbacks for |classic_script_loader_|. void OnResponse(); - void OnFinished(const v8_inspector::V8StackTraceId&); + void OnFinished(); // Implements EventTarget (via AbstractWorker -> EventTargetWithInlineData). const AtomicString& InterfaceName() const final; @@ -124,6 +148,9 @@ // Used only when PlzDedicatedWorker is enabled. std::unique_ptr<WebDedicatedWorkerHostFactoryClient> factory_client_; + // Used for tracking cross-debugger calls. + const v8_inspector::V8StackTraceId v8_stack_trace_id_; + service_manager::mojom::blink::InterfaceProviderPtrInfo interface_provider_; };
diff --git a/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc b/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc index eab1ce52..08633f82 100644 --- a/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc +++ b/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc
@@ -63,9 +63,11 @@ } SharedWorkerClientHolder::SharedWorkerClientHolder(Document& document) - : ContextLifecycleObserver(&document) { + : ContextLifecycleObserver(&document), + task_runner_(document.GetTaskRunner(blink::TaskType::kDOMManipulation)) { DCHECK(IsMainThread()); - document.GetInterfaceProvider()->GetInterface(mojo::MakeRequest(&connector_)); + document.GetInterfaceProvider()->GetInterface( + mojo::MakeRequest(&connector_, task_runner_)); } void SharedWorkerClientHolder::Connect( @@ -97,7 +99,8 @@ mojom::blink::SharedWorkerClientPtr client_ptr; client_set_.AddBinding(std::make_unique<SharedWorkerClient>(worker), - mojo::MakeRequest(&client_ptr)); + mojo::MakeRequest(&client_ptr, task_runner_), + task_runner_); connector_->Connect( std::move(info), std::move(client_ptr),
diff --git a/third_party/blink/renderer/core/workers/shared_worker_client_holder.h b/third_party/blink/renderer/core/workers/shared_worker_client_holder.h index 02c177e..fd17d0b 100644 --- a/third_party/blink/renderer/core/workers/shared_worker_client_holder.h +++ b/third_party/blink/renderer/core/workers/shared_worker_client_holder.h
@@ -87,6 +87,8 @@ mojom::blink::SharedWorkerConnectorPtr connector_; mojo::StrongBindingSet<mojom::blink::SharedWorkerClient> client_set_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + DISALLOW_COPY_AND_ASSIGN(SharedWorkerClientHolder); };
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc index f6d7045..0f6800d 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
@@ -9,7 +9,6 @@ #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h" #include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h" #include "third_party/blink/public/platform/web_mouse_event.h" #include "third_party/blink/public/platform/web_screen_info.h" @@ -227,8 +226,8 @@ } void SimulateRouteAvailable() { - media_controls_->MediaElement().RemoteRouteAvailabilityChanged( - WebRemotePlaybackAvailability::kDeviceAvailable); + RemotePlayback::From(media_controls_->MediaElement()) + .AvailabilityChangedForTesting(/* screen_is_available */ true); } void EnsureSizing() {
diff --git a/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc b/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc index 1c2521ca..5c8f34a 100644 --- a/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc +++ b/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
@@ -86,10 +86,8 @@ RemotePlayback::RemotePlayback(HTMLMediaElement& element) : ContextLifecycleObserver(element.GetExecutionContext()), RemotePlaybackController(element), - state_(element.IsPlayingRemotely() - ? WebRemotePlaybackState::kConnected - : WebRemotePlaybackState::kDisconnected), - availability_(WebRemotePlaybackAvailability::kUnknown), + state_(WebRemotePlaybackState::kDisconnected), + availability_(mojom::ScreenAvailability::UNKNOWN), media_element_(&element), is_listening_(false), presentation_connection_binding_(this) {} @@ -212,13 +210,13 @@ return promise; } - if (availability_ == WebRemotePlaybackAvailability::kDeviceNotAvailable) { + if (availability_ == mojom::ScreenAvailability::UNAVAILABLE) { resolver->Reject(DOMException::Create(DOMExceptionCode::kNotFoundError, "No remote playback devices found.")); return promise; } - if (availability_ == WebRemotePlaybackAvailability::kSourceNotCompatible) { + if (availability_ == mojom::ScreenAvailability::SOURCE_NOT_SUPPORTED) { resolver->Reject(DOMException::Create( DOMExceptionCode::kNotSupportedError, "The currentSrc is not compatible with remote playback")); @@ -380,24 +378,6 @@ observer->OnRemotePlaybackStateChanged(state_); } -void RemotePlayback::AvailabilityChanged( - WebRemotePlaybackAvailability availability) { - if (availability_ == availability) - return; - - bool old_availability = RemotePlaybackAvailable(); - availability_ = availability; - bool new_availability = RemotePlaybackAvailable(); - if (new_availability == old_availability) - return; - - for (auto& callback : availability_callbacks_.Values()) - callback->Run(this, new_availability); - - for (auto observer : observers_) - observer->OnRemotePlaybackAvailabilityChanged(availability_); -} - void RemotePlayback::PromptCancelled() { if (!prompt_promise_resolver_) return; @@ -442,6 +422,19 @@ observers_.erase(observer); } +void RemotePlayback::AvailabilityChangedForTesting(bool screen_is_available) { + // AvailabilityChanged() is only normally called when |is_listening_| is true. + is_listening_ = true; + AvailabilityChanged(screen_is_available + ? mojom::blink::ScreenAvailability::AVAILABLE + : mojom::blink::ScreenAvailability::UNAVAILABLE); +} + +void RemotePlayback::StateChangedForTesting(bool is_connected) { + StateChanged(is_connected ? WebRemotePlaybackState::kConnected + : WebRemotePlaybackState::kDisconnected); +} + bool RemotePlayback::RemotePlaybackAvailable() const { if (IsBackgroundAvailabilityMonitoringDisabled() && RuntimeEnabledFeatures::RemotePlaybackBackendEnabled() && @@ -449,7 +442,7 @@ return true; } - return availability_ == WebRemotePlaybackAvailability::kDeviceAvailable; + return availability_ == mojom::ScreenAvailability::AVAILABLE; } void RemotePlayback::RemotePlaybackDisabled() { @@ -481,31 +474,20 @@ void RemotePlayback::AvailabilityChanged( mojom::blink::ScreenAvailability availability) { DCHECK(is_listening_); + DCHECK_NE(availability, mojom::ScreenAvailability::UNKNOWN); + DCHECK_NE(availability, mojom::ScreenAvailability::DISABLED); - // TODO(avayvod): Use mojom::ScreenAvailability directly once - // WebRemotePlaybackAvailability is gone with the old pipeline. - WebRemotePlaybackAvailability remote_playback_availability = - WebRemotePlaybackAvailability::kUnknown; - switch (availability) { - case mojom::ScreenAvailability::UNKNOWN: - case mojom::ScreenAvailability::DISABLED: - NOTREACHED(); - remote_playback_availability = WebRemotePlaybackAvailability::kUnknown; - break; - case mojom::ScreenAvailability::UNAVAILABLE: - remote_playback_availability = - WebRemotePlaybackAvailability::kDeviceNotAvailable; - break; - case mojom::ScreenAvailability::SOURCE_NOT_SUPPORTED: - remote_playback_availability = - WebRemotePlaybackAvailability::kSourceNotCompatible; - break; - case mojom::ScreenAvailability::AVAILABLE: - remote_playback_availability = - WebRemotePlaybackAvailability::kDeviceAvailable; - break; - } - AvailabilityChanged(remote_playback_availability); + if (availability_ == availability) + return; + + bool old_availability = RemotePlaybackAvailable(); + availability_ = availability; + bool new_availability = RemotePlaybackAvailable(); + if (new_availability == old_availability) + return; + + for (auto& callback : availability_callbacks_.Values()) + callback->Run(this, new_availability); } const Vector<KURL>& RemotePlayback::Urls() const { @@ -581,7 +563,7 @@ if (!is_listening_) return; - availability_ = WebRemotePlaybackAvailability::kUnknown; + availability_ = mojom::ScreenAvailability::UNKNOWN; PresentationController* controller = PresentationController::FromContext(GetExecutionContext()); if (!controller)
diff --git a/third_party/blink/renderer/modules/remoteplayback/remote_playback.h b/third_party/blink/renderer/modules/remoteplayback/remote_playback.h index c483c4ee..6fbf600 100644 --- a/third_party/blink/renderer/modules/remoteplayback/remote_playback.h +++ b/third_party/blink/renderer/modules/remoteplayback/remote_playback.h
@@ -7,7 +7,6 @@ #include "mojo/public/cpp/bindings/binding.h" #include "third_party/blink/public/mojom/presentation/presentation.mojom-blink.h" -#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h" #include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h" #include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_state.h" #include "third_party/blink/public/platform/web_callbacks.h" @@ -116,9 +115,6 @@ void DidClose(mojom::blink::PresentationConnectionCloseReason) override; // WebRemotePlaybackClient implementation. - void StateChanged(WebRemotePlaybackState) override; - void AvailabilityChanged(WebRemotePlaybackAvailability) override; - void PromptCancelled() override; bool RemotePlaybackAvailable() const override; void SourceChanged(const WebURL&, bool is_source_supported) override; WebString GetPresentationId() override; @@ -126,6 +122,8 @@ // RemotePlaybackController implementation. void AddObserver(RemotePlaybackObserver*) override; void RemoveObserver(RemotePlaybackObserver*) override; + void AvailabilityChangedForTesting(bool screen_is_available) override; + void StateChangedForTesting(bool is_connected) override; // ScriptWrappable implementation. bool HasPendingActivity() const final; @@ -133,6 +131,9 @@ // ContextLifecycleObserver implementation. void ContextDestroyed(ExecutionContext*) override; + // Adjusts the internal state of |this| after a playback state change. + void StateChanged(WebRemotePlaybackState); + DEFINE_ATTRIBUTE_EVENT_LISTENER(connecting, kConnecting) DEFINE_ATTRIBUTE_EVENT_LISTENER(connect, kConnect) DEFINE_ATTRIBUTE_EVENT_LISTENER(disconnect, kDisconnect) @@ -144,6 +145,8 @@ friend class RemotePlaybackTest; friend class MediaControlsImplTest; + void PromptCancelled(); + // Calls the specified availability callback with the current availability. // Need a void() method to post it as a task. void NotifyInitialAvailability(int callback_id); @@ -161,7 +164,7 @@ void CleanupConnections(); WebRemotePlaybackState state_; - WebRemotePlaybackAvailability availability_; + mojom::blink::ScreenAvailability availability_; HeapHashMap<int, TraceWrapperMember<AvailabilityCallbackWrapper>> availability_callbacks_; Member<HTMLMediaElement> media_element_;
diff --git a/third_party/blink/renderer/platform/geometry/length.h b/third_party/blink/renderer/platform/geometry/length.h index 56c9073..0ed49fed 100644 --- a/third_party/blink/renderer/platform/geometry/length.h +++ b/third_party/blink/renderer/platform/geometry/length.h
@@ -185,34 +185,6 @@ void SetQuirk(bool quirk) { quirk_ = quirk; } - void SetValue(LengthType t, int value) { - type_ = t; - int_value_ = value; - is_float_ = false; - } - - void SetValue(int value) { - if (IsCalculated()) { - NOTREACHED(); - return; - } - SetValue(kFixed, value); - } - - void SetValue(LengthType t, float value) { - type_ = t; - float_value_ = value; - is_float_ = true; - } - - void SetValue(LengthType t, LayoutUnit value) { - type_ = t; - float_value_ = value.ToFloat(); - is_float_ = true; - } - - void SetValue(float value) { *this = Length::Fixed(value); } - bool IsMaxSizeNone() const { return GetType() == kMaxSizeNone; } // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc index 30a2c99..8a3a86db 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_context.cc +++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -391,21 +391,25 @@ namespace { -int AdjustedFocusRingOffset(int offset) { +int AdjustedFocusRingOffset(int offset, int width, bool is_outset) { #if defined(OS_MACOSX) return offset + 2; #else + if (is_outset) + return offset + width - (width + 1) / 2; return 0; #endif } } // namespace -int GraphicsContext::FocusRingOutsetExtent(int offset, int width) { +int GraphicsContext::FocusRingOutsetExtent(int offset, + int width, + bool is_outset) { // Unlike normal outlines (whole width is outside of the offset), focus - // rings are drawn with the center of the path aligned with the offset, so + // rings can be drawn with the center of the path aligned with the offset, so // only half of the width is outside of the offset. - return AdjustedFocusRingOffset(offset) + (width + 1) / 2; + return AdjustedFocusRingOffset(offset, width, is_outset) + (width + 1) / 2; } void GraphicsContext::DrawFocusRingPath(const SkPath& path, @@ -436,7 +440,8 @@ void GraphicsContext::DrawFocusRing(const Vector<IntRect>& rects, float width, int offset, - const Color& color) { + const Color& color, + bool is_outset) { if (ContextDisabled()) return; @@ -445,7 +450,7 @@ return; SkRegion focus_ring_region; - offset = AdjustedFocusRingOffset(offset); + offset = AdjustedFocusRingOffset(offset, std::ceil(width), is_outset); for (unsigned i = 0; i < rect_count; i++) { SkIRect r = rects[i]; if (r.isEmpty())
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.h b/third_party/blink/renderer/platform/graphics/graphics_context.h index af3b81cb..c489eb3 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_context.h +++ b/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -328,7 +328,8 @@ void DrawFocusRing(const Vector<IntRect>&, float width, int offset, - const Color&); + const Color&, + bool is_outset); void DrawFocusRing(const Path&, float width, int offset, const Color&); enum Edge { @@ -384,7 +385,7 @@ FloatPoint& p2, float stroke_width); - static int FocusRingOutsetExtent(int offset, int width); + static int FocusRingOutsetExtent(int offset, int width, bool is_outset); void SetInDrawingRecorder(bool); bool InDrawingRecorder() const { return in_drawing_recorder_; }
diff --git a/third_party/blink/renderer/platform/loader/BUILD.gn b/third_party/blink/renderer/platform/loader/BUILD.gn index 92c75f14..4da8750 100644 --- a/third_party/blink/renderer/platform/loader/BUILD.gn +++ b/third_party/blink/renderer/platform/loader/BUILD.gn
@@ -92,6 +92,8 @@ "fetch/script_cached_metadata_handler.h", "fetch/script_fetch_options.cc", "fetch/script_fetch_options.h", + "fetch/shared_buffer_bytes_consumer.cc", + "fetch/shared_buffer_bytes_consumer.h", "fetch/source_keyed_cached_metadata_handler.cc", "fetch/source_keyed_cached_metadata_handler.h", "fetch/stale_revalidation_resource_client.cc", @@ -147,6 +149,7 @@ "fetch/resource_response_test.cc", "fetch/resource_test.cc", "fetch/response_body_loader_test.cc", + "fetch/shared_buffer_bytes_consumer_test.cc", "fetch/source_keyed_cached_metadata_handler_test.cc", "ftp_directory_listing_test.cc", "link_header_test.cc",
diff --git a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc index d9f21543..b05491fe 100644 --- a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc +++ b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc
@@ -48,6 +48,26 @@ mojom::WebClientHintsType::kLang, enabled_hints.IsEnabled(mojom::WebClientHintsType::kLang) && RuntimeEnabledFeatures::LangClientHintHeaderEnabled()); + + enabled_hints.SetIsEnabled( + mojom::WebClientHintsType::kUA, + enabled_hints.IsEnabled(mojom::WebClientHintsType::kUA) && + RuntimeEnabledFeatures::UserAgentClientHintEnabled()); + + enabled_hints.SetIsEnabled( + mojom::WebClientHintsType::kUAArch, + enabled_hints.IsEnabled(mojom::WebClientHintsType::kUAArch) && + RuntimeEnabledFeatures::UserAgentClientHintEnabled()); + + enabled_hints.SetIsEnabled( + mojom::WebClientHintsType::kUAPlatform, + enabled_hints.IsEnabled(mojom::WebClientHintsType::kUAPlatform) && + RuntimeEnabledFeatures::UserAgentClientHintEnabled()); + + enabled_hints.SetIsEnabled( + mojom::WebClientHintsType::kUAModel, + enabled_hints.IsEnabled(mojom::WebClientHintsType::kUAModel) && + RuntimeEnabledFeatures::UserAgentClientHintEnabled()); } } // namespace
diff --git a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc index dea2544..fcf6551 100644 --- a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc
@@ -25,22 +25,39 @@ bool expectation_downlink; bool expectation_ect; bool expectation_lang; + bool expectation_ua; + bool expectation_ua_arch; + bool expectation_ua_platform; + bool expectation_ua_model; } cases[] = { {"width, dpr, viewportWidth", true, true, false, false, false, false, - false}, + false, false, false, false, false}, {"WiDtH, dPr, viewport-width, rtt, downlink, ect, lang", true, true, true, - true, true, true, true}, + true, true, true, true, false, false, false, false}, {"WiDtH, dPr, viewport-width, rtt, downlink, effective-connection-type", - true, true, true, true, true, false, false}, + true, true, true, true, true, false, false, false, false, false, false}, {"WIDTH, DPR, VIWEPROT-Width", true, true, false, false, false, false, - false}, + false, false, false, false, false}, {"VIewporT-Width, wutwut, width", true, false, true, false, false, false, - false}, - {"dprw", false, false, false, false, false, false, false}, - {"DPRW", false, false, false, false, false, false, false}, + false, false, false, false, false}, + {"dprw", false, false, false, false, false, false, false, false, false, + false, false}, + {"DPRW", false, false, false, false, false, false, false, false, false, + false, false}, + {"ua", false, false, false, false, false, false, false, true, false, + false, false}, + {"arch", false, false, false, false, false, false, false, false, true, + false, false}, + {"platform", false, false, false, false, false, false, false, false, + false, true, false}, + {"model", false, false, false, false, false, false, false, false, false, + false, true}, + {"ua, arch, platform, model", false, false, false, false, false, false, + false, true, true, true, true}, }; for (const auto& test_case : cases) { + SCOPED_TRACE(testing::Message() << test_case.header_value); ClientHintsPreferences preferences; const KURL kurl(String::FromUTF8("https://www.google.com/")); preferences.UpdateFromAcceptClientHintsHeader(test_case.header_value, kurl, @@ -61,6 +78,14 @@ preferences.ShouldSend(mojom::WebClientHintsType::kEct)); EXPECT_EQ(test_case.expectation_lang, preferences.ShouldSend(mojom::WebClientHintsType::kLang)); + EXPECT_EQ(test_case.expectation_ua, + preferences.ShouldSend(mojom::WebClientHintsType::kUA)); + EXPECT_EQ(test_case.expectation_ua_arch, + preferences.ShouldSend(mojom::WebClientHintsType::kUAArch)); + EXPECT_EQ(test_case.expectation_ua_platform, + preferences.ShouldSend(mojom::WebClientHintsType::kUAPlatform)); + EXPECT_EQ(test_case.expectation_ua_model, + preferences.ShouldSend(mojom::WebClientHintsType::kUAModel)); // Calling UpdateFromAcceptClientHintsHeader with empty header should have // no impact on client hint preferences. @@ -105,6 +130,10 @@ EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kDownlink)); EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kEct)); EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kLang)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUA)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAArch)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAPlatform)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAModel)); // Calling UpdateFromAcceptClientHintsHeader with empty header should have // no impact on client hint preferences. @@ -116,6 +145,10 @@ EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kDownlink)); EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kEct)); EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kLang)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUA)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAArch)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAPlatform)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAModel)); // Calling UpdateFromAcceptClientHintsHeader with an invalid header should // have no impact on client hint preferences. @@ -126,6 +159,10 @@ EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kRtt)); EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kDownlink)); EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kLang)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUA)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAArch)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAPlatform)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAModel)); // Calling UpdateFromAcceptClientHintsHeader with "width" header should // have no impact on already enabled client hint preferences. @@ -137,6 +174,10 @@ EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kDownlink)); EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kEct)); EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kLang)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUA)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAArch)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAPlatform)); + EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kUAModel)); preferences.UpdateFromAcceptClientHintsLifetimeHeader("1000", kurl, nullptr); EXPECT_EQ(base::TimeDelta::FromSeconds(1000), @@ -170,21 +211,27 @@ bool expect_downlink; bool expect_ect; bool expect_lang; + bool expect_ua; + bool expect_ua_arch; + bool expect_ua_platform; + bool expect_ua_model; } test_cases[] = { {"width, dpr, viewportWidth, lang", "", 0, false, true, true, false, - false, false, false, true}, + false, false, false, true, false, false, false, false}, {"width, dpr, viewportWidth", "-1000", 0, false, true, true, false, false, - false, false, false}, + false, false, false, false, false, false, false}, {"width, dpr, viewportWidth", "1000s", 0, false, true, true, false, false, - false, false, false}, + false, false, false, false, false, false, false}, {"width, dpr, viewportWidth", "1000.5", 0, false, true, true, false, - false, false, false, false}, + false, false, false, false, false, false, false, false}, {"width, dpr, rtt, downlink, ect", "1000", 1000, false, true, true, false, - true, true, true, false}, + true, true, true, false, false, false, false, false}, {"device-memory", "-1000", 0, true, false, false, false, false, false, - false, false}, + false, false, false, false, false, false}, {"dpr rtt", "1000", 1000, false, false, false, false, false, false, false, - false}, + false, false, false, false, false}, + {"ua, arch, platform, model", "1000", 1000, false, false, false, false, + false, false, false, false, true, true, true, true}, }; for (const auto& test : test_cases) { @@ -202,6 +249,11 @@ EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kDownlink)); EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kEct)); EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kLang)); + EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kUA)); + EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kUAArch)); + EXPECT_FALSE( + enabled_types.IsEnabled(mojom::WebClientHintsType::kUAPlatform)); + EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kUAModel)); TimeDelta persist_duration = preferences.GetPersistDuration(); EXPECT_EQ(base::TimeDelta(), persist_duration); @@ -236,6 +288,14 @@ enabled_types.IsEnabled(mojom::WebClientHintsType::kEct)); EXPECT_EQ(test.expect_lang, enabled_types.IsEnabled(mojom::WebClientHintsType::kLang)); + EXPECT_EQ(test.expect_ua, + enabled_types.IsEnabled(mojom::WebClientHintsType::kUA)); + EXPECT_EQ(test.expect_ua_arch, + enabled_types.IsEnabled(mojom::WebClientHintsType::kUAArch)); + EXPECT_EQ(test.expect_ua_platform, + enabled_types.IsEnabled(mojom::WebClientHintsType::kUAPlatform)); + EXPECT_EQ(test.expect_ua_model, + enabled_types.IsEnabled(mojom::WebClientHintsType::kUAModel)); } }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.h b/third_party/blink/renderer/platform/loader/fetch/resource.h index f210994..0476b9a 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -85,7 +85,8 @@ kAudio, kVideo, kManifest, - kMock // Only for testing + kMock, // Only for testing + kLast = kMock }; // A resource that is held in the cache. Classes who want to use this object @@ -619,7 +620,7 @@ #define DEFINE_RESOURCE_TYPE_CASTS(typeName) \ DEFINE_TYPE_CASTS(typeName##Resource, Resource, resource, \ resource->GetType() == ResourceType::k##typeName, \ - resource.GetType() == ResourceType::k##typeName); + resource.GetType() == ResourceType::k##typeName) } // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index 5242534e..39a53a95 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -616,8 +616,11 @@ ResourceResponse response; scoped_refptr<SharedBuffer> data; if (url.ProtocolIsData()) { - data = network_utils::ParseDataURLAndPopulateResponse(url, response); - if (!data) + int result; + std::tie(result, response, data) = + network_utils::ParseDataURLAndPopulateResponse( + url, true /* verify_mime_type */); + if (result != net::OK) return nullptr; // |response| is modified by parseDataURLAndPopulateResponse() and is // ready to be used.
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc index 19c0c1b3b..bf5014c 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -47,6 +47,7 @@ #include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/public/platform/web_url_response.h" #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h" +#include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h" #include "third_party/blink/renderer/platform/loader/cors/cors.h" #include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h" #include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer_for_data_consumer_handle.h" @@ -57,11 +58,13 @@ #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h" #include "third_party/blink/renderer/platform/loader/fetch/response_body_loader.h" +#include "third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer.h" #include "third_party/blink/renderer/platform/loader/mixed_content_autoupgrade_status.h" #include "third_party/blink/renderer/platform/network/http_names.h" #include "third_party/blink/renderer/platform/network/http_parsers.h" #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h" #include "third_party/blink/renderer/platform/network/network_instrumentation.h" +#include "third_party/blink/renderer/platform/network/network_utils.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h" #include "third_party/blink/renderer/platform/shared_buffer.h" @@ -104,6 +107,39 @@ builder.Record(recorder); } +bool CanHandleDataURLRequestLocally(const ResourceRequest& request) { + if (!request.Url().ProtocolIsData()) + return false; + + // The fast paths for data URL, Start() and HandleDataURL(), don't support + // the DownloadToBlob option. + if (request.DownloadToBlob()) + return false; + + // Data url requests from object tags may need to be intercepted as streams + // and so need to be sent to the browser. + if (request.GetRequestContext() == mojom::RequestContextType::OBJECT) + return false; + + // Optimize for the case where we can handle a data URL locally. We must + // skip this for data URLs targeted at frames since those could trigger a + // download. + // + // NOTE: We special case MIME types we can render both for performance + // reasons as well as to support unit tests. + if (request.GetFrameType() != + network::mojom::RequestContextFrameType::kTopLevel && + request.GetFrameType() != + network::mojom::RequestContextFrameType::kNested) { + return true; + } + + if (network_utils::IsDataURLMimeTypeSupported(request.Url())) + return true; + + return false; +} + } // namespace // CodeCacheRequest handles the requests to fetch data from code cache. @@ -485,24 +521,14 @@ ResourceRequest cache_aware_request(request); cache_aware_request.SetCacheMode( mojom::FetchCacheMode::kUnspecifiedOnlyIfCachedStrict); - loader_->LoadAsynchronously(WrappedResourceRequest(cache_aware_request), - this); - if (code_cache_request_) { - // Sets defers loading and initiates a fetch from code cache. - code_cache_request_->FetchFromCodeCache(loader_.get(), this); - } + RequestAsynchronously(cache_aware_request); return; } if (resource_->Options().synchronous_policy == kRequestSynchronously) { RequestSynchronously(request); } else { - loader_->LoadAsynchronously(WrappedResourceRequest(request), this); - - if (code_cache_request_) { - // Sets defers loading and initiates a fetch from code cache. - code_cache_request_->FetchFromCodeCache(loader_.get(), this); - } + RequestAsynchronously(request); } } @@ -523,6 +549,7 @@ void ResourceLoader::SetDefersLoading(bool defers) { DCHECK(loader_); + defers_ = defers; // If CodeCacheRequest handles this, then no need to handle here. if (code_cache_request_ && code_cache_request_->SetDefersLoading(defers)) return; @@ -536,6 +563,15 @@ } } + if (defers_handling_data_url_) { + if (!defers_) { + defers_handling_data_url_ = false; + GetLoadingTaskRunner()->PostTask( + FROM_HERE, + WTF::Bind(&ResourceLoader::HandleDataUrl, WrapWeakPersistent(this))); + } + } + loader_->SetDefersLoading(defers); if (defers) { resource_->VirtualTimePauser().UnpauseVirtualTime(); @@ -573,6 +609,10 @@ ResourceError::CancelledError(resource_->LastResourceRequest().Url())); } +bool ResourceLoader::IsLoading() const { + return !!loader_; +} + void ResourceLoader::CancelForRedirectAccessCheckError( const KURL& new_url, ResourceRequestBlockedReason blocked_reason) { @@ -822,22 +862,27 @@ const WebURLResponse& web_url_response, std::unique_ptr<WebDataConsumerHandle> handle) { DCHECK(!web_url_response.IsNull()); + DidReceiveResponseInternal(web_url_response.ToResourceResponse(), + std::move(handle)); +} +void ResourceLoader::DidReceiveResponseInternal( + const ResourceResponse& response, + std::unique_ptr<WebDataConsumerHandle> handle) { const ResourceRequest& request = resource_->GetResourceRequest(); if (request.IsAutomaticUpgrade()) { auto recorder = ukm::MojoUkmRecorder::Create(Platform::Current()->GetConnector()); LogMixedAutoupgradeMetrics(MixedContentAutoupgradeStatus::kResponseReceived, - web_url_response.HttpStatusCode(), + response.HttpStatusCode(), request.GetUkmSourceId(), recorder.get()); } if (fetcher_->GetProperties().IsDetached()) { // If the fetch context is already detached, we don't need further signals, // so let's cancel the request. - HandleError( - ResourceError::CancelledError(web_url_response.CurrentRequestUrl())); + HandleError(ResourceError::CancelledError(response.CurrentRequestUrl())); return; } @@ -852,8 +897,6 @@ const ResourceLoaderOptions& options = resource_->Options(); - const ResourceResponse& response = web_url_response.ToResourceResponse(); - should_use_isolated_code_cache_ = ShouldUseIsolatedCodeCache(request_context, response); @@ -1159,13 +1202,32 @@ int64_t encoded_data_length = WebURLLoaderClient::kUnknownEncodedDataLength; int64_t encoded_body_length = 0; WebBlobInfo downloaded_blob; - loader_->LoadSynchronously(request_in, this, response_out, error_out, - data_out, encoded_data_length, encoded_body_length, - downloaded_blob); + if (CanHandleDataURLRequestLocally(request)) { + ResourceResponse response; + scoped_refptr<SharedBuffer> data; + int result; + // It doesn't have to verify mime type again since it's allowed to handle + // the data url with invalid mime type in some cases. + // CanHandleDataURLRequestLocally() has already checked if the data url can + // be handled here. + std::tie(result, response, data) = + network_utils::ParseDataURLAndPopulateResponse( + resource_->Url(), false /* verify_mime_type */); + if (result != net::OK) { + error_out = WebURLError(result, resource_->Url()); + } else { + response_out = WrappedResourceResponse(response); + data_out = WebData(std::move(data)); + } + } else { + loader_->LoadSynchronously(request_in, this, response_out, error_out, + data_out, encoded_data_length, + encoded_body_length, downloaded_blob); + } // A message dispatched while synchronously fetching the resource // can bring about the cancellation of this load. - if (!loader_) + if (!IsLoading()) return; int64_t decoded_body_length = data_out.size(); if (error_out) { @@ -1174,7 +1236,7 @@ return; } DidReceiveResponse(response_out); - if (!loader_) + if (!IsLoading()) return; DCHECK_GE(response_out.ToResourceResponse().EncodedBodyLength(), 0); @@ -1201,6 +1263,24 @@ std::vector<network::cors::PreflightTimingInfo>()); } +void ResourceLoader::RequestAsynchronously(const ResourceRequest& request) { + DCHECK(loader_); + if (CanHandleDataURLRequestLocally(request)) { + DCHECK(!code_cache_request_); + // Handle DataURL in another task instead of using |loader_|. + GetLoadingTaskRunner()->PostTask( + FROM_HERE, + WTF::Bind(&ResourceLoader::HandleDataUrl, WrapWeakPersistent(this))); + return; + } + + loader_->LoadAsynchronously(WrappedResourceRequest(request), this); + if (code_cache_request_) { + // Sets defers loading and initiates a fetch from code cache. + code_cache_request_->FetchFromCodeCache(loader_.get(), this); + } +} + void ResourceLoader::Dispose() { loader_ = nullptr; progress_binding_.Close(); @@ -1313,6 +1393,49 @@ return base::nullopt; } +void ResourceLoader::HandleDataUrl() { + if (!IsLoading()) + return; + if (defers_) { + defers_handling_data_url_ = true; + return; + } + + // Extract a ResourceResponse from the data url. + ResourceResponse response; + scoped_refptr<SharedBuffer> data; + int result; + // We doesn't have to verify mime type again since it's allowed to handle the + // data url with invalid mime type in some cases. + // CanHandleDataURLRequestLocally() has already checked if the data url can be + // handled here. + std::tie(result, response, data) = + network_utils::ParseDataURLAndPopulateResponse( + resource_->Url(), false /* verify_mime_type */); + if (result != net::OK) { + HandleError(ResourceError(result, resource_->Url(), base::nullopt)); + return; + } + DCHECK(data); + const size_t data_size = data->size(); + + DidReceiveResponseInternal(response, nullptr); + if (!IsLoading()) + return; + + auto* bytes_consumer = + MakeGarbageCollected<SharedBufferBytesConsumer>(std::move(data)); + DidStartLoadingResponseBodyInternal(*bytes_consumer); + if (!IsLoading()) + return; + + // DidFinishLoading() may deferred until the response body loader reaches to + // end. + DidFinishLoading(base::TimeTicks::Now(), data_size, data_size, data_size, + false /* should_report_corb_blocking */, + {} /* cors_preflight_timing_info */); +} + bool ResourceLoader::ShouldCheckCorsInResourceLoader() const { return !RuntimeEnabledFeatures::OutOfBlinkCorsEnabled() && resource_->Options().cors_handling_by_resource_fetcher ==
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h index 4250e4e6..498766f0 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
@@ -186,11 +186,19 @@ FetchContext& Context() const; + // Returns true during resource load is happening. Methods as + // a WebURLLoaderClient should not be invoked if this returns false. + bool IsLoading() const; + void CancelForRedirectAccessCheckError(const KURL&, ResourceRequestBlockedReason); void RequestSynchronously(const ResourceRequest&); + void RequestAsynchronously(const ResourceRequest&); void Dispose(); + void DidReceiveResponseInternal(const ResourceResponse&, + std::unique_ptr<WebDataConsumerHandle>); + void CancelTimerFired(TimerBase*); void OnProgress(uint64_t delta) override; @@ -202,6 +210,9 @@ mojom::RequestContextType, const ResourceResponse&); + // Processes Data URL in ResourceLoader instead of using |loader_|. + void HandleDataUrl(); + bool ShouldCheckCorsInResourceLoader() const; std::unique_ptr<WebURLLoader> loader_; @@ -239,6 +250,12 @@ }; base::Optional<DeferredFinishLoadingInfo> deferred_finish_loading_info_; + // True if loading is deferred. + bool defers_ = false; + // True if the next call of SetDefersLoading(false) needs to invoke + // HandleDataURL(). + bool defers_handling_data_url_ = false; + TaskRunnerTimer<ResourceLoader> cancel_timer_; };
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc index 18704a9..2a00345 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc
@@ -4,7 +4,9 @@ #include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h" +#include <string> #include <utility> + #include "mojo/public/c/system/data_pipe.h" #include "services/network/public/mojom/fetch_api.mojom-shared.h" #include "testing/gtest/include/gtest/gtest.h" @@ -16,6 +18,7 @@ #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" +#include "third_party/blink/renderer/platform/loader/testing/bytes_consumer_test_reader.h" #include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h" #include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h" @@ -263,6 +266,282 @@ EXPECT_EQ(data, "hello"); } +TEST_F(ResourceLoaderTest, LoadDataURL_AsyncAndNonStream) { + auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(); + FetchContext* context = MakeGarbageCollected<MockFetchContext>(); + auto* fetcher = MakeGarbageCollected<ResourceFetcher>( + ResourceFetcherInit(*properties, context, CreateTaskRunner(), + MakeGarbageCollected<NoopLoaderFactory>())); + + // Fetch a data url. + KURL url("data:text/plain,Hello%20World!"); + ResourceRequest request(url); + request.SetRequestContext(mojom::RequestContextType::FETCH); + FetchParameters params(request); + Resource* resource = RawResource::Fetch(params, fetcher, nullptr); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get()) + ->RunUntilIdle(); + + // The resource has a parsed body. + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kCached); + scoped_refptr<const SharedBuffer> buffer = resource->ResourceBuffer(); + String data; + for (const auto& span : *buffer) { + data.append(String(span.data(), span.size())); + } + EXPECT_EQ(data, "Hello World!"); +} + +// Helper class which stores a BytesConsumer passed by RawResource and reads the +// bytes when ReadThroughBytesConsumer is called. +class TestRawResourceClient final + : public GarbageCollectedFinalized<TestRawResourceClient>, + public RawResourceClient { + USING_GARBAGE_COLLECTED_MIXIN(TestRawResourceClient); + + public: + TestRawResourceClient() = default; + + // Implements RawResourceClient. + void ResponseBodyReceived(Resource* resource, + BytesConsumer& bytes_consumer) override { + body_ = &bytes_consumer; + } + String DebugName() const override { return "TestRawResourceClient"; } + + void Trace(Visitor* visitor) override { + visitor->Trace(body_); + RawResourceClient::Trace(visitor); + } + + BytesConsumer* body() { return body_; } + + private: + Member<BytesConsumer> body_; +}; + +TEST_F(ResourceLoaderTest, LoadDataURL_AsyncAndStream) { + auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(); + FetchContext* context = MakeGarbageCollected<MockFetchContext>(); + auto* fetcher = MakeGarbageCollected<ResourceFetcher>( + ResourceFetcherInit(*properties, context, CreateTaskRunner(), + MakeGarbageCollected<NoopLoaderFactory>())); + scheduler::FakeTaskRunner* task_runner = + static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get()); + + // Fetch a data url as a stream on response. + KURL url("data:text/plain,Hello%20World!"); + ResourceRequest request(url); + request.SetRequestContext(mojom::RequestContextType::FETCH); + request.SetUseStreamOnResponse(true); + FetchParameters params(request); + auto* raw_resource_client = MakeGarbageCollected<TestRawResourceClient>(); + Resource* resource = RawResource::Fetch(params, fetcher, raw_resource_client); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + task_runner->RunUntilIdle(); + + // It's still pending because we don't read the body yet. + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + + // Read through the bytes consumer passed back from the ResourceLoader. + auto* test_reader = MakeGarbageCollected<BytesConsumerTestReader>( + raw_resource_client->body()); + Vector<char> body; + BytesConsumer::Result result; + std::tie(result, body) = test_reader->Run(task_runner); + EXPECT_EQ(result, BytesConsumer::Result::kDone); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kCached); + EXPECT_EQ(std::string(body.data(), body.size()), "Hello World!"); + + // The body is not set to ResourceBuffer since the response body is requested + // as a stream. + scoped_refptr<const SharedBuffer> buffer = resource->ResourceBuffer(); + EXPECT_FALSE(buffer); +} + +TEST_F(ResourceLoaderTest, LoadDataURL_AsyncEmptyData) { + auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(); + FetchContext* context = MakeGarbageCollected<MockFetchContext>(); + auto* fetcher = MakeGarbageCollected<ResourceFetcher>( + ResourceFetcherInit(*properties, context, CreateTaskRunner(), + MakeGarbageCollected<NoopLoaderFactory>())); + + // Fetch an empty data url. + KURL url("data:text/html,"); + ResourceRequest request(url); + request.SetRequestContext(mojom::RequestContextType::FETCH); + FetchParameters params(request); + Resource* resource = RawResource::Fetch(params, fetcher, nullptr); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get()) + ->RunUntilIdle(); + + // It successfully finishes, and no buffer is propagated. + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kCached); + scoped_refptr<const SharedBuffer> buffer = resource->ResourceBuffer(); + EXPECT_FALSE(buffer); +} + +TEST_F(ResourceLoaderTest, LoadDataURL_Sync) { + auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(); + FetchContext* context = MakeGarbageCollected<MockFetchContext>(); + auto* fetcher = MakeGarbageCollected<ResourceFetcher>( + ResourceFetcherInit(*properties, context, CreateTaskRunner(), + MakeGarbageCollected<NoopLoaderFactory>())); + + // Fetch a data url synchronously. + KURL url("data:text/plain,Hello%20World!"); + ResourceRequest request(url); + request.SetRequestContext(mojom::RequestContextType::FETCH); + FetchParameters params(request); + Resource* resource = + RawResource::FetchSynchronously(params, fetcher, nullptr); + + // The resource has a parsed body. + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kCached); + scoped_refptr<const SharedBuffer> buffer = resource->ResourceBuffer(); + String data; + for (const auto& span : *buffer) { + data.append(String(span.data(), span.size())); + } + EXPECT_EQ(data, "Hello World!"); +} + +TEST_F(ResourceLoaderTest, LoadDataURL_SyncEmptyData) { + auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(); + FetchContext* context = MakeGarbageCollected<MockFetchContext>(); + auto* fetcher = MakeGarbageCollected<ResourceFetcher>( + ResourceFetcherInit(*properties, context, CreateTaskRunner(), + MakeGarbageCollected<NoopLoaderFactory>())); + + // Fetch an empty data url synchronously. + KURL url("data:text/html,"); + ResourceRequest request(url); + request.SetRequestContext(mojom::RequestContextType::FETCH); + FetchParameters params(request); + Resource* resource = + RawResource::FetchSynchronously(params, fetcher, nullptr); + + // It successfully finishes, and no buffer is propagated. + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kCached); + scoped_refptr<const SharedBuffer> buffer = resource->ResourceBuffer(); + EXPECT_FALSE(buffer); +} + +TEST_F(ResourceLoaderTest, LoadDataURL_DefersAsyncAndNonStream) { + auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(); + FetchContext* context = MakeGarbageCollected<MockFetchContext>(); + auto* fetcher = MakeGarbageCollected<ResourceFetcher>( + ResourceFetcherInit(*properties, context, CreateTaskRunner(), + MakeGarbageCollected<NoopLoaderFactory>())); + scheduler::FakeTaskRunner* task_runner = + static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get()); + + // Fetch a data url. + KURL url("data:text/plain,Hello%20World!"); + ResourceRequest request(url); + request.SetRequestContext(mojom::RequestContextType::FETCH); + FetchParameters params(request); + Resource* resource = RawResource::Fetch(params, fetcher, nullptr); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + + // The resource should still be pending since it's deferred. + fetcher->SetDefersLoading(true); + task_runner->RunUntilIdle(); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + + // The resource should still be pending since it's deferred again. + fetcher->SetDefersLoading(true); + task_runner->RunUntilIdle(); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + + // The resource should still be pending if it's unset and set in a single + // task. + fetcher->SetDefersLoading(false); + fetcher->SetDefersLoading(true); + task_runner->RunUntilIdle(); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + + // The resource has a parsed body. + fetcher->SetDefersLoading(false); + task_runner->RunUntilIdle(); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kCached); + scoped_refptr<const SharedBuffer> buffer = resource->ResourceBuffer(); + String data; + for (const auto& span : *buffer) { + data.append(String(span.data(), span.size())); + } + EXPECT_EQ(data, "Hello World!"); +} + +TEST_F(ResourceLoaderTest, LoadDataURL_DefersAsyncAndStream) { + auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(); + FetchContext* context = MakeGarbageCollected<MockFetchContext>(); + auto* fetcher = MakeGarbageCollected<ResourceFetcher>( + ResourceFetcherInit(*properties, context, CreateTaskRunner(), + MakeGarbageCollected<NoopLoaderFactory>())); + scheduler::FakeTaskRunner* task_runner = + static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get()); + + // Fetch a data url as a stream on response. + KURL url("data:text/plain,Hello%20World!"); + ResourceRequest request(url); + request.SetRequestContext(mojom::RequestContextType::FETCH); + request.SetUseStreamOnResponse(true); + FetchParameters params(request); + auto* raw_resource_client = MakeGarbageCollected<TestRawResourceClient>(); + Resource* resource = RawResource::Fetch(params, fetcher, raw_resource_client); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + fetcher->SetDefersLoading(true); + task_runner->RunUntilIdle(); + + // It's still pending because the body should not provided yet. + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + EXPECT_FALSE(raw_resource_client->body()); + + // The body should be provided since not deferring now, but it's still pending + // since we haven't read the body yet. + fetcher->SetDefersLoading(false); + task_runner->RunUntilIdle(); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + EXPECT_TRUE(raw_resource_client->body()); + + // The resource should still be pending when it's set to deferred again. No + // body is provided when deferred. + fetcher->SetDefersLoading(true); + task_runner->RunUntilIdle(); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + const char* buffer; + size_t available; + BytesConsumer::Result result = + raw_resource_client->body()->BeginRead(&buffer, &available); + EXPECT_EQ(BytesConsumer::Result::kShouldWait, result); + + // The resource should still be pending if it's unset and set in a single + // task. No body is provided when deferred. + fetcher->SetDefersLoading(false); + fetcher->SetDefersLoading(true); + task_runner->RunUntilIdle(); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kPending); + result = raw_resource_client->body()->BeginRead(&buffer, &available); + EXPECT_EQ(BytesConsumer::Result::kShouldWait, result); + + // Read through the bytes consumer passed back from the ResourceLoader. + fetcher->SetDefersLoading(false); + task_runner->RunUntilIdle(); + auto* test_reader = MakeGarbageCollected<BytesConsumerTestReader>( + raw_resource_client->body()); + Vector<char> body; + std::tie(result, body) = test_reader->Run(task_runner); + EXPECT_EQ(resource->GetStatus(), ResourceStatus::kCached); + EXPECT_EQ(std::string(body.data(), body.size()), "Hello World!"); + + // The body is not set to ResourceBuffer since the response body is requested + // as a stream. + EXPECT_FALSE(resource->ResourceBuffer()); +} + class ResourceLoaderIsolatedCodeCacheTest : public ResourceLoaderTest { protected: bool LoadAndCheckIsolatedCodeCache(ResourceResponse response) {
diff --git a/third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer.cc b/third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer.cc new file mode 100644 index 0000000..f6a4434 --- /dev/null +++ b/third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer.cc
@@ -0,0 +1,54 @@ +// 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. + +#include "third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer.h" + +#include <utility> + +namespace blink { + +SharedBufferBytesConsumer::SharedBufferBytesConsumer( + scoped_refptr<const SharedBuffer> data) + : data_(std::move(data)), iterator_(data_->begin()) {} + +BytesConsumer::Result SharedBufferBytesConsumer::BeginRead(const char** buffer, + size_t* available) { + *buffer = nullptr; + *available = 0; + if (iterator_ == data_->end()) + return Result::kDone; + *buffer = iterator_->data() + bytes_read_in_chunk_; + *available = iterator_->size() - bytes_read_in_chunk_; + return Result::kOk; +} + +BytesConsumer::Result SharedBufferBytesConsumer::EndRead(size_t read_size) { + DCHECK(iterator_ != data_->end()); + DCHECK_LE(read_size + bytes_read_in_chunk_, iterator_->size()); + bytes_read_in_chunk_ += read_size; + if (bytes_read_in_chunk_ == iterator_->size()) { + bytes_read_in_chunk_ = 0; + ++iterator_; + } + if (iterator_ == data_->end()) + return Result::kDone; + return Result::kOk; +} + +void SharedBufferBytesConsumer::Cancel() { + iterator_ = data_->end(); + bytes_read_in_chunk_ = 0; +} + +BytesConsumer::PublicState SharedBufferBytesConsumer::GetPublicState() const { + if (iterator_ == data_->end()) + return PublicState::kClosed; + return PublicState::kReadableOrWaiting; +} + +String SharedBufferBytesConsumer::DebugName() const { + return "SharedBufferBytesConsumer"; +} + +} // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer.h b/third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer.h new file mode 100644 index 0000000..5f848e1 --- /dev/null +++ b/third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer.h
@@ -0,0 +1,42 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_SHARED_BUFFER_BYTES_CONSUMER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_SHARED_BUFFER_BYTES_CONSUMER_H_ + +#include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h" +#include "third_party/blink/renderer/platform/shared_buffer.h" + +namespace blink { + +// BytesConsumer to get data from a SharedBuffer. +class PLATFORM_EXPORT SharedBufferBytesConsumer final : public BytesConsumer { + public: + // |data| should not be modified after it passed to SharedBufferBytesConsumer. + explicit SharedBufferBytesConsumer(scoped_refptr<const SharedBuffer> data); + + // Implements BytesConsumer. + Result BeginRead(const char** buffer, size_t* available) override; + Result EndRead(size_t read_size) override; + void SetClient(Client* client) override {} + void ClearClient() override{}; + void Cancel() override; + PublicState GetPublicState() const override; + Error GetError() const override { + NOTREACHED(); + return Error(); + }; + String DebugName() const override; + + private: + scoped_refptr<const SharedBuffer> data_; + SharedBuffer::Iterator iterator_; + size_t bytes_read_in_chunk_ = 0; + + DISALLOW_COPY_AND_ASSIGN(SharedBufferBytesConsumer); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_SHARED_BUFFER_BYTES_CONSUMER_H_
diff --git a/third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer_test.cc b/third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer_test.cc new file mode 100644 index 0000000..3b98c253 --- /dev/null +++ b/third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer_test.cc
@@ -0,0 +1,68 @@ +// 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. + +#include "third_party/blink/renderer/platform/loader/fetch/shared_buffer_bytes_consumer.h" + +#include <string> +#include <utility> +#include <vector> + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/loader/testing/bytes_consumer_test_reader.h" +#include "third_party/blink/renderer/platform/scheduler/test/fake_task_runner.h" +#include "third_party/blink/renderer/platform/shared_buffer.h" + +namespace blink { + +using Result = BytesConsumer::Result; +using PublicState = BytesConsumer::PublicState; + +TEST(SharedBufferBytesConsumerTest, Read) { + const std::vector<std::string> kData{"This is a expected data!", + "This is another data!"}; + std::string flatten_expected_data; + auto shared_buffer = SharedBuffer::Create(); + for (const auto& chunk : kData) { + shared_buffer->Append(chunk.data(), chunk.size()); + flatten_expected_data += chunk; + } + + auto* bytes_consumer = + MakeGarbageCollected<SharedBufferBytesConsumer>(std::move(shared_buffer)); + EXPECT_EQ(PublicState::kReadableOrWaiting, bytes_consumer->GetPublicState()); + + auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>(); + auto* test_reader = + MakeGarbageCollected<BytesConsumerTestReader>(bytes_consumer); + Vector<char> data_from_consumer; + Result result; + std::tie(result, data_from_consumer) = test_reader->Run(task_runner.get()); + EXPECT_EQ(Result::kDone, result); + EXPECT_EQ(PublicState::kClosed, bytes_consumer->GetPublicState()); + EXPECT_EQ(flatten_expected_data, + std::string(data_from_consumer.data(), data_from_consumer.size())); +} + +TEST(SharedBufferBytesConsumerTest, Cancel) { + const std::vector<std::string> kData{"This is a expected data!", + "This is another data!"}; + auto shared_buffer = SharedBuffer::Create(); + for (const auto& chunk : kData) { + shared_buffer->Append(chunk.data(), chunk.size()); + } + + auto* bytes_consumer = + MakeGarbageCollected<SharedBufferBytesConsumer>(std::move(shared_buffer)); + EXPECT_EQ(PublicState::kReadableOrWaiting, bytes_consumer->GetPublicState()); + + bytes_consumer->Cancel(); + const char* buffer; + size_t available; + Result result = bytes_consumer->BeginRead(&buffer, &available); + EXPECT_EQ(0u, available); + EXPECT_EQ(Result::kDone, result); + EXPECT_EQ(PublicState::kClosed, bytes_consumer->GetPublicState()); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/platform/network/network_utils.cc b/third_party/blink/renderer/platform/network/network_utils.cc index a2172c0..3ecb398 100644 --- a/third_party/blink/renderer/platform/network/network_utils.cc +++ b/third_party/blink/renderer/platform/network/network_utils.cc
@@ -65,9 +65,8 @@ return String(domain.data(), domain.length()); } -scoped_refptr<SharedBuffer> ParseDataURLAndPopulateResponse( - const KURL& url, - ResourceResponse& response) { +std::tuple<int, ResourceResponse, scoped_refptr<SharedBuffer>> +ParseDataURLAndPopulateResponse(const KURL& url, bool verify_mime_type) { // The following code contains duplication of GetInfoFromDataURL() and // WebURLLoaderImpl::PopulateURLResponse() in // content/child/web_url_loader_impl.cc. Merge them once content/child is @@ -81,18 +80,18 @@ int result = net::URLRequestDataJob::BuildResponse( GURL(url), &utf8_mime_type, &utf8_charset, &data_string, headers.get()); if (result != net::OK) - return nullptr; + return std::make_tuple(result, ResourceResponse(), nullptr); - if (!blink::IsSupportedMimeType(utf8_mime_type)) - return nullptr; + if (verify_mime_type && !blink::IsSupportedMimeType(utf8_mime_type)) + return std::make_tuple(net::ERR_FAILED, ResourceResponse(), nullptr); - scoped_refptr<SharedBuffer> data = - SharedBuffer::Create(data_string.data(), data_string.size()); + auto buffer = SharedBuffer::Create(data_string.data(), data_string.size()); + ResourceResponse response; response.SetHTTPStatusCode(200); response.SetHTTPStatusText("OK"); response.SetCurrentRequestUrl(url); response.SetMimeType(WebString::FromUTF8(utf8_mime_type)); - response.SetExpectedContentLength(data->size()); + response.SetExpectedContentLength(buffer->size()); response.SetTextEncodingName(WebString::FromUTF8(utf8_charset)); size_t iter = 0; @@ -102,7 +101,7 @@ response.AddHTTPHeaderField(WebString::FromLatin1(name), WebString::FromLatin1(value)); } - return data; + return std::make_tuple(net::OK, std::move(response), std::move(buffer)); } bool IsDataURLMimeTypeSupported(const KURL& url) {
diff --git a/third_party/blink/renderer/platform/network/network_utils.h b/third_party/blink/renderer/platform/network/network_utils.h index f161f69b..9d02246 100644 --- a/third_party/blink/renderer/platform/network/network_utils.h +++ b/third_party/blink/renderer/platform/network/network_utils.h
@@ -5,6 +5,8 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_NETWORK_NETWORK_UTILS_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_NETWORK_NETWORK_UTILS_H_ +#include <tuple> + #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/forward.h" @@ -28,11 +30,14 @@ PLATFORM_EXPORT String GetDomainAndRegistry(const String& host, PrivateRegistryFilter); -// Returns the decoded data url as ResourceResponse and SharedBuffer -// if url had a supported mimetype and parsing was successful. -PLATFORM_EXPORT scoped_refptr<SharedBuffer> ParseDataURLAndPopulateResponse( - const KURL&, - ResourceResponse&); +// Returns the decoded data url as ResourceResponse and SharedBuffer if parsing +// was successful. The result is returned as net error code. It returns net::OK +// if decoding succeeds, otherwise it failed. +// When |verify_mime_type| is true, it returns net::ERR_FAILED if the mime type +// is not supported (blink::IsSupportedMimeType() returns false) even if parsing +// succeeds. +PLATFORM_EXPORT std::tuple<int, ResourceResponse, scoped_refptr<SharedBuffer>> +ParseDataURLAndPopulateResponse(const KURL&, bool verify_mime_type); // Returns true if the URL is a data URL and its MIME type is in the list of // supported/recognized MIME types.
diff --git a/third_party/blink/renderer/platform/scheduler/BUILD.gn b/third_party/blink/renderer/platform/scheduler/BUILD.gn index f6c0510..9f9ed92 100644 --- a/third_party/blink/renderer/platform/scheduler/BUILD.gn +++ b/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -11,6 +11,7 @@ sources = [ "common/cancelable_closure_holder.cc", "common/cancelable_closure_holder.h", + "common/cooperative_scheduling_manager.cc", "common/features.cc", "common/features.h", "common/frame_or_worker_scheduler.cc", @@ -101,6 +102,7 @@ "main_thread/web_render_widget_scheduling_state.cc", "main_thread/web_scoped_virtual_time_pauser.cc", "public/aggregated_metric_reporter.h", + "public/cooperative_scheduling_manager.h", "public/frame_or_worker_scheduler.h", "public/frame_scheduler.h", "public/frame_status.h", @@ -178,6 +180,7 @@ testonly = true sources = [ + "common/cooperative_scheduling_manager_unittest.cc", "common/idle_helper_unittest.cc", "common/idle_memory_reclaimer_unittest.cc", "common/metrics_helper_unittest.cc",
diff --git a/third_party/blink/renderer/platform/scheduler/common/cooperative_scheduling_manager.cc b/third_party/blink/renderer/platform/scheduler/common/cooperative_scheduling_manager.cc new file mode 100644 index 0000000..fbb4850 --- /dev/null +++ b/third_party/blink/renderer/platform/scheduler/common/cooperative_scheduling_manager.cc
@@ -0,0 +1,48 @@ +// 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. + +#include "third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h" + +#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" +#include "third_party/blink/renderer/platform/wtf/thread_specific.h" + +namespace blink { +namespace scheduler { + +// static +CooperativeSchedulingManager* CooperativeSchedulingManager::Instance() { + DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<CooperativeSchedulingManager>, + manager, ()); + return &(*manager); +} + +CooperativeSchedulingManager::WhitelistedStackScope::WhitelistedStackScope( + CooperativeSchedulingManager* manager) { + cooperative_scheduling_manager_ = manager; + cooperative_scheduling_manager_->EnterWhitelistedStackScope(); +} + +CooperativeSchedulingManager::WhitelistedStackScope::~WhitelistedStackScope() { + cooperative_scheduling_manager_->LeaveWhitelistedStackScope(); +} + +CooperativeSchedulingManager::CooperativeSchedulingManager() {} + +void CooperativeSchedulingManager::EnterWhitelistedStackScope() { + TRACE_EVENT_ASYNC_BEGIN0("renderer.scheduler", + "PreemptionWhitelistedStackScope", this); + + whitelisted_stack_scope_depth_++; +} + +void CooperativeSchedulingManager::LeaveWhitelistedStackScope() { + TRACE_EVENT_ASYNC_END0("renderer.scheduler", + "PreemptionWhitelistedStackScope", this); + whitelisted_stack_scope_depth_--; + DCHECK_GE(whitelisted_stack_scope_depth_, 0); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/common/cooperative_scheduling_manager_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/cooperative_scheduling_manager_unittest.cc new file mode 100644 index 0000000..a4720007 --- /dev/null +++ b/third_party/blink/renderer/platform/scheduler/common/cooperative_scheduling_manager_unittest.cc
@@ -0,0 +1,30 @@ +// 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. + +#include "third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +TEST(CooperativeSchedulingManager, WhitelistedStackScope) { + std::unique_ptr<CooperativeSchedulingManager> manager = + std::make_unique<CooperativeSchedulingManager>(); + { + EXPECT_FALSE(manager->InWhitelistedStackScope()); + CooperativeSchedulingManager::WhitelistedStackScope scope(manager.get()); + EXPECT_TRUE(manager->InWhitelistedStackScope()); + { + CooperativeSchedulingManager::WhitelistedStackScope nested_scope( + manager.get()); + EXPECT_TRUE(manager->InWhitelistedStackScope()); + } + EXPECT_TRUE(manager->InWhitelistedStackScope()); + } + EXPECT_FALSE(manager->InWhitelistedStackScope()); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h b/third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h new file mode 100644 index 0000000..d1b5e33 --- /dev/null +++ b/third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h
@@ -0,0 +1,56 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_COOPERATIVE_SCHEDULING_MANAGER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_COOPERATIVE_SCHEDULING_MANAGER_H_ + +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" +#include "third_party/blink/renderer/platform/wtf/time.h" + +namespace blink { +namespace scheduler { + +// This class manages the states for cooperative scheduling and decides whether +// or not to run a nested loop or not. +class PLATFORM_EXPORT CooperativeSchedulingManager { + USING_FAST_MALLOC(CooperativeSchedulingManager); + + public: + // This class is used to mark JS executions that have a C++ stack that has + // been whitelisted for reentry. + class PLATFORM_EXPORT WhitelistedStackScope { + STACK_ALLOCATED(); + + public: + WhitelistedStackScope(CooperativeSchedulingManager*); + ~WhitelistedStackScope(); + + private: + CooperativeSchedulingManager* cooperative_scheduling_manager_; + }; + + // Returns an shared instance for the current thread. + static CooperativeSchedulingManager* Instance(); + + CooperativeSchedulingManager(); + + // Returns true if the C++ stack has been whitelisted for reentry. + bool InWhitelistedStackScope() const { + return whitelisted_stack_scope_depth_ > 0; + } + + private: + void EnterWhitelistedStackScope(); + void LeaveWhitelistedStackScope(); + + int whitelisted_stack_scope_depth_ = 0; + + DISALLOW_COPY_AND_ASSIGN(CooperativeSchedulingManager); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_COOPERATIVE_SCHEDULING_MANAGER_H_
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc b/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc index 1241d56..0046775f 100644 --- a/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc +++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc
@@ -149,9 +149,13 @@ KURL kurl = params->url; if (kurl.ProtocolIsData()) { ResourceResponse response; - scoped_refptr<SharedBuffer> buffer = - network_utils::ParseDataURLAndPopulateResponse(kurl, response); + scoped_refptr<SharedBuffer> buffer; + int result; + std::tie(result, response, buffer) = + network_utils::ParseDataURLAndPopulateResponse( + kurl, true /* verify_mime_type */); DCHECK(buffer); + DCHECK_EQ(net::OK, result); params->response = WrappedResourceResponse(response); auto body_loader = std::make_unique<StaticDataNavigationBodyLoader>(); body_loader->Write(*buffer);
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json index a02e291..26066b1 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -182866,6 +182866,11 @@ {} ] ], + "screen-capture/feature-policy.https-expected.txt": [ + [ + {} + ] + ], "screen-capture/getdisplaymedia.https-expected.txt": [ [ {} @@ -277067,6 +277072,12 @@ {} ] ], + "screen-capture/feature-policy.https.html": [ + [ + "/screen-capture/feature-policy.https.html", + {} + ] + ], "screen-capture/getdisplaymedia.https.html": [ [ "/screen-capture/getdisplaymedia.https.html", @@ -394363,11 +394374,11 @@ "support" ], "domparsing/XMLSerializer-serializeToString-expected.txt": [ - "fc008ec96a92108431f392e24fbefa986a83960d", + "74a15ed0a603a456e68c8b358a1e34cae590f988", "support" ], "domparsing/XMLSerializer-serializeToString.html": [ - "5f7e2bb0d4b459bd20acb43aca19b848920ac8bb", + "81df61f5bc42880ee013287e90a3808bdccd536b", "testharness" ], "domparsing/createContextualFragment.html": [ @@ -446270,6 +446281,14 @@ "a1ef42657ad76cac417ccd52d68b9eafda283478", "support" ], + "screen-capture/feature-policy.https-expected.txt": [ + "388368b82938b61cfa60994b89dd79c876316000", + "support" + ], + "screen-capture/feature-policy.https.html": [ + "56c9e80a1307484a26ab370298789030a6fa350e", + "testharness" + ], "screen-capture/getdisplaymedia.https-expected.txt": [ "2209b8770be42f3bf4da8b471ec2bfc6f9e4314c", "support" @@ -463279,7 +463298,7 @@ "support" ], "webxr/idlharness.https.window-expected.txt": [ - "588b212fa11411f9fe57b1a56e2247f2735a2164", + "cb0fa2ae3e42af5854e11ff2fa7b159d69ee29ce", "support" ], "webxr/idlharness.https.window.js": [
diff --git a/third_party/blink/web_tests/external/wpt/domparsing/XMLSerializer-serializeToString.html b/third_party/blink/web_tests/external/wpt/domparsing/XMLSerializer-serializeToString.html index 0c3c0a9..81df61f 100644 --- a/third_party/blink/web_tests/external/wpt/domparsing/XMLSerializer-serializeToString.html +++ b/third_party/blink/web_tests/external/wpt/domparsing/XMLSerializer-serializeToString.html
@@ -27,28 +27,22 @@ } test(function() { - var serializer = new XMLSerializer(); var root = createXmlDoc().documentElement; - var xmlString = serializer.serializeToString(root); - assert_equals(xmlString, '<root><child1>value1</child1></root>'); + assert_equals(serialize(root), '<root><child1>value1</child1></root>'); }, 'check XMLSerializer.serializeToString method could parsing xmldoc to string'); test(function() { - var serializer = new XMLSerializer(); var root = createXmlDoc().documentElement; var element = root.ownerDocument.createElementNS('urn:foo', 'another'); var child1 = root.firstChild; root.replaceChild(element, child1); element.appendChild(child1); - var xmlString = serializer.serializeToString(root); - assert_equals(xmlString, '<root><another xmlns="urn:foo"><child1 xmlns="">value1</child1></another></root>'); + assert_equals(serialize(root), '<root><another xmlns="urn:foo"><child1 xmlns="">value1</child1></another></root>'); }, 'Check if the default namespace is correctly reset.'); test(function() { - var input = '<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>'; - var root = (new DOMParser()).parseFromString(input, 'text/xml').documentElement; - var xmlString = (new XMLSerializer()).serializeToString(root); - assert_equals(xmlString, '<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>'); + var root = parse('<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>'); + assert_equals(serialize(root), '<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>'); }, 'Check if there is no redundant empty namespace declaration.'); test(function() { @@ -124,34 +118,29 @@ }, 'Check if the prefix of an attribute is replaced with a generated one in a case where the prefix is already mapped to a different namespace URI.'); test(function() { - var serializer = new XMLSerializer(); - var parser = new DOMParser(); - var root = parser.parseFromString('<root />', 'text/xml').documentElement; + var root = parse('<root />'); root.setAttribute('attr', '\t'); - assert_in_array(serializer.serializeToString(root), [ + assert_in_array(serialize(root), [ '<root attr="	"/>', '<root attr="	"/>']); root.setAttribute('attr', '\n'); - assert_in_array(serializer.serializeToString(root), [ + assert_in_array(serialize(root), [ '<root attr="
"/>', '<root attr=" "/>']); root.setAttribute('attr', '\r'); - assert_in_array(serializer.serializeToString(root), [ + assert_in_array(serialize(root), [ '<root attr="
"/>', '<root attr=" "/>']); }, 'check XMLSerializer.serializeToString escapes attribute values for roundtripping'); test(function() { const root = (new Document()).createElement('root'); root.setAttributeNS('uri1', 'p:foobar', 'value1'); - root.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:p', 'uri2'); - const xmlString = (new XMLSerializer()).serializeToString(root); - assert_equals(xmlString, '<root xmlns:ns1="uri1" ns1:foobar="value1" xmlns:p="uri2"/>'); + root.setAttributeNS(XMLNS_URI, 'xmlns:p', 'uri2'); + assert_equals(serialize(root), '<root xmlns:ns1="uri1" ns1:foobar="value1" xmlns:p="uri2"/>'); }, 'Check if attribute serialization takes into account of following xmlns:* attributes'); test(function() { - const input = '<root xmlns:p="uri1"><child/></root>'; - const root = (new DOMParser()).parseFromString(input, 'text/xml').documentElement; + const root = parse('<root xmlns:p="uri1"><child/></root>'); root.firstChild.setAttributeNS('uri2', 'p:foobar', 'v'); - const xmlString = (new XMLSerializer()).serializeToString(root); - assert_equals(xmlString, '<root xmlns:p="uri1"><child xmlns:ns1="uri2" ns1:foobar="v"/></root>'); + assert_equals(serialize(root), '<root xmlns:p="uri1"><child xmlns:ns1="uri2" ns1:foobar="v"/></root>'); }, 'Check if attribute serialization takes into account of the same prefix declared in an ancestor element'); test(function() { @@ -176,30 +165,26 @@ test(function() { const root = (new Document()).createElement('root'); - root.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:p', 'uri2'); + root.setAttributeNS(XMLNS_URI, 'xmlns:p', 'uri2'); const child = root.ownerDocument.createElementNS('uri1', 'p:child'); root.appendChild(child); assert_equals(serialize(root), '<root xmlns:p="uri2"><p:child xmlns:p="uri1"/></root>'); }, 'Check if start tag serialization applied the original prefix even if it is declared in an ancestor element.'); test(function() { - const input = '<root><child1/><child2/></root>'; - const root = (new DOMParser()).parseFromString(input, 'text/xml').documentElement; + const root = parse('<root><child1/><child2/></root>'); root.firstChild.setAttributeNS('uri1', 'attr1', 'value1'); root.firstChild.setAttributeNS('uri2', 'attr2', 'value2'); root.lastChild.setAttributeNS('uri3', 'attr3', 'value3'); - const xmlString = (new XMLSerializer()).serializeToString(root); - assert_equals(xmlString, '<root><child1 xmlns:ns1="uri1" ns1:attr1="value1" xmlns:ns2="uri2" ns2:attr2="value2"/><child2 xmlns:ns3="uri3" ns3:attr3="value3"/></root>'); + assert_equals(serialize(root), '<root><child1 xmlns:ns1="uri1" ns1:attr1="value1" xmlns:ns2="uri2" ns2:attr2="value2"/><child2 xmlns:ns3="uri3" ns3:attr3="value3"/></root>'); }, 'Check if generated prefixes match to "ns${index}".'); test(function() { - const input = '<root xmlns:ns2="uri2"><child xmlns:ns1="uri1"/></root>'; - const root = (new DOMParser()).parseFromString(input, 'text/xml').documentElement; + const root = parse('<root xmlns:ns2="uri2"><child xmlns:ns1="uri1"/></root>'); root.firstChild.setAttributeNS('uri3', 'attr1', 'value1'); - const xmlString = (new XMLSerializer()).serializeToString(root); // According to 'DOM Parsing and Serialization' draft as of 2018-12-11, // 'generate a prefix' result can conflict with an existing xmlns:ns* declaration. - assert_equals(xmlString, '<root xmlns:ns2="uri2"><child xmlns:ns1="uri1" xmlns:ns1="uri3" ns1:attr1="value1"/></root>'); + assert_equals(serialize(root), '<root xmlns:ns2="uri2"><child xmlns:ns1="uri1" xmlns:ns1="uri3" ns1:attr1="value1"/></root>'); }, 'Check if "ns1" is generated even if the element already has xmlns:ns1.'); test(function() {
diff --git a/third_party/blink/web_tests/external/wpt/screen-capture/feature-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/screen-capture/feature-policy.https-expected.txt new file mode 100644 index 0000000..388368b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/screen-capture/feature-policy.https-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +FAIL Default "display-capture" feature policy ["self"] allows the top-level document. promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getDisplayMedia' on 'MediaDevices': Audio only requests are not supported" +FAIL Default "display-capture" feature policy ["self"] allows same-origin iframes. assert_equals: expected "#OK" but got "#TypeError" +FAIL Default "display-capture" feature policy ["self"] disallows cross-origin iframes. assert_equals: expected "#NotAllowedError" but got "#TypeError" +FAIL Feature policy "display-capture" can be enabled in cross-origin iframes using "allow" attribute. assert_equals: expected "#OK" but got "#TypeError" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/screen-capture/feature-policy.https.html b/third_party/blink/web_tests/external/wpt/screen-capture/feature-policy.https.html new file mode 100644 index 0000000..56c9e80a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/screen-capture/feature-policy.https.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<body> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src=/common/get-host-info.sub.js></script> + <script src=/feature-policy/resources/featurepolicy.js></script> + <script> + 'use strict'; + + async function gDM({audio, video}) { + let stream; + try { + stream = await navigator.mediaDevices.getDisplayMedia({audio, video}); + if (stream.getVideoTracks().length == 0) { + throw {name: `requested video track must be present with ` + + `audio ${audio} and video ${video}, or fail`}; + } + } finally { + if (stream) { + stream.getTracks().forEach(track => track.stop()); + } + } + } + + const cross_domain = get_host_info().HTTPS_REMOTE_ORIGIN; + run_all_fp_tests_allow_self( + cross_domain, + 'display-capture', + 'NotAllowedError', + async () => { + await gDM({video: true}); + await gDM({audio: true, video: true}); + await gDM({audio: true}); + } + ); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt index 76e0835..3de90db 100644 --- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt
@@ -1,9 +1,9 @@ This is a testharness.js-based test. PASS initialize global state -FAIL event.request has the expected headers for same-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin GET. lengths differ, expected 1 got 6" -FAIL event.request has the expected headers for same-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin POST. lengths differ, expected 2 got 8" -FAIL event.request has the expected headers for cross-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin GET. lengths differ, expected 1 got 6" -FAIL event.request has the expected headers for cross-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin POST. lengths differ, expected 2 got 8" +FAIL event.request has the expected headers for same-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin GET. lengths differ, expected 1 got 7" +FAIL event.request has the expected headers for same-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin POST. lengths differ, expected 2 got 9" +FAIL event.request has the expected headers for cross-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin GET. lengths differ, expected 1 got 7" +FAIL event.request has the expected headers for cross-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin POST. lengths differ, expected 2 got 9" PASS FetchEvent#request.body contains XHR request data (string) PASS FetchEvent#request.body contains XHR request data (blob) PASS FetchEvent#request.method is set to XHR method
diff --git a/third_party/blink/web_tests/platform/win/media/video-played-ranges-1-expected.txt b/third_party/blink/web_tests/platform/win/media/video-played-ranges-1-expected.txt deleted file mode 100644 index e69de29..0000000 --- a/third_party/blink/web_tests/platform/win/media/video-played-ranges-1-expected.txt +++ /dev/null
diff --git a/third_party/dav1d/BUILD.gn b/third_party/dav1d/BUILD.gn index aedc658..c50c7b4 100644 --- a/third_party/dav1d/BUILD.gn +++ b/third_party/dav1d/BUILD.gn
@@ -29,11 +29,35 @@ needs_stack_alignment = false # The defaults are stack_alignment=4 for x86 and stack_alignment=16 for x64. } else { + # The compiler flags, as well as the stack alignment values, all mirror + # upstream's meson.build setup: + # https://chromium.googlesource.com/external/github.com/videolan/dav1d/+/master/meson.build needs_stack_alignment = true if (current_cpu == "x86") { stack_alignment = 16 + + if (!is_clang) { + # Values used by GCC. + preferred_stack_boundary = 4 + incoming_stack_boundary = 2 + } } else if (current_cpu == "x64") { stack_alignment = 32 + + if (!is_clang) { + # Values used by GCC. + preferred_stack_boundary = 5 + incoming_stack_boundary = 4 + } + } + + if (is_clang) { + stackalign_flag = "-mstack-alignment=$stack_alignment" + stackrealign_flag = "-mstackrealign" + } else { + # Assume GCC for now. + stackalign_flag = "-mpreferred-stack-boundary=$preferred_stack_boundary" + stackrealign_flag = "-mincoming-stack-boundary=$incoming_stack_boundary" } } } else { @@ -73,7 +97,7 @@ if (!is_win) { dav1d_copts += [ "-std=c99" ] if (needs_stack_alignment) { - dav1d_copts += [ "-mstack-alignment=$stack_alignment" ] + dav1d_copts += [ stackalign_flag ] } } @@ -123,7 +147,7 @@ } if (needs_stack_alignment) { - cflags += [ "-mstackrealign" ] + cflags += [ stackrealign_flag ] } }
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index 242a590..26e12ad 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -370,6 +370,16 @@ f.write('group: files\n') +def SetMacXcodePath(): + """Set DEVELOPER_DIR to the path to hermetic Xcode.app on Mac OS X.""" + if sys.platform != 'darwin': + return + + xcode_path = os.path.join(CHROMIUM_DIR, 'build', 'mac_files', 'Xcode.app') + if os.path.exists(xcode_path): + os.environ['DEVELOPER_DIR'] = xcode_path + + win_sdk_dir = None dia_dll = None def GetWinSDKDir(): @@ -511,6 +521,7 @@ AddCMakeToPath(args) AddGnuWinToPath() + SetMacXcodePath() DeleteChromeToolsShim()
diff --git a/tools/determinism/deterministic_build_whitelist.pyl b/tools/determinism/deterministic_build_whitelist.pyl index 385e58a2..65c6551d 100644 --- a/tools/determinism/deterministic_build_whitelist.pyl +++ b/tools/determinism/deterministic_build_whitelist.pyl
@@ -33,6 +33,8 @@ 'ppapi_nacl_tests_pnacl_newlib_x32_nonsfi.nexe', 'test_data/ppapi/tests/extensions/packaged_app/nonsfi/ppapi_tests_extensions_packaged_app_pnacl_newlib_x32_nonsfi.nexe', + # https://crbug.com/932387 + 'performance_browser_tests', ], 'linux_component': [ @@ -193,5 +195,9 @@ # reason. 'nacl_irt_x86_32.nexe', 'nacl_irt_x86_32.nexe.debug', + + # https://crbug.com/932387 + 'performance_browser_tests.exe', + 'performance_browser_tests.exe.pdb', ], }
diff --git a/tools/gn/README.md b/tools/gn/README.chromium.md similarity index 100% rename from tools/gn/README.md rename to tools/gn/README.chromium.md
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py index 49a33bb..f12a63b9 100755 --- a/tools/gn/bootstrap/bootstrap.py +++ b/tools/gn/bootstrap/bootstrap.py
@@ -91,13 +91,14 @@ os.environ.get('CXXFLAGS', '').split()), ]) + '\n') subprocess.check_call(['ninja', '-C', libcxx_dir]) + shutil.copy2(os.path.join(gn_build_dir, 'libc++.gn.so'), out_dir) def append_to_env(var, vals): os.putenv(var, os.environ.get(var, '') + ' ' + ' '.join(vals)) append_to_env('LDFLAGS', [ - '-nodefaultlibs', 'libc++.so', '-lc', '-lm', '-Wl,-rpath="\$$ORIGIN/."', - '-Wl,-rpath-link=.' + '-nodefaultlibs', 'libc++.gn.so', '-lc', '-lm', + '-Wl,-rpath="\$$ORIGIN/."', '-Wl,-rpath-link=.' ]) append_to_env('CXXFLAGS', [ '-nostdinc++',
diff --git a/tools/gn/bootstrap/libc++.ninja b/tools/gn/bootstrap/libc++.ninja index 8851010..a22d0de 100644 --- a/tools/gn/bootstrap/libc++.ninja +++ b/tools/gn/bootstrap/libc++.ninja
@@ -68,4 +68,4 @@ build $libcxxabi/stdlib_stdexcept.o: cxx_libcxxabi $buildtools/$libcxxabi/stdlib_stdexcept.cpp build $libcxxabi/stdlib_typeinfo.o: cxx_libcxxabi $buildtools/$libcxxabi/stdlib_typeinfo.cpp -build ../libc++.so: link $libcxx/algorithm.o $libcxx/any.o $libcxx/bind.o $libcxx/chrono.o $libcxx/condition_variable.o $libcxx/debug.o $libcxx/exception.o $libcxx/functional.o $libcxx/future.o $libcxx/hash.o $libcxx/ios.o $libcxx/iostream.o $libcxx/locale.o $libcxx/memory.o $libcxx/mutex.o $libcxx/new.o $libcxx/optional.o $libcxx/random.o $libcxx/regex.o $libcxx/shared_mutex.o $libcxx/stdexcept.o $libcxx/string.o $libcxx/strstream.o $libcxx/system_error.o $libcxx/thread.o $libcxx/typeinfo.o $libcxx/utility.o $libcxx/valarray.o $libcxx/variant.o $libcxx/vector.o $libcxxabi/abort_message.o $libcxxabi/cxa_aux_runtime.o $libcxxabi/cxa_default_handlers.o $libcxxabi/cxa_demangle.o $libcxxabi/cxa_exception_storage.o $libcxxabi/cxa_guard.o $libcxxabi/cxa_handlers.o $libcxxabi/cxa_noexception.o $libcxxabi/cxa_unexpected.o $libcxxabi/cxa_vector.o $libcxxabi/cxa_virtual.o $libcxxabi/fallback_malloc.o $libcxxabi/private_typeinfo.o $libcxxabi/stdlib_exception.o $libcxxabi/stdlib_stdexcept.o $libcxxabi/stdlib_typeinfo.o +build ../libc++.gn.so: link $libcxx/algorithm.o $libcxx/any.o $libcxx/bind.o $libcxx/chrono.o $libcxx/condition_variable.o $libcxx/debug.o $libcxx/exception.o $libcxx/functional.o $libcxx/future.o $libcxx/hash.o $libcxx/ios.o $libcxx/iostream.o $libcxx/locale.o $libcxx/memory.o $libcxx/mutex.o $libcxx/new.o $libcxx/optional.o $libcxx/random.o $libcxx/regex.o $libcxx/shared_mutex.o $libcxx/stdexcept.o $libcxx/string.o $libcxx/strstream.o $libcxx/system_error.o $libcxx/thread.o $libcxx/typeinfo.o $libcxx/utility.o $libcxx/valarray.o $libcxx/variant.o $libcxx/vector.o $libcxxabi/abort_message.o $libcxxabi/cxa_aux_runtime.o $libcxxabi/cxa_default_handlers.o $libcxxabi/cxa_demangle.o $libcxxabi/cxa_exception_storage.o $libcxxabi/cxa_guard.o $libcxxabi/cxa_handlers.o $libcxxabi/cxa_noexception.o $libcxxabi/cxa_unexpected.o $libcxxabi/cxa_vector.o $libcxxabi/cxa_virtual.o $libcxxabi/fallback_malloc.o $libcxxabi/private_typeinfo.o $libcxxabi/stdlib_exception.o $libcxxabi/stdlib_stdexcept.o $libcxxabi/stdlib_typeinfo.o
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 2776392..de314d1 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -460,9 +460,9 @@ <int value="2" label="Maximized"/> <int value="3" label="Fullscreen"/> <int value="4" label="Snapped"/> - <int value="5" label="Docked"/> - <int value="6" label="Pinned"/> - <int value="7" label="TrustedPinned"/> + <int value="5" label="Pinned"/> + <int value="6" label="TrustedPinned"/> + <int value="7" label="Picture in picture"/> </enum> <enum name="ActivityTrackerAnalyzerCreationError"> @@ -3636,6 +3636,7 @@ <int value="16" label="Deprecated Explore Sites refresh task"/> <int value="17" label="Explore Sites refresh task"/> <int value="18" label="Download auto-resumption task"/> + <int value="19" label="One shot Background Sync wake up task"/> </enum> <enum name="BackgroundTracingState"> @@ -9789,6 +9790,10 @@ <int value="4" label="Checksum out of sync"/> </enum> +<enum name="CryptohomeDeprecatedApiCalled"> + <int value="0" label="InitializeCastKey"/> +</enum> + <enum name="CryptohomeDiskCleanupProgress"> <int value="1" label="Ephemeral User Profiles cleaned"> Ephemeral users were enabled. Removed all profiles except those currently @@ -21577,6 +21582,10 @@ <int value="2786" label="V8UserActivation_IsActive_AttributeGetter"/> <int value="2787" label="TextEncoderEncodeInto"/> <int value="2788" label="InvalidBasicCardMethodData"/> + <int value="2789" label="ClientHintsUA"/> + <int value="2790" label="ClientHintsUAArch"/> + <int value="2791" label="ClientHintsUAPlatform"/> + <int value="2792" label="ClientHintsUAModel"/> </enum> <enum name="FeaturePolicyFeature"> @@ -31478,6 +31487,7 @@ <int value="-757946835" label="OmniboxUIExperimentShowSuggestionFavicons:enabled"/> <int value="-757379927" label="Canvas2DImageChromium:enabled"/> + <int value="-757282194" label="EnableFilesystemInIncognito:enabled"/> <int value="-750175757" label="ClientLoFi:enabled"/> <int value="-749048160" label="enable-panels"/> <int value="-747463111" label="ContentSuggestionsNotifications:disabled"/> @@ -32145,6 +32155,7 @@ <int value="446316019" label="enable-threaded-compositing"/> <int value="451196246" label="disable-impl-side-painting"/> <int value="452139294" label="VrShellExperimentalRendering:enabled"/> + <int value="452955571" label="EnableFilesystemInIncognito:disabled"/> <int value="453102772" label="OfflinePagesLoadSignalCollecting:disabled"/> <int value="455698038" label="disable-gesture-requirement-for-media-playback"/> @@ -32307,6 +32318,7 @@ <int value="720931007" label="WebAuthenticationBle:enabled"/> <int value="721225492" label="PolicyTool:enabled"/> <int value="723619383" label="TopSitesFromSiteEngagement:enabled"/> + <int value="724052572" label="EnableFilesystemInIncognito"/> <int value="724208771" label="TabsInCBD:enabled"/> <int value="725270017" label="ScrollAnchorSerialization:disabled"/> <int value="726764779" label="WebXRGamepadSupport:enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 2dd4383..f3b4594 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -18935,6 +18935,17 @@ </summary> </histogram> +<histogram name="Cryptohome.DeprecatedApiCalled" + enum="CryptohomeDeprecatedApiCalled" expires_after="M80"> + <owner>apronin@chromium.org</owner> + <owner>louiscollard@chromium.org</owner> + <owner>zuan@chromium.org</owner> + <summary> + Records when a deprecated API function in cryptohome is called, so we know + which exposed DBus API can be removed without side effect. + </summary> +</histogram> + <histogram name="Cryptohome.DircryptoMigrationEndStatus" enum="DircryptoMigrationEndStatus"> <owner>dspaid@chromium.org</owner> @@ -26373,6 +26384,9 @@ <histogram name="Drive.FilesListRequestRunner.ApiErrorCode" enum="DriveApiErrorCode"> + <obsolete> + Obsolete 02/2019 as DriveFS implementation obsoletes this metric. + </obsolete> <owner>mtomasz@chromium.org</owner> <summary> Error codes returned by the Drive API for files list requests executed via @@ -26381,6 +26395,9 @@ </histogram> <histogram name="Drive.FilesListRequestRunner.MaxResults"> + <obsolete> + Obsolete 02/2019 as DriveFS implementation obsoletes this metric. + </obsolete> <owner>mtomasz@chromium.org</owner> <summary> Maximum number of results for each files list request using the Drive API.
diff --git a/tools/perf/core/cli_helpers.py b/tools/perf/core/cli_helpers.py index 45b3f370..f23a984c 100644 --- a/tools/perf/core/cli_helpers.py +++ b/tools/perf/core/cli_helpers.py
@@ -21,7 +21,7 @@ } -def colored(message, color): +def Colored(message, color): """Wraps the message into ASCII color escape codes. Args: @@ -34,39 +34,39 @@ return '\033[%dm%s\033[0m' % (COLOR_ANSI_CODE_MAP[color], message) -def info(message, **kwargs): +def Info(message, **kwargs): print(message.format(**kwargs)) -def comment(message, **kwargs): +def Comment(message, **kwargs): """Prints an import message to the user.""" - print(colored(message.format(**kwargs), 'yellow')) + print(Colored(message.format(**kwargs), 'yellow')) -def fatal(message, **kwargs): +def Fatal(message, **kwargs): """Displays an error to the user and terminates the program.""" - error(message, **kwargs) + Error(message, **kwargs) sys.exit(1) -def error(message, **kwargs): +def Error(message, **kwargs): """Displays an error to the user.""" - print(colored(message.format(**kwargs), 'red')) + print(Colored(message.format(**kwargs), 'red')) -def step(name): +def Step(name): """Display a decorated message to the user. This is useful to separate major stages of the script. For simple messages, please use comment function above. """ boundary = max(80, len(name)) - print(colored('=' * boundary, 'green')) - print(colored(name, 'green')) - print(colored('=' * boundary, 'green')) + print(Colored('=' * boundary, 'green')) + print(Colored(name, 'green')) + print(Colored('=' * boundary, 'green')) -def ask(question, answers=None, default=None): +def Ask(question, answers=None, default=None): """Asks the user to answer a question with multiple choices. Users are able to press Return to access the default answer (if specified) and @@ -121,7 +121,7 @@ raise ValueError('invalid default answer: "%s"' % default) while True: - print(colored(question + prompt, 'cyan'), end=' ') + print(Colored(question + prompt, 'cyan'), end=' ') choice = raw_input().strip().lower() if default is not None and choice == '': return inputs[default] @@ -129,11 +129,11 @@ return inputs[choice] else: choices = sorted(['"%s"' % a for a in sorted(answers.keys())]) - error('Please respond with %s or %s.' % ( + Error('Please respond with %s or %s.' % ( ', '.join(choices[:-1]), choices[-1])) -def check_log(command, log_path, env=None): +def CheckLog(command, log_path, env=None): """Executes a command and writes its stdout to a specified log file. On non-zero return value, also prints the content of the file to the screen @@ -146,27 +146,30 @@ """ with open(log_path, 'w') as f: try: - cmd_str = ' '.join(command) if isinstance(command, list) else command - print(colored(cmd_str, 'blue')) - print(colored('Logging stdout & stderr to %s' % log_path, 'blue')) + cmd_str = (' '.join(pipes.quote(c) for c in command) + if isinstance(command, list) else command) + print(Colored(cmd_str, 'blue')) + print(Colored('Logging stdout & stderr to %s' % log_path, 'blue')) subprocess.check_call( command, stdout=f, stderr=subprocess.STDOUT, shell=False, env=env) except subprocess.CalledProcessError: - error('=' * 80) - error('Received non-zero return code. Log content:') - error('=' * 80) + Error('=' * 80) + Error('Received non-zero return code. Log content:') + Error('=' * 80) subprocess.call(['cat', log_path]) - error('=' * 80) + Error('=' * 80) raise -def run(command, ok_fail=False, **kwargs): +def Run(command, ok_fail=False, **kwargs): """Prints and runs the command. Allows to ignore non-zero exit code.""" if not isinstance(command, list): raise ValueError('command must be a list') - print(colored(' '.join(pipes.quote(c) for c in command), 'blue')) + print(Colored(' '.join(pipes.quote(c) for c in command), 'blue')) try: return subprocess.check_call(command, **kwargs) - except subprocess.CalledProcessError: + except subprocess.CalledProcessError as cpe: if not ok_fail: raise + else: + return cpe.returncode
diff --git a/tools/perf/core/cli_helpers_unittest.py b/tools/perf/core/cli_helpers_unittest.py index c103684..8be9f2d 100644 --- a/tools/perf/core/cli_helpers_unittest.py +++ b/tools/perf/core/cli_helpers_unittest.py
@@ -13,34 +13,34 @@ class CLIHelpersTest(unittest.TestCase): def testUnsupportedColor(self): with self.assertRaises(AssertionError): - cli_helpers.colored('message', 'pink') + cli_helpers.Colored('message', 'pink') @mock.patch('__builtin__.print') def testPrintsInfo(self, print_mock): - cli_helpers.info('foo {sval} {ival}', sval='s', ival=42) + cli_helpers.Info('foo {sval} {ival}', sval='s', ival=42) print_mock.assert_called_once_with('foo s 42') @mock.patch('__builtin__.print') def testPrintsComment(self, print_mock): - cli_helpers.comment('foo') + cli_helpers.Comment('foo') print_mock.assert_called_once_with('\033[93mfoo\033[0m') @mock.patch('__builtin__.print') @mock.patch('sys.exit') def testFatal(self, sys_exit_mock, print_mock): - cli_helpers.fatal('foo') + cli_helpers.Fatal('foo') print_mock.assert_called_once_with('\033[91mfoo\033[0m') sys_exit_mock.assert_called_once() @mock.patch('__builtin__.print') def testPrintsError(self, print_mock): - cli_helpers.error('foo') + cli_helpers.Error('foo') print_mock.assert_called_once_with('\033[91mfoo\033[0m') @mock.patch('__builtin__.print') def testPrintsStep(self, print_mock): long_step_name = 'foobar' * 15 - cli_helpers.step(long_step_name) + cli_helpers.Step(long_step_name) self.assertListEqual(print_mock.call_args_list, [ mock.call('\033[92m' + ('=' * 90) + '\033[0m'), mock.call('\033[92m' + long_step_name + '\033[0m'), @@ -51,7 +51,7 @@ @mock.patch('__builtin__.raw_input') def testAskAgainOnInvalidAnswer(self, raw_input_mock, print_mock): raw_input_mock.side_effect = ['foobar', 'y'] - self.assertTrue(cli_helpers.ask('Ready?')) + self.assertTrue(cli_helpers.Ask('Ready?')) self.assertListEqual(print_mock.mock_calls, [ mock.call('\033[96mReady? [no/YES] \033[0m', end=' '), mock.call('\033[91mPlease respond with "no" or "yes".\033[0m'), @@ -63,7 +63,7 @@ def testAskWithCustomAnswersAndDefault(self, raw_input_mock, print_mock): raw_input_mock.side_effect = [''] self.assertFalse( - cli_helpers.ask('Ready?', {'foo': True, 'bar': False}, default='bar')) + cli_helpers.Ask('Ready?', {'foo': True, 'bar': False}, default='bar')) print_mock.assert_called_once_with( '\033[96mReady? [BAR/foo] \033[0m', end=' ') @@ -71,7 +71,7 @@ @mock.patch('__builtin__.raw_input') def testAskNoDefaultCustomAnswersAsList(self, raw_input_mock, print_mock): raw_input_mock.side_effect = ['', 'FoO'] - self.assertEqual(cli_helpers.ask('Ready?', ['foo', 'bar']), 'foo') + self.assertEqual(cli_helpers.Ask('Ready?', ['foo', 'bar']), 'foo') self.assertListEqual(print_mock.mock_calls, [ mock.call('\033[96mReady? [foo/bar] \033[0m', end=' '), mock.call('\033[91mPlease respond with "bar" or "foo".\033[0m'), @@ -80,7 +80,7 @@ def testAskWithInvalidDefaultAnswer(self): with self.assertRaises(ValueError): - cli_helpers.ask('Ready?', ['foo', 'bar'], 'baz') + cli_helpers.Ask('Ready?', ['foo', 'bar'], 'baz') @mock.patch('__builtin__.print') @mock.patch('subprocess.check_call') @@ -92,20 +92,23 @@ open_mock.return_value.__enter__.return_value = file_mock dt_mock.now.return_value.strftime.return_value = '_2018_12_10_16_22_11' - cli_helpers.check_log( - ['command', 'arg1'], '/tmp/tmpXYZ.tmp', env={'foo': 'bar'}) + cli_helpers.CheckLog( + ['command', 'arg with space'], '/tmp/tmpXYZ.tmp', env={'foo': 'bar'}) check_call_mock.assert_called_once_with( - ['command', 'arg1'], stdout=file_mock, stderr=subprocess.STDOUT, - shell=False, env={'foo': 'bar'}) + ['command', 'arg with space'], + stdout=file_mock, + stderr=subprocess.STDOUT, + shell=False, + env={'foo': 'bar'}) open_mock.assert_called_once_with('/tmp/tmpXYZ.tmp', 'w') self.assertListEqual(print_mock.mock_calls, [ - mock.call('\033[94mcommand arg1\033[0m'), + mock.call("\033[94mcommand 'arg with space'\033[0m"), mock.call('\033[94mLogging stdout & stderr to /tmp/tmpXYZ.tmp\033[0m'), ]) @mock.patch('__builtin__.print') - @mock.patch('core.cli_helpers.error') + @mock.patch('core.cli_helpers.Error') @mock.patch('subprocess.check_call') @mock.patch('subprocess.call') @mock.patch('__builtin__.open') @@ -115,7 +118,7 @@ check_call_mock.side_effect = [subprocess.CalledProcessError(87, ['cmd'])] with self.assertRaises(subprocess.CalledProcessError): - cli_helpers.check_log(['cmd'], '/tmp/tmpXYZ.tmp') + cli_helpers.CheckLog(['cmd'], '/tmp/tmpXYZ.tmp') call_mock.assert_called_once_with(['cat', '/tmp/tmpXYZ.tmp']) self.assertListEqual(error_mock.mock_calls, [ @@ -130,7 +133,7 @@ def testRun(self, check_call_mock, print_mock): check_call_mock.side_effect = [subprocess.CalledProcessError(87, ['cmd'])] with self.assertRaises(subprocess.CalledProcessError): - cli_helpers.run(['cmd', 'arg with space'], env={'a': 'b'}) + cli_helpers.Run(['cmd', 'arg with space'], env={'a': 'b'}) check_call_mock.assert_called_once_with( ['cmd', 'arg with space'], env={'a': 'b'}) print_mock.assert_called_once_with('\033[94mcmd \'arg with space\'\033[0m') @@ -140,11 +143,11 @@ def testRunOkFail(self, check_call_mock, print_mock): del print_mock # Unused. check_call_mock.side_effect = [subprocess.CalledProcessError(87, ['cmd'])] - cli_helpers.run(['cmd'], ok_fail=True) + cli_helpers.Run(['cmd'], ok_fail=True) def testRunWithNonListCommand(self): with self.assertRaises(ValueError): - cli_helpers.run('cmd with args') + cli_helpers.Run('cmd with args') if __name__ == "__main__":
diff --git a/tools/perf/update_wpr b/tools/perf/update_wpr new file mode 100755 index 0000000..0e235e3 --- /dev/null +++ b/tools/perf/update_wpr
@@ -0,0 +1,11 @@ +#!/usr/bin/env python +# Copyright 2018 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import sys + +from wpr import update_wpr + +if __name__ == '__main__': + sys.exit(update_wpr.Main(sys.argv[1:]))
diff --git a/tools/perf/wpr/__init__.py b/tools/perf/wpr/__init__.py new file mode 100644 index 0000000..1adf20d2 --- /dev/null +++ b/tools/perf/wpr/__init__.py
@@ -0,0 +1,3 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file.
diff --git a/tools/perf/wpr/update_wpr.py b/tools/perf/wpr/update_wpr.py new file mode 100644 index 0000000..ad0dc143 --- /dev/null +++ b/tools/perf/wpr/update_wpr.py
@@ -0,0 +1,205 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Script to automate updating existing WPR benchmarks from live versions of the +# sites. Only supported on Mac/Linux. + +import argparse +import datetime +import os +import re +import shutil +import subprocess +import tempfile + +from core import cli_helpers + + +SRC_ROOT = os.path.abspath( + os.path.join(os.path.dirname(__file__), '..', '..', '..')) +RESULTS2JSON = os.path.join( + SRC_ROOT, 'third_party', 'catapult', 'tracing', 'bin', 'results2json') +HISTOGRAM2CSV = os.path.join( + SRC_ROOT, 'third_party', 'catapult', 'tracing', 'bin', 'histograms2csv') +RUN_BENCHMARK = os.path.join(SRC_ROOT, 'tools', 'perf', 'run_benchmark') + + +class WprUpdater(object): + def __init__(self, args): + self.story = args.story + self.device_id = args.device_id + self.repeat = args.repeat + self.binary = args.binary + self.output_dir = tempfile.mkdtemp() + + def _PrepareEnv(self): + # Enforce the same local settings for recording and replays on the bots. + env = os.environ.copy() + env['LC_ALL'] = 'en_US.UTF-8' + return env + + def _Run(self, command, ok_fail=False): + return cli_helpers.Run(command, ok_fail=ok_fail, env=self._PrepareEnv()) + + def _CheckLog(self, command, log_name): + # This is a wrapper around cli_helpers.CheckLog that adds timestamp to the + # log filename and substitutes placeholders such as {src}, {name}, + # {device_id} in the command. + name_regex = '^%s$' % re.escape(self.story) + command = [ + c.format(src=SRC_ROOT, name=name_regex, device_id=self.device_id) + for c in command] + timestamp = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S') + log_path = os.path.join(self.output_dir, '%s_%s' % (log_name, timestamp)) + cli_helpers.CheckLog(command, log_path=log_path, env=self._PrepareEnv()) + return log_path + + def _IsDesktop(self): + return self.device_id is None + + def _ExtractLogFile(self, out_file): + # This method extracts the name of the chrome log file from the + # run_benchmark output log and copies it to the temporary directory next to + # the log file, which ensures that it is not overridden by the next run. + try: + line = subprocess.check_output( + ['grep', 'Chrome log file will be saved in', out_file]) + os.rename(line.split()[-1], out_file + '.chrome.log') + except subprocess.CalledProcessError as e: + cli_helpers.Error('Could not find log file: {error}', error=e) + + def _ExtractResultsFile(self, out_file): + results_file = out_file + '.results.html' + os.rename(os.path.join(self.output_dir, 'results.html'), results_file) + + def _RunSystemHealthMemoryBenchmark(self, log_name, live=False): + args = [RUN_BENCHMARK, 'run'] + + if self._IsDesktop(): + args.append('system_health.memory_desktop') + else: + args.extend('system_health.memory_mobile') + + if self.binary: + args.extend([ + '--browser-executable=%s' % self.binary, + '--browser=exact', + ]) + elif self._IsDesktop(): + args.append('--browser=system') + else: + args.append('--browser=android-system-chrome') + + args.extend([ + '--output-format=html', '--show-stdout', + '--reset-results', '--story-filter={name}', + '--browser-logging-verbosity=verbose', + '--pageset-repeat=%s' % self.repeat, + '--output-dir', self.output_dir]) + if live: + args.append('--use-live-sites') + out_file = self._CheckLog(args, log_name=log_name) + self._ExtractResultsFile(out_file) + self._ExtractLogFile(out_file) + return out_file + + def _PrintResultsHTMLInfo(self, out_file): + results_file = out_file + '.results.html' + histogram_json = out_file + '.hist.json' + histogram_csv = out_file + '.hist.csv' + + self._Run([RESULTS2JSON, results_file, histogram_json]) + self._Run([HISTOGRAM2CSV, histogram_json, histogram_csv]) + + cli_helpers.Info('Metrics results: file://{path}', path=results_file) + names = set([ + 'console:error:network', + 'console:error:js', + 'console:error:all', + 'console:error:security']) + with open(histogram_csv) as f: + for line in f.readlines(): + line = line.split(',') + if line[0] in names: + cli_helpers.Info(' %-26s%s' % ('[%s]:' % line[0], line[2])) + + def _PrintRunInfo(self, out_file, results_details=True): + try: + if results_details: + self._PrintResultsHTMLInfo(out_file) + except Exception as e: + cli_helpers.Error('Could not print results.html tests: %s' % e) + + def shell(cmd): + return subprocess.check_output(cmd, shell=True).rstrip() + + def statsFor(name, filters='wc -l'): + cmd = 'grep "DevTools console .%s." "%s"' % (name, out_file) + cmd += ' | ' + filters + output = shell(cmd) or '0' + if len(output) > 7: + cli_helpers.Info(' %-26s%s' % ('[%s]:' % name, cmd)) + cli_helpers.Info(' ' + output.replace('\n', '\n ')) + else: + cli_helpers.Info(' %-16s%-8s %s' % ('[%s]:' % name, output, cmd)) + + cli_helpers.Info('Stdout/Stderr Log: %s' % out_file) + cli_helpers.Info('Chrome Log: %s.chrome.log' % out_file) + cli_helpers.Info( + ' Total output: %s' % + subprocess.check_output(['wc', '-l', out_file]).rstrip()) + cli_helpers.Info( + ' Total Console: %s' % + shell('grep "DevTools console" "%s" | wc -l' % out_file)) + statsFor('security') + statsFor('network', 'cut -d " " -f 20- | sort | uniq -c | sort -nr') + + chrome_log = '%s.chrome.log' % out_file + if os.path.isfile(chrome_log): + cmd = 'grep "Uncaught .*Error" "%s"' % chrome_log + count = shell(cmd + '| wc -l') + cli_helpers.Info(' %-16s%-8s %s' % ('[javascript]:', count, cmd)) + + def LiveRun(self): + cli_helpers.Step('LIVE RUN: %s' % self.story) + out_file = self._RunSystemHealthMemoryBenchmark( + log_name='live', live=True) + self._PrintRunInfo(out_file) + return out_file + + def Cleanup(self): + if cli_helpers.Ask('Should I clean up the temp dir with logs?'): + shutil.rmtree(self.output_dir, ignore_errors=True) + else: + cli_helpers.Comment( + 'No problem. All logs will remain in %s - feel free to remove that ' + 'directory when done.' % self.output_dir) + + +def Main(argv): + parser = argparse.ArgumentParser() + parser.add_argument( + '-s', '--story', dest='story', required=True, + help='Benchmark story to be recorded, replayed or uploaded.') + parser.add_argument( + '-d', '--device-id', dest='device_id', + help='Specify the device serial number listed by `adb devices`. When not ' + 'specified, the script runs in desktop mode.') + parser.add_argument( + '--pageset-repeat', type=int, default=1, dest='repeat', + help='Number of times to repeat the entire pageset.') + parser.add_argument( + '--binary', default=None, + help='Path to the Chromium/Chrome binary relative to output directory. ' + 'Defaults to default Chrome browser installed if not specified.') + parser.add_argument( + 'command', choices=['live'], + help='Mode in which to run this script.') + + args = parser.parse_args(argv) + + updater = WprUpdater(args) + if args.command =='live': + updater.LiveRun() + updater.Cleanup()
diff --git a/tools/perf/wpr/update_wpr_unittest.py b/tools/perf/wpr/update_wpr_unittest.py new file mode 100644 index 0000000..e1a0592 --- /dev/null +++ b/tools/perf/wpr/update_wpr_unittest.py
@@ -0,0 +1,159 @@ +# Copyright 2018 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. + +# pylint: disable=protected-access + +import argparse +import unittest + +import mock + +from wpr import update_wpr + + +WPR_UPDATER = 'wpr.update_wpr.WprUpdater.' + + +class UpdateWPRTest(unittest.TestCase): + def setUp(self): + self.maxDiff = None + + self._check_log = mock.patch('core.cli_helpers.CheckLog').start() + self._run = mock.patch('core.cli_helpers.Run').start() + self._check_output = mock.patch('subprocess.check_output').start() + self._check_call = mock.patch('subprocess.check_call').start() + self._info = mock.patch('core.cli_helpers.Info').start() + self._comment = mock.patch('core.cli_helpers.Comment').start() + self._open = mock.patch('__builtin__.open').start() + datetime = mock.patch('datetime.datetime').start() + datetime.now.return_value.strftime.return_value = '<tstamp>' + + mock.patch('tempfile.mkdtemp', return_value='/tmp/dir').start() + mock.patch('core.cli_helpers.Fatal').start() + mock.patch('core.cli_helpers.Error').start() + mock.patch('core.cli_helpers.Step').start() + mock.patch('os.environ').start().copy.return_value = {} + mock.patch('wpr.update_wpr.SRC_ROOT', '...').start() + mock.patch('wpr.update_wpr.RESULTS2JSON', '.../results2json').start() + mock.patch('wpr.update_wpr.HISTOGRAM2CSV', '.../histograms2csv').start() + mock.patch('wpr.update_wpr.RUN_BENCHMARK', '.../run_benchmark').start() + mock.patch('os.path.join', lambda *parts: '/'.join(parts)).start() + + self.wpr_updater = update_wpr.WprUpdater(argparse.Namespace( + story='<story>', device_id=None, repeat=1, binary=None)) + + def tearDown(self): + mock.patch.stopall() + + def testMain(self): + wpr_updater_cls = mock.patch('wpr.update_wpr.WprUpdater').start() + update_wpr.Main([ + 'live', + '-s', 'foo:bar:story:2019', + '-d', 'H2345234FC33', + '--binary', '<binary>' + ]) + self.assertListEqual(wpr_updater_cls.mock_calls, [ + mock.call(argparse.Namespace( + binary='<binary>', command='live', device_id='H2345234FC33', + repeat=1, story='foo:bar:story:2019')), + mock.call().LiveRun(), + mock.call().Cleanup(), + ]) + + def testCleanupManual(self): + mock.patch('core.cli_helpers.Ask', return_value=False).start() + rmtree = mock.patch('shutil.rmtree').start() + self.wpr_updater.Cleanup() + self._comment.assert_called_once_with( + 'No problem. All logs will remain in /tmp/dir - feel free to remove ' + 'that directory when done.') + rmtree.assert_not_called() + + def testCleanupAutomatic(self): + mock.patch('core.cli_helpers.Ask', return_value=True).start() + rmtree = mock.patch('shutil.rmtree').start() + self.wpr_updater.Cleanup() + rmtree.assert_called_once_with('/tmp/dir', ignore_errors=True) + + def testLiveRun(self): + run_benchmark = mock.patch( + WPR_UPDATER + '_RunSystemHealthMemoryBenchmark', + return_value='<out-file>').start() + print_run_info = mock.patch(WPR_UPDATER + '_PrintRunInfo').start() + self.wpr_updater.LiveRun() + run_benchmark.assert_called_once_with(log_name='live', live=True) + print_run_info.assert_called_once_with('<out-file>') + + def testRunBenchmark(self): + rename = mock.patch('os.rename').start() + self._check_output.return_value = ' <chrome-log>' + + self.wpr_updater._RunSystemHealthMemoryBenchmark('<log_name>', True) + + # Check correct arguments when running benchmark. + self._check_log.assert_called_once_with( + [ + '.../run_benchmark', 'run', 'system_health.memory_desktop', + '--browser=system', '--output-format=html', '--show-stdout', + '--reset-results', '--story-filter=^\\<story\\>$', + '--browser-logging-verbosity=verbose', '--pageset-repeat=1', + '--output-dir', '/tmp/dir', '--use-live-sites' + ], + env={'LC_ALL': 'en_US.UTF-8'}, + log_path='/tmp/dir/<log_name>_<tstamp>') + + # Check logs are correctly extracted. + self.assertListEqual(rename.mock_calls, [ + mock.call( + '/tmp/dir/results.html', '/tmp/dir/<log_name>_<tstamp>.results.html'), + mock.call('<chrome-log>', '/tmp/dir/<log_name>_<tstamp>.chrome.log'), + ]) + + def testPrintResultsHTMLInfo(self): + self._open.return_value.__enter__.return_value.readlines.return_value = [ + 'console:error:network,foo,bar', + 'console:error:js,foo,bar', + 'console:error:security,foo,bar', + ] + self.wpr_updater._PrintResultsHTMLInfo('<outfile>') + self.assertListEqual(self._run.mock_calls, [ + mock.call( + ['.../results2json', '<outfile>.results.html', '<outfile>.hist.json'], + env={'LC_ALL': 'en_US.UTF-8'}, ok_fail=False), + mock.call( + ['.../histograms2csv', '<outfile>.hist.json', '<outfile>.hist.csv'], + env={'LC_ALL': 'en_US.UTF-8'}, ok_fail=False), + ]) + self._open.assert_called_once_with('<outfile>.hist.csv') + self.assertListEqual(self._info.mock_calls, [ + mock.call( + 'Metrics results: file://{path}', path='<outfile>.results.html'), + mock.call(' [console:error:network]: bar'), + mock.call(' [console:error:js]: bar'), + mock.call(' [console:error:security]: bar') + ]) + + def testPrintRunInfo(self): + print_results = mock.patch( + WPR_UPDATER + '_PrintResultsHTMLInfo', + side_effect=[Exception()]).start() + self._check_output.return_value = '0\n' + self.wpr_updater._PrintRunInfo('<outfile>', True) + print_results.assert_called_once_with('<outfile>') + self.assertListEqual(self._info.mock_calls, [ + mock.call('Stdout/Stderr Log: <outfile>'), + mock.call('Chrome Log: <outfile>.chrome.log'), + mock.call(' Total output: 0'), + mock.call(' Total Console: 0'), + mock.call(' [security]: 0 grep "DevTools console ' + '.security." "<outfile>" | wc -l'), + mock.call(' [network]: 0 grep "DevTools console ' + '.network." "<outfile>" | cut -d " " -f 20- | sort | uniq -c ' + '| sort -nr'), + ]) + + +if __name__ == "__main__": + unittest.main()
diff --git a/tools/run-swarmed.py b/tools/run-swarmed.py index ef7097e..e81a2e8 100755 --- a/tools/run-swarmed.py +++ b/tools/run-swarmed.py
@@ -33,21 +33,20 @@ """Triggers a swarming job. The arguments passed are: - The index of the job; - The command line arguments object; - - The hash of the isolate job used to trigger; - - Value of --gtest_filter arg, or empty if none. + - The hash of the isolate job used to trigger. The return value is passed to a collect-style map() and consists of: - The index of the job; - The json file created by triggering and used to collect results; - The command line arguments object. """ - index, args, isolated_hash, gtest_filter = args + index, args, isolated_hash = args json_file = os.path.join(args.results, '%d.json' % index) trigger_args = [ 'tools/swarming_client/swarming.py', 'trigger', '-S', 'https://chromium-swarm.appspot.com', '-I', 'https://isolateserver.appspot.com', - '-d', 'pool', 'Chrome', + '-d', 'pool', args.pool, '-s', isolated_hash, '--dump-json', json_file, ] @@ -60,12 +59,37 @@ ] elif args.target_os == 'win': trigger_args += [ '-d', 'os', 'Windows' ] + elif args.target_os == 'android': + # The canonical version numbers are stored in the infra repository here: + # build/scripts/slave/recipe_modules/swarming/api.py + cpython_version = 'version:2.7.14.chromium14' + vpython_version = 'git_revision:96f81e737868d43124b4661cf1c325296ca04944' + cpython_pkg = ( + '.swarming_module:infra/python/cpython/${platform}:' + + cpython_version) + vpython_native_pkg = ( + '.swarming_module:infra/tools/luci/vpython-native/${platform}:' + + vpython_version) + vpython_pkg = ( + '.swarming_module:infra/tools/luci/vpython/${platform}:' + + vpython_version) + trigger_args += [ + '-d', 'os', 'Android', + '-d', 'device_os', args.device_os, + '--cipd-package', cpython_pkg, + '--cipd-package', vpython_native_pkg, + '--cipd-package', vpython_pkg, + '--env-prefix', 'PATH', '.swarming_module', + '--env-prefix', 'PATH', '.swarming_module/bin', + '--env-prefix', 'VPYTHON_VIRTUALENV_ROOT', + '.swarming_module_cache/vpython', + ] trigger_args += [ '--', '--test-launcher-summary-output=${ISOLATED_OUTDIR}/output.json', '--system-log-file=${ISOLATED_OUTDIR}/system_log'] - if gtest_filter: - trigger_args.append('--gtest_filter=' + gtest_filter) + if args.gtest_filter: + trigger_args.append('--gtest_filter=' + args.gtest_filter) elif args.target_os == 'fuchsia': filter_file = \ 'testing/buildbot/filters/fuchsia.' + args.test_name + '.filter' @@ -108,6 +132,10 @@ help='CPU architecture of the test binary.') parser.add_argument('--copies', '-n', type=int, default=1, help='Number of copies to spawn.') + parser.add_argument('--device-os', default='M', + help='Run tests on the given version of Android.') + parser.add_argument('--pool', default='Chrome', + help='Use the given swarming pool.') parser.add_argument('--results', '-r', default='results', help='Directory in which to store results.') parser.add_argument('--gtest_filter', @@ -160,8 +188,7 @@ try: print 'Triggering %d tasks...' % args.copies pool = multiprocessing.Pool() - spawn_args = map(lambda i: (i, args, isolated_hash, args.gtest_filter), - range(args.copies)) + spawn_args = map(lambda i: (i, args, isolated_hash), range(args.copies)) spawn_results = pool.imap_unordered(_Spawn, spawn_args) exit_codes = []
diff --git a/tools/ubsan/blacklist.txt b/tools/ubsan/blacklist.txt index 1c965ae..68e25a21 100644 --- a/tools/ubsan/blacklist.txt +++ b/tools/ubsan/blacklist.txt
@@ -7,33 +7,23 @@ src:*/third_party/yasm/* ############################################################################# -# V8 gives too many false positives. Ignore them for now. -src:*/v8/* - -############################################################################# # Ignore system libraries. src:*/usr/* ############################################################################# -# V8 UBsan supressions, commented out for now since we are ignorning v8 -# completely. -# fun:*v8*internal*FastD2I* -# fun:*v8*internal*ComputeIntegerHash* -# fun:*v8*internal*ComputeLongHash* -# fun:*v8*internal*ComputePointerHash* -# src:*/v8/src/base/bits.cc -# src:*/v8/src/base/functional.cc -# Undefined behaviour (integer overflow) is expected but ignored in this -# function. -# fun:*JsonParser*ParseJsonNumber* +# V8 UBsan supressions +# UBSan bug, fixed in LLVM r350779. Drop this suppression when that +# revision has rolled into Chromium's bundled Clang. +fun:*v8*internal*NewArray* -# Runtime numeric functions. -# src:*/v8/src/runtime/runtime-numbers.cc +# Bug v8:8735: PropertyCallbackInfo<void> vs PropertyCallbackInfo<T>. +fun:*v8*internal*PropertyCallbackArguments*CallAccessorSetter* +fun:*v8*internal*PropertyCallbackArguments*BasicCallNamedGetterCallback* +fun:*v8*internal*InvokeAccessorGetterCallback* -# Shifts of negative numbers -# fun:*v8*internal*HPositionInfo*TagPosition* -# fun:*v8*internal*Range*Shl* -# fun:*v8*internal*RelocInfoWriter*WriteTaggedData* +# Bug v8:8735: WeakCallbackInfo<void> vs. WeakCallbackInfo<T>. +fun:*v8*internal*GlobalHandles*PendingPhantomCallback*Invoke* +fun:*v8*internal*GlobalHandles*Node*PostGarbageCollectionProcessing* ############################################################################# # Undefined arithmetic that can be safely ignored.
diff --git a/tools/web_dev_style/js_checker.py b/tools/web_dev_style/js_checker.py index 263867f..8638786 100644 --- a/tools/web_dev_style/js_checker.py +++ b/tools/web_dev_style/js_checker.py
@@ -50,7 +50,7 @@ def PolymerLocalIdCheck(self, i, line): """Checks for use of element.$.localId.""" - return self.RegexCheck(i, line, r"(?<!this)(\.\$)[\[\.]", + return self.RegexCheck(i, line, r"(?<!this)(\.\$)[\[\.](?![a-zA-Z]+\()", "Please only use this.$.localId, not element.$.localId") def RunEsLintChecks(self, affected_js_files, format='stylish'):
diff --git a/tools/web_dev_style/js_checker_test.py b/tools/web_dev_style/js_checker_test.py index b5a4ced..ce62e24 100755 --- a/tools/web_dev_style/js_checker_test.py +++ b/tools/web_dev_style/js_checker_test.py
@@ -207,6 +207,7 @@ "this.$.id", "this.$.localId", "this.$['fancy-id']", + "this.page.$.flushForTesting()", ] for line in lines: self.ShouldPassPolymerLocalIdCheck(line)
diff --git a/ui/gfx/vsync_provider.cc b/ui/gfx/vsync_provider.cc index 6276b7f..ff4b4a5 100644 --- a/ui/gfx/vsync_provider.cc +++ b/ui/gfx/vsync_provider.cc
@@ -6,9 +6,8 @@ namespace gfx { -void FixedVSyncProvider::GetVSyncParameters( - const UpdateVSyncCallback& callback) { - callback.Run(timebase_, interval_); +void FixedVSyncProvider::GetVSyncParameters(UpdateVSyncCallback callback) { + std::move(callback).Run(timebase_, interval_); } bool FixedVSyncProvider::GetVSyncParametersIfAvailable(
diff --git a/ui/gfx/vsync_provider.h b/ui/gfx/vsync_provider.h index e8aa0fe7..87b0a15 100644 --- a/ui/gfx/vsync_provider.h +++ b/ui/gfx/vsync_provider.h
@@ -15,8 +15,8 @@ public: virtual ~VSyncProvider() {} - typedef base::Callback< - void(const base::TimeTicks timebase, const base::TimeDelta interval)> + typedef base::OnceCallback<void(const base::TimeTicks timebase, + const base::TimeDelta interval)> UpdateVSyncCallback; // Get the time of the most recent screen refresh, along with the time @@ -25,7 +25,7 @@ // later via a PostTask to the current MessageLoop, or never (if we have // no data source). We provide the strong guarantee that the callback will // not be called once the instance of this class is destroyed. - virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) = 0; + virtual void GetVSyncParameters(UpdateVSyncCallback callback) = 0; // Similar to GetVSyncParameters(). It returns true, if the data is available. // Otherwise false is returned. @@ -48,7 +48,7 @@ ~FixedVSyncProvider() override {} - void GetVSyncParameters(const UpdateVSyncCallback& callback) override; + void GetVSyncParameters(UpdateVSyncCallback callback) override; bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase, base::TimeDelta* interval) override; bool SupportGetVSyncParametersIfAvailable() const override;
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc index 2eab605a..53766f81 100644 --- a/ui/gl/gl_surface_glx.cc +++ b/ui/gl/gl_surface_glx.cc
@@ -266,8 +266,7 @@ } } - void GetVSyncParameters( - const gfx::VSyncProvider::UpdateVSyncCallback& callback) { + void GetVSyncParameters(gfx::VSyncProvider::UpdateVSyncCallback callback) { base::TimeTicks now; { // Don't allow |window_| destruction while we're probing vsync. @@ -291,8 +290,8 @@ const base::TimeDelta kDefaultInterval = base::TimeDelta::FromSeconds(1) / 60; - task_runner_->PostTask(FROM_HERE, - base::BindOnce(callback, now, kDefaultInterval)); + task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), now, kDefaultInterval)); } private: @@ -344,11 +343,11 @@ } void GetVSyncParameters( - const gfx::VSyncProvider::UpdateVSyncCallback& callback) override { + gfx::VSyncProvider::UpdateVSyncCallback callback) override { // Only one outstanding request per surface. if (!pending_callback_) { DCHECK(callback); - pending_callback_ = callback; + pending_callback_ = std::move(callback); vsync_thread_->task_runner()->PostTask( FROM_HERE, base::BindOnce(&SGIVideoSyncProviderThreadShim::GetVSyncParameters,
diff --git a/ui/gl/sync_control_vsync_provider.cc b/ui/gl/sync_control_vsync_provider.cc index 2b94e43a..6e49834 100644 --- a/ui/gl/sync_control_vsync_provider.cc +++ b/ui/gl/sync_control_vsync_provider.cc
@@ -37,11 +37,11 @@ SyncControlVSyncProvider::~SyncControlVSyncProvider() {} void SyncControlVSyncProvider::GetVSyncParameters( - const UpdateVSyncCallback& callback) { + UpdateVSyncCallback callback) { base::TimeTicks timebase; base::TimeDelta interval; if (GetVSyncParametersIfAvailable(&timebase, &interval)) - callback.Run(timebase, interval); + std::move(callback).Run(timebase, interval); } bool SyncControlVSyncProvider::GetVSyncParametersIfAvailable(
diff --git a/ui/gl/sync_control_vsync_provider.h b/ui/gl/sync_control_vsync_provider.h index 735d7ee..d958a2b2 100644 --- a/ui/gl/sync_control_vsync_provider.h +++ b/ui/gl/sync_control_vsync_provider.h
@@ -20,7 +20,7 @@ SyncControlVSyncProvider(); ~SyncControlVSyncProvider() override; - void GetVSyncParameters(const UpdateVSyncCallback& callback) override; + void GetVSyncParameters(UpdateVSyncCallback callback) override; bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase, base::TimeDelta* interval) override; bool SupportGetVSyncParametersIfAvailable() const override;
diff --git a/ui/gl/vsync_provider_win.cc b/ui/gl/vsync_provider_win.cc index 34dc0077..918c0d1 100644 --- a/ui/gl/vsync_provider_win.cc +++ b/ui/gl/vsync_provider_win.cc
@@ -29,11 +29,11 @@ ::LoadLibrary(L"dwmapi.dll"); } -void VSyncProviderWin::GetVSyncParameters(const UpdateVSyncCallback& callback) { +void VSyncProviderWin::GetVSyncParameters(UpdateVSyncCallback callback) { base::TimeTicks timebase; base::TimeDelta interval; if (GetVSyncParametersIfAvailable(&timebase, &interval)) - callback.Run(timebase, interval); + std::move(callback).Run(timebase, interval); } bool VSyncProviderWin::GetVSyncParametersIfAvailable(
diff --git a/ui/gl/vsync_provider_win.h b/ui/gl/vsync_provider_win.h index 3ee9a29..00b1ef2e 100644 --- a/ui/gl/vsync_provider_win.h +++ b/ui/gl/vsync_provider_win.h
@@ -19,7 +19,7 @@ static void InitializeOneOff(); // gfx::VSyncProvider overrides; - void GetVSyncParameters(const UpdateVSyncCallback& callback) override; + void GetVSyncParameters(UpdateVSyncCallback callback) override; bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase, base::TimeDelta* interval) override; bool SupportGetVSyncParametersIfAvailable() const override;
diff --git a/ui/keyboard/public/keyboard_switches.cc b/ui/keyboard/public/keyboard_switches.cc index f99e8e95..261acac 100644 --- a/ui/keyboard/public/keyboard_switches.cc +++ b/ui/keyboard/public/keyboard_switches.cc
@@ -10,7 +10,6 @@ const char kDisableInputView[] = "disable-input-view"; const char kDisableVoiceInput[] = "disable-voice-input"; const char kDisableGestureTyping[] = "disable-gesture-typing"; -const char kDisableGestureEditing[] = "disable-gesture-editing"; const char kEnableVirtualKeyboard[] = "enable-virtual-keyboard"; const char kDisableVirtualKeyboardOverscroll[] = "disable-virtual-keyboard-overscroll";
diff --git a/ui/keyboard/public/keyboard_switches.h b/ui/keyboard/public/keyboard_switches.h index ae172d5..a2ac6b7 100644 --- a/ui/keyboard/public/keyboard_switches.h +++ b/ui/keyboard/public/keyboard_switches.h
@@ -20,10 +20,6 @@ // Flag which disables gesture typing for the virtual keyboard. KEYBOARD_EXPORT extern const char kDisableGestureTyping[]; -// Controls the appearance of the settings option to enable gesture editing -// for the virtual keyboard. -KEYBOARD_EXPORT extern const char kDisableGestureEditing[]; - // Enables the virtual keyboard. KEYBOARD_EXPORT extern const char kEnableVirtualKeyboard[];
diff --git a/ui/login/account_picker/md_screen_account_picker.css b/ui/login/account_picker/chromeos_screen_account_picker.css similarity index 100% rename from ui/login/account_picker/md_screen_account_picker.css rename to ui/login/account_picker/chromeos_screen_account_picker.css
diff --git a/ui/login/account_picker/md_screen_account_picker.html b/ui/login/account_picker/chromeos_screen_account_picker.html similarity index 100% rename from ui/login/account_picker/md_screen_account_picker.html rename to ui/login/account_picker/chromeos_screen_account_picker.html
diff --git a/ui/login/account_picker/md_screen_account_picker.js b/ui/login/account_picker/chromeos_screen_account_picker.js similarity index 99% rename from ui/login/account_picker/md_screen_account_picker.js rename to ui/login/account_picker/chromeos_screen_account_picker.js index 58f36a968..931b0d8 100644 --- a/ui/login/account_picker/md_screen_account_picker.js +++ b/ui/login/account_picker/chromeos_screen_account_picker.js
@@ -388,7 +388,7 @@ * Sets the authentication type used to authenticate the user. * @param {string} username Username of selected user * @param {number} authType Authentication type, must be a valid value in - * the AUTH_TYPE enum in user_pod_row.js. + * the AUTH_TYPE enum in chromeos_user_pod_row.js. * @param {string} value The initial value to use for authentication. */ setAuthType: function(username, authType, value) {
diff --git a/ui/login/account_picker/md_user_pod_row.css b/ui/login/account_picker/chromeos_user_pod_row.css similarity index 100% rename from ui/login/account_picker/md_user_pod_row.css rename to ui/login/account_picker/chromeos_user_pod_row.css
diff --git a/ui/login/account_picker/md_user_pod_row.js b/ui/login/account_picker/chromeos_user_pod_row.js similarity index 100% rename from ui/login/account_picker/md_user_pod_row.js rename to ui/login/account_picker/chromeos_user_pod_row.js
diff --git a/ui/login/account_picker/md_user_pod_template.css b/ui/login/account_picker/chromeos_user_pod_template.css similarity index 96% rename from ui/login/account_picker/md_user_pod_template.css rename to ui/login/account_picker/chromeos_user_pod_template.css index 9679433..83bc20f 100644 --- a/ui/login/account_picker/md_user_pod_template.css +++ b/ui/login/account_picker/chromeos_user_pod_template.css
@@ -3,7 +3,7 @@ * found in the LICENSE file. * * This is the stylesheet imported into the style module in - * user_pod_template.html. + * chromeos_user_pod_template.html. */ .action-box-remove-user-warning .remove-warning-button {
diff --git a/ui/login/account_picker/md_user_pod_template.html b/ui/login/account_picker/chromeos_user_pod_template.html similarity index 99% rename from ui/login/account_picker/md_user_pod_template.html rename to ui/login/account_picker/chromeos_user_pod_template.html index 2ce17750..0161e8d 100644 --- a/ui/login/account_picker/md_user_pod_template.html +++ b/ui/login/account_picker/chromeos_user_pod_template.html
@@ -1,6 +1,6 @@ <dom-module id="user-pod-template-shared-styles"> <template> - <link rel="stylesheet" href="md_user_pod_template.css"> + <link rel="stylesheet" href="chromeos_user_pod_template.css"> </template> </dom-module>