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