1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/test/task_environment.h"
6 #include "services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h"
7 
8 #include "base/bind.h"
9 #include "base/callback_helpers.h"
10 #include "base/memory/ref_counted_memory.h"
11 #include "base/run_loop.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/test/test_io_thread.h"
14 #include "base/test/trace_event_analyzer.h"
15 #include "base/threading/sequenced_task_runner_handle.h"
16 #include "base/trace_event/memory_dump_manager.h"
17 #include "base/trace_event/memory_dump_manager_test_utils.h"
18 #include "base/trace_event/memory_dump_scheduler.h"
19 #include "base/trace_event/memory_infra_background_allowlist.h"
20 #include "base/trace_event/trace_buffer.h"
21 #include "base/trace_event/trace_config.h"
22 #include "base/trace_event/trace_config_memory_test_util.h"
23 #include "base/trace_event/trace_log.h"
24 #include "mojo/public/cpp/bindings/pending_receiver.h"
25 #include "mojo/public/cpp/bindings/pending_remote.h"
26 #include "mojo/public/cpp/bindings/receiver_set.h"
27 #include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 
31 using testing::_;
32 using testing::AnyNumber;
33 using testing::Invoke;
34 using testing::Return;
35 
36 using base::trace_event::MemoryAllocatorDump;
37 using base::trace_event::MemoryDumpArgs;
38 using base::trace_event::MemoryDumpDeterminism;
39 using base::trace_event::MemoryDumpLevelOfDetail;
40 using base::trace_event::MemoryDumpManager;
41 using base::trace_event::MemoryDumpProvider;
42 using base::trace_event::MemoryDumpRequestArgs;
43 using base::trace_event::MemoryDumpScheduler;
44 using base::trace_event::MemoryDumpType;
45 using base::trace_event::ProcessMemoryDump;
46 using base::trace_event::TraceConfig;
47 using base::trace_event::TraceLog;
48 using base::trace_event::TraceResultBuffer;
49 
50 namespace memory_instrumentation {
51 
52 namespace {
53 
54 const char kMDPName[] = "TestDumpProvider";
55 const char* kWhitelistedMDPName = "WhitelistedTestDumpProvider";
56 const char* kBackgroundButNotSummaryWhitelistedMDPName =
57     "BackgroundButNotSummaryWhitelistedTestDumpProvider";
58 const char* const kTestMDPWhitelist[] = {
59     kWhitelistedMDPName, kBackgroundButNotSummaryWhitelistedMDPName, nullptr};
60 
61 // GTest matchers for MemoryDumpRequestArgs arguments.
62 MATCHER(IsDetailedDump, "") {
63   return arg.level_of_detail == MemoryDumpLevelOfDetail::DETAILED;
64 }
65 
66 MATCHER(IsLightDump, "") {
67   return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
68 }
69 
70 MATCHER(IsBackgroundDump, "") {
71   return arg.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND;
72 }
73 
74 // TODO(ssid): This class is replicated in memory_dump_manager_unittest. Move
75 // this to memory_dump_manager_test_utils.h crbug.com/728199.
76 class MockMemoryDumpProvider : public MemoryDumpProvider {
77  public:
78   MOCK_METHOD0(Destructor, void());
79   MOCK_METHOD2(OnMemoryDump,
80                bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
81 
MockMemoryDumpProvider()82   MockMemoryDumpProvider() : enable_mock_destructor(false) {
83     ON_CALL(*this, OnMemoryDump(_, _))
84         .WillByDefault(
85             Invoke([](const MemoryDumpArgs&, ProcessMemoryDump* pmd) -> bool {
86               return true;
87             }));
88   }
89 
~MockMemoryDumpProvider()90   ~MockMemoryDumpProvider() override {
91     if (enable_mock_destructor)
92       Destructor();
93   }
94 
95   bool enable_mock_destructor;
96 };
97 
98 }  // namespace
99 
100 class MemoryTracingIntegrationTest;
101 
102 class MockCoordinator : public mojom::Coordinator {
103  public:
MockCoordinator(MemoryTracingIntegrationTest * client)104   explicit MockCoordinator(MemoryTracingIntegrationTest* client)
105       : client_(client) {}
106 
BindReceiver(mojo::PendingReceiver<mojom::Coordinator> receiver)107   void BindReceiver(mojo::PendingReceiver<mojom::Coordinator> receiver) {
108     receivers_.Add(this, std::move(receiver));
109   }
110 
111   void RequestGlobalMemoryDump(
112       MemoryDumpType dump_type,
113       MemoryDumpLevelOfDetail level_of_detail,
114       MemoryDumpDeterminism determinism,
115       const std::vector<std::string>& allocator_dump_names,
116       RequestGlobalMemoryDumpCallback) override;
117 
RequestGlobalMemoryDumpForPid(base::ProcessId pid,const std::vector<std::string> & allocator_dump_names,RequestGlobalMemoryDumpForPidCallback)118   void RequestGlobalMemoryDumpForPid(
119       base::ProcessId pid,
120       const std::vector<std::string>& allocator_dump_names,
121       RequestGlobalMemoryDumpForPidCallback) override {}
122 
RequestPrivateMemoryFootprint(base::ProcessId pid,RequestPrivateMemoryFootprintCallback)123   void RequestPrivateMemoryFootprint(
124       base::ProcessId pid,
125       RequestPrivateMemoryFootprintCallback) override {}
126 
127   void RequestGlobalMemoryDumpAndAppendToTrace(
128       MemoryDumpType dump_type,
129       MemoryDumpLevelOfDetail level_of_detail,
130       MemoryDumpDeterminism determinism,
131       RequestGlobalMemoryDumpAndAppendToTraceCallback) override;
132 
133  private:
134   mojo::ReceiverSet<mojom::Coordinator> receivers_;
135   MemoryTracingIntegrationTest* client_;
136 };
137 
138 class MemoryTracingIntegrationTest : public testing::Test {
139  public:
SetUp()140   void SetUp() override {
141     task_environment_ =
142         std::make_unique<base::test::SingleThreadTaskEnvironment>();
143     coordinator_ = std::make_unique<MockCoordinator>(this);
144   }
145 
InitializeClientProcess(mojom::ProcessType process_type)146   void InitializeClientProcess(mojom::ProcessType process_type) {
147     mdm_ = MemoryDumpManager::CreateInstanceForTesting();
148     mdm_->set_dumper_registrations_ignored_for_testing(true);
149 
150     mojo::PendingRemote<mojom::Coordinator> coordinator;
151     mojo::PendingRemote<mojom::ClientProcess> process;
152     auto process_receiver = process.InitWithNewPipeAndPassReceiver();
153     coordinator_->BindReceiver(coordinator.InitWithNewPipeAndPassReceiver());
154     client_process_.reset(new ClientProcessImpl(
155         std::move(process_receiver), std::move(coordinator),
156         process_type == mojom::ProcessType::BROWSER,
157         /*initialize_memory_instrumentation=*/false));
158   }
159 
TearDown()160   void TearDown() override {
161     TraceLog::GetInstance()->SetDisabled();
162     mdm_.reset();
163     client_process_.reset();
164     coordinator_.reset();
165     task_environment_.reset();
166     TraceLog::ResetForTesting();
167   }
168 
169   // Blocks the current thread (spinning a nested message loop) until the
170   // memory dump is complete. Returns:
171   // - return value: the |success| from the RequestChromeMemoryDump() callback.
RequestChromeDumpAndWait(MemoryDumpType dump_type,MemoryDumpLevelOfDetail level_of_detail,std::unique_ptr<base::trace_event::ProcessMemoryDump> * result=nullptr)172   bool RequestChromeDumpAndWait(
173       MemoryDumpType dump_type,
174       MemoryDumpLevelOfDetail level_of_detail,
175       std::unique_ptr<base::trace_event::ProcessMemoryDump>* result = nullptr) {
176     base::RunLoop run_loop;
177     bool success = false;
178     uint64_t req_guid = ++guid_counter_;
179     MemoryDumpRequestArgs request_args{req_guid, dump_type, level_of_detail};
180     ClientProcessImpl::RequestChromeMemoryDumpCallback callback =
181         base::BindOnce(
182             [](bool* curried_success, base::OnceClosure curried_quit_closure,
183                std::unique_ptr<base::trace_event::ProcessMemoryDump>*
184                    curried_result,
185                uint64_t curried_expected_guid, bool success, uint64_t dump_guid,
186                std::unique_ptr<base::trace_event::ProcessMemoryDump> result) {
187               EXPECT_EQ(curried_expected_guid, dump_guid);
188               *curried_success = success;
189               if (curried_result)
190                 *curried_result = std::move(result);
191               std::move(curried_quit_closure).Run();
192             },
193             &success, run_loop.QuitClosure(), result, req_guid);
194     client_process_->RequestChromeMemoryDump(request_args, std::move(callback));
195     run_loop.Run();
196     return success;
197   }
198 
RequestChromeDump(MemoryDumpType dump_type,MemoryDumpLevelOfDetail level_of_detail,MemoryDumpDeterminism determinism)199   void RequestChromeDump(MemoryDumpType dump_type,
200                          MemoryDumpLevelOfDetail level_of_detail,
201                          MemoryDumpDeterminism determinism) {
202     uint64_t req_guid = ++guid_counter_;
203     MemoryDumpRequestArgs request_args{req_guid, dump_type, level_of_detail,
204                                        determinism};
205     ClientProcessImpl::RequestChromeMemoryDumpCallback callback =
206         base::BindOnce(
207             [](bool success, uint64_t dump_guid,
208                std::unique_ptr<base::trace_event::ProcessMemoryDump> result) {
209             });
210     client_process_->RequestChromeMemoryDump(request_args, std::move(callback));
211   }
212 
213  protected:
EnableMemoryInfraTracing()214   void EnableMemoryInfraTracing() {
215     TraceLog::GetInstance()->SetEnabled(
216         TraceConfig(MemoryDumpManager::kTraceCategory, ""),
217         TraceLog::RECORDING_MODE);
218   }
219 
EnableMemoryInfraTracingWithTraceConfig(const std::string & trace_config)220   void EnableMemoryInfraTracingWithTraceConfig(
221       const std::string& trace_config) {
222     TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config),
223                                         TraceLog::RECORDING_MODE);
224   }
225 
DisableTracing()226   void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
227 
RegisterDumpProvider(MemoryDumpProvider * mdp,scoped_refptr<base::SingleThreadTaskRunner> task_runner,const MemoryDumpProvider::Options & options,const char * name=kMDPName)228   void RegisterDumpProvider(
229       MemoryDumpProvider* mdp,
230       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
231       const MemoryDumpProvider::Options& options,
232       const char* name = kMDPName) {
233     mdm_->set_dumper_registrations_ignored_for_testing(false);
234     mdm_->RegisterDumpProvider(mdp, name, std::move(task_runner), options);
235     mdm_->set_dumper_registrations_ignored_for_testing(true);
236   }
237 
RegisterDumpProvider(MemoryDumpProvider * mdp,scoped_refptr<base::SingleThreadTaskRunner> task_runner)238   void RegisterDumpProvider(
239       MemoryDumpProvider* mdp,
240       scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
241     RegisterDumpProvider(mdp, task_runner, MemoryDumpProvider::Options());
242   }
243 
IsPeriodicDumpingEnabled() const244   bool IsPeriodicDumpingEnabled() const {
245     return MemoryDumpScheduler::GetInstance()->is_enabled_for_testing();
246   }
247 
248   std::unique_ptr<MemoryDumpManager> mdm_;
249 
250  private:
251   std::unique_ptr<base::test::SingleThreadTaskEnvironment> task_environment_;
252   std::unique_ptr<MockCoordinator> coordinator_;
253   std::unique_ptr<ClientProcessImpl> client_process_;
254   uint64_t guid_counter_ = 0;
255 };
256 
RequestGlobalMemoryDump(MemoryDumpType dump_type,MemoryDumpLevelOfDetail level_of_detail,MemoryDumpDeterminism determinism,const std::vector<std::string> & allocator_dump_names,RequestGlobalMemoryDumpCallback callback)257 void MockCoordinator::RequestGlobalMemoryDump(
258     MemoryDumpType dump_type,
259     MemoryDumpLevelOfDetail level_of_detail,
260     MemoryDumpDeterminism determinism,
261     const std::vector<std::string>& allocator_dump_names,
262     RequestGlobalMemoryDumpCallback callback) {
263   client_->RequestChromeDump(dump_type, level_of_detail, determinism);
264   std::move(callback).Run(true, mojom::GlobalMemoryDumpPtr());
265 }
266 
RequestGlobalMemoryDumpAndAppendToTrace(MemoryDumpType dump_type,MemoryDumpLevelOfDetail level_of_detail,MemoryDumpDeterminism determinism,RequestGlobalMemoryDumpAndAppendToTraceCallback callback)267 void MockCoordinator::RequestGlobalMemoryDumpAndAppendToTrace(
268     MemoryDumpType dump_type,
269     MemoryDumpLevelOfDetail level_of_detail,
270     MemoryDumpDeterminism determinism,
271     RequestGlobalMemoryDumpAndAppendToTraceCallback callback) {
272   client_->RequestChromeDump(dump_type, level_of_detail, determinism);
273   std::move(callback).Run(1, true);
274 }
275 
276 // Checks that is the ClientProcessImpl is initialized after tracing already
277 // began, it will still late-join the party (real use case: startup tracing).
TEST_F(MemoryTracingIntegrationTest,InitializedAfterStartOfTracing)278 TEST_F(MemoryTracingIntegrationTest, InitializedAfterStartOfTracing) {
279   EnableMemoryInfraTracing();
280 
281   // TODO(ssid): Add tests for
282   // MemoryInstrumentation::RequestGlobalDumpAndAppendToTrace to fail gracefully
283   // before creating ClientProcessImpl.
284 
285   // Now late-initialize and check that the CreateProcessDump() completes
286   // successfully.
287   InitializeClientProcess(mojom::ProcessType::RENDERER);
288   MockMemoryDumpProvider mdp;
289   RegisterDumpProvider(&mdp, nullptr, MemoryDumpProvider::Options());
290   EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
291   EXPECT_TRUE(RequestChromeDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
292                                        MemoryDumpLevelOfDetail::DETAILED));
293   DisableTracing();
294 }
295 
296 // Configures periodic dumps with MemoryDumpLevelOfDetail::BACKGROUND triggers
297 // and tests that only BACKGROUND are added to the trace, but not LIGHT or
298 // DETAILED, even if requested explicitly.
TEST_F(MemoryTracingIntegrationTest,TestBackgroundTracingSetup)299 TEST_F(MemoryTracingIntegrationTest, TestBackgroundTracingSetup) {
300   InitializeClientProcess(mojom::ProcessType::BROWSER);
301   base::trace_event::SetDumpProviderAllowlistForTesting(kTestMDPWhitelist);
302   auto mdp = std::make_unique<MockMemoryDumpProvider>();
303   RegisterDumpProvider(&*mdp, nullptr, MemoryDumpProvider::Options(),
304                        kWhitelistedMDPName);
305 
306   base::RunLoop run_loop;
307   auto test_task_runner = base::ThreadTaskRunnerHandle::Get();
308   auto quit_closure = run_loop.QuitClosure();
309 
310   {
311     testing::InSequence sequence;
312     EXPECT_CALL(*mdp, OnMemoryDump(IsBackgroundDump(), _))
313         .Times(3)
314         .WillRepeatedly(Invoke(
315             [](const MemoryDumpArgs&, ProcessMemoryDump*) { return true; }));
316     EXPECT_CALL(*mdp, OnMemoryDump(IsBackgroundDump(), _))
317         .WillOnce(Invoke([test_task_runner, quit_closure](const MemoryDumpArgs&,
318                                                           ProcessMemoryDump*) {
319           test_task_runner->PostTask(FROM_HERE, quit_closure);
320           return true;
321         }));
322     EXPECT_CALL(*mdp, OnMemoryDump(IsBackgroundDump(), _)).Times(AnyNumber());
323   }
324 
325   EnableMemoryInfraTracingWithTraceConfig(
326       base::trace_event::TraceConfigMemoryTestUtil::
327           GetTraceConfig_BackgroundTrigger(1 /* period_ms */));
328 
329   run_loop.Run();
330 
331   // When requesting non-BACKGROUND dumps the MDP will be invoked.
332   EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _));
333   EXPECT_TRUE(RequestChromeDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
334                                        MemoryDumpLevelOfDetail::LIGHT));
335 
336   EXPECT_CALL(*mdp, OnMemoryDump(IsDetailedDump(), _));
337   EXPECT_TRUE(RequestChromeDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
338                                        MemoryDumpLevelOfDetail::DETAILED));
339 
340   ASSERT_TRUE(IsPeriodicDumpingEnabled());
341   DisableTracing();
342   mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdp));
343 }
344 
345 // This test (and the TraceConfigExpectationsWhenIsCoordinator below)
346 // crystallizes the expectations of the chrome://tracing UI and chrome telemetry
347 // w.r.t. periodic dumps in memory-infra, handling gracefully the transition
348 // between the legacy and the new-style (JSON-based) TraceConfig.
TEST_F(MemoryTracingIntegrationTest,TraceConfigExpectations)349 TEST_F(MemoryTracingIntegrationTest, TraceConfigExpectations) {
350   InitializeClientProcess(mojom::ProcessType::RENDERER);
351 
352   // We don't need to create any dump in this test, only check whether the dumps
353   // are requested or not.
354 
355   // Enabling memory-infra in a non-coordinator process should not trigger any
356   // periodic dumps.
357   EnableMemoryInfraTracing();
358   EXPECT_FALSE(IsPeriodicDumpingEnabled());
359   DisableTracing();
360 
361   // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator
362   // process with a fully defined trigger config should NOT enable any periodic
363   // dumps.
364   EnableMemoryInfraTracingWithTraceConfig(
365       base::trace_event::TraceConfigMemoryTestUtil::
366           GetTraceConfig_PeriodicTriggers(1, 5));
367   EXPECT_FALSE(IsPeriodicDumpingEnabled());
368   DisableTracing();
369 }
370 
TEST_F(MemoryTracingIntegrationTest,TraceConfigExpectationsWhenIsCoordinator)371 TEST_F(MemoryTracingIntegrationTest, TraceConfigExpectationsWhenIsCoordinator) {
372   InitializeClientProcess(mojom::ProcessType::BROWSER);
373 
374   // Enabling memory-infra with the legacy TraceConfig (category filter) in
375   // a coordinator process should not enable periodic dumps.
376   EnableMemoryInfraTracing();
377   EXPECT_FALSE(IsPeriodicDumpingEnabled());
378   DisableTracing();
379 
380   // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
381   // process while specifying a "memory_dump_config" section should enable
382   // periodic dumps. This is to preserve the behavior chrome://tracing UI, that
383   // is: ticking memory-infra should dump periodically with an explicit config.
384   EnableMemoryInfraTracingWithTraceConfig(
385       base::trace_event::TraceConfigMemoryTestUtil::
386           GetTraceConfig_PeriodicTriggers(100, 5));
387 
388   EXPECT_TRUE(IsPeriodicDumpingEnabled());
389   DisableTracing();
390 
391   // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
392   // process with an empty "memory_dump_config" should NOT enable periodic
393   // dumps. This is the way telemetry is supposed to use memory-infra with
394   // only explicitly triggered dumps.
395   EnableMemoryInfraTracingWithTraceConfig(
396       base::trace_event::TraceConfigMemoryTestUtil::
397           GetTraceConfig_EmptyTriggers());
398   EXPECT_FALSE(IsPeriodicDumpingEnabled());
399   DisableTracing();
400 }
401 
TEST_F(MemoryTracingIntegrationTest,PeriodicDumpingWithMultipleModes)402 TEST_F(MemoryTracingIntegrationTest, PeriodicDumpingWithMultipleModes) {
403   InitializeClientProcess(mojom::ProcessType::BROWSER);
404 
405   // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
406   // process with a fully defined trigger config should cause periodic dumps to
407   // be performed in the correct order.
408   base::RunLoop run_loop;
409   auto test_task_runner = base::ThreadTaskRunnerHandle::Get();
410   auto quit_closure = run_loop.QuitClosure();
411 
412   const int kHeavyDumpRate = 5;
413   const int kLightDumpPeriodMs = 1;
414   const int kHeavyDumpPeriodMs = kHeavyDumpRate * kLightDumpPeriodMs;
415 
416   // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,...
417   auto mdp = std::make_unique<MockMemoryDumpProvider>();
418   RegisterDumpProvider(&*mdp, nullptr, MemoryDumpProvider::Options(),
419                        kWhitelistedMDPName);
420 
421   testing::InSequence sequence;
422   EXPECT_CALL(*mdp, OnMemoryDump(IsDetailedDump(), _));
423   EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _)).Times(kHeavyDumpRate - 1);
424   EXPECT_CALL(*mdp, OnMemoryDump(IsDetailedDump(), _));
425   EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _)).Times(kHeavyDumpRate - 2);
426   EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _))
427       .WillOnce(Invoke([test_task_runner, quit_closure](const MemoryDumpArgs&,
428                                                         ProcessMemoryDump*) {
429         test_task_runner->PostTask(FROM_HERE, quit_closure);
430         return true;
431       }));
432 
433   // Swallow all the final spurious calls until tracing gets disabled.
434   EXPECT_CALL(*mdp, OnMemoryDump(_, _)).Times(AnyNumber());
435 
436   EnableMemoryInfraTracingWithTraceConfig(
437       base::trace_event::TraceConfigMemoryTestUtil::
438           GetTraceConfig_PeriodicTriggers(kLightDumpPeriodMs,
439                                           kHeavyDumpPeriodMs));
440   run_loop.Run();
441   DisableTracing();
442   mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdp));
443 }
444 
TEST_F(MemoryTracingIntegrationTest,TestWhitelistingMDP)445 TEST_F(MemoryTracingIntegrationTest, TestWhitelistingMDP) {
446   InitializeClientProcess(mojom::ProcessType::RENDERER);
447   base::trace_event::SetDumpProviderAllowlistForTesting(kTestMDPWhitelist);
448   std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider);
449   RegisterDumpProvider(mdp1.get(), nullptr);
450   std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider);
451   RegisterDumpProvider(mdp2.get(), nullptr, MemoryDumpProvider::Options(),
452                        kWhitelistedMDPName);
453 
454   EXPECT_CALL(*mdp1, OnMemoryDump(_, _)).Times(0);
455   EXPECT_CALL(*mdp2, OnMemoryDump(_, _)).Times(1);
456 
457   EnableMemoryInfraTracing();
458   EXPECT_FALSE(IsPeriodicDumpingEnabled());
459   EXPECT_TRUE(RequestChromeDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
460                                        MemoryDumpLevelOfDetail::BACKGROUND));
461   DisableTracing();
462 }
463 
464 // Regression test for https://crbug.com/766274 .
TEST_F(MemoryTracingIntegrationTest,GenerationChangeDoesntReenterMDM)465 TEST_F(MemoryTracingIntegrationTest, GenerationChangeDoesntReenterMDM) {
466   InitializeClientProcess(mojom::ProcessType::RENDERER);
467 
468   // We want the ThreadLocalEventBuffer MDPs to auto-register to repro this bug.
469   mdm_->set_dumper_registrations_ignored_for_testing(false);
470 
471   // Disable any other tracing category, so we are likely to hit the
472   // ThreadLocalEventBuffer in MemoryDumpManager::InbokeOnMemoryDump() first.
473   const std::string kMemoryInfraTracingOnly =
474       std::string("-*,") + MemoryDumpManager::kTraceCategory;
475 
476   auto thread =
477       std::make_unique<base::TestIOThread>(base::TestIOThread::kAutoStart);
478 
479   TraceLog::GetInstance()->SetEnabled(
480       TraceConfig(kMemoryInfraTracingOnly,
481                   base::trace_event::RECORD_UNTIL_FULL),
482       TraceLog::RECORDING_MODE);
483 
484   // Creating a new thread after tracing has started causes the posted
485   // TRACE_EVENT0 to initialize and register a new ThreadLocalEventBuffer.
486   base::RunLoop run_loop;
487   thread->PostTask(
488       FROM_HERE,
489       base::BindOnce(
490           [](scoped_refptr<base::SequencedTaskRunner> main_task_runner,
491              base::OnceClosure quit_closure) {
492             TRACE_EVENT0(MemoryDumpManager::kTraceCategory, "foo");
493             main_task_runner->PostTask(FROM_HERE, std::move(quit_closure));
494           },
495           base::SequencedTaskRunnerHandle::Get(), run_loop.QuitClosure()));
496   run_loop.Run();
497 
498   EXPECT_TRUE(RequestChromeDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
499                                        MemoryDumpLevelOfDetail::DETAILED));
500   DisableTracing();
501 
502   // Now enable tracing again with a different RECORD_ mode. This will cause
503   // a TraceLog generation change. The generation change will be lazily detected
504   // in the |thread|'s ThreadLocalEventBuffer on its next TRACE_EVENT call (or
505   // whatever ends up calling InitializeThreadLocalEventBufferIfSupported()).
506   // The bug here conisted in MemoryDumpManager::InvokeOnMemoryDump() to hit
507   // that (which in turn causes an invalidation of the ThreadLocalEventBuffer)
508   // after having checked that the MDP is valid and having decided to invoke it.
509   TraceLog::GetInstance()->SetEnabled(
510       TraceConfig(kMemoryInfraTracingOnly,
511                   base::trace_event::RECORD_CONTINUOUSLY),
512       TraceLog::RECORDING_MODE);
513   EXPECT_TRUE(RequestChromeDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
514                                        MemoryDumpLevelOfDetail::DETAILED));
515   DisableTracing();
516 }
517 
518 }  // namespace memory_instrumentation
519