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 <inttypes.h>
8 #include <stdio.h>
9
10 #include <algorithm>
11 #include <memory>
12 #include <utility>
13
14 #include "base/allocator/buildflags.h"
15 #include "base/base_switches.h"
16 #include "base/command_line.h"
17 #include "base/debug/alias.h"
18 #include "base/debug/stack_trace.h"
19 #include "base/debug/thread_heap_usage_tracker.h"
20 #include "base/memory/ptr_util.h"
21 #include "base/sequenced_task_runner.h"
22 #include "base/strings/string_util.h"
23 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
24 #include "base/threading/thread.h"
25 #include "base/threading/thread_task_runner_handle.h"
26 #include "base/trace_event/heap_profiler.h"
27 #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
28 #include "base/trace_event/heap_profiler_event_filter.h"
29 #include "base/trace_event/malloc_dump_provider.h"
30 #include "base/trace_event/memory_dump_provider.h"
31 #include "base/trace_event/memory_dump_scheduler.h"
32 #include "base/trace_event/memory_infra_background_whitelist.h"
33 #include "base/trace_event/process_memory_dump.h"
34 #include "base/trace_event/trace_event.h"
35 #include "base/trace_event/trace_event_argument.h"
36 #include "build/build_config.h"
37
38 #if defined(OS_ANDROID)
39 #include "base/trace_event/java_heap_dump_provider_android.h"
40
41 #if BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE)
42 #include "base/trace_event/cfi_backtrace_android.h"
43 #endif
44
45 #endif // defined(OS_ANDROID)
46
47 namespace base {
48 namespace trace_event {
49
50 namespace {
51
52 MemoryDumpManager* g_memory_dump_manager_for_testing = nullptr;
53
54 // Temporary (until scheduler is moved outside of here)
55 // trampoline function to match the |request_dump_function| passed to Initialize
56 // to the callback expected by MemoryDumpScheduler.
57 // TODO(primiano): remove this.
DoGlobalDumpWithoutCallback(MemoryDumpManager::RequestGlobalDumpFunction global_dump_fn,MemoryDumpType dump_type,MemoryDumpLevelOfDetail level_of_detail)58 void DoGlobalDumpWithoutCallback(
59 MemoryDumpManager::RequestGlobalDumpFunction global_dump_fn,
60 MemoryDumpType dump_type,
61 MemoryDumpLevelOfDetail level_of_detail) {
62 global_dump_fn.Run(dump_type, level_of_detail);
63 }
64
65 } // namespace
66
67 // static
68 const char* const MemoryDumpManager::kTraceCategory =
69 TRACE_DISABLED_BY_DEFAULT("memory-infra");
70
71 // static
72 const int MemoryDumpManager::kMaxConsecutiveFailuresCount = 3;
73
74 // static
75 const uint64_t MemoryDumpManager::kInvalidTracingProcessId = 0;
76
77 // static
78 const char* const MemoryDumpManager::kSystemAllocatorPoolName =
79 #if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
80 MallocDumpProvider::kAllocatedObjects;
81 #else
82 nullptr;
83 #endif
84
85 // static
GetInstance()86 MemoryDumpManager* MemoryDumpManager::GetInstance() {
87 if (g_memory_dump_manager_for_testing)
88 return g_memory_dump_manager_for_testing;
89
90 return Singleton<MemoryDumpManager,
91 LeakySingletonTraits<MemoryDumpManager>>::get();
92 }
93
94 // static
95 std::unique_ptr<MemoryDumpManager>
CreateInstanceForTesting()96 MemoryDumpManager::CreateInstanceForTesting() {
97 DCHECK(!g_memory_dump_manager_for_testing);
98 std::unique_ptr<MemoryDumpManager> instance(new MemoryDumpManager());
99 g_memory_dump_manager_for_testing = instance.get();
100 return instance;
101 }
102
MemoryDumpManager()103 MemoryDumpManager::MemoryDumpManager()
104 : is_coordinator_(false),
105 tracing_process_id_(kInvalidTracingProcessId),
106 dumper_registrations_ignored_for_testing_(false) {}
107
~MemoryDumpManager()108 MemoryDumpManager::~MemoryDumpManager() {
109 Thread* dump_thread = nullptr;
110 {
111 AutoLock lock(lock_);
112 if (dump_thread_) {
113 dump_thread = dump_thread_.get();
114 }
115 }
116 if (dump_thread) {
117 dump_thread->Stop();
118 }
119 AutoLock lock(lock_);
120 dump_thread_.reset();
121 g_memory_dump_manager_for_testing = nullptr;
122 }
123
Initialize(RequestGlobalDumpFunction request_dump_function,bool is_coordinator)124 void MemoryDumpManager::Initialize(
125 RequestGlobalDumpFunction request_dump_function,
126 bool is_coordinator) {
127 {
128 AutoLock lock(lock_);
129 DCHECK(!request_dump_function.is_null());
130 DCHECK(!can_request_global_dumps());
131 request_dump_function_ = request_dump_function;
132 is_coordinator_ = is_coordinator;
133 }
134
135 // Enable the core dump providers.
136 #if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
137 RegisterDumpProvider(MallocDumpProvider::GetInstance(), "Malloc", nullptr);
138 #endif
139
140 #if defined(OS_ANDROID)
141 RegisterDumpProvider(JavaHeapDumpProvider::GetInstance(), "JavaHeap",
142 nullptr);
143 #endif
144
145 TRACE_EVENT_WARMUP_CATEGORY(kTraceCategory);
146 }
147
RegisterDumpProvider(MemoryDumpProvider * mdp,const char * name,scoped_refptr<SingleThreadTaskRunner> task_runner,MemoryDumpProvider::Options options)148 void MemoryDumpManager::RegisterDumpProvider(
149 MemoryDumpProvider* mdp,
150 const char* name,
151 scoped_refptr<SingleThreadTaskRunner> task_runner,
152 MemoryDumpProvider::Options options) {
153 options.dumps_on_single_thread_task_runner = true;
154 RegisterDumpProviderInternal(mdp, name, std::move(task_runner), options);
155 }
156
RegisterDumpProvider(MemoryDumpProvider * mdp,const char * name,scoped_refptr<SingleThreadTaskRunner> task_runner)157 void MemoryDumpManager::RegisterDumpProvider(
158 MemoryDumpProvider* mdp,
159 const char* name,
160 scoped_refptr<SingleThreadTaskRunner> task_runner) {
161 // Set |dumps_on_single_thread_task_runner| to true because all providers
162 // without task runner are run on dump thread.
163 MemoryDumpProvider::Options options;
164 options.dumps_on_single_thread_task_runner = true;
165 RegisterDumpProviderInternal(mdp, name, std::move(task_runner), options);
166 }
167
RegisterDumpProviderWithSequencedTaskRunner(MemoryDumpProvider * mdp,const char * name,scoped_refptr<SequencedTaskRunner> task_runner,MemoryDumpProvider::Options options)168 void MemoryDumpManager::RegisterDumpProviderWithSequencedTaskRunner(
169 MemoryDumpProvider* mdp,
170 const char* name,
171 scoped_refptr<SequencedTaskRunner> task_runner,
172 MemoryDumpProvider::Options options) {
173 DCHECK(task_runner);
174 options.dumps_on_single_thread_task_runner = false;
175 RegisterDumpProviderInternal(mdp, name, std::move(task_runner), options);
176 }
177
RegisterDumpProviderInternal(MemoryDumpProvider * mdp,const char * name,scoped_refptr<SequencedTaskRunner> task_runner,const MemoryDumpProvider::Options & options)178 void MemoryDumpManager::RegisterDumpProviderInternal(
179 MemoryDumpProvider* mdp,
180 const char* name,
181 scoped_refptr<SequencedTaskRunner> task_runner,
182 const MemoryDumpProvider::Options& options) {
183 if (dumper_registrations_ignored_for_testing_)
184 return;
185
186 // Only a handful of MDPs are required to compute the memory metrics. These
187 // have small enough performance overhead that it is resonable to run them
188 // in the background while the user is doing other things. Those MDPs are
189 // 'whitelisted for background mode'.
190 bool whitelisted_for_background_mode = IsMemoryDumpProviderWhitelisted(name);
191
192 scoped_refptr<MemoryDumpProviderInfo> mdpinfo =
193 new MemoryDumpProviderInfo(mdp, name, std::move(task_runner), options,
194 whitelisted_for_background_mode);
195
196 {
197 AutoLock lock(lock_);
198 bool already_registered = !dump_providers_.insert(mdpinfo).second;
199 // This actually happens in some tests which don't have a clean tear-down
200 // path for RenderThreadImpl::Init().
201 if (already_registered)
202 return;
203 }
204 }
205
UnregisterDumpProvider(MemoryDumpProvider * mdp)206 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
207 UnregisterDumpProviderInternal(mdp, false /* delete_async */);
208 }
209
UnregisterAndDeleteDumpProviderSoon(std::unique_ptr<MemoryDumpProvider> mdp)210 void MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon(
211 std::unique_ptr<MemoryDumpProvider> mdp) {
212 UnregisterDumpProviderInternal(mdp.release(), true /* delete_async */);
213 }
214
UnregisterDumpProviderInternal(MemoryDumpProvider * mdp,bool take_mdp_ownership_and_delete_async)215 void MemoryDumpManager::UnregisterDumpProviderInternal(
216 MemoryDumpProvider* mdp,
217 bool take_mdp_ownership_and_delete_async) {
218 std::unique_ptr<MemoryDumpProvider> owned_mdp;
219 if (take_mdp_ownership_and_delete_async)
220 owned_mdp.reset(mdp);
221
222 AutoLock lock(lock_);
223
224 auto mdp_iter = dump_providers_.begin();
225 for (; mdp_iter != dump_providers_.end(); ++mdp_iter) {
226 if ((*mdp_iter)->dump_provider == mdp)
227 break;
228 }
229
230 if (mdp_iter == dump_providers_.end())
231 return; // Not registered / already unregistered.
232
233 if (take_mdp_ownership_and_delete_async) {
234 // The MDP will be deleted whenever the MDPInfo struct will, that is either:
235 // - At the end of this function, if no dump is in progress.
236 // - In ContinueAsyncProcessDump() when MDPInfo is removed from
237 // |pending_dump_providers|.
238 DCHECK(!(*mdp_iter)->owned_dump_provider);
239 (*mdp_iter)->owned_dump_provider = std::move(owned_mdp);
240 } else {
241 // If you hit this DCHECK, your dump provider has a bug.
242 // Unregistration of a MemoryDumpProvider is safe only if:
243 // - The MDP has specified a sequenced task runner affinity AND the
244 // unregistration happens on the same task runner. So that the MDP cannot
245 // unregister and be in the middle of a OnMemoryDump() at the same time.
246 // - The MDP has NOT specified a task runner affinity and its ownership is
247 // transferred via UnregisterAndDeleteDumpProviderSoon().
248 // In all the other cases, it is not possible to guarantee that the
249 // unregistration will not race with OnMemoryDump() calls.
250 DCHECK((*mdp_iter)->task_runner &&
251 (*mdp_iter)->task_runner->RunsTasksInCurrentSequence())
252 << "MemoryDumpProvider \"" << (*mdp_iter)->name << "\" attempted to "
253 << "unregister itself in a racy way. Please file a crbug.";
254 }
255
256 // The MDPInfo instance can still be referenced by the
257 // |ProcessMemoryDumpAsyncState.pending_dump_providers|. For this reason
258 // the MDPInfo is flagged as disabled. It will cause InvokeOnMemoryDump()
259 // to just skip it, without actually invoking the |mdp|, which might be
260 // destroyed by the caller soon after this method returns.
261 (*mdp_iter)->disabled = true;
262 dump_providers_.erase(mdp_iter);
263 }
264
IsDumpProviderRegisteredForTesting(MemoryDumpProvider * provider)265 bool MemoryDumpManager::IsDumpProviderRegisteredForTesting(
266 MemoryDumpProvider* provider) {
267 AutoLock lock(lock_);
268
269 for (const auto& info : dump_providers_) {
270 if (info->dump_provider == provider)
271 return true;
272 }
273 return false;
274 }
275
276 scoped_refptr<base::SequencedTaskRunner>
GetOrCreateBgTaskRunnerLocked()277 MemoryDumpManager::GetOrCreateBgTaskRunnerLocked() {
278 lock_.AssertAcquired();
279
280 if (dump_thread_)
281 return dump_thread_->task_runner();
282
283 dump_thread_ = std::make_unique<Thread>("MemoryInfra");
284 bool started = dump_thread_->Start();
285 CHECK(started);
286
287 return dump_thread_->task_runner();
288 }
289
CreateProcessDump(const MemoryDumpRequestArgs & args,const ProcessMemoryDumpCallback & callback)290 void MemoryDumpManager::CreateProcessDump(
291 const MemoryDumpRequestArgs& args,
292 const ProcessMemoryDumpCallback& callback) {
293 char guid_str[20];
294 sprintf(guid_str, "0x%" PRIx64, args.dump_guid);
295 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(kTraceCategory, "ProcessMemoryDump",
296 TRACE_ID_LOCAL(args.dump_guid), "dump_guid",
297 TRACE_STR_COPY(guid_str));
298
299 // If argument filter is enabled then only background mode dumps should be
300 // allowed. In case the trace config passed for background tracing session
301 // missed the allowed modes argument, it crashes here instead of creating
302 // unexpected dumps.
303 if (TraceLog::GetInstance()
304 ->GetCurrentTraceConfig()
305 .IsArgumentFilterEnabled()) {
306 CHECK_EQ(MemoryDumpLevelOfDetail::BACKGROUND, args.level_of_detail);
307 }
308
309 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
310 {
311 AutoLock lock(lock_);
312
313 pmd_async_state.reset(new ProcessMemoryDumpAsyncState(
314 args, dump_providers_, callback, GetOrCreateBgTaskRunnerLocked()));
315 }
316
317 // Start the process dump. This involves task runner hops as specified by the
318 // MemoryDumpProvider(s) in RegisterDumpProvider()).
319 ContinueAsyncProcessDump(pmd_async_state.release());
320 }
321
322 // Invokes OnMemoryDump() on all MDPs that are next in the pending list and run
323 // on the current sequenced task runner. If the next MDP does not run in current
324 // sequenced task runner, then switches to that task runner and continues. All
325 // OnMemoryDump() invocations are linearized. |lock_| is used in these functions
326 // purely to ensure consistency w.r.t. (un)registrations of |dump_providers_|.
ContinueAsyncProcessDump(ProcessMemoryDumpAsyncState * owned_pmd_async_state)327 void MemoryDumpManager::ContinueAsyncProcessDump(
328 ProcessMemoryDumpAsyncState* owned_pmd_async_state) {
329 HEAP_PROFILER_SCOPED_IGNORE;
330 // Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs
331 // in the PostTask below don't end up registering their own dump providers
332 // (for discounting trace memory overhead) while holding the |lock_|.
333 TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
334
335 // In theory |owned_pmd_async_state| should be a unique_ptr. The only reason
336 // why it isn't is because of the corner case logic of |did_post_task|
337 // above, which needs to take back the ownership of the |pmd_async_state| when
338 // the PostTask() fails.
339 // Unfortunately, PostTask() destroys the unique_ptr arguments upon failure
340 // to prevent accidental leaks. Using a unique_ptr would prevent us to to
341 // skip the hop and move on. Hence the manual naked -> unique ptr juggling.
342 auto pmd_async_state = WrapUnique(owned_pmd_async_state);
343 owned_pmd_async_state = nullptr;
344
345 while (!pmd_async_state->pending_dump_providers.empty()) {
346 // Read MemoryDumpProviderInfo thread safety considerations in
347 // memory_dump_manager.h when accessing |mdpinfo| fields.
348 MemoryDumpProviderInfo* mdpinfo =
349 pmd_async_state->pending_dump_providers.back().get();
350
351 // If we are in background mode, we should invoke only the whitelisted
352 // providers. Ignore other providers and continue.
353 if (pmd_async_state->req_args.level_of_detail ==
354 MemoryDumpLevelOfDetail::BACKGROUND &&
355 !mdpinfo->whitelisted_for_background_mode) {
356 pmd_async_state->pending_dump_providers.pop_back();
357 continue;
358 }
359
360 // If the dump provider did not specify a task runner affinity, dump on
361 // |dump_thread_|.
362 scoped_refptr<SequencedTaskRunner> task_runner = mdpinfo->task_runner;
363 if (!task_runner) {
364 DCHECK(mdpinfo->options.dumps_on_single_thread_task_runner);
365 task_runner = pmd_async_state->dump_thread_task_runner;
366 DCHECK(task_runner);
367 }
368
369 // If |RunsTasksInCurrentSequence()| is true then no PostTask is
370 // required since we are on the right SequencedTaskRunner.
371 if (task_runner->RunsTasksInCurrentSequence()) {
372 InvokeOnMemoryDump(mdpinfo, pmd_async_state->process_memory_dump.get());
373 pmd_async_state->pending_dump_providers.pop_back();
374 continue;
375 }
376
377 bool did_post_task = task_runner->PostTask(
378 FROM_HERE,
379 BindOnce(&MemoryDumpManager::ContinueAsyncProcessDump, Unretained(this),
380 Unretained(pmd_async_state.get())));
381
382 if (did_post_task) {
383 // Ownership is tranferred to the posted task.
384 ignore_result(pmd_async_state.release());
385 return;
386 }
387
388 // PostTask usually fails only if the process or thread is shut down. So,
389 // the dump provider is disabled here. But, don't disable unbound dump
390 // providers, since the |dump_thread_| is controlled by MDM.
391 if (mdpinfo->task_runner) {
392 // A locked access is required to R/W |disabled| (for the
393 // UnregisterAndDeleteDumpProviderSoon() case).
394 AutoLock lock(lock_);
395 mdpinfo->disabled = true;
396 }
397
398 // PostTask failed. Ignore the dump provider and continue.
399 pmd_async_state->pending_dump_providers.pop_back();
400 }
401
402 FinishAsyncProcessDump(std::move(pmd_async_state));
403 }
404
405 // This function is called on the right task runner for current MDP. It is
406 // either the task runner specified by MDP or |dump_thread_task_runner| if the
407 // MDP did not specify task runner. Invokes the dump provider's OnMemoryDump()
408 // (unless disabled).
InvokeOnMemoryDump(MemoryDumpProviderInfo * mdpinfo,ProcessMemoryDump * pmd)409 void MemoryDumpManager::InvokeOnMemoryDump(MemoryDumpProviderInfo* mdpinfo,
410 ProcessMemoryDump* pmd) {
411 HEAP_PROFILER_SCOPED_IGNORE;
412 DCHECK(!mdpinfo->task_runner ||
413 mdpinfo->task_runner->RunsTasksInCurrentSequence());
414
415 TRACE_EVENT1(kTraceCategory, "MemoryDumpManager::InvokeOnMemoryDump",
416 "dump_provider.name", mdpinfo->name);
417
418 // Do not add any other TRACE_EVENT macro (or function that might have them)
419 // below this point. Under some rare circunstances, they can re-initialize
420 // and invalide the current ThreadLocalEventBuffer MDP, making the
421 // |should_dump| check below susceptible to TOCTTOU bugs
422 // (https://crbug.com/763365).
423
424 bool is_thread_bound;
425 {
426 // A locked access is required to R/W |disabled| (for the
427 // UnregisterAndDeleteDumpProviderSoon() case).
428 AutoLock lock(lock_);
429
430 // Unregister the dump provider if it failed too many times consecutively.
431 if (!mdpinfo->disabled &&
432 mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) {
433 mdpinfo->disabled = true;
434 DLOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name
435 << "\". Dump failed multiple times consecutively.";
436 }
437 if (mdpinfo->disabled)
438 return;
439
440 is_thread_bound = mdpinfo->task_runner != nullptr;
441 } // AutoLock lock(lock_);
442
443 // Invoke the dump provider.
444
445 // A stack allocated string with dump provider name is useful to debug
446 // crashes while invoking dump after a |dump_provider| is not unregistered
447 // in safe way.
448 char provider_name_for_debugging[16];
449 strncpy(provider_name_for_debugging, mdpinfo->name,
450 sizeof(provider_name_for_debugging) - 1);
451 provider_name_for_debugging[sizeof(provider_name_for_debugging) - 1] = '\0';
452 base::debug::Alias(provider_name_for_debugging);
453
454 ANNOTATE_BENIGN_RACE(&mdpinfo->disabled, "best-effort race detection");
455 CHECK(!is_thread_bound ||
456 !*(static_cast<volatile bool*>(&mdpinfo->disabled)));
457 bool dump_successful =
458 mdpinfo->dump_provider->OnMemoryDump(pmd->dump_args(), pmd);
459 mdpinfo->consecutive_failures =
460 dump_successful ? 0 : mdpinfo->consecutive_failures + 1;
461 }
462
FinishAsyncProcessDump(std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state)463 void MemoryDumpManager::FinishAsyncProcessDump(
464 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
465 HEAP_PROFILER_SCOPED_IGNORE;
466 DCHECK(pmd_async_state->pending_dump_providers.empty());
467 const uint64_t dump_guid = pmd_async_state->req_args.dump_guid;
468 if (!pmd_async_state->callback_task_runner->BelongsToCurrentThread()) {
469 scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
470 pmd_async_state->callback_task_runner;
471 callback_task_runner->PostTask(
472 FROM_HERE, BindOnce(&MemoryDumpManager::FinishAsyncProcessDump,
473 Unretained(this), std::move(pmd_async_state)));
474 return;
475 }
476
477 TRACE_EVENT0(kTraceCategory, "MemoryDumpManager::FinishAsyncProcessDump");
478
479 if (!pmd_async_state->callback.is_null()) {
480 pmd_async_state->callback.Run(
481 true /* success */, dump_guid,
482 std::move(pmd_async_state->process_memory_dump));
483 pmd_async_state->callback.Reset();
484 }
485
486 TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump",
487 TRACE_ID_LOCAL(dump_guid));
488 }
489
SetupForTracing(const TraceConfig::MemoryDumpConfig & memory_dump_config)490 void MemoryDumpManager::SetupForTracing(
491 const TraceConfig::MemoryDumpConfig& memory_dump_config) {
492 AutoLock lock(lock_);
493
494 // At this point we must have the ability to request global dumps.
495 DCHECK(can_request_global_dumps());
496
497 MemoryDumpScheduler::Config periodic_config;
498 for (const auto& trigger : memory_dump_config.triggers) {
499 if (trigger.trigger_type == MemoryDumpType::PERIODIC_INTERVAL) {
500 if (periodic_config.triggers.empty()) {
501 periodic_config.callback =
502 BindRepeating(&DoGlobalDumpWithoutCallback, request_dump_function_,
503 MemoryDumpType::PERIODIC_INTERVAL);
504 }
505 periodic_config.triggers.push_back(
506 {trigger.level_of_detail, trigger.min_time_between_dumps_ms});
507 }
508 }
509
510 // Only coordinator process triggers periodic memory dumps.
511 if (is_coordinator_ && !periodic_config.triggers.empty()) {
512 MemoryDumpScheduler::GetInstance()->Start(periodic_config,
513 GetOrCreateBgTaskRunnerLocked());
514 }
515 }
516
TeardownForTracing()517 void MemoryDumpManager::TeardownForTracing() {
518 // There might be a memory dump in progress while this happens. Therefore,
519 // ensure that the MDM state which depends on the tracing enabled / disabled
520 // state is always accessed by the dumping methods holding the |lock_|.
521 AutoLock lock(lock_);
522
523 MemoryDumpScheduler::GetInstance()->Stop();
524 }
525
ProcessMemoryDumpAsyncState(MemoryDumpRequestArgs req_args,const MemoryDumpProviderInfo::OrderedSet & dump_providers,ProcessMemoryDumpCallback callback,scoped_refptr<SequencedTaskRunner> dump_thread_task_runner)526 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
527 MemoryDumpRequestArgs req_args,
528 const MemoryDumpProviderInfo::OrderedSet& dump_providers,
529 ProcessMemoryDumpCallback callback,
530 scoped_refptr<SequencedTaskRunner> dump_thread_task_runner)
531 : req_args(req_args),
532 callback(callback),
533 callback_task_runner(ThreadTaskRunnerHandle::Get()),
534 dump_thread_task_runner(std::move(dump_thread_task_runner)) {
535 pending_dump_providers.reserve(dump_providers.size());
536 pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend());
537 MemoryDumpArgs args = {req_args.level_of_detail, req_args.dump_guid};
538 process_memory_dump = std::make_unique<ProcessMemoryDump>(args);
539 }
540
541 MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() =
542 default;
543
544 } // namespace trace_event
545 } // namespace base
546