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