
Creates BrowserTaskEnvironment before TestContentClientInitializer, since the --force-renderer-accessibility uses a BrowserThread from the TestContentClientInitializer constructor. Cq-Include-Trybots: luci.chromium.try:linux-blink-web-tests-force-accessibility-rel Bug: 369650613 Change-Id: I3ab2dcddcb1e8c7c0d055be10358e8b67535f136 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5891334 Commit-Queue: Daniel Cheng <dcheng@chromium.org> Commit-Queue: Joe Mason <joenotcharles@google.com> Auto-Submit: Joe Mason <joenotcharles@google.com> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Cr-Commit-Position: refs/heads/main@{#1360193}
525 lines
22 KiB
C++
525 lines
22 KiB
C++
// Copyright 2013 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "content/renderer/render_thread_impl.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "base/base_switches.h"
|
|
#include "base/command_line.h"
|
|
#include "base/containers/heap_array.h"
|
|
#include "base/debug/leak_annotations.h"
|
|
#include "base/functional/bind.h"
|
|
#include "base/functional/callback.h"
|
|
#include "base/location.h"
|
|
#include "base/memory/discardable_memory.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/memory/read_only_shared_memory_region.h"
|
|
#include "base/memory/structured_shared_memory.h"
|
|
#include "base/metrics/field_trial.h"
|
|
#include "base/run_loop.h"
|
|
#include "base/strings/string_number_conversions.h"
|
|
#include "base/task/sequenced_task_runner.h"
|
|
#include "base/task/single_thread_task_runner.h"
|
|
#include "base/task/thread_pool/thread_pool_instance.h"
|
|
#include "base/test/test_switches.h"
|
|
#include "base/time/time.h"
|
|
#include "cc/base/switches.h"
|
|
#include "content/app/mojo/mojo_init.h"
|
|
#include "content/common/in_process_child_thread_params.h"
|
|
#include "content/common/pseudonymization_salt.h"
|
|
#include "content/public/browser/browser_task_traits.h"
|
|
#include "content/public/browser/browser_thread.h"
|
|
#include "content/public/browser/child_process_host.h"
|
|
#include "content/public/browser/child_process_host_delegate.h"
|
|
#include "content/public/browser/content_browser_client.h"
|
|
#include "content/public/common/content_client.h"
|
|
#include "content/public/common/content_features.h"
|
|
#include "content/public/common/content_switches.h"
|
|
#include "content/public/renderer/content_renderer_client.h"
|
|
#include "content/public/test/browser_task_environment.h"
|
|
#include "content/public/test/browser_test.h"
|
|
#include "content/public/test/content_browser_test.h"
|
|
#include "content/public/test/content_browser_test_utils.h"
|
|
#include "content/public/test/content_test_suite_base.h"
|
|
#include "content/public/test/test_content_client_initializer.h"
|
|
#include "content/public/test/test_launcher.h"
|
|
#include "content/renderer/render_process_impl.h"
|
|
#include "gpu/config/gpu_switches.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
#include "third_party/blink/public/common/performance/performance_scenarios.h"
|
|
#include "third_party/blink/public/platform/platform.h"
|
|
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
|
|
#include "third_party/blink/public/platform/scheduler/test/web_mock_thread_scheduler.h"
|
|
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
|
|
#include "ui/base/ui_base_switches.h"
|
|
|
|
// IPC messages for testing ----------------------------------------------------
|
|
|
|
#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC)
|
|
// TODO(mdempsky): Fix properly by moving into a separate
|
|
// browsertest_message_generator.cc file.
|
|
#undef IPC_IPC_MESSAGE_MACROS_H_
|
|
#undef IPC_MESSAGE_EXTRA
|
|
#define IPC_MESSAGE_IMPL
|
|
#include "ipc/ipc_message_macros.h"
|
|
#include "ipc/ipc_message_start.h"
|
|
#include "ipc/ipc_message_templates_impl.h"
|
|
|
|
#undef IPC_MESSAGE_START
|
|
#define IPC_MESSAGE_START TestMsgStart
|
|
IPC_MESSAGE_CONTROL0(TestMsg_QuitRunLoop)
|
|
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// These tests leak memory, this macro disables the test when under the
|
|
// LeakSanitizer.
|
|
#ifdef LEAK_SANITIZER
|
|
#define WILL_LEAK(NAME) DISABLED_##NAME
|
|
#else
|
|
#define WILL_LEAK(NAME) NAME
|
|
#endif
|
|
|
|
namespace content {
|
|
|
|
// FIXME: It would be great if there was a reusable mock SingleThreadTaskRunner
|
|
class TestTaskCounter : public base::SingleThreadTaskRunner {
|
|
public:
|
|
TestTaskCounter() : count_(0) {}
|
|
|
|
// SingleThreadTaskRunner implementation.
|
|
bool PostDelayedTask(const base::Location&,
|
|
base::OnceClosure,
|
|
base::TimeDelta) override {
|
|
base::AutoLock auto_lock(lock_);
|
|
count_++;
|
|
return true;
|
|
}
|
|
|
|
bool PostNonNestableDelayedTask(const base::Location&,
|
|
base::OnceClosure,
|
|
base::TimeDelta) override {
|
|
base::AutoLock auto_lock(lock_);
|
|
count_++;
|
|
return true;
|
|
}
|
|
|
|
bool RunsTasksInCurrentSequence() const override { return true; }
|
|
|
|
int NumTasksPosted() const {
|
|
base::AutoLock auto_lock(lock_);
|
|
return count_;
|
|
}
|
|
|
|
private:
|
|
~TestTaskCounter() override {}
|
|
|
|
mutable base::Lock lock_;
|
|
int count_;
|
|
};
|
|
|
|
#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC)
|
|
class QuitOnTestMsgFilter : public IPC::MessageFilter {
|
|
public:
|
|
explicit QuitOnTestMsgFilter(base::OnceClosure quit_closure)
|
|
: origin_task_runner_(
|
|
blink::scheduler::GetSequencedTaskRunnerForTesting()),
|
|
quit_closure_(std::move(quit_closure)) {}
|
|
|
|
// IPC::MessageFilter overrides:
|
|
bool OnMessageReceived(const IPC::Message& message) override {
|
|
origin_task_runner_->PostTask(FROM_HERE, std::move(quit_closure_));
|
|
return true;
|
|
}
|
|
|
|
bool GetSupportedMessageClasses(
|
|
std::vector<uint32_t>* supported_message_classes) const override {
|
|
supported_message_classes->push_back(TestMsgStart);
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
~QuitOnTestMsgFilter() override {}
|
|
|
|
scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
|
|
base::OnceClosure quit_closure_;
|
|
};
|
|
#endif
|
|
|
|
class RenderThreadImplBrowserTest : public testing::Test,
|
|
public ChildProcessHostDelegate {
|
|
public:
|
|
RenderThreadImplBrowserTest() {}
|
|
|
|
RenderThreadImplBrowserTest(const RenderThreadImplBrowserTest&) = delete;
|
|
RenderThreadImplBrowserTest& operator=(const RenderThreadImplBrowserTest&) =
|
|
delete;
|
|
|
|
void SetUp() override {
|
|
content_renderer_client_ = std::make_unique<ContentRendererClient>();
|
|
SetRendererClientForTesting(content_renderer_client_.get());
|
|
|
|
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
|
|
GetIOThreadTaskRunner({});
|
|
|
|
InitializeMojo();
|
|
process_host_ =
|
|
ChildProcessHost::Create(this, ChildProcessHost::IpcMode::kNormal);
|
|
process_host_->CreateChannelMojo();
|
|
|
|
CHECK(!process_.get());
|
|
process_ = std::make_unique<RenderProcess>();
|
|
test_task_counter_ = base::MakeRefCounted<TestTaskCounter>();
|
|
|
|
// RenderThreadImpl expects the browser to pass these flags.
|
|
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
|
|
base::CommandLine::StringVector old_argv = cmd->argv();
|
|
|
|
cmd->AppendSwitchASCII(switches::kLang, "en-US");
|
|
|
|
cmd->AppendSwitchASCII(cc::switches::kNumRasterThreads, "1");
|
|
|
|
// To avoid creating a GPU channel to query if
|
|
// accelerated_video_decode is blocklisted on older Android system
|
|
// in RenderThreadImpl::Init().
|
|
cmd->AppendSwitch(switches::kIgnoreGpuBlocklist);
|
|
|
|
ContentTestSuiteBase::InitializeResourceBundle();
|
|
|
|
blink::Platform::InitializeBlink();
|
|
auto main_thread_scheduler =
|
|
blink::scheduler::CreateMockWebMainThreadSchedulerForTests();
|
|
scoped_refptr<base::SingleThreadTaskRunner> test_task_counter(
|
|
test_task_counter_.get());
|
|
|
|
// This handles the --force-fieldtrials flag passed to content_browsertests.
|
|
base::FieldTrialList::CreateTrialsFromString(
|
|
cmd->GetSwitchValueASCII(::switches::kForceFieldTrials));
|
|
thread_ = new RenderThreadImpl(
|
|
InProcessChildThreadParams(io_task_runner,
|
|
&process_host_->GetMojoInvitation().value()),
|
|
/*renderer_client_id=*/1, std::move(main_thread_scheduler));
|
|
cmd->InitFromArgv(old_argv);
|
|
|
|
run_loop_ = std::make_unique<base::RunLoop>();
|
|
#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC)
|
|
test_msg_filter_ = base::MakeRefCounted<QuitOnTestMsgFilter>(
|
|
run_loop_->QuitWhenIdleClosure());
|
|
thread_->AddFilter(test_msg_filter_.get());
|
|
#endif
|
|
|
|
main_thread_scheduler_ =
|
|
static_cast<blink::scheduler::WebMockThreadScheduler*>(
|
|
thread_->GetWebMainThreadScheduler());
|
|
}
|
|
|
|
void TearDown() override {
|
|
SetRendererClientForTesting(nullptr);
|
|
CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
switches::kSingleProcessTests));
|
|
// In a single-process mode, we need to avoid destructing `process_`
|
|
// because it will call _exit(0) and kill the process before the browser
|
|
// side is ready to exit.
|
|
ANNOTATE_LEAKING_OBJECT_PTR(process_.get());
|
|
// TODO(crbug.com/40771960): `StopIOThreadForTesting()` is a stop-gap
|
|
// solution to fix flaky tests (see crbug.com/1126157). The underlying
|
|
// reason for this issue is that the `RenderThreadImpl` created in `SetUp()`
|
|
// above actually shares its main thread with the browser's, which is
|
|
// inconsistent with how in-process renderers work in production and other
|
|
// tests. Despite sharing its main thread with the browser, it still has its
|
|
// own IO thread (owned and created by `ChildProcess`). In these tests, the
|
|
// `BrowserTaskEnvironment` has no idea about this separate renderer IO
|
|
// thread, which can post tasks back to the browser's main thread. During
|
|
// `BrowserTaskEnvironment` shutdown, it CHECK()s that after the threads are
|
|
// stopped and flushed, no other tasks exist on its SequenceManager's task
|
|
// queues. However if we don't stop the IO thread here, then it may continue
|
|
// to post tasks to the `BrowserTaskEnvironment`'s main thread, causing the
|
|
// CHECK() to get hit. We should really fix the above tests to create a
|
|
// `RenderThreadImpl` on its own thread the traditional route, but this fix
|
|
// will work until we have the time to explore that option.
|
|
process_->StopIOThreadForTesting();
|
|
process_.release();
|
|
}
|
|
|
|
// ChildProcessHostDelegate implementation:
|
|
bool OnMessageReceived(const IPC::Message&) override { return true; }
|
|
const base::Process& GetProcess() override { return null_process_; }
|
|
|
|
protected:
|
|
IPC::Sender* sender() { return process_host_.get(); }
|
|
|
|
void SetBackgroundState(base::Process::Priority process_priority) {
|
|
mojom::Renderer* renderer_interface = thread_;
|
|
const mojom::RenderProcessVisibleState visible_state =
|
|
RendererIsHidden() ? mojom::RenderProcessVisibleState::kHidden
|
|
: mojom::RenderProcessVisibleState::kVisible;
|
|
renderer_interface->SetProcessState(process_priority, visible_state);
|
|
}
|
|
|
|
void SetVisibleState(mojom::RenderProcessVisibleState visible_state) {
|
|
mojom::Renderer* renderer_interface = thread_;
|
|
const base::Process::Priority process_priority =
|
|
RendererIsBackgrounded() ? base::Process::Priority::kBestEffort
|
|
: base::Process::Priority::kUserBlocking;
|
|
renderer_interface->SetProcessState(process_priority, visible_state);
|
|
}
|
|
|
|
bool RendererIsBackgrounded() { return thread_->RendererIsBackgrounded(); }
|
|
bool RendererIsHidden() { return thread_->RendererIsHidden(); }
|
|
|
|
scoped_refptr<TestTaskCounter> test_task_counter_;
|
|
|
|
// Must be created before TestContentClientInitializer, since with
|
|
// --force-renderer-accessibility that creates a BrowserAccessibilityStateImpl
|
|
// that uses a browser thread.
|
|
BrowserTaskEnvironment browser_threads_{
|
|
BrowserTaskEnvironment::REAL_IO_THREAD};
|
|
|
|
TestContentClientInitializer content_client_initializer_;
|
|
std::unique_ptr<ContentRendererClient> content_renderer_client_;
|
|
|
|
const base::Process null_process_;
|
|
std::unique_ptr<ChildProcessHost> process_host_;
|
|
|
|
std::unique_ptr<RenderProcess> process_;
|
|
#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC)
|
|
scoped_refptr<QuitOnTestMsgFilter> test_msg_filter_;
|
|
#endif
|
|
|
|
raw_ptr<blink::scheduler::WebMockThreadScheduler> main_thread_scheduler_;
|
|
|
|
// RenderThreadImpl doesn't currently support a proper shutdown sequence
|
|
// and it's okay when we're running in multi-process mode because renderers
|
|
// get killed by the OS. Memory leaks aren't nice but it's test-only.
|
|
raw_ptr<RenderThreadImpl> thread_;
|
|
|
|
std::unique_ptr<base::RunLoop> run_loop_;
|
|
};
|
|
|
|
#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC)
|
|
// Disabled under LeakSanitizer due to memory leaks.
|
|
TEST_F(RenderThreadImplBrowserTest,
|
|
WILL_LEAK(NonResourceDispatchIPCTasksDontGoThroughScheduler)) {
|
|
// This seems to deflake the test on Android.
|
|
browser_threads_.RunIOThreadUntilIdle();
|
|
|
|
// NOTE other than not being a resource message, the actual message is
|
|
// unimportant.
|
|
sender()->Send(new TestMsg_QuitRunLoop());
|
|
|
|
// In-process RenderThreadImpl does not start a browser loop so the random
|
|
// browser seed is never generated. To allow the ChildProcessHost to correctly
|
|
// send a seed to the ChildProcess without hitting a DCHECK, set the seed to
|
|
// an arbitrary non-zero value.
|
|
SetPseudonymizationSalt(0xDEADBEEF);
|
|
|
|
run_loop_->Run();
|
|
|
|
EXPECT_EQ(0, test_task_counter_->NumTasksPosted());
|
|
}
|
|
#endif
|
|
|
|
TEST_F(RenderThreadImplBrowserTest, RendererIsBackgrounded) {
|
|
SetBackgroundState(base::Process::Priority::kBestEffort);
|
|
EXPECT_TRUE(RendererIsBackgrounded());
|
|
|
|
SetBackgroundState(base::Process::Priority::kUserBlocking);
|
|
EXPECT_FALSE(RendererIsBackgrounded());
|
|
}
|
|
|
|
TEST_F(RenderThreadImplBrowserTest, RendererIsHidden) {
|
|
SetVisibleState(mojom::RenderProcessVisibleState::kHidden);
|
|
EXPECT_TRUE(RendererIsHidden());
|
|
|
|
SetVisibleState(mojom::RenderProcessVisibleState::kVisible);
|
|
EXPECT_FALSE(RendererIsHidden());
|
|
}
|
|
|
|
TEST_F(RenderThreadImplBrowserTest, RendererStateTransitionVisible) {
|
|
// Going from an unknown to a visible state should mark the renderer as
|
|
// foregrounded and visible.
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false));
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false));
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
|
|
SetVisibleState(mojom::RenderProcessVisibleState::kVisible);
|
|
testing::Mock::VerifyAndClear(main_thread_scheduler_);
|
|
|
|
// Going from a hidden to a visible state should mark the renderer as visible.
|
|
SetVisibleState(mojom::RenderProcessVisibleState::kHidden);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false));
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
|
|
SetVisibleState(mojom::RenderProcessVisibleState::kVisible);
|
|
testing::Mock::VerifyAndClear(main_thread_scheduler_);
|
|
|
|
// Going from a visible to a hidden state should mark the renderer as hidden.
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true));
|
|
SetVisibleState(mojom::RenderProcessVisibleState::kHidden);
|
|
testing::Mock::VerifyAndClear(main_thread_scheduler_);
|
|
|
|
testing::Mock::AllowLeak(main_thread_scheduler_);
|
|
}
|
|
|
|
TEST_F(RenderThreadImplBrowserTest, RendererStateTransitionHidden) {
|
|
// Going from an unknown to a visible state should mark the renderer as
|
|
// foregrounded and hidden.
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false));
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true));
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
|
|
SetVisibleState(mojom::RenderProcessVisibleState::kHidden);
|
|
testing::Mock::VerifyAndClear(main_thread_scheduler_);
|
|
|
|
testing::Mock::AllowLeak(main_thread_scheduler_);
|
|
}
|
|
|
|
TEST_F(RenderThreadImplBrowserTest, RendererStateTransitionBackgrounded) {
|
|
// Going from an unknown to a backgrounded state should mark the renderer as
|
|
// backgrounded but not hidden.
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true));
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false));
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
|
|
SetBackgroundState(base::Process::Priority::kBestEffort);
|
|
testing::Mock::VerifyAndClear(main_thread_scheduler_);
|
|
|
|
// Going from a backgrounded to a foregrounded state should mark the renderer
|
|
// as foregrounded.
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false));
|
|
SetBackgroundState(base::Process::Priority::kUserBlocking);
|
|
testing::Mock::VerifyAndClear(main_thread_scheduler_);
|
|
|
|
// Going from a foregrounded state to another foregrounded state should not
|
|
// remark the renderer as foregrounded.
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
|
|
SetBackgroundState(base::Process::Priority::kUserVisible);
|
|
testing::Mock::VerifyAndClear(main_thread_scheduler_);
|
|
|
|
// Going from a foregrounded to a backgrounded state should mark the renderer
|
|
// as backgrounded.
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true));
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
|
|
SetBackgroundState(base::Process::Priority::kBestEffort);
|
|
testing::Mock::VerifyAndClear(main_thread_scheduler_);
|
|
|
|
testing::Mock::AllowLeak(main_thread_scheduler_);
|
|
}
|
|
|
|
TEST_F(RenderThreadImplBrowserTest, RendererStateTransitionForegrounded) {
|
|
// Going from an unknown to a foregrounded state should mark the renderer as
|
|
// foregrounded and visible.
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false));
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
|
|
EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false));
|
|
SetBackgroundState(base::Process::Priority::kUserBlocking);
|
|
testing::Mock::VerifyAndClear(main_thread_scheduler_);
|
|
|
|
testing::Mock::AllowLeak(main_thread_scheduler_);
|
|
}
|
|
|
|
TEST_F(RenderThreadImplBrowserTest, TransferSharedMemoryRegions) {
|
|
using blink::performance_scenarios::Scope;
|
|
using blink::performance_scenarios::ScopedReadOnlyScenarioMemory;
|
|
|
|
auto time_memory = base::AtomicSharedMemory<base::TimeTicks>::Create();
|
|
ASSERT_TRUE(time_memory.has_value());
|
|
auto scenario_memory =
|
|
blink::performance_scenarios::SharedScenarioState::Create();
|
|
ASSERT_TRUE(scenario_memory.has_value());
|
|
|
|
// No shared memory regions mapped by default.
|
|
EXPECT_EQ(base::internal::GetSharedLastForegroundTimeForMetricsForTesting(),
|
|
nullptr);
|
|
EXPECT_EQ(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
|
|
Scope::kCurrentProcess),
|
|
nullptr);
|
|
EXPECT_EQ(ScopedReadOnlyScenarioMemory::GetMappingForTesting(Scope::kGlobal),
|
|
nullptr);
|
|
|
|
// Invalid handles should be accepted.
|
|
thread_->TransferSharedMemoryRegions(base::ReadOnlySharedMemoryRegion(),
|
|
base::ReadOnlySharedMemoryRegion(),
|
|
base::ReadOnlySharedMemoryRegion());
|
|
EXPECT_EQ(base::internal::GetSharedLastForegroundTimeForMetricsForTesting(),
|
|
nullptr);
|
|
EXPECT_EQ(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
|
|
Scope::kCurrentProcess),
|
|
nullptr);
|
|
EXPECT_EQ(ScopedReadOnlyScenarioMemory::GetMappingForTesting(Scope::kGlobal),
|
|
nullptr);
|
|
|
|
// SharedLastForegroundTimeForMetrics should never be overwritten after it's
|
|
// set, in case a thread is accessing the memory as it's unmapped. Performance
|
|
// scenario memory can be overwritten since the mapping is refcounted.
|
|
thread_->TransferSharedMemoryRegions(time_memory->DuplicateReadOnlyRegion(),
|
|
base::ReadOnlySharedMemoryRegion(),
|
|
base::ReadOnlySharedMemoryRegion());
|
|
const auto* last_foreground_time_ptr =
|
|
base::internal::GetSharedLastForegroundTimeForMetricsForTesting();
|
|
EXPECT_NE(last_foreground_time_ptr, nullptr);
|
|
EXPECT_EQ(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
|
|
Scope::kCurrentProcess),
|
|
nullptr);
|
|
EXPECT_EQ(ScopedReadOnlyScenarioMemory::GetMappingForTesting(Scope::kGlobal),
|
|
nullptr);
|
|
|
|
thread_->TransferSharedMemoryRegions(
|
|
time_memory->DuplicateReadOnlyRegion(),
|
|
scenario_memory->DuplicateReadOnlyRegion(),
|
|
base::ReadOnlySharedMemoryRegion());
|
|
EXPECT_EQ(base::internal::GetSharedLastForegroundTimeForMetricsForTesting(),
|
|
last_foreground_time_ptr);
|
|
EXPECT_NE(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
|
|
Scope::kCurrentProcess),
|
|
nullptr);
|
|
EXPECT_EQ(ScopedReadOnlyScenarioMemory::GetMappingForTesting(Scope::kGlobal),
|
|
nullptr);
|
|
|
|
thread_->TransferSharedMemoryRegions(
|
|
time_memory->DuplicateReadOnlyRegion(),
|
|
scenario_memory->DuplicateReadOnlyRegion(),
|
|
scenario_memory->DuplicateReadOnlyRegion());
|
|
EXPECT_EQ(base::internal::GetSharedLastForegroundTimeForMetricsForTesting(),
|
|
last_foreground_time_ptr);
|
|
EXPECT_NE(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
|
|
Scope::kCurrentProcess),
|
|
nullptr);
|
|
EXPECT_NE(ScopedReadOnlyScenarioMemory::GetMappingForTesting(Scope::kGlobal),
|
|
nullptr);
|
|
|
|
thread_->TransferSharedMemoryRegions(base::ReadOnlySharedMemoryRegion(),
|
|
base::ReadOnlySharedMemoryRegion(),
|
|
base::ReadOnlySharedMemoryRegion());
|
|
EXPECT_EQ(base::internal::GetSharedLastForegroundTimeForMetricsForTesting(),
|
|
last_foreground_time_ptr);
|
|
EXPECT_EQ(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
|
|
Scope::kCurrentProcess),
|
|
nullptr);
|
|
EXPECT_EQ(ScopedReadOnlyScenarioMemory::GetMappingForTesting(Scope::kGlobal),
|
|
nullptr);
|
|
}
|
|
|
|
} // namespace content
|