123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/performance_manager/v8_memory/web_memory_impl.h"
- #include <memory>
- #include <string>
- #include <utility>
- #include "base/containers/flat_map.h"
- #include "base/memory/weak_ptr.h"
- #include "base/run_loop.h"
- #include "base/test/bind.h"
- #include "base/test/task_environment.h"
- #include "base/time/time.h"
- #include "components/performance_manager/graph/frame_node_impl.h"
- #include "components/performance_manager/public/graph/frame_node.h"
- #include "components/performance_manager/public/mojom/web_memory.mojom.h"
- #include "components/performance_manager/public/performance_manager.h"
- #include "components/performance_manager/public/v8_memory/v8_detailed_memory.h"
- #include "components/performance_manager/public/v8_memory/web_memory.h"
- #include "components/performance_manager/v8_memory/v8_memory_test_helpers.h"
- #include "content/public/browser/render_frame_host.h"
- #include "content/public/test/test_renderer_host.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/blink/public/common/tokens/tokens.h"
- namespace performance_manager {
- namespace v8_memory {
- using WebMemoryImplPMTest = V8MemoryPerformanceManagerTestHarness;
- class WebMemoryImplTest : public WebMemoryTestHarness {
- protected:
- void MeasureAndVerify(FrameNodeImpl* frame,
- base::flat_map<std::string, Bytes> expected);
- };
- class FakeSecurityChecker : public WebMeasureMemorySecurityChecker {
- public:
- explicit FakeSecurityChecker(bool allowed) : allowed_(allowed) {}
- void CheckMeasureMemoryIsAllowed(
- const FrameNode* frame_node,
- MeasureMemoryCallback measure_memory_callback,
- mojo::ReportBadMessageCallback bad_message_callback) const override {
- if (allowed_) {
- std::move(measure_memory_callback)
- .Run(FrameNodeImpl::FromNode(frame_node)->GetWeakPtr());
- } else {
- std::move(bad_message_callback).Run("disallowed");
- }
- }
- private:
- bool allowed_;
- };
- void WebMemoryImplTest::MeasureAndVerify(
- FrameNodeImpl* frame,
- base::flat_map<std::string, Bytes> expected) {
- bool measurement_done = false;
- WebMemoryMeasurer web_memory(
- frame->frame_token(), V8DetailedMemoryRequest::MeasurementMode::kDefault,
- base::BindLambdaForTesting([&measurement_done, &expected](
- mojom::WebMemoryMeasurementPtr result) {
- base::flat_map<std::string, Bytes> actual;
- for (const auto& entry : result->breakdown) {
- EXPECT_EQ(1u, entry->attribution.size());
- std::string attribution_tag =
- (mojom::WebMemoryAttribution::Scope::kWindow ==
- entry->attribution[0]->scope)
- ? *entry->attribution[0]->url
- : *entry->attribution[0]->src;
- actual[attribution_tag] =
- entry->memory ? Bytes{entry->memory->bytes} : absl::nullopt;
- }
- EXPECT_EQ(expected, actual);
- measurement_done = true;
- }));
- V8DetailedMemoryProcessData process_data;
- web_memory.MeasurementComplete(process_node(), &process_data);
- EXPECT_TRUE(measurement_done);
- }
- TEST_F(WebMemoryImplTest, MeasurerIncludesSameOriginRelatedFrames) {
- auto* main = AddFrameNode("http://foo.com/", Bytes{10u});
- AddFrameNode("http://foo.com/iframe", Bytes{20}, main);
- MeasureAndVerify(main, {
- {"http://foo.com/", Bytes{10u}},
- {"http://foo.com/iframe", Bytes{20u}},
- });
- }
- TEST_F(WebMemoryImplTest, MeasurerIncludesCrossOriginFrames) {
- auto* main = AddFrameNode("http://foo.com", Bytes{10u});
- AddFrameNode("http://bar.com/iframe", Bytes{20}, main, "bar_id",
- "http://bar.com/iframe_src");
- MeasureAndVerify(main, {{"http://foo.com/", Bytes{10u}},
- {
- "http://bar.com/iframe_src",
- Bytes{20},
- }});
- }
- TEST_F(WebMemoryImplTest, MeasurerSkipsCrossBrowserContextGroupFrames) {
- auto* main = AddFrameNode("http://foo.com", Bytes{10u});
- AddCrossBrowsingInstanceFrameNode("http://foo.com/unrelated", Bytes{20});
- MeasureAndVerify(main, {{"http://foo.com/", Bytes{10u}}});
- }
- TEST_F(WebMemoryImplPMTest, WebMeasureMemory) {
- blink::LocalFrameToken frame_token =
- blink::LocalFrameToken(main_frame()->GetFrameToken());
- // Call WebMeasureMemory on the performance manager sequence and verify that
- // the result matches the data provided by the mock reporter.
- base::RunLoop run_loop;
- auto measurement_callback =
- base::BindLambdaForTesting([&](mojom::WebMemoryMeasurementPtr result) {
- EXPECT_EQ(1u, result->breakdown.size());
- const auto& entry = result->breakdown[0];
- EXPECT_EQ(1u, entry->attribution.size());
- EXPECT_EQ(kMainFrameUrl, *(entry->attribution[0]->url));
- ASSERT_TRUE(entry->memory);
- EXPECT_EQ(1001u, entry->memory->bytes);
- run_loop.Quit();
- });
- auto bad_message_callback =
- base::BindLambdaForTesting([&](base::StringPiece error) {
- ADD_FAILURE() << error;
- run_loop.Quit();
- });
- base::WeakPtr<FrameNode> frame_node_wrapper =
- PerformanceManager::GetFrameNodeForRenderFrameHost(main_frame());
- PerformanceManager::CallOnGraph(
- FROM_HERE, base::BindLambdaForTesting([&]() {
- ASSERT_TRUE(frame_node_wrapper);
- FrameNode* frame_node = frame_node_wrapper.get();
- WebMeasureMemory(
- frame_node, mojom::WebMemoryMeasurement::Mode::kDefault,
- std::make_unique<FakeSecurityChecker>(true),
- std::move(measurement_callback), std::move(bad_message_callback));
- }));
- // Set up and bind the mock reporter.
- MockV8DetailedMemoryReporter mock_reporter;
- {
- auto data = NewPerProcessV8MemoryUsage(1);
- AddIsolateMemoryUsage(frame_token, 1001u, data->isolates[0].get());
- ExpectBindAndRespondToQuery(&mock_reporter, std::move(data),
- main_process_id());
- }
- // Finally, run all tasks to verify that the memory measurement callback
- // is actually invoked. The test will time out if not.
- run_loop.Run();
- }
- TEST_F(WebMemoryImplPMTest, MeasurementInterrupted) {
- CreateCrossProcessChildFrame();
- blink::LocalFrameToken frame_token =
- blink::LocalFrameToken(child_frame()->GetFrameToken());
- // Call WebMeasureMemory on the performance manager sequence but delete the
- // process being measured before the result arrives.
- auto measurement_callback =
- base::BindOnce([](mojom::WebMemoryMeasurementPtr result) {
- FAIL() << "Measurement callback ran unexpectedly";
- });
- auto bad_message_callback =
- base::BindOnce([](base::StringPiece error) { FAIL() << error; });
- base::WeakPtr<FrameNode> frame_node_wrapper =
- PerformanceManager::GetFrameNodeForRenderFrameHost(child_frame());
- PerformanceManager::CallOnGraph(
- FROM_HERE, base::BindLambdaForTesting([&]() {
- ASSERT_TRUE(frame_node_wrapper);
- FrameNode* frame_node = frame_node_wrapper.get();
- WebMeasureMemory(
- frame_node, mojom::WebMemoryMeasurement::Mode::kDefault,
- std::make_unique<FakeSecurityChecker>(true),
- std::move(measurement_callback), std::move(bad_message_callback));
- }));
- // Set up and bind the mock reporter.
- MockV8DetailedMemoryReporter mock_reporter;
- {
- ::testing::InSequence seq;
- ExpectBindReceiver(&mock_reporter, child_process_id());
- auto data = NewPerProcessV8MemoryUsage(1);
- AddIsolateMemoryUsage(frame_token, 1001u, data->isolates[0].get());
- ExpectQueryAndDelayReply(&mock_reporter, base::Seconds(10),
- std::move(data));
- }
- // Verify that requests are sent but reply is not yet received.
- task_environment()->FastForwardBy(base::Seconds(5));
- ::testing::Mock::VerifyAndClearExpectations(&mock_reporter);
- // Remove the child frame, which will destroy the child process.
- content::RenderFrameHostTester::For(child_frame())->Detach();
- // Advance until the reply is expected to make sure nothing explodes.
- task_environment()->FastForwardBy(base::Seconds(5));
- }
- TEST_F(WebMemoryImplPMTest, MeasurementDisallowed) {
- // Call WebMeasureMemory on the performance manager sequence but expect the
- // mojo ReportBadMessage callback to be called.
- base::RunLoop run_loop;
- auto measurement_callback =
- base::BindLambdaForTesting([&](mojom::WebMemoryMeasurementPtr result) {
- ADD_FAILURE() << "Measurement callback ran unexpectedly.";
- run_loop.Quit();
- });
- auto bad_message_callback =
- base::BindLambdaForTesting([&](base::StringPiece error) {
- SUCCEED() << error;
- run_loop.Quit();
- });
- base::WeakPtr<FrameNode> frame_node_wrapper =
- PerformanceManager::GetFrameNodeForRenderFrameHost(main_frame());
- PerformanceManager::CallOnGraph(
- FROM_HERE, base::BindLambdaForTesting([&]() {
- ASSERT_TRUE(frame_node_wrapper);
- FrameNode* frame_node = frame_node_wrapper.get();
- WebMeasureMemory(
- frame_node, mojom::WebMemoryMeasurement::Mode::kDefault,
- std::make_unique<FakeSecurityChecker>(false),
- std::move(measurement_callback), std::move(bad_message_callback));
- }));
- run_loop.Run();
- }
- } // namespace v8_memory
- } // namespace performance_manager
|