// Copyright 2020 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/metrics/content/subprocess_metrics_provider.h" #include #include "base/metrics/histogram.h" #include "base/metrics/persistent_histogram_allocator.h" #include "base/metrics/persistent_memory_allocator.h" #include "content/public/browser/child_process_termination_info.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/shell/browser/shell.h" #include "net/dns/mock_host_resolver.h" namespace metrics { namespace { // Returns a random histogram in Allocator. It hard to know which metric will // not be deprecated and exist after navigation. this will work because we // always pick up a histogram from render process and verify if it is copied to // the global allocator. std::string GetAnyHistogramInAllocator( base::PersistentHistogramAllocator* allocator) { base::PersistentHistogramAllocator::Iterator iter(allocator); std::string histogram_name; if (std::unique_ptr histogram = iter.GetNext()) histogram_name = histogram->histogram_name(); return histogram_name; } bool HasHistogramInAllocator(base::PersistentHistogramAllocator* allocator, const std::string& histogram_name) { base::PersistentHistogramAllocator::Iterator iter(allocator); while (std::unique_ptr histogram = iter.GetNext()) { if (histogram_name == histogram->histogram_name()) return true; } return false; } size_t GetRenderProcessHostCount() { auto it = content::RenderProcessHost::AllHostsIterator(); size_t count = 0; while (!it.IsAtEnd()) { it.Advance(); count++; } return count; } } // namespace class SubprocessMetricsProviderBrowserTest : public content::ContentBrowserTest { public: void CreateSubprocessMetricsProvider() { provider_ = std::make_unique(); } SubprocessMetricsProvider::AllocatorByIdMap& get_allocators_by_id() { return provider_->allocators_by_id_; } base::ScopedMultiSourceObservation& get_scoped_observations() { return provider_->scoped_observations_; } base::PersistentHistogramAllocator* GetMainFrameAllocator() { return get_allocators_by_id().Lookup( shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID()); } void SimulateRenderProcessExit() { provider_->RenderProcessExited( shell()->web_contents()->GetPrimaryMainFrame()->GetProcess(), content::ChildProcessTerminationInfo()); } void SimulateRenderProcessHostDestroyed() { provider_->RenderProcessHostDestroyed( shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()); } protected: void SetUpOnMainThread() override { content::ContentBrowserTest::SetUpOnMainThread(); host_resolver()->AddRule("*", "127.0.0.1"); } void SetUp() override { ASSERT_TRUE(embedded_test_server()->Start()); base::GlobalHistogramAllocator::CreateWithLocalMemory(4 << 20, 0x935DDD43, "BrowserMetrics"); content::ContentBrowserTest::SetUp(); } void TearDown() override { content::ContentBrowserTest::TearDown(); provider_.reset(); } private: std::unique_ptr provider_; }; IN_PROC_BROWSER_TEST_F(SubprocessMetricsProviderBrowserTest, RegisterExistingNotReadyRenderProcesses) { ASSERT_TRUE(GetRenderProcessHostCount() > 0); CreateSubprocessMetricsProvider(); EXPECT_EQ(get_scoped_observations().GetSourcesCount(), GetRenderProcessHostCount()); EXPECT_EQ(get_allocators_by_id().size(), 0u); GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); content::NavigateToURLBlockUntilNavigationsComplete(shell(), url_a, 1); // Verify that the number of scoped observer matches the number of // RenderProcessHost and the main frame allocator exists. EXPECT_EQ(get_scoped_observations().GetSourcesCount(), GetRenderProcessHostCount()); auto* main_frame_allocator = GetMainFrameAllocator(); EXPECT_TRUE(main_frame_allocator); // Verify the render process's allocator have the render process metrics. std::string render_process_histogram = GetAnyHistogramInAllocator(main_frame_allocator); EXPECT_FALSE(render_process_histogram.empty()); // Verify the global histogram allocator have no render process metrics. base::GlobalHistogramAllocator* global_histogram_allocator = base::GlobalHistogramAllocator::Get(); ASSERT_TRUE(global_histogram_allocator); EXPECT_FALSE(HasHistogramInAllocator(global_histogram_allocator, render_process_histogram)) << " The histogram in the context is " << render_process_histogram; SimulateRenderProcessExit(); // Verify the allocator deregistered. EXPECT_FALSE(GetMainFrameAllocator()); // Verify the render process metrics were merged to the global histogram // allocator. EXPECT_TRUE(HasHistogramInAllocator(global_histogram_allocator, render_process_histogram)) << " The histogram in the context is " << render_process_histogram; auto* main_frame_process_host = shell()->web_contents()->GetPrimaryMainFrame()->GetProcess(); SimulateRenderProcessHostDestroyed(); // Verify the observer removed. EXPECT_FALSE( get_scoped_observations().IsObservingSource(main_frame_process_host)); } IN_PROC_BROWSER_TEST_F(SubprocessMetricsProviderBrowserTest, RegisterExistingReadyRenderProcesses) { GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); content::NavigateToURLBlockUntilNavigationsComplete(shell(), url_a, 1); CreateSubprocessMetricsProvider(); // Verify that the number of scoped observer matches the number of // RenderProcessHost and the main frame allocator exists. EXPECT_EQ(get_scoped_observations().GetSourcesCount(), GetRenderProcessHostCount()); auto* main_frame_allocator = GetMainFrameAllocator(); EXPECT_TRUE(main_frame_allocator); // Verify the render process's allocator have the render process metrics. std::string render_process_histogram = GetAnyHistogramInAllocator(main_frame_allocator); EXPECT_FALSE(render_process_histogram.empty()); // Verify the global histogram allocator have no render process metrics. base::GlobalHistogramAllocator* global_histogram_allocator = base::GlobalHistogramAllocator::Get(); ASSERT_TRUE(global_histogram_allocator); EXPECT_FALSE(HasHistogramInAllocator(global_histogram_allocator, render_process_histogram)) << " The histogram in the context is " << render_process_histogram; SimulateRenderProcessExit(); // Verify the allocator deregistered. EXPECT_FALSE(GetMainFrameAllocator()); // Verify the render process metrics were merged to the global histogram // allocator. EXPECT_TRUE(HasHistogramInAllocator(global_histogram_allocator, render_process_histogram)) << " The histogram in the context is " << render_process_histogram; auto* main_frame_process_host = shell()->web_contents()->GetPrimaryMainFrame()->GetProcess(); SimulateRenderProcessHostDestroyed(); // Verify the observer removed. EXPECT_FALSE( get_scoped_observations().IsObservingSource(main_frame_process_host)); } } // namespace metrics