123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "services/resource_coordinator/memory_instrumentation/coordinator_impl.h"
- #include <inttypes.h>
- #include <stdio.h>
- #include <utility>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/command_line.h"
- #include "base/containers/contains.h"
- #include "base/location.h"
- #include "base/logging.h"
- #include "base/memory/ref_counted.h"
- #include "base/metrics/histogram_macros.h"
- #include "base/threading/sequenced_task_runner_handle.h"
- #include "base/trace_event/memory_dump_manager.h"
- #include "base/trace_event/memory_dump_request_args.h"
- #include "base/trace_event/trace_event.h"
- #include "build/build_config.h"
- #include "services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.h"
- #include "services/resource_coordinator/memory_instrumentation/switches.h"
- #include "services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h"
- #include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto.h"
- #include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.h"
- #include "services/resource_coordinator/public/mojom/memory_instrumentation/constants.mojom.h"
- #include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
- #if BUILDFLAG(IS_MAC)
- #include "base/mac/mac_util.h"
- #endif
- using base::trace_event::MemoryDumpDeterminism;
- using base::trace_event::MemoryDumpLevelOfDetail;
- using base::trace_event::MemoryDumpType;
- namespace memory_instrumentation {
- namespace {
- memory_instrumentation::CoordinatorImpl* g_coordinator_impl;
- constexpr base::TimeDelta kHeapDumpTimeout = base::Seconds(60);
- // A wrapper classes that allows a string to be exported as JSON in a trace
- // event.
- class StringWrapper : public base::trace_event::ConvertableToTraceFormat {
- public:
- explicit StringWrapper(std::string&& json) : json_(std::move(json)) {}
- void AppendAsTraceFormat(std::string* out) const override {
- out->append(json_);
- }
- std::string json_;
- };
- } // namespace
- CoordinatorImpl::CoordinatorImpl()
- : next_dump_id_(0),
- client_process_timeout_(base::Seconds(15)),
- use_proto_writer_(!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseMemoryTrackingJsonWriter)),
- write_proto_heap_profile_(
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseHeapProfilingProtoWriter)) {
- DCHECK(!g_coordinator_impl);
- g_coordinator_impl = this;
- base::trace_event::MemoryDumpManager::GetInstance()->set_tracing_process_id(
- mojom::kServiceTracingProcessId);
- if (use_proto_writer_) {
- tracing_observer_ = std::make_unique<TracingObserverProto>(
- base::trace_event::TraceLog::GetInstance(), nullptr);
- } else {
- tracing_observer_ = std::make_unique<TracingObserverTracedValue>(
- base::trace_event::TraceLog::GetInstance(), nullptr);
- }
- }
- CoordinatorImpl::~CoordinatorImpl() {
- g_coordinator_impl = nullptr;
- }
- // static
- CoordinatorImpl* CoordinatorImpl::GetInstance() {
- return g_coordinator_impl;
- }
- void CoordinatorImpl::RegisterHeapProfiler(
- mojo::PendingRemote<mojom::HeapProfiler> profiler,
- mojo::PendingReceiver<mojom::HeapProfilerHelper> helper_receiver) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- heap_profiler_.Bind(std::move(profiler));
- heap_profiler_helper_receiver_.Bind(std::move(helper_receiver));
- }
- void CoordinatorImpl::RegisterClientProcess(
- mojo::PendingReceiver<mojom::Coordinator> receiver,
- mojo::PendingRemote<mojom::ClientProcess> client_process,
- mojom::ProcessType process_type,
- base::ProcessId process_id,
- const absl::optional<std::string>& service_name) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- mojo::Remote<mojom::ClientProcess> process(std::move(client_process));
- if (receiver.is_valid())
- coordinator_receivers_.Add(this, std::move(receiver), process_id);
- process.set_disconnect_handler(
- base::BindOnce(&CoordinatorImpl::UnregisterClientProcess,
- base::Unretained(this), process_id));
- auto result = clients_.emplace(
- process_id, std::make_unique<ClientInfo>(std::move(process), process_type,
- service_name));
- DCHECK(result.second) << "Cannot register process " << process_id
- << " with type " << static_cast<int>(process_type)
- << ". Already registered for "
- << static_cast<int>(
- clients_.find(process_id)->second->process_type);
- }
- void CoordinatorImpl::RequestGlobalMemoryDump(
- MemoryDumpType dump_type,
- MemoryDumpLevelOfDetail level_of_detail,
- MemoryDumpDeterminism determinism,
- const std::vector<std::string>& allocator_dump_names,
- RequestGlobalMemoryDumpCallback callback) {
- // This merely strips out the |dump_guid| argument.
- auto adapter = [](RequestGlobalMemoryDumpCallback callback, bool success,
- uint64_t, mojom::GlobalMemoryDumpPtr global_memory_dump) {
- std::move(callback).Run(success, std::move(global_memory_dump));
- };
- QueuedRequest::Args args(dump_type, level_of_detail, determinism,
- allocator_dump_names, false /* add_to_trace */,
- base::kNullProcessId,
- /*memory_footprint_only=*/false);
- RequestGlobalMemoryDumpInternal(args,
- base::BindOnce(adapter, std::move(callback)));
- }
- void CoordinatorImpl::RequestGlobalMemoryDumpForPid(
- base::ProcessId pid,
- const std::vector<std::string>& allocator_dump_names,
- RequestGlobalMemoryDumpForPidCallback callback) {
- // Error out early if process id is null to avoid confusing with global
- // dump for all processes case when pid is kNullProcessId.
- if (pid == base::kNullProcessId) {
- std::move(callback).Run(false, nullptr);
- return;
- }
- // This merely strips out the |dump_guid| argument; this is not relevant
- // as we are not adding to trace.
- auto adapter = [](RequestGlobalMemoryDumpForPidCallback callback,
- bool success, uint64_t,
- mojom::GlobalMemoryDumpPtr global_memory_dump) {
- std::move(callback).Run(success, std::move(global_memory_dump));
- };
- QueuedRequest::Args args(
- base::trace_event::MemoryDumpType::SUMMARY_ONLY,
- base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND,
- base::trace_event::MemoryDumpDeterminism::NONE, allocator_dump_names,
- false /* add_to_trace */, pid,
- /*memory_footprint_only=*/false);
- RequestGlobalMemoryDumpInternal(args,
- base::BindOnce(adapter, std::move(callback)));
- }
- void CoordinatorImpl::RequestPrivateMemoryFootprint(
- base::ProcessId pid,
- RequestPrivateMemoryFootprintCallback callback) {
- // This merely strips out the |dump_guid| argument; this is not relevant
- // as we are not adding to trace.
- auto adapter = [](RequestPrivateMemoryFootprintCallback callback,
- bool success, uint64_t,
- mojom::GlobalMemoryDumpPtr global_memory_dump) {
- std::move(callback).Run(success, std::move(global_memory_dump));
- };
- QueuedRequest::Args args(
- base::trace_event::MemoryDumpType::SUMMARY_ONLY,
- base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND,
- base::trace_event::MemoryDumpDeterminism::NONE, {},
- false /* add_to_trace */, pid, /*memory_footprint_only=*/true);
- RequestGlobalMemoryDumpInternal(args,
- base::BindOnce(adapter, std::move(callback)));
- }
- void CoordinatorImpl::RequestGlobalMemoryDumpAndAppendToTrace(
- MemoryDumpType dump_type,
- MemoryDumpLevelOfDetail level_of_detail,
- MemoryDumpDeterminism determinism,
- RequestGlobalMemoryDumpAndAppendToTraceCallback callback) {
- // This merely strips out the |dump_ptr| argument.
- auto adapter = [](RequestGlobalMemoryDumpAndAppendToTraceCallback callback,
- bool success, uint64_t dump_guid,
- mojom::GlobalMemoryDumpPtr) {
- std::move(callback).Run(success, dump_guid);
- };
- QueuedRequest::Args args(dump_type, level_of_detail, determinism, {},
- true /* add_to_trace */, base::kNullProcessId,
- /*memory_footprint_only=*/false);
- RequestGlobalMemoryDumpInternal(args,
- base::BindOnce(adapter, std::move(callback)));
- }
- void CoordinatorImpl::GetVmRegionsForHeapProfiler(
- const std::vector<base::ProcessId>& pids,
- GetVmRegionsForHeapProfilerCallback callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- uint64_t dump_guid = ++next_dump_id_;
- std::unique_ptr<QueuedVmRegionRequest> request =
- std::make_unique<QueuedVmRegionRequest>(dump_guid, std::move(callback));
- in_progress_vm_region_requests_[dump_guid] = std::move(request);
- std::vector<QueuedRequestDispatcher::ClientInfo> clients;
- for (const auto& entry : clients_) {
- const base::ProcessId pid = entry.first;
- clients.emplace_back(entry.second->client.get(), pid,
- entry.second->process_type,
- entry.second->service_name);
- }
- QueuedVmRegionRequest* request_ptr =
- in_progress_vm_region_requests_[dump_guid].get();
- auto os_callback =
- base::BindRepeating(&CoordinatorImpl::OnOSMemoryDumpForVMRegions,
- weak_ptr_factory_.GetWeakPtr(), dump_guid);
- QueuedRequestDispatcher::SetUpAndDispatchVmRegionRequest(request_ptr, clients,
- pids, os_callback);
- FinalizeVmRegionDumpIfAllManagersReplied(dump_guid);
- }
- void CoordinatorImpl::UnregisterClientProcess(base::ProcessId process_id) {
- QueuedRequest* request = GetCurrentRequest();
- if (request != nullptr) {
- // Check if we are waiting for an ack from this client process.
- auto it = request->pending_responses.begin();
- while (it != request->pending_responses.end()) {
- // The calls to On*MemoryDumpResponse below, if executed, will delete the
- // element under the iterator which invalidates it. To avoid this we
- // increment the iterator in advance while keeping a reference to the
- // current element.
- std::set<QueuedRequest::PendingResponse>::iterator current = it++;
- if (current->process_id != process_id)
- continue;
- RemovePendingResponse(process_id, current->type);
- DLOG(ERROR)
- << "Memory dump request failed due to disconnected child process "
- << process_id;
- request->failed_memory_dump_count++;
- }
- FinalizeGlobalMemoryDumpIfAllManagersReplied();
- }
- for (auto& pair : in_progress_vm_region_requests_) {
- QueuedVmRegionRequest* in_progress_request = pair.second.get();
- auto it = in_progress_request->pending_responses.begin();
- while (it != in_progress_request->pending_responses.end()) {
- auto current = it++;
- if (*current == process_id) {
- in_progress_request->pending_responses.erase(current);
- }
- }
- }
- // Try to finalize all outstanding vm region requests.
- for (auto& pair : in_progress_vm_region_requests_) {
- // PostTask to avoid re-entrancy or modification of data-structure during
- // iteration.
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(
- &CoordinatorImpl::FinalizeVmRegionDumpIfAllManagersReplied,
- weak_ptr_factory_.GetWeakPtr(), pair.second->dump_guid));
- }
- size_t num_deleted = clients_.erase(process_id);
- DCHECK(num_deleted == 1);
- }
- void CoordinatorImpl::RequestGlobalMemoryDumpInternal(
- const QueuedRequest::Args& args,
- RequestGlobalMemoryDumpInternalCallback callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- UMA_HISTOGRAM_COUNTS_1000(
- "Memory.Experimental.Debug.GlobalDumpQueueLength",
- base::saturated_cast<int32_t>(queued_memory_dump_requests_.size()));
- bool another_dump_is_queued = !queued_memory_dump_requests_.empty();
- // If this is a periodic or peak memory dump request and there already is
- // another request in the queue with the same level of detail, there's no
- // point in enqueuing this request.
- if (another_dump_is_queued &&
- args.dump_type == MemoryDumpType::PERIODIC_INTERVAL) {
- for (const auto& request : queued_memory_dump_requests_) {
- if (request.args.level_of_detail == args.level_of_detail) {
- VLOG(1) << "RequestGlobalMemoryDump("
- << base::trace_event::MemoryDumpTypeToString(args.dump_type)
- << ") skipped because another dump request with the same "
- "level of detail ("
- << base::trace_event::MemoryDumpLevelOfDetailToString(
- args.level_of_detail)
- << ") is already in the queue";
- std::move(callback).Run(false /* success */, 0 /* dump_guid */,
- nullptr /* global_memory_dump */);
- return;
- }
- }
- }
- queued_memory_dump_requests_.emplace_back(args, ++next_dump_id_,
- std::move(callback));
- // If another dump is already in queued, this dump will automatically be
- // scheduled when the other dump finishes.
- if (another_dump_is_queued)
- return;
- PerformNextQueuedGlobalMemoryDump();
- }
- void CoordinatorImpl::OnQueuedRequestTimedOut(uint64_t dump_guid) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- QueuedRequest* request = GetCurrentRequest();
- // TODO(lalitm): add metrics for how often this happens.
- // Only consider the current request timed out if we fired off this
- // delayed callback in association with this request.
- if (!request || request->dump_guid != dump_guid)
- return;
- // Fail all remaining dumps being waited upon and clear the vector.
- if (request->pending_responses.size() > 0) {
- DLOG(ERROR) << "Global dump request timed out waiting for "
- << request->pending_responses.size() << " requests";
- }
- request->failed_memory_dump_count += request->pending_responses.size();
- request->pending_responses.clear();
- // Callback the consumer of the service.
- FinalizeGlobalMemoryDumpIfAllManagersReplied();
- }
- void CoordinatorImpl::OnHeapDumpTimeOut(uint64_t dump_guid) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- QueuedRequest* request = GetCurrentRequest();
- // TODO(lalitm): add metrics for how often this happens.
- // Only consider the current request timed out if we fired off this
- // delayed callback in association with this request.
- if (!request || request->dump_guid != dump_guid)
- return;
- // Fail all remaining dumps being waited upon and clear the vector.
- if (request->heap_dump_in_progress) {
- request->heap_dump_in_progress = false;
- FinalizeGlobalMemoryDumpIfAllManagersReplied();
- }
- }
- void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- QueuedRequest* request = GetCurrentRequest();
- if (request == nullptr)
- return;
- std::vector<QueuedRequestDispatcher::ClientInfo> clients;
- for (const auto& entry : clients_) {
- const base::ProcessId pid = entry.first;
- clients.emplace_back(entry.second->client.get(), pid,
- entry.second->process_type,
- entry.second->service_name);
- }
- auto chrome_callback =
- base::BindRepeating(&CoordinatorImpl::OnChromeMemoryDumpResponse,
- weak_ptr_factory_.GetWeakPtr());
- auto os_callback =
- base::BindRepeating(&CoordinatorImpl::OnOSMemoryDumpResponse,
- weak_ptr_factory_.GetWeakPtr(), request->dump_guid);
- QueuedRequestDispatcher::SetUpAndDispatch(request, clients, chrome_callback,
- os_callback);
- base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&CoordinatorImpl::OnQueuedRequestTimedOut,
- weak_ptr_factory_.GetWeakPtr(), request->dump_guid),
- client_process_timeout_);
- if (request->args.add_to_trace && heap_profiler_) {
- request->heap_dump_in_progress = true;
- // |IsArgumentFilterEnabled| is the round-about way of asking to anonymize
- // the trace. The only way that PII gets leaked is if the full path is
- // emitted for mapped files. Passing |strip_path_from_mapped_files|
- // is all that is necessary to anonymize the trace.
- bool strip_path_from_mapped_files =
- base::trace_event::TraceLog::GetInstance()
- ->GetCurrentTraceConfig()
- .IsArgumentFilterEnabled();
- heap_profiler_->DumpProcessesForTracing(
- strip_path_from_mapped_files, write_proto_heap_profile_,
- base::BindOnce(&CoordinatorImpl::OnDumpProcessesForTracing,
- weak_ptr_factory_.GetWeakPtr(), request->dump_guid));
- base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&CoordinatorImpl::OnHeapDumpTimeOut,
- weak_ptr_factory_.GetWeakPtr(), request->dump_guid),
- kHeapDumpTimeout);
- }
- // Run the callback in case there are no client processes registered.
- FinalizeGlobalMemoryDumpIfAllManagersReplied();
- }
- QueuedRequest* CoordinatorImpl::GetCurrentRequest() {
- if (queued_memory_dump_requests_.empty()) {
- return nullptr;
- }
- return &queued_memory_dump_requests_.front();
- }
- void CoordinatorImpl::OnChromeMemoryDumpResponse(
- base::ProcessId process_id,
- bool success,
- uint64_t dump_guid,
- std::unique_ptr<base::trace_event::ProcessMemoryDump> chrome_memory_dump) {
- using ResponseType = QueuedRequest::PendingResponse::Type;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- QueuedRequest* request = GetCurrentRequest();
- if (request == nullptr || request->dump_guid != dump_guid) {
- return;
- }
- RemovePendingResponse(process_id, ResponseType::kChromeDump);
- if (!base::Contains(clients_, process_id)) {
- VLOG(1) << "Received a memory dump response from an unregistered client";
- return;
- }
- auto* response = &request->responses[process_id];
- response->chrome_dump = std::move(chrome_memory_dump);
- if (!success) {
- DLOG(ERROR) << "Memory dump request failed: NACK from client process";
- request->failed_memory_dump_count++;
- }
- FinalizeGlobalMemoryDumpIfAllManagersReplied();
- }
- void CoordinatorImpl::OnOSMemoryDumpResponse(uint64_t dump_guid,
- base::ProcessId process_id,
- bool success,
- OSMemDumpMap os_dumps) {
- using ResponseType = QueuedRequest::PendingResponse::Type;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- QueuedRequest* request = GetCurrentRequest();
- if (request == nullptr || request->dump_guid != dump_guid) {
- return;
- }
- RemovePendingResponse(process_id, ResponseType::kOSDump);
- if (!base::Contains(clients_, process_id)) {
- VLOG(1) << "Received a memory dump response from an unregistered client";
- return;
- }
- request->responses[process_id].os_dumps = std::move(os_dumps);
- if (!success) {
- DLOG(ERROR) << "Memory dump request failed: NACK from client process";
- request->failed_memory_dump_count++;
- }
- FinalizeGlobalMemoryDumpIfAllManagersReplied();
- }
- void CoordinatorImpl::OnOSMemoryDumpForVMRegions(uint64_t dump_guid,
- base::ProcessId process_id,
- bool success,
- OSMemDumpMap os_dumps) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- auto request_it = in_progress_vm_region_requests_.find(dump_guid);
- DCHECK(request_it != in_progress_vm_region_requests_.end());
- QueuedVmRegionRequest* request = request_it->second.get();
- auto it = request->pending_responses.find(process_id);
- DCHECK(it != request->pending_responses.end());
- request->pending_responses.erase(it);
- request->responses[process_id].os_dumps = std::move(os_dumps);
- FinalizeVmRegionDumpIfAllManagersReplied(request->dump_guid);
- }
- void CoordinatorImpl::FinalizeVmRegionDumpIfAllManagersReplied(
- uint64_t dump_guid) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- auto it = in_progress_vm_region_requests_.find(dump_guid);
- if (it == in_progress_vm_region_requests_.end())
- return;
- if (!it->second->pending_responses.empty())
- return;
- QueuedRequestDispatcher::VmRegions results =
- QueuedRequestDispatcher::FinalizeVmRegionRequest(it->second.get());
- std::move(it->second->callback).Run(std::move(results));
- in_progress_vm_region_requests_.erase(it);
- }
- void CoordinatorImpl::OnDumpProcessesForTracing(
- uint64_t dump_guid,
- std::vector<mojom::HeapProfileResultPtr> heap_profile_results) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- QueuedRequest* request = GetCurrentRequest();
- if (!request || request->dump_guid != dump_guid) {
- return;
- }
- request->heap_dump_in_progress = false;
- for (auto& result : heap_profile_results) {
- base::trace_event::TraceArguments args(
- "dumps", std::make_unique<StringWrapper>(std::move(result->json)));
- // Using the same id merges all of the heap dumps into a single detailed
- // dump node in the UI.
- TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
- TRACE_EVENT_PHASE_MEMORY_DUMP,
- base::trace_event::TraceLog::GetCategoryGroupEnabled(
- base::trace_event::MemoryDumpManager::kTraceCategory),
- "periodic_interval", trace_event_internal::kGlobalScope, dump_guid,
- result->pid, &args, TRACE_EVENT_FLAG_HAS_ID);
- }
- FinalizeGlobalMemoryDumpIfAllManagersReplied();
- }
- void CoordinatorImpl::RemovePendingResponse(
- base::ProcessId process_id,
- QueuedRequest::PendingResponse::Type type) {
- QueuedRequest* request = GetCurrentRequest();
- if (request == nullptr) {
- NOTREACHED() << "No current dump request.";
- return;
- }
- auto it = request->pending_responses.find({process_id, type});
- if (it == request->pending_responses.end()) {
- VLOG(1) << "Unexpected memory dump response";
- return;
- }
- request->pending_responses.erase(it);
- }
- void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() {
- TRACE_EVENT0(base::trace_event::MemoryDumpManager::kTraceCategory,
- "GlobalMemoryDump.Computation");
- DCHECK(!queued_memory_dump_requests_.empty());
- QueuedRequest* request = &queued_memory_dump_requests_.front();
- if (!request->dump_in_progress || request->pending_responses.size() > 0 ||
- request->heap_dump_in_progress) {
- return;
- }
- QueuedRequestDispatcher::Finalize(request, tracing_observer_.get(),
- use_proto_writer_);
- queued_memory_dump_requests_.pop_front();
- request = nullptr;
- // Schedule the next queued dump (if applicable).
- if (!queued_memory_dump_requests_.empty()) {
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&CoordinatorImpl::PerformNextQueuedGlobalMemoryDump,
- weak_ptr_factory_.GetWeakPtr()));
- }
- }
- CoordinatorImpl::ClientInfo::ClientInfo(
- mojo::Remote<mojom::ClientProcess> client,
- mojom::ProcessType process_type,
- absl::optional<std::string> service_name)
- : client(std::move(client)),
- process_type(process_type),
- service_name(std::move(service_name)) {}
- CoordinatorImpl::ClientInfo::~ClientInfo() = default;
- } // namespace memory_instrumentation
|