1 // Copyright 2015 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/trace_event/memory_dump_manager.h"
6 
7 #include <stdint.h>
8 
9 #include <memory>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/allocator/buildflags.h"
14 #include "base/base_switches.h"
15 #include "base/bind.h"
16 #include "base/callback.h"
17 #include "base/command_line.h"
18 #include "base/macros.h"
19 #include "base/run_loop.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/synchronization/waitable_event.h"
22 #include "base/task/post_task.h"
23 #include "base/task/thread_pool.h"
24 #include "base/test/task_environment.h"
25 #include "base/test/test_io_thread.h"
26 #include "base/threading/platform_thread.h"
27 #include "base/threading/sequenced_task_runner_handle.h"
28 #include "base/threading/thread.h"
29 #include "base/threading/thread_task_runner_handle.h"
30 #include "base/trace_event/memory_dump_manager_test_utils.h"
31 #include "base/trace_event/memory_dump_provider.h"
32 #include "base/trace_event/memory_dump_request_args.h"
33 #include "base/trace_event/memory_dump_scheduler.h"
34 #include "base/trace_event/memory_infra_background_allowlist.h"
35 #include "base/trace_event/process_memory_dump.h"
36 #include "build/build_config.h"
37 #include "testing/gmock/include/gmock/gmock.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39 
40 using testing::_;
41 using testing::AtMost;
42 using testing::Between;
43 using testing::Invoke;
44 using testing::Return;
45 
46 namespace base {
47 namespace trace_event {
48 
49 // GTest matchers for MemoryDumpRequestArgs arguments.
50 MATCHER(IsDetailedDump, "") {
51   return arg.level_of_detail == MemoryDumpLevelOfDetail::DETAILED;
52 }
53 
54 MATCHER(IsLightDump, "") {
55   return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
56 }
57 
58 MATCHER(IsDeterministicDump, "") {
59   return arg.determinism == MemoryDumpDeterminism::FORCE_GC;
60 }
61 
62 MATCHER(IsNotDeterministicDump, "") {
63   return arg.determinism == MemoryDumpDeterminism::NONE;
64 }
65 
66 namespace {
67 
68 const char* kMDPName = "TestDumpProvider";
69 const char* kWhitelistedMDPName = "WhitelistedTestDumpProvider";
70 const char* const kTestMDPWhitelist[] = {kWhitelistedMDPName, nullptr};
71 
RegisterDumpProvider(MemoryDumpProvider * mdp,scoped_refptr<base::SingleThreadTaskRunner> task_runner,const MemoryDumpProvider::Options & options,const char * name=kMDPName)72 void RegisterDumpProvider(
73     MemoryDumpProvider* mdp,
74     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
75     const MemoryDumpProvider::Options& options,
76     const char* name = kMDPName) {
77   MemoryDumpManager* mdm = MemoryDumpManager::GetInstance();
78   mdm->set_dumper_registrations_ignored_for_testing(false);
79   mdm->RegisterDumpProvider(mdp, name, std::move(task_runner), options);
80   mdm->set_dumper_registrations_ignored_for_testing(true);
81 }
82 
RegisterDumpProvider(MemoryDumpProvider * mdp,scoped_refptr<base::SingleThreadTaskRunner> task_runner)83 void RegisterDumpProvider(
84     MemoryDumpProvider* mdp,
85     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
86   RegisterDumpProvider(mdp, task_runner, MemoryDumpProvider::Options());
87 }
88 
RegisterDumpProviderWithSequencedTaskRunner(MemoryDumpProvider * mdp,scoped_refptr<base::SequencedTaskRunner> task_runner,const MemoryDumpProvider::Options & options)89 void RegisterDumpProviderWithSequencedTaskRunner(
90     MemoryDumpProvider* mdp,
91     scoped_refptr<base::SequencedTaskRunner> task_runner,
92     const MemoryDumpProvider::Options& options) {
93   MemoryDumpManager* mdm = MemoryDumpManager::GetInstance();
94   mdm->set_dumper_registrations_ignored_for_testing(false);
95   mdm->RegisterDumpProviderWithSequencedTaskRunner(mdp, kMDPName, task_runner,
96                                                    options);
97   mdm->set_dumper_registrations_ignored_for_testing(true);
98 }
99 
100 // Posts |task| to |task_runner| and blocks until it is executed.
PostTaskAndWait(const Location & from_here,SequencedTaskRunner * task_runner,base::OnceClosure task)101 void PostTaskAndWait(const Location& from_here,
102                      SequencedTaskRunner* task_runner,
103                      base::OnceClosure task) {
104   base::WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
105                             WaitableEvent::InitialState::NOT_SIGNALED);
106   task_runner->PostTask(from_here, std::move(task));
107   task_runner->PostTask(FROM_HERE, base::BindOnce(&WaitableEvent::Signal,
108                                                   base::Unretained(&event)));
109   // The SequencedTaskRunner guarantees that |event| will only be signaled after
110   // |task| is executed.
111   event.Wait();
112 }
113 
114 class MockMemoryDumpProvider : public MemoryDumpProvider {
115  public:
116   MOCK_METHOD0(Destructor, void());
117   MOCK_METHOD2(OnMemoryDump,
118                bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
119 
MockMemoryDumpProvider()120   MockMemoryDumpProvider() : enable_mock_destructor(false) {
121     ON_CALL(*this, OnMemoryDump(_, _))
122         .WillByDefault(
123             Invoke([](const MemoryDumpArgs&, ProcessMemoryDump* pmd) -> bool {
124               return true;
125             }));
126   }
~MockMemoryDumpProvider()127   ~MockMemoryDumpProvider() override {
128     if (enable_mock_destructor)
129       Destructor();
130   }
131 
132   bool enable_mock_destructor;
133 };
134 
135 class TestSequencedTaskRunner : public SequencedTaskRunner {
136  public:
137   TestSequencedTaskRunner() = default;
138 
set_enabled(bool value)139   void set_enabled(bool value) { enabled_ = value; }
no_of_post_tasks() const140   unsigned no_of_post_tasks() const { return num_of_post_tasks_; }
141 
PostNonNestableDelayedTask(const Location & from_here,OnceClosure task,TimeDelta delay)142   bool PostNonNestableDelayedTask(const Location& from_here,
143                                   OnceClosure task,
144                                   TimeDelta delay) override {
145     NOTREACHED();
146     return false;
147   }
148 
PostDelayedTask(const Location & from_here,OnceClosure task,TimeDelta delay)149   bool PostDelayedTask(const Location& from_here,
150                        OnceClosure task,
151                        TimeDelta delay) override {
152     num_of_post_tasks_++;
153     if (enabled_) {
154       return task_runner_->PostDelayedTask(from_here, std::move(task), delay);
155     }
156     return false;
157   }
158 
RunsTasksInCurrentSequence() const159   bool RunsTasksInCurrentSequence() const override {
160     return task_runner_->RunsTasksInCurrentSequence();
161   }
162 
163  private:
164   ~TestSequencedTaskRunner() override = default;
165 
166   const scoped_refptr<SequencedTaskRunner> task_runner_ =
167       ThreadPool::CreateSequencedTaskRunner({});
168   bool enabled_ = true;
169   unsigned num_of_post_tasks_ = 0;
170 };
171 
172 }  // namespace
173 
174 class MemoryDumpManagerTest : public testing::Test {
175  public:
MemoryDumpManagerTest(bool is_coordinator=false)176   MemoryDumpManagerTest(bool is_coordinator = false)
177       : is_coordinator_(is_coordinator) {}
178 
SetUp()179   void SetUp() override {
180     // Bring up and initialize MemoryDumpManager while single-threaded (before
181     // instantiating TaskEnvironment) to avoid data races if worker
182     // threads use tracing globals early.
183     mdm_ = MemoryDumpManager::CreateInstanceForTesting();
184     ASSERT_EQ(mdm_.get(), MemoryDumpManager::GetInstance());
185 
186     InitializeMemoryDumpManagerForInProcessTesting(is_coordinator_);
187 
188     task_environment_ = std::make_unique<test::TaskEnvironment>();
189   }
190 
TearDown()191   void TearDown() override {
192     task_environment_.reset();
193 
194     // Tear down the MemoryDumpManager while single-threaded to mirror logic in
195     // SetUp().
196     mdm_.reset();
197     TraceLog::ResetForTesting();
198   }
199 
200  protected:
201   // Blocks the current thread (spinning a nested message loop) until the
202   // memory dump is complete. Returns:
203   // - return value: the |success| from the CreateProcessDump() callback.
RequestProcessDumpAndWait(MemoryDumpType dump_type,MemoryDumpLevelOfDetail level_of_detail,MemoryDumpDeterminism determinism)204   bool RequestProcessDumpAndWait(MemoryDumpType dump_type,
205                                  MemoryDumpLevelOfDetail level_of_detail,
206                                  MemoryDumpDeterminism determinism) {
207     RunLoop run_loop;
208     bool success = false;
209     static uint64_t test_guid = 1;
210     test_guid++;
211     MemoryDumpRequestArgs request_args{test_guid, dump_type, level_of_detail,
212                                        determinism};
213 
214     // The signature of the callback delivered by MemoryDumpManager is:
215     // void ProcessMemoryDumpCallback(
216     //     uint64_t dump_guid,
217     //     bool success,
218     //     std::unique_ptr<ProcessMemoryDump> pmd)
219     // The extra arguments prepended to the |callback| below (the ones with the
220     // "curried_" prefix) are just passed from the BindOnce(). This is just to
221     // get around the limitation of BindOnce() in supporting only capture-less
222     // lambdas.
223     ProcessMemoryDumpCallback callback = BindOnce(
224         [](bool* curried_success, OnceClosure curried_quit_closure,
225            uint64_t curried_expected_guid, bool success, uint64_t dump_guid,
226            std::unique_ptr<ProcessMemoryDump> pmd) {
227           *curried_success = success;
228           EXPECT_EQ(curried_expected_guid, dump_guid);
229           ThreadTaskRunnerHandle::Get()->PostTask(
230               FROM_HERE, std::move(curried_quit_closure));
231         },
232         Unretained(&success), run_loop.QuitClosure(), test_guid);
233 
234     mdm_->CreateProcessDump(request_args, std::move(callback));
235     run_loop.Run();
236     return success;
237   }
238 
EnableForTracing()239   void EnableForTracing() {
240     mdm_->SetupForTracing(TraceConfig::MemoryDumpConfig());
241   }
242 
EnableForTracingWithTraceConfig(const std::string trace_config_string)243   void EnableForTracingWithTraceConfig(const std::string trace_config_string) {
244     TraceConfig trace_config(trace_config_string);
245     mdm_->SetupForTracing(trace_config.memory_dump_config());
246   }
247 
DisableTracing()248   void DisableTracing() { mdm_->TeardownForTracing(); }
249 
GetMaxConsecutiveFailuresCount() const250   int GetMaxConsecutiveFailuresCount() const {
251     return MemoryDumpManager::kMaxConsecutiveFailuresCount;
252   }
253 
254   const MemoryDumpProvider::Options kDefaultOptions;
255   std::unique_ptr<MemoryDumpManager> mdm_;
256 
257  private:
258   // To tear down the singleton instance after each test.
259   ShadowingAtExitManager at_exit_manager_;
260 
261   std::unique_ptr<test::TaskEnvironment> task_environment_;
262 
263   // Whether the test MemoryDumpManager should be initialized as the
264   // coordinator.
265   const bool is_coordinator_;
266 
267   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerTest);
268 };
269 
270 class MemoryDumpManagerTestAsCoordinator : public MemoryDumpManagerTest {
271  public:
MemoryDumpManagerTestAsCoordinator()272   MemoryDumpManagerTestAsCoordinator() : MemoryDumpManagerTest(true) {}
273 
274  private:
275   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerTestAsCoordinator);
276 };
277 
278 // Basic sanity checks. Registers a memory dump provider and checks that it is
279 // called.
TEST_F(MemoryDumpManagerTest,SingleDumper)280 TEST_F(MemoryDumpManagerTest, SingleDumper) {
281   MockMemoryDumpProvider mdp;
282   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
283 
284   // Now repeat enabling the memory category and check that the dumper is
285   // invoked this time.
286   EnableForTracing();
287   EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3);
288   for (int i = 0; i < 3; ++i) {
289     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
290                                           MemoryDumpLevelOfDetail::DETAILED,
291                                           MemoryDumpDeterminism::NONE));
292   }
293   DisableTracing();
294 
295   mdm_->UnregisterDumpProvider(&mdp);
296 
297   // Finally check the unregister logic: the global dump handler will be invoked
298   // but not the dump provider, as it has been unregistered.
299   EnableForTracing();
300   EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
301   for (int i = 0; i < 3; ++i) {
302     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
303                                           MemoryDumpLevelOfDetail::DETAILED,
304                                           MemoryDumpDeterminism::NONE));
305   }
306   DisableTracing();
307 }
308 
309 // Checks that requesting dumps with high level of detail actually propagates
310 // the level of the detail properly to OnMemoryDump() call on dump providers.
TEST_F(MemoryDumpManagerTest,CheckMemoryDumpArgs)311 TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
312   MockMemoryDumpProvider mdp;
313 
314   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
315   EnableForTracing();
316   EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _));
317   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
318                                         MemoryDumpLevelOfDetail::DETAILED,
319                                         MemoryDumpDeterminism::NONE));
320   DisableTracing();
321   mdm_->UnregisterDumpProvider(&mdp);
322 
323   // Check that requesting dumps with low level of detail actually propagates to
324   // OnMemoryDump() call on dump providers.
325   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
326   EnableForTracing();
327   EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _));
328   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
329                                         MemoryDumpLevelOfDetail::LIGHT,
330                                         MemoryDumpDeterminism::NONE));
331   DisableTracing();
332   mdm_->UnregisterDumpProvider(&mdp);
333 }
334 
335 // Checks that requesting deterministic dumps actually propagates
336 // the deterministic option properly to OnMemoryDump() call on dump providers.
TEST_F(MemoryDumpManagerTest,CheckMemoryDumpArgsDeterministic)337 TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgsDeterministic) {
338   MockMemoryDumpProvider mdp;
339 
340   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
341   EnableForTracing();
342   EXPECT_CALL(mdp, OnMemoryDump(IsDeterministicDump(), _));
343   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
344                                         MemoryDumpLevelOfDetail::DETAILED,
345                                         MemoryDumpDeterminism::FORCE_GC));
346   DisableTracing();
347   mdm_->UnregisterDumpProvider(&mdp);
348 
349   // Check that requesting dumps with deterministic option set to false
350   // actually propagates to OnMemoryDump() call on dump providers.
351   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
352   EnableForTracing();
353   EXPECT_CALL(mdp, OnMemoryDump(IsNotDeterministicDump(), _));
354   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
355                                         MemoryDumpLevelOfDetail::LIGHT,
356                                         MemoryDumpDeterminism::NONE));
357   DisableTracing();
358   mdm_->UnregisterDumpProvider(&mdp);
359 }
360 
361 // Checks that the (Un)RegisterDumpProvider logic behaves sanely.
TEST_F(MemoryDumpManagerTest,MultipleDumpers)362 TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
363   MockMemoryDumpProvider mdp1;
364   MockMemoryDumpProvider mdp2;
365 
366   // Enable only mdp1.
367   RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
368   EnableForTracing();
369   EXPECT_CALL(mdp1, OnMemoryDump(_, _));
370   EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
371   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
372                                         MemoryDumpLevelOfDetail::DETAILED,
373                                         MemoryDumpDeterminism::NONE));
374   DisableTracing();
375 
376   // Invert: enable mdp2 and disable mdp1.
377   mdm_->UnregisterDumpProvider(&mdp1);
378   RegisterDumpProvider(&mdp2, nullptr);
379   EnableForTracing();
380   EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
381   EXPECT_CALL(mdp2, OnMemoryDump(_, _));
382   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
383                                         MemoryDumpLevelOfDetail::DETAILED,
384                                         MemoryDumpDeterminism::NONE));
385   DisableTracing();
386 
387   // Enable both mdp1 and mdp2.
388   RegisterDumpProvider(&mdp1, nullptr);
389   EnableForTracing();
390   EXPECT_CALL(mdp1, OnMemoryDump(_, _));
391   EXPECT_CALL(mdp2, OnMemoryDump(_, _));
392   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
393                                         MemoryDumpLevelOfDetail::DETAILED,
394                                         MemoryDumpDeterminism::NONE));
395   DisableTracing();
396 }
397 
398 // Checks that the dump provider invocations depend only on the current
399 // registration state and not on previous registrations and dumps.
400 // Flaky on iOS, see crbug.com/706874
401 #if defined(OS_IOS)
402 #define MAYBE_RegistrationConsistency DISABLED_RegistrationConsistency
403 #else
404 #define MAYBE_RegistrationConsistency RegistrationConsistency
405 #endif
TEST_F(MemoryDumpManagerTest,MAYBE_RegistrationConsistency)406 TEST_F(MemoryDumpManagerTest, MAYBE_RegistrationConsistency) {
407   MockMemoryDumpProvider mdp;
408 
409   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
410 
411   {
412     EXPECT_CALL(mdp, OnMemoryDump(_, _));
413     EnableForTracing();
414     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
415                                           MemoryDumpLevelOfDetail::DETAILED,
416                                           MemoryDumpDeterminism::NONE));
417     DisableTracing();
418   }
419 
420   mdm_->UnregisterDumpProvider(&mdp);
421 
422   {
423     EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
424     EnableForTracing();
425     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
426                                           MemoryDumpLevelOfDetail::DETAILED,
427                                           MemoryDumpDeterminism::NONE));
428     DisableTracing();
429   }
430 
431   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
432   mdm_->UnregisterDumpProvider(&mdp);
433 
434   {
435     EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
436     EnableForTracing();
437     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
438                                           MemoryDumpLevelOfDetail::DETAILED,
439                                           MemoryDumpDeterminism::NONE));
440     DisableTracing();
441   }
442 
443   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
444   mdm_->UnregisterDumpProvider(&mdp);
445   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
446 
447   {
448     EXPECT_CALL(mdp, OnMemoryDump(_, _));
449     EnableForTracing();
450     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
451                                           MemoryDumpLevelOfDetail::DETAILED,
452                                           MemoryDumpDeterminism::NONE));
453     DisableTracing();
454   }
455 }
456 
457 // Checks that the MemoryDumpManager respects the thread affinity when a
458 // MemoryDumpProvider specifies a task_runner(). The test starts creating 8
459 // threads and registering a MemoryDumpProvider on each of them. At each
460 // iteration, one thread is removed, to check the live unregistration logic.
TEST_F(MemoryDumpManagerTest,RespectTaskRunnerAffinity)461 TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
462   const uint32_t kNumInitialThreads = 8;
463 
464   std::vector<std::unique_ptr<Thread>> threads;
465   std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps;
466 
467   // Create the threads and setup the expectations. Given that at each iteration
468   // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
469   // invoked a number of times equal to its index.
470   for (uint32_t i = kNumInitialThreads; i > 0; --i) {
471     threads.push_back(std::make_unique<Thread>("test thread"));
472     auto* thread = threads.back().get();
473     thread->Start();
474     scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner();
475     mdps.push_back(std::make_unique<MockMemoryDumpProvider>());
476     auto* mdp = mdps.back().get();
477     RegisterDumpProvider(mdp, task_runner, kDefaultOptions);
478     EXPECT_CALL(*mdp, OnMemoryDump(_, _))
479         .Times(i)
480         .WillRepeatedly(Invoke(
481             [task_runner](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
482               EXPECT_TRUE(task_runner->RunsTasksInCurrentSequence());
483               return true;
484             }));
485   }
486   EnableForTracing();
487 
488   while (!threads.empty()) {
489     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
490                                           MemoryDumpLevelOfDetail::DETAILED,
491                                           MemoryDumpDeterminism::NONE));
492 
493     // Unregister a MDP and destroy one thread at each iteration to check the
494     // live unregistration logic. The unregistration needs to happen on the same
495     // thread the MDP belongs to.
496     {
497       RunLoop run_loop;
498       OnceClosure unregistration =
499           BindOnce(&MemoryDumpManager::UnregisterDumpProvider,
500                    Unretained(mdm_.get()), Unretained(mdps.back().get()));
501       threads.back()->task_runner()->PostTaskAndReply(
502           FROM_HERE, std::move(unregistration), run_loop.QuitClosure());
503       run_loop.Run();
504     }
505     mdps.pop_back();
506     threads.back()->Stop();
507     threads.pop_back();
508   }
509 
510   DisableTracing();
511 }
512 
513 // Check that the memory dump calls are always posted on task runner for
514 // SequencedTaskRunner case and that the dump provider gets disabled when
515 // PostTask fails, but the dump still succeeds.
TEST_F(MemoryDumpManagerTest,PostTaskForSequencedTaskRunner)516 TEST_F(MemoryDumpManagerTest, PostTaskForSequencedTaskRunner) {
517   std::vector<MockMemoryDumpProvider> mdps(3);
518   scoped_refptr<TestSequencedTaskRunner> task_runner1(
519       MakeRefCounted<TestSequencedTaskRunner>());
520   scoped_refptr<TestSequencedTaskRunner> task_runner2(
521       MakeRefCounted<TestSequencedTaskRunner>());
522   RegisterDumpProviderWithSequencedTaskRunner(&mdps[0], task_runner1,
523                                               kDefaultOptions);
524   RegisterDumpProviderWithSequencedTaskRunner(&mdps[1], task_runner2,
525                                               kDefaultOptions);
526   RegisterDumpProviderWithSequencedTaskRunner(&mdps[2], task_runner2,
527                                               kDefaultOptions);
528   // |mdps[0]| should be disabled permanently after first dump.
529   EXPECT_CALL(mdps[0], OnMemoryDump(_, _)).Times(0);
530   EXPECT_CALL(mdps[1], OnMemoryDump(_, _)).Times(2);
531   EXPECT_CALL(mdps[2], OnMemoryDump(_, _)).Times(2);
532 
533   EnableForTracing();
534 
535   task_runner1->set_enabled(false);
536   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
537                                         MemoryDumpLevelOfDetail::DETAILED,
538                                         MemoryDumpDeterminism::NONE));
539   EXPECT_EQ(1u, task_runner1->no_of_post_tasks());
540   EXPECT_EQ(1u, task_runner2->no_of_post_tasks());
541 
542   task_runner1->set_enabled(true);
543   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
544                                         MemoryDumpLevelOfDetail::DETAILED,
545                                         MemoryDumpDeterminism::NONE));
546   EXPECT_EQ(2u, task_runner1->no_of_post_tasks());
547   EXPECT_EQ(2u, task_runner2->no_of_post_tasks());
548   DisableTracing();
549 }
550 
551 // Checks that providers get disabled after 3 consecutive failures, but not
552 // otherwise (e.g., if interleaved).
TEST_F(MemoryDumpManagerTest,DisableFailingDumpers)553 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
554   MockMemoryDumpProvider mdp1;
555   MockMemoryDumpProvider mdp2;
556 
557   RegisterDumpProvider(&mdp1, nullptr);
558   RegisterDumpProvider(&mdp2, nullptr);
559   EnableForTracing();
560 
561   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
562       .Times(GetMaxConsecutiveFailuresCount())
563       .WillRepeatedly(Return(false));
564 
565   EXPECT_CALL(mdp2, OnMemoryDump(_, _))
566       .WillOnce(Return(false))
567       .WillOnce(Return(true))
568       .WillOnce(Return(false))
569       .WillOnce(Return(false))
570       .WillOnce(Return(true))
571       .WillOnce(Return(false));
572 
573   const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount();
574   for (int i = 0; i < kNumDumps; i++) {
575     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
576                                           MemoryDumpLevelOfDetail::DETAILED,
577                                           MemoryDumpDeterminism::NONE));
578   }
579 
580   DisableTracing();
581 }
582 
583 // Sneakily registers an extra memory dump provider while an existing one is
584 // dumping and expect it to take part in the already active tracing session.
TEST_F(MemoryDumpManagerTest,RegisterDumperWhileDumping)585 TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
586   MockMemoryDumpProvider mdp1;
587   MockMemoryDumpProvider mdp2;
588 
589   RegisterDumpProvider(&mdp1, nullptr);
590   EnableForTracing();
591 
592   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
593       .Times(4)
594       .WillOnce(Return(true))
595       .WillOnce(
596           Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
597             RegisterDumpProvider(&mdp2, nullptr);
598             return true;
599           }))
600       .WillRepeatedly(Return(true));
601 
602   // Depending on the insertion order (before or after mdp1), mdp2 might be
603   // called also immediately after it gets registered.
604   EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(Between(2, 3));
605 
606   for (int i = 0; i < 4; i++) {
607     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
608                                           MemoryDumpLevelOfDetail::DETAILED,
609                                           MemoryDumpDeterminism::NONE));
610   }
611 
612   DisableTracing();
613 }
614 
615 // Like RegisterDumperWhileDumping, but unregister the dump provider instead.
TEST_F(MemoryDumpManagerTest,UnregisterDumperWhileDumping)616 TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
617   MockMemoryDumpProvider mdp1;
618   MockMemoryDumpProvider mdp2;
619 
620   RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
621   RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
622   EnableForTracing();
623 
624   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
625       .Times(4)
626       .WillOnce(Return(true))
627       .WillOnce(
628           Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
629             MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2);
630             return true;
631           }))
632       .WillRepeatedly(Return(true));
633 
634   // Depending on the insertion order (before or after mdp1), mdp2 might have
635   // been already called when UnregisterDumpProvider happens.
636   EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(Between(1, 2));
637 
638   for (int i = 0; i < 4; i++) {
639     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
640                                           MemoryDumpLevelOfDetail::DETAILED,
641                                           MemoryDumpDeterminism::NONE));
642   }
643 
644   DisableTracing();
645 }
646 
647 // Checks that the dump does not abort when unregistering a provider while
648 // dumping from a different thread than the dumping thread.
TEST_F(MemoryDumpManagerTest,UnregisterDumperFromThreadWhileDumping)649 TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
650   std::vector<std::unique_ptr<TestIOThread>> threads;
651   std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps;
652 
653   for (int i = 0; i < 2; i++) {
654     threads.push_back(std::make_unique<TestIOThread>(TestIOThread::kAutoStart));
655     mdps.push_back(std::make_unique<MockMemoryDumpProvider>());
656     RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(),
657                          kDefaultOptions);
658   }
659 
660   int on_memory_dump_call_count = 0;
661 
662   // When OnMemoryDump is called on either of the dump providers, it will
663   // unregister the other one.
664   for (const std::unique_ptr<MockMemoryDumpProvider>& mdp : mdps) {
665     int other_idx = (mdps.front() == mdp);
666     // TestIOThread's task runner must be obtained from the main thread but can
667     // then be used from other threads.
668     scoped_refptr<SingleThreadTaskRunner> other_runner =
669         threads[other_idx]->task_runner();
670     MockMemoryDumpProvider* other_mdp = mdps[other_idx].get();
671     auto on_dump = [this, other_runner, other_mdp, &on_memory_dump_call_count](
672                        const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
673       PostTaskAndWait(FROM_HERE, other_runner.get(),
674                       base::BindOnce(&MemoryDumpManager::UnregisterDumpProvider,
675                                      base::Unretained(&*mdm_), other_mdp));
676       on_memory_dump_call_count++;
677       return true;
678     };
679 
680     // OnMemoryDump is called once for the provider that dumps first, and zero
681     // times for the other provider.
682     EXPECT_CALL(*mdp, OnMemoryDump(_, _))
683         .Times(AtMost(1))
684         .WillOnce(Invoke(on_dump));
685   }
686 
687   EnableForTracing();
688   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
689                                         MemoryDumpLevelOfDetail::DETAILED,
690                                         MemoryDumpDeterminism::NONE));
691   ASSERT_EQ(1, on_memory_dump_call_count);
692 
693   DisableTracing();
694 }
695 
696 // If a thread (with a dump provider living on it) is torn down during a dump
697 // its dump provider should be skipped but the dump itself should succeed.
TEST_F(MemoryDumpManagerTest,TearDownThreadWhileDumping)698 TEST_F(MemoryDumpManagerTest, TearDownThreadWhileDumping) {
699   std::vector<std::unique_ptr<TestIOThread>> threads;
700   std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps;
701 
702   for (int i = 0; i < 2; i++) {
703     threads.push_back(std::make_unique<TestIOThread>(TestIOThread::kAutoStart));
704     mdps.push_back(std::make_unique<MockMemoryDumpProvider>());
705     RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(),
706                          kDefaultOptions);
707   }
708 
709   int on_memory_dump_call_count = 0;
710 
711   // When OnMemoryDump is called on either of the dump providers, it will
712   // tear down the thread of the other one.
713   for (const std::unique_ptr<MockMemoryDumpProvider>& mdp : mdps) {
714     int other_idx = (mdps.front() == mdp);
715     TestIOThread* other_thread = threads[other_idx].get();
716     // TestIOThread isn't thread-safe and must be stopped on the |main_runner|.
717     scoped_refptr<SequencedTaskRunner> main_runner =
718         SequencedTaskRunnerHandle::Get();
719     auto on_dump = [other_thread, main_runner, &on_memory_dump_call_count](
720                        const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
721       PostTaskAndWait(
722           FROM_HERE, main_runner.get(),
723           base::BindOnce(&TestIOThread::Stop, base::Unretained(other_thread)));
724       on_memory_dump_call_count++;
725       return true;
726     };
727 
728     // OnMemoryDump is called once for the provider that dumps first, and zero
729     // times for the other provider.
730     EXPECT_CALL(*mdp, OnMemoryDump(_, _))
731         .Times(AtMost(1))
732         .WillOnce(Invoke(on_dump));
733   }
734 
735   EnableForTracing();
736   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
737                                         MemoryDumpLevelOfDetail::DETAILED,
738                                         MemoryDumpDeterminism::NONE));
739   ASSERT_EQ(1, on_memory_dump_call_count);
740 
741   DisableTracing();
742 }
743 
744 // Checks that the callback is invoked if CreateProcessDump() is called when
745 // tracing is not enabled.
TEST_F(MemoryDumpManagerTest,TriggerDumpWithoutTracing)746 TEST_F(MemoryDumpManagerTest, TriggerDumpWithoutTracing) {
747   MockMemoryDumpProvider mdp;
748   RegisterDumpProvider(&mdp, nullptr);
749   EXPECT_CALL(mdp, OnMemoryDump(_, _));
750   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
751                                         MemoryDumpLevelOfDetail::DETAILED,
752                                         MemoryDumpDeterminism::NONE));
753 }
754 
TEST_F(MemoryDumpManagerTest,BackgroundWhitelisting)755 TEST_F(MemoryDumpManagerTest, BackgroundWhitelisting) {
756   SetDumpProviderAllowlistForTesting(kTestMDPWhitelist);
757 
758   // Standard provider with default options (create dump for current process).
759   MockMemoryDumpProvider backgroundMdp;
760   RegisterDumpProvider(&backgroundMdp, nullptr, kDefaultOptions,
761                        kWhitelistedMDPName);
762 
763   EnableForTracing();
764 
765   EXPECT_CALL(backgroundMdp, OnMemoryDump(_, _)).Times(1);
766   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::SUMMARY_ONLY,
767                                         MemoryDumpLevelOfDetail::BACKGROUND,
768                                         MemoryDumpDeterminism::NONE));
769   DisableTracing();
770 }
771 
772 // Tests the basics of the UnregisterAndDeleteDumpProviderSoon(): the
773 // unregistration should actually delete the providers and not leak them.
TEST_F(MemoryDumpManagerTest,UnregisterAndDeleteDumpProviderSoon)774 TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoon) {
775   static const int kNumProviders = 3;
776   int dtor_count = 0;
777   std::vector<std::unique_ptr<MemoryDumpProvider>> mdps;
778   for (int i = 0; i < kNumProviders; ++i) {
779     std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider);
780     mdp->enable_mock_destructor = true;
781     EXPECT_CALL(*mdp, Destructor())
782         .WillOnce(Invoke([&dtor_count]() { dtor_count++; }));
783     RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions);
784     mdps.push_back(std::move(mdp));
785   }
786 
787   while (!mdps.empty()) {
788     mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdps.back()));
789     mdps.pop_back();
790   }
791 
792   ASSERT_EQ(kNumProviders, dtor_count);
793 }
794 
795 // This test checks against races when unregistering an unbound dump provider
796 // from another thread while dumping. It registers one MDP and, when
797 // OnMemoryDump() is called, it invokes UnregisterAndDeleteDumpProviderSoon()
798 // from another thread. The OnMemoryDump() and the dtor call are expected to
799 // happen on the same thread (the MemoryDumpManager utility thread).
TEST_F(MemoryDumpManagerTest,UnregisterAndDeleteDumpProviderSoonDuringDump)800 TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoonDuringDump) {
801   std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider);
802   mdp->enable_mock_destructor = true;
803   RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions);
804 
805   base::PlatformThreadRef thread_ref;
806   auto self_unregister_from_another_thread = [&mdp, &thread_ref](
807       const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
808     thread_ref = PlatformThread::CurrentRef();
809     TestIOThread thread_for_unregistration(TestIOThread::kAutoStart);
810     PostTaskAndWait(
811         FROM_HERE, thread_for_unregistration.task_runner().get(),
812         base::BindOnce(&MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon,
813                        base::Unretained(MemoryDumpManager::GetInstance()),
814                        std::move(mdp)));
815     thread_for_unregistration.Stop();
816     return true;
817   };
818   EXPECT_CALL(*mdp, OnMemoryDump(_, _))
819       .Times(1)
820       .WillOnce(Invoke(self_unregister_from_another_thread));
821   EXPECT_CALL(*mdp, Destructor())
822       .Times(1)
823       .WillOnce(Invoke([&thread_ref]() {
824         EXPECT_EQ(thread_ref, PlatformThread::CurrentRef());
825       }));
826 
827   EnableForTracing();
828   for (int i = 0; i < 2; ++i) {
829     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
830                                           MemoryDumpLevelOfDetail::DETAILED,
831                                           MemoryDumpDeterminism::NONE));
832   }
833   DisableTracing();
834 }
835 
836 // Mock MDP class that tests if the number of OnMemoryDump() calls are expected.
837 // It is implemented without gmocks since EXPECT_CALL implementation is slow
838 // when there are 1000s of instances, as required in
839 // NoStackOverflowWithTooManyMDPs test.
840 class SimpleMockMemoryDumpProvider : public MemoryDumpProvider {
841  public:
SimpleMockMemoryDumpProvider(int expected_num_dump_calls)842   SimpleMockMemoryDumpProvider(int expected_num_dump_calls)
843       : expected_num_dump_calls_(expected_num_dump_calls), num_dump_calls_(0) {}
844 
~SimpleMockMemoryDumpProvider()845   ~SimpleMockMemoryDumpProvider() override {
846     EXPECT_EQ(expected_num_dump_calls_, num_dump_calls_);
847   }
848 
OnMemoryDump(const MemoryDumpArgs & args,ProcessMemoryDump * pmd)849   bool OnMemoryDump(const MemoryDumpArgs& args,
850                     ProcessMemoryDump* pmd) override {
851     ++num_dump_calls_;
852     return true;
853   }
854 
855  private:
856   int expected_num_dump_calls_;
857   int num_dump_calls_;
858 };
859 
TEST_F(MemoryDumpManagerTest,NoStackOverflowWithTooManyMDPs)860 TEST_F(MemoryDumpManagerTest, NoStackOverflowWithTooManyMDPs) {
861   SetDumpProviderAllowlistForTesting(kTestMDPWhitelist);
862 
863   int kMDPCount = 1000;
864   std::vector<std::unique_ptr<SimpleMockMemoryDumpProvider>> mdps;
865   for (int i = 0; i < kMDPCount; ++i) {
866     mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(1));
867     RegisterDumpProvider(mdps.back().get(), nullptr);
868   }
869   for (int i = 0; i < kMDPCount; ++i) {
870     mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(3));
871     RegisterDumpProvider(mdps.back().get(), nullptr, kDefaultOptions,
872                          kWhitelistedMDPName);
873   }
874   std::unique_ptr<Thread> stopped_thread(new Thread("test thread"));
875   stopped_thread->Start();
876   for (int i = 0; i < kMDPCount; ++i) {
877     mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(0));
878     RegisterDumpProvider(mdps.back().get(), stopped_thread->task_runner(),
879                          kDefaultOptions, kWhitelistedMDPName);
880   }
881   stopped_thread->Stop();
882 
883   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
884                                         MemoryDumpLevelOfDetail::DETAILED,
885                                         MemoryDumpDeterminism::NONE));
886   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
887                                         MemoryDumpLevelOfDetail::BACKGROUND,
888                                         MemoryDumpDeterminism::NONE));
889   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::SUMMARY_ONLY,
890                                         MemoryDumpLevelOfDetail::BACKGROUND,
891                                         MemoryDumpDeterminism::NONE));
892 }
893 
894 }  // namespace trace_event
895 }  // namespace base
896