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