| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/performance_manager/public/resource_attribution/process_context.h" |
| |
| #include <memory> |
| #include <optional> |
| |
| #include "base/memory/weak_ptr.h" |
| #include "components/performance_manager/public/graph/process_node.h" |
| #include "components/performance_manager/public/performance_manager.h" |
| #include "components/performance_manager/public/render_process_host_id.h" |
| #include "components/performance_manager/resource_attribution/performance_manager_aliases.h" |
| #include "components/performance_manager/test_support/performance_manager_test_harness.h" |
| #include "components/performance_manager/test_support/test_browser_child_process.h" |
| #include "content/public/browser/browser_child_process_host.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/process_type.h" |
| #include "content/public/test/navigation_simulator.h" |
| #include "content/public/test/test_renderer_host.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace resource_attribution { |
| |
| namespace { |
| |
| using TestBrowserChildProcess = performance_manager::TestBrowserChildProcess; |
| |
| using ResourceAttrProcessContextTest = |
| performance_manager::PerformanceManagerTestHarness; |
| using ResourceAttrProcessContextNoPMTest = content::RenderViewHostTestHarness; |
| |
| TEST_F(ResourceAttrProcessContextTest, BrowserProcessContext) { |
| // PerformanceManager creates a browser ProcessNode when the test harness |
| // initializes it. |
| const std::optional<ProcessContext> process_context = |
| ProcessContext::FromBrowserProcess(); |
| ASSERT_TRUE(process_context.has_value()); |
| EXPECT_TRUE(process_context->IsBrowserProcessContext()); |
| |
| EXPECT_FALSE(process_context->IsRenderProcessContext()); |
| EXPECT_EQ(nullptr, process_context->GetRenderProcessHost()); |
| EXPECT_TRUE(process_context->GetRenderProcessHostId().is_null()); |
| EXPECT_FALSE(process_context->IsBrowserChildProcessContext()); |
| EXPECT_EQ(nullptr, process_context->GetBrowserChildProcessHost()); |
| EXPECT_TRUE(process_context->GetBrowserChildProcessHostId().is_null()); |
| |
| base::WeakPtr<ProcessNode> process_node = |
| process_context->GetWeakProcessNode(); |
| base::WeakPtr<ProcessNode> process_node_from_pm = |
| PerformanceManager::GetProcessNodeForBrowserProcess(); |
| |
| ASSERT_TRUE(process_node); |
| ASSERT_TRUE(process_node_from_pm); |
| EXPECT_EQ(process_node.get(), process_node_from_pm.get()); |
| |
| EXPECT_EQ(process_node.get(), process_context->GetProcessNode()); |
| EXPECT_EQ(process_context.value(), process_node->GetResourceContext()); |
| EXPECT_EQ(process_context.value(), |
| ProcessContext::FromProcessNode(process_node.get())); |
| EXPECT_EQ(process_context.value(), |
| ProcessContext::FromWeakProcessNode(process_node)); |
| |
| performance_manager::DeleteBrowserProcessNodeForTesting(); |
| |
| EXPECT_TRUE(process_context->IsBrowserProcessContext()); |
| EXPECT_FALSE(process_node); |
| EXPECT_EQ(nullptr, process_context->GetProcessNode()); |
| EXPECT_EQ(std::nullopt, ProcessContext::FromWeakProcessNode(process_node)); |
| } |
| |
| TEST_F(ResourceAttrProcessContextTest, RenderProcessContext) { |
| std::unique_ptr<content::WebContents> web_contents = CreateTestWebContents(); |
| |
| // Navigate to an initial page to create a renderer process. |
| content::RenderFrameHost* rfh = |
| content::NavigationSimulator::NavigateAndCommitFromBrowser( |
| web_contents.get(), GURL("https://a.com/")); |
| ASSERT_TRUE(rfh); |
| content::RenderProcessHost* rph = rfh->GetProcess(); |
| ASSERT_TRUE(rph); |
| const RenderProcessHostId rph_id = rph->GetID(); |
| std::optional<ProcessContext> process_context = |
| ProcessContext::FromRenderProcessHost(rph); |
| ASSERT_TRUE(process_context.has_value()); |
| EXPECT_TRUE(process_context->IsRenderProcessContext()); |
| EXPECT_EQ(rph, process_context->GetRenderProcessHost()); |
| EXPECT_EQ(rph_id, process_context->GetRenderProcessHostId()); |
| |
| EXPECT_FALSE(process_context->IsBrowserProcessContext()); |
| EXPECT_FALSE(process_context->IsBrowserChildProcessContext()); |
| EXPECT_EQ(nullptr, process_context->GetBrowserChildProcessHost()); |
| EXPECT_TRUE(process_context->GetBrowserChildProcessHostId().is_null()); |
| |
| base::WeakPtr<ProcessNode> process_node = |
| process_context->GetWeakProcessNode(); |
| base::WeakPtr<ProcessNode> process_node_from_pm = |
| PerformanceManager::GetProcessNodeForRenderProcessHost(rph); |
| |
| ASSERT_TRUE(process_node); |
| ASSERT_TRUE(process_node_from_pm); |
| EXPECT_EQ(process_node.get(), process_node_from_pm.get()); |
| |
| EXPECT_EQ(process_node.get(), process_context->GetProcessNode()); |
| EXPECT_EQ(process_context.value(), process_node->GetResourceContext()); |
| EXPECT_EQ(process_context.value(), |
| ProcessContext::FromProcessNode(process_node.get())); |
| EXPECT_EQ(process_context.value(), |
| ProcessContext::FromWeakProcessNode(process_node)); |
| |
| // Make sure a second process gets a different context. |
| std::unique_ptr<content::WebContents> web_contents2 = CreateTestWebContents(); |
| content::RenderFrameHost* rfh2 = |
| content::NavigationSimulator::NavigateAndCommitFromBrowser( |
| web_contents2.get(), GURL("https://b.com/")); |
| ASSERT_TRUE(rfh2); |
| content::RenderProcessHost* rph2 = rfh2->GetProcess(); |
| ASSERT_TRUE(rph2); |
| EXPECT_NE(rph, rph2); |
| std::optional<ProcessContext> process_context2 = |
| ProcessContext::FromRenderProcessHost(rph2); |
| EXPECT_TRUE(process_context2.has_value()); |
| EXPECT_NE(process_context2, process_context); |
| |
| web_contents.reset(); |
| |
| EXPECT_EQ(std::nullopt, ProcessContext::FromRenderProcessHost(rph)); |
| EXPECT_TRUE(process_context->IsRenderProcessContext()); |
| EXPECT_EQ(nullptr, process_context->GetRenderProcessHost()); |
| EXPECT_EQ(rph_id, process_context->GetRenderProcessHostId()); |
| |
| EXPECT_FALSE(process_node); |
| EXPECT_EQ(nullptr, process_context->GetProcessNode()); |
| EXPECT_EQ(std::nullopt, ProcessContext::FromWeakProcessNode(process_node)); |
| } |
| |
| TEST_F(ResourceAttrProcessContextTest, BrowserChildProcessContext) { |
| auto utility_process = |
| std::make_unique<TestBrowserChildProcess>(content::PROCESS_TYPE_UTILITY); |
| utility_process->SimulateLaunch(); |
| |
| std::optional<ProcessContext> process_context = |
| ProcessContext::FromBrowserChildProcessHost(utility_process->host()); |
| ASSERT_TRUE(process_context.has_value()); |
| EXPECT_TRUE(process_context->IsBrowserChildProcessContext()); |
| EXPECT_EQ(utility_process->host(), |
| process_context->GetBrowserChildProcessHost()); |
| EXPECT_EQ(utility_process->GetId(), |
| process_context->GetBrowserChildProcessHostId()); |
| |
| EXPECT_FALSE(process_context->IsBrowserProcessContext()); |
| EXPECT_FALSE(process_context->IsRenderProcessContext()); |
| EXPECT_EQ(nullptr, process_context->GetRenderProcessHost()); |
| EXPECT_TRUE(process_context->GetRenderProcessHostId().is_null()); |
| |
| base::WeakPtr<ProcessNode> process_node = |
| process_context->GetWeakProcessNode(); |
| base::WeakPtr<ProcessNode> process_node_from_pm = |
| PerformanceManager::GetProcessNodeForBrowserChildProcessHost( |
| utility_process->host()); |
| |
| ASSERT_TRUE(process_node); |
| ASSERT_TRUE(process_node_from_pm); |
| EXPECT_EQ(process_node.get(), process_node_from_pm.get()); |
| |
| EXPECT_EQ(process_node.get(), process_context->GetProcessNode()); |
| EXPECT_EQ(process_context.value(), process_node->GetResourceContext()); |
| EXPECT_EQ(process_context.value(), |
| ProcessContext::FromProcessNode(process_node.get())); |
| EXPECT_EQ(process_context.value(), |
| ProcessContext::FromWeakProcessNode(process_node)); |
| |
| // Make sure a second process gets a different context. |
| TestBrowserChildProcess gpu_process(content::PROCESS_TYPE_GPU); |
| gpu_process.SimulateLaunch(); |
| std::optional<ProcessContext> process_context2 = |
| ProcessContext::FromBrowserChildProcessHost(gpu_process.host()); |
| EXPECT_TRUE(process_context2.has_value()); |
| EXPECT_NE(process_context2, process_context); |
| |
| const BrowserChildProcessHostId utility_id = utility_process->GetId(); |
| utility_process.reset(); |
| |
| EXPECT_TRUE(process_context->IsBrowserChildProcessContext()); |
| EXPECT_EQ(nullptr, process_context->GetBrowserChildProcessHost()); |
| EXPECT_EQ(utility_id, process_context->GetBrowserChildProcessHostId()); |
| |
| EXPECT_FALSE(process_node); |
| EXPECT_EQ(nullptr, process_context->GetProcessNode()); |
| EXPECT_EQ(std::nullopt, ProcessContext::FromWeakProcessNode(process_node)); |
| } |
| |
| TEST_F(ResourceAttrProcessContextNoPMTest, ProcessContextWithoutPM) { |
| // When PerformanceManager isn't initialized, factory functions should return |
| // nullopt, not a context that's missing PM info. |
| EXPECT_EQ(std::nullopt, ProcessContext::FromBrowserProcess()); |
| |
| // Navigate to an initial page to create a renderer process. |
| std::unique_ptr<content::WebContents> web_contents = CreateTestWebContents(); |
| content::RenderFrameHost* rfh = |
| content::NavigationSimulator::NavigateAndCommitFromBrowser( |
| web_contents.get(), GURL("https://a.com/")); |
| ASSERT_TRUE(rfh); |
| content::RenderProcessHost* rph = rfh->GetProcess(); |
| ASSERT_TRUE(rph); |
| EXPECT_EQ(std::nullopt, ProcessContext::FromRenderProcessHost(rph)); |
| |
| TestBrowserChildProcess utility_process(content::PROCESS_TYPE_UTILITY); |
| EXPECT_EQ(std::nullopt, ProcessContext::FromBrowserChildProcessHost( |
| utility_process.host())); |
| } |
| |
| } // namespace |
| |
| } // namespace resource_attribution |