Index: trace_event/memory_dump_manager_unittest.cc |
diff --git a/trace_event/memory_dump_manager_unittest.cc b/trace_event/memory_dump_manager_unittest.cc |
index 9835415f4e7ff0305c5c08d7a1a41e5aaab413c9..6fb8c321e5bd978b50c6cf1468a684bd14e70ddd 100644 |
--- a/trace_event/memory_dump_manager_unittest.cc |
+++ b/trace_event/memory_dump_manager_unittest.cc |
@@ -8,6 +8,7 @@ |
#include "base/memory/scoped_vector.h" |
#include "base/message_loop/message_loop.h" |
#include "base/run_loop.h" |
+#include "base/test/test_io_thread.h" |
#include "base/thread_task_runner_handle.h" |
#include "base/threading/thread.h" |
#include "base/trace_event/memory_dump_provider.h" |
@@ -16,6 +17,7 @@ |
#include "testing/gtest/include/gtest/gtest.h" |
using testing::_; |
+using testing::AtMost; |
using testing::Between; |
using testing::Invoke; |
using testing::Return; |
@@ -282,6 +284,55 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) { |
DisableTracing(); |
} |
+// Verify that whether OnMemoryDump is called depends only on the current |
+// registration state and not on previous registrations and dumps. |
+TEST_F(MemoryDumpManagerTest, RegistrationConsistency) { |
+ MockDumpProvider mdp; |
+ |
+ mdm_->RegisterDumpProvider(&mdp); |
+ |
+ { |
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1); |
+ EnableTracing(kTraceCategory); |
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
+ high_detail_args); |
+ DisableTracing(); |
+ } |
+ |
+ mdm_->UnregisterDumpProvider(&mdp); |
+ |
+ { |
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); |
+ EnableTracing(kTraceCategory); |
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
+ high_detail_args); |
+ DisableTracing(); |
+ } |
+ |
+ mdm_->RegisterDumpProvider(&mdp); |
+ mdm_->UnregisterDumpProvider(&mdp); |
+ |
+ { |
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); |
+ EnableTracing(kTraceCategory); |
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
+ high_detail_args); |
+ DisableTracing(); |
+ } |
+ |
+ mdm_->RegisterDumpProvider(&mdp); |
+ mdm_->UnregisterDumpProvider(&mdp); |
+ mdm_->RegisterDumpProvider(&mdp); |
+ |
+ { |
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1); |
+ EnableTracing(kTraceCategory); |
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
+ high_detail_args); |
+ DisableTracing(); |
+ } |
+} |
+ |
// Checks that the MemoryDumpManager respects the thread affinity when a |
// MemoryDumpProvider specifies a task_runner(). The test starts creating 8 |
// threads and registering a MemoryDumpProvider on each of them. At each |
@@ -433,6 +484,61 @@ TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) { |
DisableTracing(); |
} |
+// Verify that the dump does not abort when unregistering a provider while |
+// dumping from a different thread than the dumping thread. |
+TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) { |
+ ScopedVector<TestIOThread> threads; |
+ ScopedVector<MockDumpProvider> mdps; |
+ |
+ for (int i = 0; i < 2; i++) { |
+ threads.push_back(new TestIOThread(TestIOThread::kAutoStart)); |
+ mdps.push_back(new MockDumpProvider(threads.back()->task_runner())); |
+ mdm_->RegisterDumpProvider(mdps.back(), threads.back()->task_runner()); |
+ } |
+ |
+ int on_memory_dump_call_count = 0; |
+ RunLoop run_loop; |
+ |
+ // When OnMemoryDump is called on either of the dump providers, it will |
+ // unregister the other one. |
+ for (MockDumpProvider* mdp : mdps) { |
+ int other_idx = (mdps.front() == mdp); |
+ TestIOThread* other_thread = threads[other_idx]; |
+ MockDumpProvider* other_mdp = mdps[other_idx]; |
+ auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count]( |
+ const MemoryDumpArgs& args, ProcessMemoryDump* pmd) { |
+ other_thread->PostTaskAndWait( |
+ FROM_HERE, base::Bind(&MemoryDumpManager::UnregisterDumpProvider, |
+ base::Unretained(&*mdm_), other_mdp)); |
+ on_memory_dump_call_count++; |
+ return true; |
+ }; |
+ |
+ // OnMemoryDump is called once for the provider that dumps first, and zero |
+ // times for the other provider. |
+ EXPECT_CALL(*mdp, OnMemoryDump(_, _)) |
+ .Times(AtMost(1)) |
+ .WillOnce(Invoke(on_dump)); |
+ } |
+ |
+ last_callback_success_ = false; |
+ MemoryDumpCallback callback = |
+ Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this), |
+ MessageLoop::current()->task_runner(), run_loop.QuitClosure()); |
+ |
+ EnableTracing(kTraceCategory); |
+ MemoryDumpRequestArgs request_args = {0, MemoryDumpType::EXPLICITLY_TRIGGERED, |
+ high_detail_args}; |
+ mdm_->CreateProcessDump(request_args, callback); |
+ |
+ run_loop.Run(); |
+ |
+ ASSERT_EQ(1, on_memory_dump_call_count); |
+ ASSERT_EQ(true, last_callback_success_); |
+ |
+ DisableTracing(); |
+} |
+ |
// Ensures that a NACK callback is invoked if RequestGlobalDump is called when |
// tracing is not enabled. |
TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) { |