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