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/bind_helpers.h" 14 #include "base/callback.h" 15 #include "base/memory/ptr_util.h" 16 #include "base/memory/ref_counted_memory.h" 17 #include "base/message_loop/message_loop.h" 18 #include "base/run_loop.h" 19 #include "base/strings/stringprintf.h" 20 #include "base/synchronization/waitable_event.h" 21 #include "base/test/sequenced_worker_pool_owner.h" 22 #include "base/test/test_io_thread.h" 23 #include "base/test/trace_event_analyzer.h" 24 #include "base/threading/platform_thread.h" 25 #include "base/threading/sequenced_task_runner_handle.h" 26 #include "base/threading/sequenced_worker_pool.h" 27 #include "base/threading/thread.h" 28 #include "base/threading/thread_task_runner_handle.h" 29 #include "base/trace_event/memory_dump_provider.h" 30 #include "base/trace_event/memory_dump_scheduler.h" 31 #include "base/trace_event/memory_infra_background_whitelist.h" 32 #include "base/trace_event/process_memory_dump.h" 33 #include "base/trace_event/trace_buffer.h" 34 #include "base/trace_event/trace_config_memory_test_util.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::AnyNumber; 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(IsBackgroundDump, "") { 59 return arg.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND; 60 } 61 62 namespace { 63 64 const char* kMDPName = "TestDumpProvider"; 65 const char* kWhitelistedMDPName = "WhitelistedTestDumpProvider"; 66 const char* const kTestMDPWhitelist[] = {kWhitelistedMDPName, nullptr}; 67 68 void RegisterDumpProvider( 69 MemoryDumpProvider* mdp, 70 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 71 const MemoryDumpProvider::Options& options, 72 const char* name = kMDPName) { 73 MemoryDumpManager* mdm = MemoryDumpManager::GetInstance(); 74 mdm->set_dumper_registrations_ignored_for_testing(false); 75 mdm->RegisterDumpProvider(mdp, name, std::move(task_runner), options); 76 mdm->set_dumper_registrations_ignored_for_testing(true); 77 } 78 79 void RegisterDumpProvider( 80 MemoryDumpProvider* mdp, 81 scoped_refptr<base::SingleThreadTaskRunner> task_runner) { 82 RegisterDumpProvider(mdp, task_runner, MemoryDumpProvider::Options()); 83 } 84 85 void RegisterDumpProviderWithSequencedTaskRunner( 86 MemoryDumpProvider* mdp, 87 scoped_refptr<base::SequencedTaskRunner> task_runner, 88 const MemoryDumpProvider::Options& options) { 89 MemoryDumpManager* mdm = MemoryDumpManager::GetInstance(); 90 mdm->set_dumper_registrations_ignored_for_testing(false); 91 mdm->RegisterDumpProviderWithSequencedTaskRunner(mdp, kMDPName, task_runner, 92 options); 93 mdm->set_dumper_registrations_ignored_for_testing(true); 94 } 95 96 void OnTraceDataCollected(Closure quit_closure, 97 trace_event::TraceResultBuffer* buffer, 98 const scoped_refptr<RefCountedString>& json, 99 bool has_more_events) { 100 buffer->AddFragment(json->data()); 101 if (!has_more_events) 102 quit_closure.Run(); 103 } 104 105 // Posts |task| to |task_runner| and blocks until it is executed. 106 void PostTaskAndWait(const tracked_objects::Location& from_here, 107 SequencedTaskRunner* task_runner, 108 base::OnceClosure task) { 109 base::WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, 110 WaitableEvent::InitialState::NOT_SIGNALED); 111 task_runner->PostTask(from_here, std::move(task)); 112 task_runner->PostTask( 113 FROM_HERE, base::Bind(&WaitableEvent::Signal, base::Unretained(&event))); 114 // The SequencedTaskRunner guarantees that |event| will only be signaled after 115 // |task| is executed. 116 event.Wait(); 117 } 118 119 // Testing MemoryDumpManagerDelegate which, by default, short-circuits dump 120 // requests locally to the MemoryDumpManager instead of performing IPC dances. 121 class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate { 122 public: 123 MemoryDumpManagerDelegateForTesting(bool is_coordinator) 124 : is_coordinator_(is_coordinator) { 125 ON_CALL(*this, RequestGlobalMemoryDump(_, _)) 126 .WillByDefault(Invoke( 127 this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump)); 128 } 129 130 MOCK_METHOD2(RequestGlobalMemoryDump, 131 void(const MemoryDumpRequestArgs& args, 132 const MemoryDumpCallback& callback)); 133 134 bool IsCoordinator() const override { return is_coordinator_; } 135 136 // Promote the CreateProcessDump to public so it can be used by test fixtures. 137 using MemoryDumpManagerDelegate::CreateProcessDump; 138 139 private: 140 bool is_coordinator_; 141 }; 142 143 class MockMemoryDumpProvider : public MemoryDumpProvider { 144 public: 145 MOCK_METHOD0(Destructor, void()); 146 MOCK_METHOD2(OnMemoryDump, 147 bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd)); 148 MOCK_METHOD1(PollFastMemoryTotal, void(uint64_t* memory_total)); 149 MOCK_METHOD0(SuspendFastMemoryPolling, void()); 150 151 MockMemoryDumpProvider() : enable_mock_destructor(false) { 152 ON_CALL(*this, OnMemoryDump(_, _)) 153 .WillByDefault(Invoke([](const MemoryDumpArgs&, 154 ProcessMemoryDump* pmd) -> bool { 155 // |session_state| should not be null under any circumstances when 156 // invoking a memory dump. The problem might arise in race conditions 157 // like crbug.com/600570 . 158 EXPECT_TRUE(pmd->session_state().get() != nullptr); 159 return true; 160 })); 161 162 ON_CALL(*this, PollFastMemoryTotal(_)) 163 .WillByDefault( 164 Invoke([](uint64_t* memory_total) -> void { NOTREACHED(); })); 165 } 166 ~MockMemoryDumpProvider() override { 167 if (enable_mock_destructor) 168 Destructor(); 169 } 170 171 bool enable_mock_destructor; 172 }; 173 174 class TestSequencedTaskRunner : public SequencedTaskRunner { 175 public: 176 TestSequencedTaskRunner() 177 : worker_pool_(2 /* max_threads */, "Test Task Runner"), 178 enabled_(true), 179 num_of_post_tasks_(0) {} 180 181 void set_enabled(bool value) { enabled_ = value; } 182 unsigned no_of_post_tasks() const { return num_of_post_tasks_; } 183 184 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, 185 OnceClosure task, 186 TimeDelta delay) override { 187 NOTREACHED(); 188 return false; 189 } 190 191 bool PostDelayedTask(const tracked_objects::Location& from_here, 192 OnceClosure task, 193 TimeDelta delay) override { 194 num_of_post_tasks_++; 195 if (enabled_) { 196 return worker_pool_.pool()->PostSequencedWorkerTask(token_, from_here, 197 std::move(task)); 198 } 199 return false; 200 } 201 202 bool RunsTasksOnCurrentThread() const override { 203 return worker_pool_.pool()->RunsTasksOnCurrentThread(); 204 } 205 206 private: 207 ~TestSequencedTaskRunner() override {} 208 209 SequencedWorkerPoolOwner worker_pool_; 210 const SequencedWorkerPool::SequenceToken token_; 211 bool enabled_; 212 unsigned num_of_post_tasks_; 213 }; 214 215 } // namespace 216 217 class MemoryDumpManagerTest : public testing::Test { 218 public: 219 MemoryDumpManagerTest() : testing::Test(), kDefaultOptions() {} 220 221 void SetUp() override { 222 last_callback_success_ = false; 223 message_loop_.reset(new MessageLoop()); 224 mdm_.reset(new MemoryDumpManager()); 225 MemoryDumpManager::SetInstanceForTesting(mdm_.get()); 226 ASSERT_EQ(mdm_.get(), MemoryDumpManager::GetInstance()); 227 } 228 229 void TearDown() override { 230 MemoryDumpManager::SetInstanceForTesting(nullptr); 231 delegate_ = nullptr; 232 mdm_.reset(); 233 message_loop_.reset(); 234 TraceLog::DeleteForTesting(); 235 } 236 237 // Turns a Closure into a MemoryDumpCallback, keeping track of the callback 238 // result and taking care of posting the closure on the correct task runner. 239 void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner, 240 Closure closure, 241 uint64_t dump_guid, 242 bool success) { 243 last_callback_success_ = success; 244 task_runner->PostTask(FROM_HERE, closure); 245 } 246 247 void PollFastMemoryTotal(uint64_t* memory_total) { 248 mdm_->PollFastMemoryTotal(memory_total); 249 } 250 251 protected: 252 void InitializeMemoryDumpManager(bool is_coordinator) { 253 mdm_->set_dumper_registrations_ignored_for_testing(true); 254 delegate_ = new MemoryDumpManagerDelegateForTesting(is_coordinator); 255 mdm_->Initialize(base::WrapUnique(delegate_)); 256 } 257 258 void RequestGlobalDumpAndWait(MemoryDumpType dump_type, 259 MemoryDumpLevelOfDetail level_of_detail) { 260 RunLoop run_loop; 261 MemoryDumpCallback callback = 262 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this), 263 ThreadTaskRunnerHandle::Get(), run_loop.QuitClosure()); 264 mdm_->RequestGlobalDump(dump_type, level_of_detail, callback); 265 run_loop.Run(); 266 } 267 268 void EnableTracingWithLegacyCategories(const char* category) { 269 TraceLog::GetInstance()->SetEnabled(TraceConfig(category, ""), 270 TraceLog::RECORDING_MODE); 271 } 272 273 void EnableTracingWithTraceConfig(const std::string& trace_config) { 274 TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config), 275 TraceLog::RECORDING_MODE); 276 } 277 278 void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); } 279 280 bool IsPeriodicDumpingEnabled() const { 281 return MemoryDumpScheduler::GetInstance() 282 ->IsPeriodicTimerRunningForTesting(); 283 } 284 285 int GetMaxConsecutiveFailuresCount() const { 286 return MemoryDumpManager::kMaxConsecutiveFailuresCount; 287 } 288 289 const MemoryDumpProvider::Options kDefaultOptions; 290 std::unique_ptr<MemoryDumpManager> mdm_; 291 MemoryDumpManagerDelegateForTesting* delegate_; 292 bool last_callback_success_; 293 294 private: 295 std::unique_ptr<MessageLoop> message_loop_; 296 297 // We want our singleton torn down after each test. 298 ShadowingAtExitManager at_exit_manager_; 299 }; 300 301 // Basic sanity checks. Registers a memory dump provider and checks that it is 302 // called, but only when memory-infra is enabled. 303 TEST_F(MemoryDumpManagerTest, SingleDumper) { 304 InitializeMemoryDumpManager(false /* is_coordinator */); 305 MockMemoryDumpProvider mdp; 306 RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); 307 308 // Check that the dumper is not called if the memory category is not enabled. 309 EnableTracingWithLegacyCategories("foobar-but-not-memory"); 310 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0); 311 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); 312 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 313 MemoryDumpLevelOfDetail::DETAILED); 314 DisableTracing(); 315 316 // Now repeat enabling the memory category and check that the dumper is 317 // invoked this time. 318 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 319 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3); 320 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true)); 321 for (int i = 0; i < 3; ++i) 322 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 323 MemoryDumpLevelOfDetail::DETAILED); 324 DisableTracing(); 325 326 mdm_->UnregisterDumpProvider(&mdp); 327 328 // Finally check the unregister logic: the delegate will be invoked but not 329 // the dump provider, as it has been unregistered. 330 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 331 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3); 332 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); 333 334 for (int i = 0; i < 3; ++i) { 335 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 336 MemoryDumpLevelOfDetail::DETAILED); 337 } 338 DisableTracing(); 339 } 340 341 // Checks that requesting dumps with high level of detail actually propagates 342 // the level of the detail properly to OnMemoryDump() call on dump providers. 343 TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) { 344 InitializeMemoryDumpManager(false /* is_coordinator */); 345 MockMemoryDumpProvider mdp; 346 347 RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); 348 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 349 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 350 EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _)).WillOnce(Return(true)); 351 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 352 MemoryDumpLevelOfDetail::DETAILED); 353 DisableTracing(); 354 mdm_->UnregisterDumpProvider(&mdp); 355 356 // Check that requesting dumps with low level of detail actually propagates to 357 // OnMemoryDump() call on dump providers. 358 RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); 359 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 360 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 361 EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _)).WillOnce(Return(true)); 362 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 363 MemoryDumpLevelOfDetail::LIGHT); 364 DisableTracing(); 365 mdm_->UnregisterDumpProvider(&mdp); 366 } 367 368 // Checks that the SharedSessionState object is acqually shared over time. 369 TEST_F(MemoryDumpManagerTest, SharedSessionState) { 370 InitializeMemoryDumpManager(false /* is_coordinator */); 371 MockMemoryDumpProvider mdp1; 372 MockMemoryDumpProvider mdp2; 373 RegisterDumpProvider(&mdp1, nullptr); 374 RegisterDumpProvider(&mdp2, nullptr); 375 376 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 377 const MemoryDumpSessionState* session_state = 378 mdm_->session_state_for_testing().get(); 379 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2); 380 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) 381 .Times(2) 382 .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&, 383 ProcessMemoryDump* pmd) -> bool { 384 EXPECT_EQ(session_state, pmd->session_state().get()); 385 return true; 386 })); 387 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) 388 .Times(2) 389 .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&, 390 ProcessMemoryDump* pmd) -> bool { 391 EXPECT_EQ(session_state, pmd->session_state().get()); 392 return true; 393 })); 394 395 for (int i = 0; i < 2; ++i) { 396 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 397 MemoryDumpLevelOfDetail::DETAILED); 398 } 399 400 DisableTracing(); 401 } 402 403 // Checks that the (Un)RegisterDumpProvider logic behaves sanely. 404 TEST_F(MemoryDumpManagerTest, MultipleDumpers) { 405 InitializeMemoryDumpManager(false /* is_coordinator */); 406 MockMemoryDumpProvider mdp1; 407 MockMemoryDumpProvider mdp2; 408 409 // Enable only mdp1. 410 RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get()); 411 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 412 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 413 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true)); 414 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0); 415 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 416 MemoryDumpLevelOfDetail::DETAILED); 417 DisableTracing(); 418 419 // Invert: enable mdp1 and disable mdp2. 420 mdm_->UnregisterDumpProvider(&mdp1); 421 RegisterDumpProvider(&mdp2, nullptr); 422 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 423 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 424 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0); 425 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true)); 426 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 427 MemoryDumpLevelOfDetail::DETAILED); 428 DisableTracing(); 429 430 // Enable both mdp1 and mdp2. 431 RegisterDumpProvider(&mdp1, nullptr); 432 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 433 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 434 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true)); 435 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true)); 436 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 437 MemoryDumpLevelOfDetail::DETAILED); 438 DisableTracing(); 439 } 440 441 // Checks that the dump provider invocations depend only on the current 442 // registration state and not on previous registrations and dumps. 443 // Flaky on iOS, see crbug.com/706874 444 #if defined(OS_IOS) 445 #define MAYBE_RegistrationConsistency DISABLED_RegistrationConsistency 446 #else 447 #define MAYBE_RegistrationConsistency RegistrationConsistency 448 #endif 449 TEST_F(MemoryDumpManagerTest, MAYBE_RegistrationConsistency) { 450 InitializeMemoryDumpManager(false /* is_coordinator */); 451 MockMemoryDumpProvider mdp; 452 453 RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); 454 455 { 456 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 457 EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true)); 458 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 459 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 460 MemoryDumpLevelOfDetail::DETAILED); 461 DisableTracing(); 462 } 463 464 mdm_->UnregisterDumpProvider(&mdp); 465 466 { 467 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 468 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); 469 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 470 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 471 MemoryDumpLevelOfDetail::DETAILED); 472 DisableTracing(); 473 } 474 475 RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); 476 mdm_->UnregisterDumpProvider(&mdp); 477 478 { 479 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 480 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); 481 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 482 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 483 MemoryDumpLevelOfDetail::DETAILED); 484 DisableTracing(); 485 } 486 487 RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); 488 mdm_->UnregisterDumpProvider(&mdp); 489 RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); 490 491 { 492 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 493 EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true)); 494 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 495 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 496 MemoryDumpLevelOfDetail::DETAILED); 497 DisableTracing(); 498 } 499 } 500 501 // Checks that the MemoryDumpManager respects the thread affinity when a 502 // MemoryDumpProvider specifies a task_runner(). The test starts creating 8 503 // threads and registering a MemoryDumpProvider on each of them. At each 504 // iteration, one thread is removed, to check the live unregistration logic. 505 TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) { 506 InitializeMemoryDumpManager(false /* is_coordinator */); 507 const uint32_t kNumInitialThreads = 8; 508 509 std::vector<std::unique_ptr<Thread>> threads; 510 std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps; 511 512 // Create the threads and setup the expectations. Given that at each iteration 513 // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be 514 // invoked a number of times equal to its index. 515 for (uint32_t i = kNumInitialThreads; i > 0; --i) { 516 threads.push_back(WrapUnique(new Thread("test thread"))); 517 auto* thread = threads.back().get(); 518 thread->Start(); 519 scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner(); 520 mdps.push_back(WrapUnique(new MockMemoryDumpProvider())); 521 auto* mdp = mdps.back().get(); 522 RegisterDumpProvider(mdp, task_runner, kDefaultOptions); 523 EXPECT_CALL(*mdp, OnMemoryDump(_, _)) 524 .Times(i) 525 .WillRepeatedly(Invoke( 526 [task_runner](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { 527 EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread()); 528 return true; 529 })); 530 } 531 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 532 533 while (!threads.empty()) { 534 last_callback_success_ = false; 535 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 536 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 537 MemoryDumpLevelOfDetail::DETAILED); 538 EXPECT_TRUE(last_callback_success_); 539 540 // Unregister a MDP and destroy one thread at each iteration to check the 541 // live unregistration logic. The unregistration needs to happen on the same 542 // thread the MDP belongs to. 543 { 544 RunLoop run_loop; 545 Closure unregistration = 546 Bind(&MemoryDumpManager::UnregisterDumpProvider, 547 Unretained(mdm_.get()), Unretained(mdps.back().get())); 548 threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration, 549 run_loop.QuitClosure()); 550 run_loop.Run(); 551 } 552 mdps.pop_back(); 553 threads.back()->Stop(); 554 threads.pop_back(); 555 } 556 557 DisableTracing(); 558 } 559 560 // Check that the memory dump calls are always posted on task runner for 561 // SequencedTaskRunner case and that the dump provider gets disabled when 562 // PostTask fails, but the dump still succeeds. 563 TEST_F(MemoryDumpManagerTest, PostTaskForSequencedTaskRunner) { 564 InitializeMemoryDumpManager(false /* is_coordinator */); 565 std::vector<MockMemoryDumpProvider> mdps(3); 566 scoped_refptr<TestSequencedTaskRunner> task_runner1( 567 make_scoped_refptr(new TestSequencedTaskRunner())); 568 scoped_refptr<TestSequencedTaskRunner> task_runner2( 569 make_scoped_refptr(new TestSequencedTaskRunner())); 570 RegisterDumpProviderWithSequencedTaskRunner(&mdps[0], task_runner1, 571 kDefaultOptions); 572 RegisterDumpProviderWithSequencedTaskRunner(&mdps[1], task_runner2, 573 kDefaultOptions); 574 RegisterDumpProviderWithSequencedTaskRunner(&mdps[2], task_runner2, 575 kDefaultOptions); 576 // |mdps[0]| should be disabled permanently after first dump. 577 EXPECT_CALL(mdps[0], OnMemoryDump(_, _)).Times(0); 578 EXPECT_CALL(mdps[1], OnMemoryDump(_, _)).Times(2); 579 EXPECT_CALL(mdps[2], OnMemoryDump(_, _)).Times(2); 580 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2); 581 582 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 583 584 task_runner1->set_enabled(false); 585 last_callback_success_ = false; 586 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 587 MemoryDumpLevelOfDetail::DETAILED); 588 // Tasks should be individually posted even if |mdps[1]| and |mdps[2]| belong 589 // to same task runner. 590 EXPECT_EQ(1u, task_runner1->no_of_post_tasks()); 591 EXPECT_EQ(2u, task_runner2->no_of_post_tasks()); 592 EXPECT_TRUE(last_callback_success_); 593 594 task_runner1->set_enabled(true); 595 last_callback_success_ = false; 596 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 597 MemoryDumpLevelOfDetail::DETAILED); 598 EXPECT_EQ(2u, task_runner1->no_of_post_tasks()); 599 EXPECT_EQ(4u, task_runner2->no_of_post_tasks()); 600 EXPECT_TRUE(last_callback_success_); 601 DisableTracing(); 602 } 603 604 // Checks that providers get disabled after 3 consecutive failures, but not 605 // otherwise (e.g., if interleaved). 606 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) { 607 InitializeMemoryDumpManager(false /* is_coordinator */); 608 MockMemoryDumpProvider mdp1; 609 MockMemoryDumpProvider mdp2; 610 611 RegisterDumpProvider(&mdp1, nullptr); 612 RegisterDumpProvider(&mdp2, nullptr); 613 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 614 615 const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount(); 616 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(kNumDumps); 617 618 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) 619 .Times(GetMaxConsecutiveFailuresCount()) 620 .WillRepeatedly(Return(false)); 621 622 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) 623 .WillOnce(Return(false)) 624 .WillOnce(Return(true)) 625 .WillOnce(Return(false)) 626 .WillOnce(Return(false)) 627 .WillOnce(Return(true)) 628 .WillOnce(Return(false)); 629 630 for (int i = 0; i < kNumDumps; i++) { 631 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 632 MemoryDumpLevelOfDetail::DETAILED); 633 } 634 635 DisableTracing(); 636 } 637 638 // Sneakily registers an extra memory dump provider while an existing one is 639 // dumping and expect it to take part in the already active tracing session. 640 TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) { 641 InitializeMemoryDumpManager(false /* is_coordinator */); 642 MockMemoryDumpProvider mdp1; 643 MockMemoryDumpProvider mdp2; 644 645 RegisterDumpProvider(&mdp1, nullptr); 646 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 647 648 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4); 649 650 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) 651 .Times(4) 652 .WillOnce(Return(true)) 653 .WillOnce( 654 Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { 655 RegisterDumpProvider(&mdp2, nullptr); 656 return true; 657 })) 658 .WillRepeatedly(Return(true)); 659 660 // Depending on the insertion order (before or after mdp1), mdp2 might be 661 // called also immediately after it gets registered. 662 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) 663 .Times(Between(2, 3)) 664 .WillRepeatedly(Return(true)); 665 666 for (int i = 0; i < 4; i++) { 667 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 668 MemoryDumpLevelOfDetail::DETAILED); 669 } 670 671 DisableTracing(); 672 } 673 674 // Like RegisterDumperWhileDumping, but unregister the dump provider instead. 675 TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) { 676 InitializeMemoryDumpManager(false /* is_coordinator */); 677 MockMemoryDumpProvider mdp1; 678 MockMemoryDumpProvider mdp2; 679 680 RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), kDefaultOptions); 681 RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), kDefaultOptions); 682 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 683 684 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4); 685 686 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) 687 .Times(4) 688 .WillOnce(Return(true)) 689 .WillOnce( 690 Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { 691 MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2); 692 return true; 693 })) 694 .WillRepeatedly(Return(true)); 695 696 // Depending on the insertion order (before or after mdp1), mdp2 might have 697 // been already called when UnregisterDumpProvider happens. 698 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) 699 .Times(Between(1, 2)) 700 .WillRepeatedly(Return(true)); 701 702 for (int i = 0; i < 4; i++) { 703 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 704 MemoryDumpLevelOfDetail::DETAILED); 705 } 706 707 DisableTracing(); 708 } 709 710 // Checks that the dump does not abort when unregistering a provider while 711 // dumping from a different thread than the dumping thread. 712 TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) { 713 InitializeMemoryDumpManager(false /* is_coordinator */); 714 std::vector<std::unique_ptr<TestIOThread>> threads; 715 std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps; 716 717 for (int i = 0; i < 2; i++) { 718 threads.push_back( 719 WrapUnique(new TestIOThread(TestIOThread::kAutoStart))); 720 mdps.push_back(WrapUnique(new MockMemoryDumpProvider())); 721 RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(), 722 kDefaultOptions); 723 } 724 725 int on_memory_dump_call_count = 0; 726 727 // When OnMemoryDump is called on either of the dump providers, it will 728 // unregister the other one. 729 for (const std::unique_ptr<MockMemoryDumpProvider>& mdp : mdps) { 730 int other_idx = (mdps.front() == mdp); 731 // TestIOThread's task runner must be obtained from the main thread but can 732 // then be used from other threads. 733 scoped_refptr<SingleThreadTaskRunner> other_runner = 734 threads[other_idx]->task_runner(); 735 MockMemoryDumpProvider* other_mdp = mdps[other_idx].get(); 736 auto on_dump = [this, other_runner, other_mdp, &on_memory_dump_call_count]( 737 const MemoryDumpArgs& args, ProcessMemoryDump* pmd) { 738 PostTaskAndWait(FROM_HERE, other_runner.get(), 739 base::Bind(&MemoryDumpManager::UnregisterDumpProvider, 740 base::Unretained(&*mdm_), other_mdp)); 741 on_memory_dump_call_count++; 742 return true; 743 }; 744 745 // OnMemoryDump is called once for the provider that dumps first, and zero 746 // times for the other provider. 747 EXPECT_CALL(*mdp, OnMemoryDump(_, _)) 748 .Times(AtMost(1)) 749 .WillOnce(Invoke(on_dump)); 750 } 751 752 last_callback_success_ = false; 753 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 754 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 755 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 756 MemoryDumpLevelOfDetail::DETAILED); 757 ASSERT_EQ(1, on_memory_dump_call_count); 758 ASSERT_TRUE(last_callback_success_); 759 760 DisableTracing(); 761 } 762 763 TEST_F(MemoryDumpManagerTest, TestPollingOnDumpThread) { 764 InitializeMemoryDumpManager(false /* is_coordinator */); 765 std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider()); 766 std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider()); 767 mdp1->enable_mock_destructor = true; 768 mdp2->enable_mock_destructor = true; 769 770 EXPECT_CALL(*mdp1, SuspendFastMemoryPolling()).Times(1); 771 EXPECT_CALL(*mdp2, SuspendFastMemoryPolling()).Times(1); 772 EXPECT_CALL(*mdp1, Destructor()); 773 EXPECT_CALL(*mdp2, Destructor()); 774 775 MemoryDumpProvider::Options options; 776 options.is_fast_polling_supported = true; 777 RegisterDumpProvider(mdp1.get(), nullptr, options); 778 779 RunLoop run_loop; 780 scoped_refptr<SingleThreadTaskRunner> test_task_runner = 781 ThreadTaskRunnerHandle::Get(); 782 auto quit_closure = run_loop.QuitClosure(); 783 784 const int kPollsToQuit = 10; 785 int call_count = 0; 786 MemoryDumpManager* mdm = mdm_.get(); 787 const auto poll_function1 = [&call_count, &test_task_runner, quit_closure, 788 &mdp2, mdm, &options, kPollsToQuit, 789 this](uint64_t* total) -> void { 790 ++call_count; 791 if (call_count == 1) 792 RegisterDumpProvider(mdp2.get(), nullptr, options, kMDPName); 793 else if (call_count == 4) 794 mdm->UnregisterAndDeleteDumpProviderSoon(std::move(mdp2)); 795 else if (call_count == kPollsToQuit) 796 test_task_runner->PostTask(FROM_HERE, quit_closure); 797 798 // Record increase of 1 GiB of memory at each call. 799 *total = static_cast<uint64_t>(call_count) * 1024 * 1024 * 1024; 800 }; 801 EXPECT_CALL(*mdp1, PollFastMemoryTotal(_)) 802 .Times(testing::AtLeast(kPollsToQuit)) 803 .WillRepeatedly(Invoke(poll_function1)); 804 805 // Depending on the order of PostTask calls the mdp2 might be registered after 806 // all polls or in between polls. 807 EXPECT_CALL(*mdp2, PollFastMemoryTotal(_)) 808 .Times(Between(0, kPollsToQuit - 1)) 809 .WillRepeatedly(Return()); 810 811 MemoryDumpScheduler::SetPollingIntervalForTesting(1); 812 EnableTracingWithTraceConfig( 813 TraceConfigMemoryTestUtil::GetTraceConfig_PeakDetectionTrigger(3)); 814 815 int last_poll_to_request_dump = -2; 816 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)) 817 .Times(testing::AtLeast(2)) 818 .WillRepeatedly(Invoke([&last_poll_to_request_dump, &call_count]( 819 const MemoryDumpRequestArgs& args, 820 const MemoryDumpCallback& callback) -> void { 821 // Minimum number of polls between dumps must be 3 (polling interval is 822 // 1ms). 823 EXPECT_GE(call_count - last_poll_to_request_dump, 3); 824 last_poll_to_request_dump = call_count; 825 })); 826 827 run_loop.Run(); 828 DisableTracing(); 829 mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdp1)); 830 } 831 832 // If a thread (with a dump provider living on it) is torn down during a dump 833 // its dump provider should be skipped but the dump itself should succeed. 834 TEST_F(MemoryDumpManagerTest, TearDownThreadWhileDumping) { 835 InitializeMemoryDumpManager(false /* is_coordinator */); 836 std::vector<std::unique_ptr<TestIOThread>> threads; 837 std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps; 838 839 for (int i = 0; i < 2; i++) { 840 threads.push_back( 841 WrapUnique(new TestIOThread(TestIOThread::kAutoStart))); 842 mdps.push_back(WrapUnique(new MockMemoryDumpProvider())); 843 RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(), 844 kDefaultOptions); 845 } 846 847 int on_memory_dump_call_count = 0; 848 849 // When OnMemoryDump is called on either of the dump providers, it will 850 // tear down the thread of the other one. 851 for (const std::unique_ptr<MockMemoryDumpProvider>& mdp : mdps) { 852 int other_idx = (mdps.front() == mdp); 853 TestIOThread* other_thread = threads[other_idx].get(); 854 // TestIOThread isn't thread-safe and must be stopped on the |main_runner|. 855 scoped_refptr<SequencedTaskRunner> main_runner = 856 SequencedTaskRunnerHandle::Get(); 857 auto on_dump = [other_thread, main_runner, &on_memory_dump_call_count]( 858 const MemoryDumpArgs& args, ProcessMemoryDump* pmd) { 859 PostTaskAndWait( 860 FROM_HERE, main_runner.get(), 861 base::Bind(&TestIOThread::Stop, base::Unretained(other_thread))); 862 on_memory_dump_call_count++; 863 return true; 864 }; 865 866 // OnMemoryDump is called once for the provider that dumps first, and zero 867 // times for the other provider. 868 EXPECT_CALL(*mdp, OnMemoryDump(_, _)) 869 .Times(AtMost(1)) 870 .WillOnce(Invoke(on_dump)); 871 } 872 873 last_callback_success_ = false; 874 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 875 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 876 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 877 MemoryDumpLevelOfDetail::DETAILED); 878 ASSERT_EQ(1, on_memory_dump_call_count); 879 ASSERT_TRUE(last_callback_success_); 880 881 DisableTracing(); 882 } 883 884 // Checks that a NACK callback is invoked if RequestGlobalDump() is called when 885 // tracing is not enabled. 886 TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) { 887 InitializeMemoryDumpManager(false /* is_coordinator */); 888 MockMemoryDumpProvider mdp1; 889 RegisterDumpProvider(&mdp1, nullptr); 890 891 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0); 892 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0); 893 894 last_callback_success_ = true; 895 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 896 MemoryDumpLevelOfDetail::DETAILED); 897 EXPECT_FALSE(last_callback_success_); 898 } 899 900 // Checks that is the MemoryDumpManager is initialized after tracing already 901 // began, it will still late-join the party (real use case: startup tracing). 902 TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) { 903 MockMemoryDumpProvider mdp; 904 RegisterDumpProvider(&mdp, nullptr); 905 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 906 907 // First check that a RequestGlobalDump() issued before the MemoryDumpManager 908 // initialization gets NACK-ed cleanly. 909 { 910 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); 911 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 912 MemoryDumpLevelOfDetail::DETAILED); 913 EXPECT_FALSE(last_callback_success_); 914 } 915 916 // Now late-initialize the MemoryDumpManager and check that the 917 // RequestGlobalDump completes successfully. 918 { 919 InitializeMemoryDumpManager(false /* is_coordinator */); 920 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1); 921 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 922 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 923 MemoryDumpLevelOfDetail::DETAILED); 924 EXPECT_TRUE(last_callback_success_); 925 } 926 DisableTracing(); 927 } 928 929 // This test (and the MemoryDumpManagerTestCoordinator below) crystallizes the 930 // expectations of the chrome://tracing UI and chrome telemetry w.r.t. periodic 931 // dumps in memory-infra, handling gracefully the transition between the legacy 932 // and the new-style (JSON-based) TraceConfig. 933 TEST_F(MemoryDumpManagerTest, TraceConfigExpectations) { 934 InitializeMemoryDumpManager(false /* is_coordinator */); 935 MemoryDumpManagerDelegateForTesting& delegate = *delegate_; 936 937 // Don't trigger the default behavior of the mock delegate in this test, 938 // which would short-circuit the dump request to the actual 939 // CreateProcessDump(). 940 // We don't want to create any dump in this test, only check whether the dumps 941 // are requested or not. 942 ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return()); 943 944 // Enabling memory-infra in a non-coordinator process should not trigger any 945 // periodic dumps. 946 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 947 EXPECT_FALSE(IsPeriodicDumpingEnabled()); 948 DisableTracing(); 949 950 // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator 951 // process with a fully defined trigger config should NOT enable any periodic 952 // dumps. 953 EnableTracingWithTraceConfig( 954 TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(1, 5)); 955 EXPECT_FALSE(IsPeriodicDumpingEnabled()); 956 DisableTracing(); 957 } 958 959 TEST_F(MemoryDumpManagerTest, TraceConfigExpectationsWhenIsCoordinator) { 960 InitializeMemoryDumpManager(true /* is_coordinator */); 961 MemoryDumpManagerDelegateForTesting& delegate = *delegate_; 962 ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return()); 963 964 // Enabling memory-infra with the legacy TraceConfig (category filter) in 965 // a coordinator process should enable periodic dumps. 966 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 967 EXPECT_TRUE(IsPeriodicDumpingEnabled()); 968 DisableTracing(); 969 970 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator 971 // process without specifying any "memory_dump_config" section should enable 972 // periodic dumps. This is to preserve the behavior chrome://tracing UI, that 973 // is: ticking memory-infra should dump periodically with the default config. 974 EnableTracingWithTraceConfig( 975 TraceConfigMemoryTestUtil::GetTraceConfig_NoTriggers()); 976 EXPECT_TRUE(IsPeriodicDumpingEnabled()); 977 DisableTracing(); 978 979 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator 980 // process with an empty "memory_dump_config" should NOT enable periodic 981 // dumps. This is the way telemetry is supposed to use memory-infra with 982 // only explicitly triggered dumps. 983 EnableTracingWithTraceConfig( 984 TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers()); 985 EXPECT_FALSE(IsPeriodicDumpingEnabled()); 986 DisableTracing(); 987 988 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator 989 // process with a fully defined trigger config should cause periodic dumps to 990 // be performed in the correct order. 991 RunLoop run_loop; 992 auto quit_closure = run_loop.QuitClosure(); 993 994 const int kHeavyDumpRate = 5; 995 const int kLightDumpPeriodMs = 1; 996 const int kHeavyDumpPeriodMs = kHeavyDumpRate * kLightDumpPeriodMs; 997 // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,... 998 testing::InSequence sequence; 999 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _)); 1000 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _)) 1001 .Times(kHeavyDumpRate - 1); 1002 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _)); 1003 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _)) 1004 .Times(kHeavyDumpRate - 2); 1005 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _)) 1006 .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args, 1007 const MemoryDumpCallback& callback) { 1008 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure); 1009 })); 1010 1011 // Swallow all the final spurious calls until tracing gets disabled. 1012 EXPECT_CALL(delegate, RequestGlobalMemoryDump(_, _)).Times(AnyNumber()); 1013 1014 EnableTracingWithTraceConfig( 1015 TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers( 1016 kLightDumpPeriodMs, kHeavyDumpPeriodMs)); 1017 run_loop.Run(); 1018 DisableTracing(); 1019 } 1020 1021 // Tests against race conditions that might arise when disabling tracing in the 1022 // middle of a global memory dump. 1023 // Flaky on iOS, see crbug.com/706961 1024 #if defined(OS_IOS) 1025 #define MAYBE_DisableTracingWhileDumping DISABLED_DisableTracingWhileDumping 1026 #else 1027 #define MAYBE_DisableTracingWhileDumping DisableTracingWhileDumping 1028 #endif 1029 TEST_F(MemoryDumpManagerTest, MAYBE_DisableTracingWhileDumping) { 1030 base::WaitableEvent tracing_disabled_event( 1031 WaitableEvent::ResetPolicy::AUTOMATIC, 1032 WaitableEvent::InitialState::NOT_SIGNALED); 1033 InitializeMemoryDumpManager(false /* is_coordinator */); 1034 1035 // Register a bound dump provider. 1036 std::unique_ptr<Thread> mdp_thread(new Thread("test thread")); 1037 mdp_thread->Start(); 1038 MockMemoryDumpProvider mdp_with_affinity; 1039 RegisterDumpProvider(&mdp_with_affinity, mdp_thread->task_runner(), 1040 kDefaultOptions); 1041 1042 // Register also an unbound dump provider. Unbound dump providers are always 1043 // invoked after bound ones. 1044 MockMemoryDumpProvider unbound_mdp; 1045 RegisterDumpProvider(&unbound_mdp, nullptr, kDefaultOptions); 1046 1047 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 1048 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 1049 EXPECT_CALL(mdp_with_affinity, OnMemoryDump(_, _)) 1050 .Times(1) 1051 .WillOnce( 1052 Invoke([&tracing_disabled_event](const MemoryDumpArgs&, 1053 ProcessMemoryDump* pmd) -> bool { 1054 tracing_disabled_event.Wait(); 1055 1056 // At this point tracing has been disabled and the 1057 // MemoryDumpManager.dump_thread_ has been shut down. 1058 return true; 1059 })); 1060 1061 // |unbound_mdp| should never be invoked because the thread for unbound dump 1062 // providers has been shutdown in the meanwhile. 1063 EXPECT_CALL(unbound_mdp, OnMemoryDump(_, _)).Times(0); 1064 1065 last_callback_success_ = true; 1066 RunLoop run_loop; 1067 MemoryDumpCallback callback = 1068 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this), 1069 ThreadTaskRunnerHandle::Get(), run_loop.QuitClosure()); 1070 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, 1071 MemoryDumpLevelOfDetail::DETAILED, callback); 1072 DisableTracing(); 1073 tracing_disabled_event.Signal(); 1074 run_loop.Run(); 1075 1076 EXPECT_FALSE(last_callback_success_); 1077 } 1078 1079 // Tests against race conditions that can happen if tracing is disabled before 1080 // the CreateProcessDump() call. Real-world regression: crbug.com/580295 . 1081 TEST_F(MemoryDumpManagerTest, DisableTracingRightBeforeStartOfDump) { 1082 base::WaitableEvent tracing_disabled_event( 1083 WaitableEvent::ResetPolicy::AUTOMATIC, 1084 WaitableEvent::InitialState::NOT_SIGNALED); 1085 InitializeMemoryDumpManager(false /* is_coordinator */); 1086 1087 std::unique_ptr<Thread> mdp_thread(new Thread("test thread")); 1088 mdp_thread->Start(); 1089 1090 // Create both same-thread MDP and another MDP with dedicated thread 1091 MockMemoryDumpProvider mdp1; 1092 RegisterDumpProvider(&mdp1, nullptr); 1093 MockMemoryDumpProvider mdp2; 1094 RegisterDumpProvider(&mdp2, mdp_thread->task_runner(), kDefaultOptions); 1095 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 1096 1097 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)) 1098 .WillOnce(Invoke([this](const MemoryDumpRequestArgs& args, 1099 const MemoryDumpCallback& callback) { 1100 DisableTracing(); 1101 delegate_->CreateProcessDump(args, callback); 1102 })); 1103 1104 // If tracing is disabled for current session CreateProcessDump() should NOT 1105 // request dumps from providers. Real-world regression: crbug.com/600570 . 1106 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0); 1107 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0); 1108 1109 last_callback_success_ = true; 1110 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 1111 MemoryDumpLevelOfDetail::DETAILED); 1112 EXPECT_FALSE(last_callback_success_); 1113 } 1114 1115 TEST_F(MemoryDumpManagerTest, DumpOnBehalfOfOtherProcess) { 1116 using trace_analyzer::Query; 1117 1118 InitializeMemoryDumpManager(false /* is_coordinator */); 1119 1120 // Standard provider with default options (create dump for current process). 1121 MemoryDumpProvider::Options options; 1122 MockMemoryDumpProvider mdp1; 1123 RegisterDumpProvider(&mdp1, nullptr, options); 1124 1125 // Provider with out-of-process dumping. 1126 MockMemoryDumpProvider mdp2; 1127 options.target_pid = 123; 1128 RegisterDumpProvider(&mdp2, nullptr, options); 1129 1130 // Another provider with out-of-process dumping. 1131 MockMemoryDumpProvider mdp3; 1132 options.target_pid = 456; 1133 RegisterDumpProvider(&mdp3, nullptr, options); 1134 1135 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 1136 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 1137 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true)); 1138 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true)); 1139 EXPECT_CALL(mdp3, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true)); 1140 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 1141 MemoryDumpLevelOfDetail::DETAILED); 1142 DisableTracing(); 1143 1144 // Flush the trace into JSON. 1145 trace_event::TraceResultBuffer buffer; 1146 TraceResultBuffer::SimpleOutput trace_output; 1147 buffer.SetOutputCallback(trace_output.GetCallback()); 1148 RunLoop run_loop; 1149 buffer.Start(); 1150 trace_event::TraceLog::GetInstance()->Flush( 1151 Bind(&OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer))); 1152 run_loop.Run(); 1153 buffer.Finish(); 1154 1155 // Analyze the JSON. 1156 std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer = WrapUnique( 1157 trace_analyzer::TraceAnalyzer::Create(trace_output.json_output)); 1158 trace_analyzer::TraceEventVector events; 1159 analyzer->FindEvents(Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP), 1160 &events); 1161 1162 ASSERT_EQ(3u, events.size()); 1163 ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(123))); 1164 ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(456))); 1165 ASSERT_EQ(1u, trace_analyzer::CountMatches( 1166 events, Query::EventPidIs(GetCurrentProcId()))); 1167 ASSERT_EQ(events[0]->id, events[1]->id); 1168 ASSERT_EQ(events[0]->id, events[2]->id); 1169 } 1170 1171 // Tests the basics of the UnregisterAndDeleteDumpProviderSoon(): the 1172 // unregistration should actually delete the providers and not leak them. 1173 TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoon) { 1174 InitializeMemoryDumpManager(false /* is_coordinator */); 1175 static const int kNumProviders = 3; 1176 int dtor_count = 0; 1177 std::vector<std::unique_ptr<MemoryDumpProvider>> mdps; 1178 for (int i = 0; i < kNumProviders; ++i) { 1179 std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider); 1180 mdp->enable_mock_destructor = true; 1181 EXPECT_CALL(*mdp, Destructor()) 1182 .WillOnce(Invoke([&dtor_count]() { dtor_count++; })); 1183 RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions); 1184 mdps.push_back(std::move(mdp)); 1185 } 1186 1187 while (!mdps.empty()) { 1188 mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdps.back())); 1189 mdps.pop_back(); 1190 } 1191 1192 ASSERT_EQ(kNumProviders, dtor_count); 1193 } 1194 1195 // This test checks against races when unregistering an unbound dump provider 1196 // from another thread while dumping. It registers one MDP and, when 1197 // OnMemoryDump() is called, it invokes UnregisterAndDeleteDumpProviderSoon() 1198 // from another thread. The OnMemoryDump() and the dtor call are expected to 1199 // happen on the same thread (the MemoryDumpManager utility thread). 1200 TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoonDuringDump) { 1201 InitializeMemoryDumpManager(false /* is_coordinator */); 1202 std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider); 1203 mdp->enable_mock_destructor = true; 1204 RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions); 1205 1206 base::PlatformThreadRef thread_ref; 1207 auto self_unregister_from_another_thread = [&mdp, &thread_ref]( 1208 const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { 1209 thread_ref = PlatformThread::CurrentRef(); 1210 TestIOThread thread_for_unregistration(TestIOThread::kAutoStart); 1211 PostTaskAndWait( 1212 FROM_HERE, thread_for_unregistration.task_runner().get(), 1213 base::Bind( 1214 &MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon, 1215 base::Unretained(MemoryDumpManager::GetInstance()), 1216 base::Passed(std::unique_ptr<MemoryDumpProvider>(std::move(mdp))))); 1217 thread_for_unregistration.Stop(); 1218 return true; 1219 }; 1220 EXPECT_CALL(*mdp, OnMemoryDump(_, _)) 1221 .Times(1) 1222 .WillOnce(Invoke(self_unregister_from_another_thread)); 1223 EXPECT_CALL(*mdp, Destructor()) 1224 .Times(1) 1225 .WillOnce(Invoke([&thread_ref]() { 1226 EXPECT_EQ(thread_ref, PlatformThread::CurrentRef()); 1227 })); 1228 1229 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 1230 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2); 1231 for (int i = 0; i < 2; ++i) { 1232 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 1233 MemoryDumpLevelOfDetail::DETAILED); 1234 } 1235 DisableTracing(); 1236 } 1237 1238 TEST_F(MemoryDumpManagerTest, TestWhitelistingMDP) { 1239 InitializeMemoryDumpManager(false /* is_coordinator */); 1240 SetDumpProviderWhitelistForTesting(kTestMDPWhitelist); 1241 std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider); 1242 RegisterDumpProvider(mdp1.get(), nullptr); 1243 std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider); 1244 RegisterDumpProvider(mdp2.get(), nullptr, kDefaultOptions, 1245 kWhitelistedMDPName); 1246 1247 EXPECT_CALL(*mdp1, OnMemoryDump(_, _)).Times(0); 1248 EXPECT_CALL(*mdp2, OnMemoryDump(_, _)).Times(1).WillOnce(Return(true)); 1249 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); 1250 1251 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); 1252 EXPECT_FALSE(IsPeriodicDumpingEnabled()); 1253 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 1254 MemoryDumpLevelOfDetail::BACKGROUND); 1255 DisableTracing(); 1256 } 1257 1258 TEST_F(MemoryDumpManagerTest, TestBackgroundTracingSetup) { 1259 InitializeMemoryDumpManager(true /* is_coordinator */); 1260 1261 RunLoop run_loop; 1262 auto quit_closure = run_loop.QuitClosure(); 1263 1264 testing::InSequence sequence; 1265 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(IsBackgroundDump(), _)) 1266 .Times(5); 1267 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(IsBackgroundDump(), _)) 1268 .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args, 1269 const MemoryDumpCallback& callback) { 1270 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure); 1271 })); 1272 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(AnyNumber()); 1273 1274 EnableTracingWithTraceConfig( 1275 TraceConfigMemoryTestUtil::GetTraceConfig_BackgroundTrigger( 1276 1 /* period_ms */)); 1277 1278 // Only background mode dumps should be allowed with the trace config. 1279 last_callback_success_ = false; 1280 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 1281 MemoryDumpLevelOfDetail::LIGHT); 1282 EXPECT_FALSE(last_callback_success_); 1283 last_callback_success_ = false; 1284 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, 1285 MemoryDumpLevelOfDetail::DETAILED); 1286 EXPECT_FALSE(last_callback_success_); 1287 1288 ASSERT_TRUE(IsPeriodicDumpingEnabled()); 1289 run_loop.Run(); 1290 DisableTracing(); 1291 } 1292 1293 TEST_F(MemoryDumpManagerTest, TestBlacklistedUnsafeUnregistration) { 1294 InitializeMemoryDumpManager(false /* is_coordinator */); 1295 MockMemoryDumpProvider mdp1; 1296 RegisterDumpProvider(&mdp1, nullptr, kDefaultOptions, 1297 "BlacklistTestDumpProvider"); 1298 // Not calling UnregisterAndDeleteDumpProviderSoon() should not crash. 1299 mdm_->UnregisterDumpProvider(&mdp1); 1300 1301 Thread thread("test thread"); 1302 thread.Start(); 1303 RegisterDumpProvider(&mdp1, thread.task_runner(), kDefaultOptions, 1304 "BlacklistTestDumpProvider"); 1305 // Unregistering on wrong thread should not crash. 1306 mdm_->UnregisterDumpProvider(&mdp1); 1307 thread.Stop(); 1308 } 1309 1310 } // namespace trace_event 1311 } // namespace base 1312