| // Copyright (c) 2012 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 "components/tracing/child/child_trace_message_filter.h" |
| |
| #include <memory> |
| |
| #include "base/metrics/statistics_recorder.h" |
| #include "base/trace_event/memory_dump_manager.h" |
| #include "base/trace_event/trace_event.h" |
| #include "components/tracing/common/tracing_messages.h" |
| #include "ipc/ipc_channel.h" |
| |
| using base::trace_event::MemoryDumpManager; |
| using base::trace_event::TraceLog; |
| |
| namespace tracing { |
| |
| namespace { |
| |
| const int kMinTimeBetweenHistogramChangesInSeconds = 10; |
| |
| } // namespace |
| |
| ChildTraceMessageFilter::ChildTraceMessageFilter( |
| base::SingleThreadTaskRunner* ipc_task_runner) |
| : enabled_tracing_modes_(0), |
| sender_(nullptr), |
| ipc_task_runner_(ipc_task_runner) {} |
| |
| void ChildTraceMessageFilter::OnFilterAdded(IPC::Channel* channel) { |
| sender_ = channel; |
| sender_->Send(new TracingHostMsg_ChildSupportsTracing()); |
| } |
| |
| void ChildTraceMessageFilter::SetSenderForTesting(IPC::Sender* sender) { |
| sender_ = sender; |
| } |
| |
| void ChildTraceMessageFilter::OnFilterRemoved() { |
| sender_ = nullptr; |
| } |
| |
| bool ChildTraceMessageFilter::OnMessageReceived(const IPC::Message& message) { |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(ChildTraceMessageFilter, message) |
| IPC_MESSAGE_HANDLER(TracingMsg_SetTracingProcessId, OnSetTracingProcessId) |
| IPC_MESSAGE_HANDLER(TracingMsg_SetUMACallback, OnSetUMACallback) |
| IPC_MESSAGE_HANDLER(TracingMsg_ClearUMACallback, OnClearUMACallback) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| return handled; |
| } |
| |
| ChildTraceMessageFilter::~ChildTraceMessageFilter() {} |
| |
| void ChildTraceMessageFilter::OnSetTracingProcessId( |
| uint64_t tracing_process_id) { |
| MemoryDumpManager::GetInstance()->set_tracing_process_id(tracing_process_id); |
| } |
| |
| void ChildTraceMessageFilter::OnHistogramChanged( |
| const std::string& histogram_name, |
| base::Histogram::Sample reference_lower_value, |
| base::Histogram::Sample reference_upper_value, |
| bool repeat, |
| base::Histogram::Sample actual_value) { |
| if (actual_value < reference_lower_value || |
| actual_value > reference_upper_value) { |
| if (!repeat) { |
| ipc_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &ChildTraceMessageFilter::SendAbortBackgroundTracingMessage, |
| this)); |
| } |
| return; |
| } |
| |
| ipc_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&ChildTraceMessageFilter::SendTriggerMessage, |
| this, histogram_name)); |
| } |
| |
| void ChildTraceMessageFilter::SendTriggerMessage( |
| const std::string& histogram_name) { |
| if (!histogram_last_changed_.is_null()) { |
| base::Time computed_next_allowed_time = |
| histogram_last_changed_ + |
| base::TimeDelta::FromSeconds(kMinTimeBetweenHistogramChangesInSeconds); |
| if (computed_next_allowed_time > TRACE_TIME_NOW()) |
| return; |
| } |
| histogram_last_changed_ = TRACE_TIME_NOW(); |
| |
| if (sender_) |
| sender_->Send(new TracingHostMsg_TriggerBackgroundTrace(histogram_name)); |
| } |
| |
| void ChildTraceMessageFilter::SendAbortBackgroundTracingMessage() { |
| if (sender_) |
| sender_->Send(new TracingHostMsg_AbortBackgroundTrace()); |
| } |
| |
| void ChildTraceMessageFilter::OnSetUMACallback( |
| const std::string& histogram_name, |
| int histogram_lower_value, |
| int histogram_upper_value, |
| bool repeat) { |
| histogram_last_changed_ = base::Time(); |
| base::StatisticsRecorder::SetCallback( |
| histogram_name, base::Bind(&ChildTraceMessageFilter::OnHistogramChanged, |
| this, histogram_name, histogram_lower_value, |
| histogram_upper_value, repeat)); |
| |
| base::HistogramBase* existing_histogram = |
| base::StatisticsRecorder::FindHistogram(histogram_name); |
| if (!existing_histogram) |
| return; |
| |
| std::unique_ptr<base::HistogramSamples> samples = |
| existing_histogram->SnapshotSamples(); |
| if (!samples) |
| return; |
| |
| std::unique_ptr<base::SampleCountIterator> sample_iterator = |
| samples->Iterator(); |
| if (!sample_iterator) |
| return; |
| |
| while (!sample_iterator->Done()) { |
| base::HistogramBase::Sample min; |
| int64_t max; |
| base::HistogramBase::Count count; |
| sample_iterator->Get(&min, &max, &count); |
| |
| if (min >= histogram_lower_value && max <= histogram_upper_value) { |
| ipc_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&ChildTraceMessageFilter::SendTriggerMessage, this, |
| histogram_name)); |
| break; |
| } else if (!repeat) { |
| ipc_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &ChildTraceMessageFilter::SendAbortBackgroundTracingMessage, |
| this)); |
| break; |
| } |
| |
| sample_iterator->Next(); |
| } |
| } |
| |
| void ChildTraceMessageFilter::OnClearUMACallback( |
| const std::string& histogram_name) { |
| histogram_last_changed_ = base::Time(); |
| base::StatisticsRecorder::ClearCallback(histogram_name); |
| } |
| |
| } // namespace tracing |