summaryrefslogtreecommitdiff
path: root/chromium/services/tracing
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-07-31 15:50:41 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 12:35:23 +0000
commit7b2ffa587235a47d4094787d72f38102089f402a (patch)
tree30e82af9cbab08a7fa028bb18f4f2987a3f74dfa /chromium/services/tracing
parentd94af01c90575348c4e81a418257f254b6f8d225 (diff)
downloadqtwebengine-chromium-7b2ffa587235a47d4094787d72f38102089f402a.tar.gz
BASELINE: Update Chromium to 76.0.3809.94
Change-Id: I321c3f5f929c105aec0f98c5091ef6108822e647 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/services/tracing')
-rw-r--r--chromium/services/tracing/BUILD.gn42
-rw-r--r--chromium/services/tracing/coordinator.cc7
-rw-r--r--chromium/services/tracing/manifest.cc13
-rw-r--r--chromium/services/tracing/perfetto/consumer_host.cc623
-rw-r--r--chromium/services/tracing/perfetto/consumer_host.h129
-rw-r--r--chromium/services/tracing/perfetto/consumer_host_unittest.cc290
-rw-r--r--chromium/services/tracing/perfetto/json_exporter_main.cc77
-rw-r--r--chromium/services/tracing/perfetto/json_trace_exporter.cc5
-rw-r--r--chromium/services/tracing/perfetto/json_trace_exporter.h6
-rw-r--r--chromium/services/tracing/perfetto/json_trace_exporter_unittest.cc9
-rw-r--r--chromium/services/tracing/perfetto/perfetto_integration_unittest.cc68
-rw-r--r--chromium/services/tracing/perfetto/perfetto_service.cc79
-rw-r--r--chromium/services/tracing/perfetto/perfetto_service.h22
-rw-r--r--chromium/services/tracing/perfetto/perfetto_tracing_coordinator.cc12
-rw-r--r--chromium/services/tracing/perfetto/privacy_filtered_fields-inl.h98
-rw-r--r--chromium/services/tracing/perfetto/privacy_filtering_check.cc101
-rw-r--r--chromium/services/tracing/perfetto/privacy_filtering_check.h41
-rw-r--r--chromium/services/tracing/perfetto/producer_host.cc38
-rw-r--r--chromium/services/tracing/perfetto/producer_host.h4
-rw-r--r--chromium/services/tracing/perfetto/test_utils.cc94
-rw-r--r--chromium/services/tracing/perfetto/test_utils.h27
-rw-r--r--chromium/services/tracing/perfetto/track_event_json_exporter_unittest.cc11
-rw-r--r--chromium/services/tracing/public/cpp/BUILD.gn8
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/dummy_producer.cc65
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/dummy_producer.h59
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_config.cc76
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_config.h3
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_producer.cc44
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_producer.h73
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc105
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_traced_process.h112
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/producer_client.cc187
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/producer_client.h108
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/system_producer.cc10
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/system_producer.h23
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/task_runner.cc101
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/task_runner.h21
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/task_runner_unittest.cc68
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.cc132
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.h48
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc17
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc4
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h2
-rw-r--r--chromium/services/tracing/public/cpp/trace_event_agent.cc7
-rw-r--r--chromium/services/tracing/public/cpp/trace_event_agent_unittest.cc2
-rw-r--r--chromium/services/tracing/public/cpp/trace_event_args_whitelist.cc5
-rw-r--r--chromium/services/tracing/public/cpp/trace_startup.cc35
-rw-r--r--chromium/services/tracing/public/cpp/traced_process_impl.cc12
-rw-r--r--chromium/services/tracing/public/cpp/traced_process_impl.h3
-rw-r--r--chromium/services/tracing/public/cpp/tracing_features.cc11
-rw-r--r--chromium/services/tracing/public/cpp/tracing_features.h6
-rw-r--r--chromium/services/tracing/public/mojom/perfetto_service.mojom70
-rw-r--r--chromium/services/tracing/public/mojom/perfetto_service.typemap1
-rw-r--r--chromium/services/tracing/public/mojom/trace_config_mojom_traits.cc15
-rw-r--r--chromium/services/tracing/public/mojom/trace_config_mojom_traits.h29
-rw-r--r--chromium/services/tracing/public/mojom/traced_process.mojom2
-rw-r--r--chromium/services/tracing/tracing_service.cc71
57 files changed, 2314 insertions, 1017 deletions
diff --git a/chromium/services/tracing/BUILD.gn b/chromium/services/tracing/BUILD.gn
index f03baabd789..e0c20c7c3cc 100644
--- a/chromium/services/tracing/BUILD.gn
+++ b/chromium/services/tracing/BUILD.gn
@@ -45,6 +45,31 @@ source_set("lib") {
]
}
+executable("trace_json_exporter") {
+ sources = [
+ "perfetto/json_exporter_main.cc",
+ "perfetto/json_trace_exporter.cc",
+ "perfetto/json_trace_exporter.h",
+ "perfetto/track_event_json_exporter.cc",
+ "perfetto/track_event_json_exporter.h",
+ ]
+
+ configs += [ "//build/config/compiler:rtti" ]
+
+ deps = [
+ "//base",
+ "//third_party/perfetto:libperfetto",
+ "//third_party/perfetto/include/perfetto/protozero:protozero",
+ "//third_party/perfetto/protos/perfetto/common:lite",
+ "//third_party/perfetto/protos/perfetto/trace:lite",
+ "//third_party/perfetto/protos/perfetto/trace/chrome:lite",
+ "//third_party/perfetto/protos/perfetto/trace/chrome:minimal_complete_lite",
+ "//third_party/perfetto/protos/perfetto/trace/interned_data:lite",
+ "//third_party/perfetto/protos/perfetto/trace/track_event:lite",
+ "//third_party/perfetto/src/protozero:protozero",
+ ]
+}
+
source_set("manifest") {
sources = [
"manifest.cc",
@@ -54,10 +79,27 @@ source_set("manifest") {
deps = [
"//base",
"//services/service_manager/public/cpp",
+ "//services/tracing/public/cpp",
"//services/tracing/public/mojom",
]
}
+source_set("privacy_check") {
+ testonly = true
+
+ sources = [
+ "perfetto/privacy_filtered_fields-inl.h",
+ "perfetto/privacy_filtering_check.cc",
+ "perfetto/privacy_filtering_check.h",
+ ]
+
+ deps = [
+ "//base",
+ "//third_party/perfetto:libperfetto",
+ "//third_party/perfetto/src/protozero:protozero",
+ ]
+}
+
source_set("tests") {
testonly = true
diff --git a/chromium/services/tracing/coordinator.cc b/chromium/services/tracing/coordinator.cc
index fecd79da67c..9c8c296549d 100644
--- a/chromium/services/tracing/coordinator.cc
+++ b/chromium/services/tracing/coordinator.cc
@@ -12,7 +12,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback_forward.h"
-#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/json/json_writer.h"
#include "base/json/string_escape.h"
@@ -304,13 +303,13 @@ void Coordinator::Reset() {
start_tracing_callback_timer_.Stop();
if (!stop_and_flush_callback_.is_null()) {
- base::ResetAndReturn(&stop_and_flush_callback_)
+ std::move(stop_and_flush_callback_)
.Run(base::Value(base::Value::Type::DICTIONARY));
}
if (!start_tracing_callback_.is_null())
- base::ResetAndReturn(&start_tracing_callback_).Run(false);
+ std::move(start_tracing_callback_).Run(false);
if (!request_buffer_usage_callback_.is_null())
- base::ResetAndReturn(&request_buffer_usage_callback_).Run(false, 0, 0);
+ std::move(request_buffer_usage_callback_).Run(false, 0, 0);
if (trace_streamer_) {
// We are in the middle of flushing trace data. We need to
diff --git a/chromium/services/tracing/manifest.cc b/chromium/services/tracing/manifest.cc
index 2a413d68017..ef733e8e894 100644
--- a/chromium/services/tracing/manifest.cc
+++ b/chromium/services/tracing/manifest.cc
@@ -4,8 +4,10 @@
#include "services/tracing/manifest.h"
+#include "base/feature_list.h"
#include "base/no_destructor.h"
#include "services/service_manager/public/cpp/manifest_builder.h"
+#include "services/tracing/public/cpp/tracing_features.h"
#include "services/tracing/public/mojom/constants.mojom.h"
#include "services/tracing/public/mojom/perfetto_service.mojom.h"
#include "services/tracing/public/mojom/traced_process.mojom.h"
@@ -13,12 +15,23 @@
namespace tracing {
+namespace {
+
+service_manager::Manifest::ExecutionMode GetTracingExecutionMode() {
+ return base::FeatureList::IsEnabled(features::kTracingServiceInProcess)
+ ? service_manager::Manifest::ExecutionMode::kInProcessBuiltin
+ : service_manager::Manifest::ExecutionMode::kOutOfProcessBuiltin;
+}
+
+} // namespace
+
const service_manager::Manifest& GetManifest() {
static base::NoDestructor<service_manager::Manifest> manifest{
service_manager::ManifestBuilder()
.WithServiceName(mojom::kServiceName)
.WithDisplayName("Tracing")
.WithOptions(service_manager::ManifestOptionsBuilder()
+ .WithExecutionMode(GetTracingExecutionMode())
.WithInstanceSharingPolicy(
service_manager::Manifest::
InstanceSharingPolicy::kSingleton)
diff --git a/chromium/services/tracing/perfetto/consumer_host.cc b/chromium/services/tracing/perfetto/consumer_host.cc
index 1726aeeb080..a8b515f30a3 100644
--- a/chromium/services/tracing/perfetto/consumer_host.cc
+++ b/chromium/services/tracing/perfetto/consumer_host.cc
@@ -16,12 +16,14 @@
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "base/task/post_task.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/wait.h"
#include "services/tracing/perfetto/json_trace_exporter.h"
#include "services/tracing/perfetto/perfetto_service.h"
#include "services/tracing/perfetto/track_event_json_exporter.h"
+#include "services/tracing/public/cpp/trace_event_args_whitelist.h"
#include "third_party/perfetto/include/perfetto/tracing/core/observable_events.h"
#include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h"
#include "third_party/perfetto/include/perfetto/tracing/core/trace_packet.h"
@@ -34,62 +36,113 @@ namespace {
const int32_t kEnableTracingTimeoutSeconds = 10;
-bool StringToProcessId(const std::string& input, base::ProcessId* output) {
- // Pid is encoded as uint in the string.
- return base::StringToUint(input, reinterpret_cast<uint32_t*>(output));
+perfetto::TraceConfig AdjustTraceConfig(
+ const perfetto::TraceConfig& trace_config) {
+ perfetto::TraceConfig trace_config_copy(trace_config);
+ // Clock snapshotting is incompatible with chrome's process sandboxing.
+ // Telemetry uses its own way of snapshotting clocks anyway.
+ auto* builtin_data_sources = trace_config_copy.mutable_builtin_data_sources();
+ builtin_data_sources->set_disable_clock_snapshotting(true);
+ return trace_config_copy;
}
} // namespace
-// static
-bool ConsumerHost::ParsePidFromProducerName(const std::string& producer_name,
- base::ProcessId* pid) {
- if (!base::StartsWith(producer_name, mojom::kPerfettoProducerNamePrefix,
- base::CompareCase::SENSITIVE)) {
- LOG(DFATAL) << "Unexpected producer name: " << producer_name;
- return false;
- }
+class ConsumerHost::StreamWriter {
+ public:
+ using Slices = std::vector<std::string>;
- static const size_t kPrefixLength =
- strlen(mojom::kPerfettoProducerNamePrefix);
- if (!StringToProcessId(producer_name.substr(kPrefixLength), pid)) {
- LOG(DFATAL) << "Unexpected producer name: " << producer_name;
- return false;
+ static scoped_refptr<base::SequencedTaskRunner> CreateTaskRunner() {
+ return base::CreateSequencedTaskRunnerWithTraits(
+ {base::WithBaseSyncPrimitives(), base::TaskPriority::BEST_EFFORT});
}
- return true;
-}
-
-// static
-void ConsumerHost::BindConsumerRequest(
- PerfettoService* service,
- mojom::ConsumerHostRequest request,
- const service_manager::BindSourceInfo& source_info) {
- mojo::MakeStrongBinding(std::make_unique<ConsumerHost>(service),
- std::move(request));
-}
-ConsumerHost::ConsumerHost(PerfettoService* service)
- : service_(service), weak_factory_(this) {
- DETACH_FROM_SEQUENCE(sequence_checker_);
- consumer_endpoint_ =
- service_->GetService()->ConnectConsumer(this, 0 /*uid_t*/);
- consumer_endpoint_->ObserveEvents(
- perfetto::TracingService::ConsumerEndpoint::ObservableEventType::
- kDataSourceInstances);
- service_->RegisterConsumerHost(this);
-}
+ StreamWriter(mojo::ScopedDataPipeProducerHandle stream,
+ TracingSession::ReadBuffersCallback callback,
+ base::OnceClosure disconnect_callback,
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner)
+ : stream_(std::move(stream)),
+ read_buffers_callback_(std::move(callback)),
+ disconnect_callback_(std::move(disconnect_callback)),
+ callback_task_runner_(callback_task_runner) {}
+
+ void WriteToStream(std::unique_ptr<Slices> slices, bool has_more) {
+ DCHECK(stream_.is_valid());
+ for (const auto& slice : *slices) {
+ uint32_t write_position = 0;
+
+ while (write_position < slice.size()) {
+ uint32_t write_bytes = slice.size() - write_position;
+
+ MojoResult result =
+ stream_->WriteData(slice.data() + write_position, &write_bytes,
+ MOJO_WRITE_DATA_FLAG_NONE);
+
+ if (result == MOJO_RESULT_OK) {
+ write_position += write_bytes;
+ continue;
+ }
-ConsumerHost::~ConsumerHost() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- service_->UnregisterConsumerHost(this);
-}
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ result = mojo::Wait(stream_.get(), MOJO_HANDLE_SIGNAL_WRITABLE);
+ }
-void ConsumerHost::EnableTracing(mojom::TracingSessionPtr tracing_session,
- const perfetto::TraceConfig& trace_config) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (result != MOJO_RESULT_OK) {
+ if (!disconnect_callback_.is_null()) {
+ callback_task_runner_->PostTask(FROM_HERE,
+ std::move(disconnect_callback_));
+ }
+ return;
+ }
+ }
+ }
- tracing_session_ = std::move(tracing_session);
+ if (!has_more && !read_buffers_callback_.is_null()) {
+ callback_task_runner_->PostTask(FROM_HERE,
+ std::move(read_buffers_callback_));
+ }
+ }
+ private:
+ mojo::ScopedDataPipeProducerHandle stream_;
+ TracingSession::ReadBuffersCallback read_buffers_callback_;
+ base::OnceClosure disconnect_callback_;
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(StreamWriter);
+};
+
+ConsumerHost::TracingSession::TracingSession(
+ ConsumerHost* host,
+ mojom::TracingSessionHostRequest tracing_session_host,
+ mojom::TracingSessionClientPtr tracing_session_client,
+ const perfetto::TraceConfig& trace_config,
+ mojom::TracingClientPriority priority)
+ : host_(host),
+ tracing_session_client_(std::move(tracing_session_client)),
+ binding_(this, std::move(tracing_session_host)),
+ tracing_priority_(priority) {
+ host_->service()->RegisterTracingSession(this);
+
+ tracing_session_client_.set_connection_error_handler(base::BindOnce(
+ &ConsumerHost::DestructTracingSession, base::Unretained(host)));
+ binding_.set_connection_error_handler(base::BindOnce(
+ &ConsumerHost::DestructTracingSession, base::Unretained(host)));
+
+ privacy_filtering_enabled_ = false;
+ for (const auto& data_source : trace_config.data_sources()) {
+ if (data_source.config().chrome_config().privacy_filtering_enabled()) {
+ privacy_filtering_enabled_ = true;
+ }
+ }
+#if DCHECK_IS_ON()
+ if (privacy_filtering_enabled_) {
+ // If enabled, filtering must be enabled for all data sources.
+ for (const auto& data_source : trace_config.data_sources()) {
+ DCHECK(data_source.config().chrome_config().privacy_filtering_enabled());
+ }
+ }
+#endif
perfetto::TraceConfig trace_config_copy = AdjustTraceConfig(trace_config);
filtered_pids_.clear();
@@ -97,7 +150,7 @@ void ConsumerHost::EnableTracing(mojom::TracingSessionPtr tracing_session,
if (ds_config.config().name() == mojom::kTraceEventDataSourceName) {
for (const auto& filter : ds_config.producer_name_filter()) {
base::ProcessId pid;
- if (ParsePidFromProducerName(filter, &pid)) {
+ if (PerfettoService::ParsePidFromProducerName(filter, &pid)) {
filtered_pids_.insert(pid);
}
}
@@ -105,11 +158,11 @@ void ConsumerHost::EnableTracing(mojom::TracingSessionPtr tracing_session,
}
}
- pending_enable_tracing_ack_pids_ = service_->active_service_pids();
+ pending_enable_tracing_ack_pids_ = host_->service()->active_service_pids();
base::EraseIf(*pending_enable_tracing_ack_pids_,
[this](base::ProcessId pid) { return !IsExpectedPid(pid); });
- consumer_endpoint_->EnableTracing(trace_config_copy);
+ host_->consumer_endpoint()->EnableTracing(trace_config_copy);
MaybeSendEnableTracingAck();
if (pending_enable_tracing_ack_pids_) {
@@ -119,148 +172,19 @@ void ConsumerHost::EnableTracing(mojom::TracingSessionPtr tracing_session,
// case.
enable_tracing_ack_timer_.Start(
FROM_HERE, base::TimeDelta::FromSeconds(kEnableTracingTimeoutSeconds),
- this, &ConsumerHost::OnEnableTracingTimeout);
+ this, &ConsumerHost::TracingSession::OnEnableTracingTimeout);
}
}
-void ConsumerHost::ChangeTraceConfig(
- const perfetto::TraceConfig& trace_config) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- perfetto::TraceConfig trace_config_copy = AdjustTraceConfig(trace_config);
- consumer_endpoint_->ChangeTraceConfig(trace_config_copy);
-}
-
-perfetto::TraceConfig ConsumerHost::AdjustTraceConfig(
- const perfetto::TraceConfig& trace_config) {
- perfetto::TraceConfig trace_config_copy(trace_config);
- // Clock snapshotting is incompatible with chrome's process sandboxing.
- // Telemetry uses its own way of snapshotting clocks anyway.
- trace_config_copy.set_disable_clock_snapshotting(true);
- return trace_config_copy;
-}
-
-void ConsumerHost::DisableTracing() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- consumer_endpoint_->DisableTracing();
-}
-
-void ConsumerHost::Flush(uint32_t timeout,
- base::OnceCallback<void(bool)> callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- flush_callback_ = std::move(callback);
- base::WeakPtr<ConsumerHost> weak_this = weak_factory_.GetWeakPtr();
- consumer_endpoint_->Flush(timeout, [weak_this](bool success) {
- if (!weak_this) {
- return;
- }
-
- if (weak_this->flush_callback_) {
- std::move(weak_this->flush_callback_).Run(success);
- }
- });
-}
-
-void ConsumerHost::ReadBuffers(mojo::ScopedDataPipeProducerHandle stream,
- ReadBuffersCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- read_buffers_stream_ = std::move(stream);
- read_buffers_callback_ = std::move(callback);
-
- consumer_endpoint_->ReadBuffers();
-}
-
-void ConsumerHost::DisableTracingAndEmitJson(
- const std::string& agent_label_filter,
- mojo::ScopedDataPipeProducerHandle stream,
- DisableTracingAndEmitJsonCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(!read_buffers_stream_ && !read_buffers_callback_ &&
- !json_trace_exporter_);
-
- read_buffers_stream_ = std::move(stream);
- read_buffers_callback_ = std::move(callback);
-
- // TODO(eseckler): Support argument/metadata filtering.
- json_trace_exporter_ = std::make_unique<TrackEventJSONExporter>(
- JSONTraceExporter::ArgumentFilterPredicate(),
- JSONTraceExporter::MetadataFilterPredicate(),
- base::BindRepeating(&ConsumerHost::OnJSONTraceData,
- base::Unretained(this)));
-
- json_trace_exporter_->set_label_filter(agent_label_filter);
-
- consumer_endpoint_->DisableTracing();
-}
-
-void ConsumerHost::FreeBuffers() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- consumer_endpoint_->FreeBuffers();
-}
-
-void ConsumerHost::RequestBufferUsage(RequestBufferUsageCallback callback) {
- if (!request_buffer_usage_callback_.is_null()) {
- std::move(callback).Run(false, 0);
- return;
- }
-
- request_buffer_usage_callback_ = std::move(callback);
- consumer_endpoint_->GetTraceStats();
-}
-
-void ConsumerHost::OnConnect() {}
-
-void ConsumerHost::OnDisconnect() {}
-
-void ConsumerHost::OnTracingDisabled() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(tracing_session_);
-
- if (enable_tracing_ack_timer_.IsRunning()) {
- enable_tracing_ack_timer_.FireNow();
- }
- DCHECK(!pending_enable_tracing_ack_pids_);
-
- tracing_session_.reset();
-
- if (json_trace_exporter_) {
- consumer_endpoint_->ReadBuffers();
+ConsumerHost::TracingSession::~TracingSession() {
+ host_->service()->UnregisterTracingSession(this);
+ if (host_->consumer_endpoint()) {
+ host_->consumer_endpoint()->FreeBuffers();
}
}
-void ConsumerHost::OnTraceData(std::vector<perfetto::TracePacket> packets,
- bool has_more) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (json_trace_exporter_) {
- json_trace_exporter_->OnTraceData(std::move(packets), has_more);
- if (!has_more) {
- json_trace_exporter_.reset();
- }
- return;
- }
-
- for (auto& packet : packets) {
- char* data;
- size_t size;
- std::tie(data, size) = packet.GetProtoPreamble();
- WriteToStream(data, size);
- auto& slices = packet.slices();
- for (auto& slice : slices) {
- WriteToStream(slice.start, slice.size);
- }
- }
-
- if (!has_more) {
- read_buffers_stream_.reset();
- if (read_buffers_callback_) {
- std::move(read_buffers_callback_).Run();
- }
- }
-}
-
-void ConsumerHost::OnObservableEvents(
+void ConsumerHost::TracingSession::OnPerfettoEvents(
const perfetto::ObservableEvents& events) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!pending_enable_tracing_ack_pids_) {
return;
}
@@ -278,7 +202,8 @@ void ConsumerHost::OnObservableEvents(
// Attempt to parse the PID out of the producer name.
base::ProcessId pid;
- if (!ParsePidFromProducerName(state_change.producer_name(), &pid)) {
+ if (!PerfettoService::ParsePidFromProducerName(state_change.producer_name(),
+ &pid)) {
continue;
}
@@ -287,14 +212,16 @@ void ConsumerHost::OnObservableEvents(
MaybeSendEnableTracingAck();
}
-void ConsumerHost::OnActiveServicePidAdded(base::ProcessId pid) {
+void ConsumerHost::TracingSession::OnActiveServicePidAdded(
+ base::ProcessId pid) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (pending_enable_tracing_ack_pids_ && IsExpectedPid(pid)) {
pending_enable_tracing_ack_pids_->insert(pid);
}
}
-void ConsumerHost::OnActiveServicePidRemoved(base::ProcessId pid) {
+void ConsumerHost::TracingSession::OnActiveServicePidRemoved(
+ base::ProcessId pid) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (pending_enable_tracing_ack_pids_) {
pending_enable_tracing_ack_pids_->erase(pid);
@@ -302,41 +229,205 @@ void ConsumerHost::OnActiveServicePidRemoved(base::ProcessId pid) {
}
}
-void ConsumerHost::OnActiveServicePidsInitialized() {
+void ConsumerHost::TracingSession::OnActiveServicePidsInitialized() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
MaybeSendEnableTracingAck();
}
-void ConsumerHost::OnEnableTracingTimeout() {
+void ConsumerHost::TracingSession::RequestDisableTracing(
+ base::OnceClosure on_disabled_callback) {
+ DCHECK(!on_disabled_callback_);
+ on_disabled_callback_ = std::move(on_disabled_callback);
+ DisableTracing();
+}
+
+void ConsumerHost::TracingSession::OnEnableTracingTimeout() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!pending_enable_tracing_ack_pids_) {
return;
}
- DCHECK(tracing_session_);
- tracing_session_->OnTracingEnabled();
+
+ std::stringstream error;
+ error << "Timed out waiting for processes to ack BeginTracing: ";
+ for (auto pid : *pending_enable_tracing_ack_pids_) {
+ error << pid << " ";
+ }
+ LOG(ERROR) << error.rdbuf();
+
+ DCHECK(tracing_session_client_);
+ tracing_session_client_->OnTracingEnabled();
pending_enable_tracing_ack_pids_.reset();
}
-void ConsumerHost::MaybeSendEnableTracingAck() {
+void ConsumerHost::TracingSession::MaybeSendEnableTracingAck() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!pending_enable_tracing_ack_pids_ ||
!pending_enable_tracing_ack_pids_->empty() ||
- !service_->active_service_pids_initialized()) {
+ !host_->service()->active_service_pids_initialized()) {
return;
}
- DCHECK(tracing_session_);
- tracing_session_->OnTracingEnabled();
+ DCHECK(tracing_session_client_);
+ tracing_session_client_->OnTracingEnabled();
pending_enable_tracing_ack_pids_.reset();
enable_tracing_ack_timer_.Stop();
}
-bool ConsumerHost::IsExpectedPid(base::ProcessId pid) const {
+bool ConsumerHost::TracingSession::IsExpectedPid(base::ProcessId pid) const {
return filtered_pids_.empty() || base::ContainsKey(filtered_pids_, pid);
}
-void ConsumerHost::OnTraceStats(bool success,
- const perfetto::TraceStats& stats) {
+void ConsumerHost::TracingSession::ChangeTraceConfig(
+ const perfetto::TraceConfig& trace_config) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ perfetto::TraceConfig trace_config_copy = AdjustTraceConfig(trace_config);
+ host_->consumer_endpoint()->ChangeTraceConfig(trace_config_copy);
+}
+
+void ConsumerHost::TracingSession::DisableTracing() {
+ host_->consumer_endpoint()->DisableTracing();
+}
+
+void ConsumerHost::TracingSession::OnTracingDisabled() {
+ DCHECK(tracing_session_client_);
+
+ if (enable_tracing_ack_timer_.IsRunning()) {
+ enable_tracing_ack_timer_.FireNow();
+ }
+ DCHECK(!pending_enable_tracing_ack_pids_);
+
+ tracing_session_client_->OnTracingDisabled();
+
+ if (json_trace_exporter_) {
+ host_->consumer_endpoint()->ReadBuffers();
+ }
+
+ tracing_enabled_ = false;
+
+ if (on_disabled_callback_) {
+ std::move(on_disabled_callback_).Run();
+ }
+}
+
+void ConsumerHost::TracingSession::OnConsumerClientDisconnected() {
+ // The TracingSession will be deleted after this point.
+ host_->DestructTracingSession();
+}
+
+void ConsumerHost::TracingSession::ReadBuffers(
+ mojo::ScopedDataPipeProducerHandle stream,
+ ReadBuffersCallback callback) {
+ read_buffers_stream_writer_ = base::SequenceBound<StreamWriter>(
+ StreamWriter::CreateTaskRunner(), std::move(stream), std::move(callback),
+ base::BindOnce(&TracingSession::OnConsumerClientDisconnected,
+ weak_factory_.GetWeakPtr()),
+ base::SequencedTaskRunnerHandle::Get());
+
+ host_->consumer_endpoint()->ReadBuffers();
+}
+
+void ConsumerHost::TracingSession::RequestBufferUsage(
+ RequestBufferUsageCallback callback) {
+ if (!request_buffer_usage_callback_.is_null()) {
+ std::move(callback).Run(false, 0);
+ return;
+ }
+
+ request_buffer_usage_callback_ = std::move(callback);
+ host_->consumer_endpoint()->GetTraceStats();
+}
+
+void ConsumerHost::TracingSession::DisableTracingAndEmitJson(
+ const std::string& agent_label_filter,
+ mojo::ScopedDataPipeProducerHandle stream,
+ DisableTracingAndEmitJsonCallback callback) {
+ DCHECK(!read_buffers_stream_writer_);
+
+ read_buffers_stream_writer_ = base::SequenceBound<StreamWriter>(
+ StreamWriter::CreateTaskRunner(), std::move(stream), std::move(callback),
+ base::BindOnce(&TracingSession::OnConsumerClientDisconnected,
+ weak_factory_.GetWeakPtr()),
+ base::SequencedTaskRunnerHandle::Get());
+
+ // In legacy backend, the trace event agent sets the predicate used by
+ // TraceLog. For perfetto backend, ensure that predicate is always set
+ // before creating the exporter. The agent can be created later than this
+ // point.
+ if (base::trace_event::TraceLog::GetInstance()
+ ->GetArgumentFilterPredicate()
+ .is_null()) {
+ base::trace_event::TraceLog::GetInstance()->SetArgumentFilterPredicate(
+ base::BindRepeating(&IsTraceEventArgsWhitelisted));
+ base::trace_event::TraceLog::GetInstance()->SetMetadataFilterPredicate(
+ base::BindRepeating(&IsMetadataWhitelisted));
+ }
+
+ JSONTraceExporter::ArgumentFilterPredicate arg_filter_predicate;
+ JSONTraceExporter::MetadataFilterPredicate metadata_filter_predicate;
+ if (privacy_filtering_enabled_) {
+ auto* trace_log = base::trace_event::TraceLog::GetInstance();
+ arg_filter_predicate = trace_log->GetArgumentFilterPredicate();
+ metadata_filter_predicate = trace_log->GetMetadataFilterPredicate();
+ }
+ json_trace_exporter_ = std::make_unique<TrackEventJSONExporter>(
+ std::move(arg_filter_predicate), std::move(metadata_filter_predicate),
+ base::BindRepeating(&ConsumerHost::TracingSession::OnJSONTraceData,
+ base::Unretained(this)));
+
+ json_trace_exporter_->set_label_filter(agent_label_filter);
+
+ DisableTracing();
+}
+
+void ConsumerHost::TracingSession::OnJSONTraceData(
+ std::string* json,
+ base::DictionaryValue* metadata,
+ bool has_more) {
+ auto slices = std::make_unique<StreamWriter::Slices>();
+ slices->push_back(std::string());
+ slices->back().swap(*json);
+ read_buffers_stream_writer_.Post(FROM_HERE, &StreamWriter::WriteToStream,
+ std::move(slices), has_more);
+
+ if (!has_more) {
+ read_buffers_stream_writer_.Reset();
+ }
+}
+
+void ConsumerHost::TracingSession::OnTraceData(
+ std::vector<perfetto::TracePacket> packets,
+ bool has_more) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (json_trace_exporter_) {
+ json_trace_exporter_->OnTraceData(std::move(packets), has_more);
+ if (!has_more) {
+ json_trace_exporter_.reset();
+ }
+ return;
+ }
+
+ auto copy = std::make_unique<StreamWriter::Slices>();
+ for (auto& packet : packets) {
+ char* data;
+ size_t size;
+ std::tie(data, size) = packet.GetProtoPreamble();
+ copy->emplace_back(data, size);
+ auto& slices = packet.slices();
+ for (auto& slice : slices) {
+ copy->emplace_back(static_cast<const char*>(slice.start), slice.size);
+ }
+ }
+ read_buffers_stream_writer_.Post(FROM_HERE, &StreamWriter::WriteToStream,
+ std::move(copy), has_more);
+ if (!has_more) {
+ read_buffers_stream_writer_.Reset();
+ }
+}
+
+void ConsumerHost::TracingSession::OnTraceStats(
+ bool success,
+ const perfetto::TraceStats& stats) {
if (!request_buffer_usage_callback_) {
return;
}
@@ -357,54 +448,116 @@ void ConsumerHost::OnTraceStats(bool success,
std::move(request_buffer_usage_callback_).Run(true, percent_full);
}
-void ConsumerHost::OnJSONTraceData(const std::string& json,
- base::DictionaryValue* metadata,
- bool has_more) {
- WriteToStream(json.data(), json.size());
+void ConsumerHost::TracingSession::Flush(
+ uint32_t timeout,
+ base::OnceCallback<void(bool)> callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ flush_callback_ = std::move(callback);
+ base::WeakPtr<TracingSession> weak_this = weak_factory_.GetWeakPtr();
+ host_->consumer_endpoint()->Flush(timeout, [weak_this](bool success) {
+ if (!weak_this) {
+ return;
+ }
- if (has_more) {
- return;
- }
+ if (weak_this->flush_callback_) {
+ std::move(weak_this->flush_callback_).Run(success);
+ }
+ });
+}
- read_buffers_stream_.reset();
- if (read_buffers_callback_) {
- std::move(read_buffers_callback_).Run();
- }
+// static
+void ConsumerHost::BindConsumerRequest(
+ PerfettoService* service,
+ mojom::ConsumerHostRequest request,
+ const service_manager::BindSourceInfo& source_info) {
+ mojo::MakeStrongBinding(std::make_unique<ConsumerHost>(service),
+ std::move(request));
+}
+
+ConsumerHost::ConsumerHost(PerfettoService* service) : service_(service) {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+ consumer_endpoint_ =
+ service_->GetService()->ConnectConsumer(this, 0 /*uid_t*/);
+ consumer_endpoint_->ObserveEvents(
+ perfetto::TracingService::ConsumerEndpoint::ObservableEventType::
+ kDataSourceInstances);
}
-void ConsumerHost::WriteToStream(const void* start, size_t size) {
- TRACE_EVENT0("ipc", "ConsumerHost::WriteToStream");
- DCHECK(read_buffers_stream_.is_valid());
- uint32_t write_position = 0;
+ConsumerHost::~ConsumerHost() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Make sure the tracing_session is destroyed first, as it keeps a pointer to
+ // the ConsumerHost parent and accesses it on destruction.
+ tracing_session_.reset();
+}
- while (write_position < size) {
- uint32_t write_bytes = size - write_position;
+void ConsumerHost::EnableTracing(
+ mojom::TracingSessionHostRequest tracing_session_host,
+ mojom::TracingSessionClientPtr tracing_session_client,
+ const perfetto::TraceConfig& trace_config,
+ mojom::TracingClientPriority priority) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!tracing_session_);
+
+ // We create our new TracingSession async, if the PerfettoService allows
+ // us to, after it's stopped any currently running lower or equal priority
+ // tracing sessions.
+ service_->RequestTracingSession(
+ priority,
+ base::BindOnce(
+ [](base::WeakPtr<ConsumerHost> weak_this,
+ mojom::TracingSessionHostRequest tracing_session_host,
+ mojom::TracingSessionClientPtr tracing_session_client,
+ const perfetto::TraceConfig& trace_config,
+ mojom::TracingClientPriority priority) {
+ if (!weak_this) {
+ return;
+ }
+
+ weak_this->tracing_session_ = std::make_unique<TracingSession>(
+ weak_this.get(), std::move(tracing_session_host),
+ std::move(tracing_session_client), trace_config, priority);
+ },
+ weak_factory_.GetWeakPtr(), std::move(tracing_session_host),
+ std::move(tracing_session_client), trace_config, priority));
+}
- MojoResult result = read_buffers_stream_->WriteData(
- static_cast<const uint8_t*>(start) + write_position, &write_bytes,
- MOJO_WRITE_DATA_FLAG_NONE);
+void ConsumerHost::OnConnect() {}
- if (result == MOJO_RESULT_OK) {
- write_position += write_bytes;
- continue;
- }
+void ConsumerHost::OnDisconnect() {}
- if (result == MOJO_RESULT_SHOULD_WAIT) {
- // TODO(oysteine): If we end up actually blocking here it means
- // the client is consuming data slower than Perfetto is producing
- // it. Consider other solutions at that point because it means
- // eventually Producers will run out of chunks and will stall waiting
- // for new ones.
- result =
- mojo::Wait(read_buffers_stream_.get(), MOJO_HANDLE_SIGNAL_WRITABLE);
- }
+void ConsumerHost::OnTracingDisabled() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (tracing_session_) {
+ tracing_session_->OnTracingDisabled();
+ }
+}
- if (result != MOJO_RESULT_OK) {
- // Bail out; destination handle got closed.
- consumer_endpoint_->FreeBuffers();
- return;
- }
+void ConsumerHost::OnTraceData(std::vector<perfetto::TracePacket> packets,
+ bool has_more) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (tracing_session_) {
+ tracing_session_->OnTraceData(std::move(packets), has_more);
}
}
+void ConsumerHost::OnObservableEvents(
+ const perfetto::ObservableEvents& events) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (tracing_session_) {
+ tracing_session_->OnPerfettoEvents(events);
+ }
+}
+
+void ConsumerHost::OnTraceStats(bool success,
+ const perfetto::TraceStats& stats) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (tracing_session_) {
+ tracing_session_->OnTraceStats(success, stats);
+ }
+}
+
+void ConsumerHost::DestructTracingSession() {
+ tracing_session_.reset();
+}
+
} // namespace tracing
diff --git a/chromium/services/tracing/perfetto/consumer_host.h b/chromium/services/tracing/perfetto/consumer_host.h
index d88d8a814ba..afb26770275 100644
--- a/chromium/services/tracing/perfetto/consumer_host.h
+++ b/chromium/services/tracing/perfetto/consumer_host.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
+#include "base/threading/sequence_bound.h"
#include "base/timer/timer.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/tracing/public/mojom/perfetto_service.mojom.h"
@@ -36,29 +37,94 @@ class ConsumerHost : public perfetto::Consumer, public mojom::ConsumerHost {
mojom::ConsumerHostRequest request,
const service_manager::BindSourceInfo& source_info);
- static bool ParsePidFromProducerName(const std::string& producer_name,
- base::ProcessId* pid);
+ class StreamWriter;
+ class TracingSession : public mojom::TracingSessionHost {
+ public:
+ TracingSession(ConsumerHost* host,
+ mojom::TracingSessionHostRequest tracing_session_host,
+ mojom::TracingSessionClientPtr tracing_session_client,
+ const perfetto::TraceConfig& trace_config,
+ mojom::TracingClientPriority priority);
+ ~TracingSession() override;
+
+ void OnPerfettoEvents(const perfetto::ObservableEvents&);
+ void OnTraceData(std::vector<perfetto::TracePacket> packets, bool has_more);
+ void OnTraceStats(bool success, const perfetto::TraceStats&);
+ void OnTracingDisabled();
+ void OnConsumerClientDisconnected();
+ void Flush(uint32_t timeout, base::OnceCallback<void(bool)> callback);
+
+ mojom::TracingClientPriority tracing_priority() const {
+ return tracing_priority_;
+ }
+ bool tracing_enabled() const { return tracing_enabled_; }
+ ConsumerHost* host() const { return host_; }
+
+ // Called by TracingService.
+ void OnActiveServicePidAdded(base::ProcessId pid);
+ void OnActiveServicePidRemoved(base::ProcessId pid);
+ void OnActiveServicePidsInitialized();
+ void RequestDisableTracing(base::OnceClosure on_disabled_callback);
+
+ // mojom::TracingSessionHost implementation.
+ void ChangeTraceConfig(const perfetto::TraceConfig& config) override;
+ void DisableTracing() override;
+ void ReadBuffers(mojo::ScopedDataPipeProducerHandle stream,
+ ReadBuffersCallback callback) override;
+
+ void RequestBufferUsage(RequestBufferUsageCallback callback) override;
+ void DisableTracingAndEmitJson(
+ const std::string& agent_label_filter,
+ mojo::ScopedDataPipeProducerHandle stream,
+ DisableTracingAndEmitJsonCallback callback) override;
+
+ private:
+ void OnJSONTraceData(std::string* json,
+ base::DictionaryValue* metadata,
+ bool has_more);
+ void OnEnableTracingTimeout();
+ void MaybeSendEnableTracingAck();
+ bool IsExpectedPid(base::ProcessId pid) const;
+
+ ConsumerHost* const host_;
+ mojom::TracingSessionClientPtr tracing_session_client_;
+ mojo::Binding<mojom::TracingSessionHost> binding_;
+ bool privacy_filtering_enabled_ = false;
+ base::SequenceBound<StreamWriter> read_buffers_stream_writer_;
+ RequestBufferUsageCallback request_buffer_usage_callback_;
+ std::unique_ptr<JSONTraceExporter> json_trace_exporter_;
+ base::OnceCallback<void(bool)> flush_callback_;
+ const mojom::TracingClientPriority tracing_priority_;
+ base::OnceClosure on_disabled_callback_;
+ std::set<base::ProcessId> filtered_pids_;
+ bool tracing_enabled_ = true;
+
+ // If set, we didn't issue OnTracingEnabled() on the session yet. If set and
+ // empty, no more pids are pending and we should issue OnTracingEnabled().
+ base::Optional<std::set<base::ProcessId>> pending_enable_tracing_ack_pids_;
+ base::OneShotTimer enable_tracing_ack_timer_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+ base::WeakPtrFactory<TracingSession> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(TracingSession);
+ };
// The owner of ConsumerHost should make sure to destroy
// |service| after destroying this.
explicit ConsumerHost(PerfettoService* service);
~ConsumerHost() override;
+ PerfettoService* service() const { return service_; }
+ perfetto::TracingService::ConsumerEndpoint* consumer_endpoint() const {
+ return consumer_endpoint_.get();
+ }
+
// mojom::ConsumerHost implementation.
- void EnableTracing(mojom::TracingSessionPtr tracing_session,
- const perfetto::TraceConfig& config) override;
- void ChangeTraceConfig(const perfetto::TraceConfig& config) override;
- void DisableTracing() override;
- void ReadBuffers(mojo::ScopedDataPipeProducerHandle stream,
- ReadBuffersCallback callback) override;
- void DisableTracingAndEmitJson(
- const std::string& agent_label_filter,
- mojo::ScopedDataPipeProducerHandle stream,
- DisableTracingAndEmitJsonCallback callback) override;
- void RequestBufferUsage(RequestBufferUsageCallback callback) override;
-
- void Flush(uint32_t timeout, base::OnceCallback<void(bool)> callback);
- void FreeBuffers();
+ void EnableTracing(mojom::TracingSessionHostRequest tracing_session_host,
+ mojom::TracingSessionClientPtr tracing_session_client,
+ const perfetto::TraceConfig& config,
+ mojom::TracingClientPriority priority) override;
// perfetto::Consumer implementation.
// This gets called by the Perfetto service as control signals,
@@ -75,34 +141,15 @@ class ConsumerHost : public perfetto::Consumer, public mojom::ConsumerHost {
void OnDetach(bool success) override {}
void OnAttach(bool success, const perfetto::TraceConfig&) override {}
- // Called by TracingService.
- void OnActiveServicePidAdded(base::ProcessId pid);
- void OnActiveServicePidRemoved(base::ProcessId pid);
- void OnActiveServicePidsInitialized();
+ TracingSession* tracing_session_for_testing() {
+ return tracing_session_.get();
+ }
private:
- perfetto::TraceConfig AdjustTraceConfig(
- const perfetto::TraceConfig& trace_config);
- void OnEnableTracingTimeout();
- void MaybeSendEnableTracingAck();
- bool IsExpectedPid(base::ProcessId pid) const;
- void OnJSONTraceData(const std::string& json,
- base::DictionaryValue* metadata,
- bool has_more);
- void WriteToStream(const void* start, size_t size);
+ void DestructTracingSession();
PerfettoService* const service_;
- mojo::ScopedDataPipeProducerHandle read_buffers_stream_;
- ReadBuffersCallback read_buffers_callback_;
- base::OnceCallback<void(bool)> flush_callback_;
- mojom::TracingSessionPtr tracing_session_;
- std::set<base::ProcessId> filtered_pids_;
- // If set, we didn't issue OnTracingEnabled() on the session yet. If set and
- // empty, no more pids are pending and we should issue OnTracingEnabled().
- base::Optional<std::set<base::ProcessId>> pending_enable_tracing_ack_pids_;
- base::OneShotTimer enable_tracing_ack_timer_;
- RequestBufferUsageCallback request_buffer_usage_callback_;
- std::unique_ptr<JSONTraceExporter> json_trace_exporter_;
+ std::unique_ptr<TracingSession> tracing_session_;
SEQUENCE_CHECKER(sequence_checker_);
@@ -110,7 +157,7 @@ class ConsumerHost : public perfetto::Consumer, public mojom::ConsumerHost {
std::unique_ptr<perfetto::TracingService::ConsumerEndpoint>
consumer_endpoint_;
- base::WeakPtrFactory<ConsumerHost> weak_factory_;
+ base::WeakPtrFactory<ConsumerHost> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(ConsumerHost);
};
diff --git a/chromium/services/tracing/perfetto/consumer_host_unittest.cc b/chromium/services/tracing/perfetto/consumer_host_unittest.cc
index 160f8d8a937..2670a78de8e 100644
--- a/chromium/services/tracing/perfetto/consumer_host_unittest.cc
+++ b/chromium/services/tracing/perfetto/consumer_host_unittest.cc
@@ -39,7 +39,7 @@ constexpr base::ProcessId kProducerPid = 1234;
// different sequences (ProducerClient side, Service side, and
// whatever connects via Mojo to the Producer). This is needed
// so we don't get into read/write locks.
-class ThreadedPerfettoService : public mojom::TracingSession {
+class ThreadedPerfettoService : public mojom::TracingSessionClient {
public:
ThreadedPerfettoService()
: task_runner_(base::CreateSequencedTaskRunnerWithTraits(
@@ -66,8 +66,6 @@ class ThreadedPerfettoService : public mojom::TracingSession {
task_runner_->DeleteSoon(FROM_HERE, std::move(consumer_));
}
- task_runner_->DeleteSoon(FROM_HERE, std::move(perfetto_service_));
-
{
base::RunLoop wait_for_destruction;
task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
@@ -77,18 +75,22 @@ class ThreadedPerfettoService : public mojom::TracingSession {
{
base::RunLoop wait_for_destruction;
- ProducerClient::GetTaskRunner()->task_runner()->PostTaskAndReply(
- FROM_HERE, base::DoNothing(), wait_for_destruction.QuitClosure());
+ PerfettoTracedProcess::GetTaskRunner()
+ ->GetOrCreateTaskRunner()
+ ->PostTaskAndReply(FROM_HERE, base::DoNothing(),
+ wait_for_destruction.QuitClosure());
wait_for_destruction.Run();
}
}
- // mojom::TracingSession implementation:
+ // mojom::TracingSessionClient implementation:
void OnTracingEnabled() override {
EXPECT_FALSE(tracing_enabled_);
tracing_enabled_ = true;
}
+ void OnTracingDisabled() override {}
+
void CreateProducer(const std::string& data_source_name,
size_t num_packets,
base::OnceClosure on_tracing_started) {
@@ -129,38 +131,50 @@ class ThreadedPerfettoService : public mojom::TracingSession {
}
void EnableTracingOnSequence(const perfetto::TraceConfig& config) {
- tracing::mojom::TracingSessionPtr tracing_session;
-
- binding_ = std::make_unique<mojo::Binding<mojom::TracingSession>>(
- this, mojo::MakeRequest(&tracing_session));
-
- consumer_->EnableTracing(std::move(tracing_session), std::move(config));
+ tracing::mojom::TracingSessionClientPtr tracing_session_client;
+ binding_ = std::make_unique<mojo::Binding<mojom::TracingSessionClient>>(
+ this, mojo::MakeRequest(&tracing_session_client));
+
+ consumer_->EnableTracing(
+ mojo::MakeRequest(&tracing_session_host_),
+ std::move(tracing_session_client), std::move(config),
+ tracing::mojom::TracingClientPriority::kUserInitiated);
}
void ReadBuffers(mojo::ScopedDataPipeProducerHandle stream,
- ConsumerHost::ReadBuffersCallback callback) {
+ ConsumerHost::TracingSession::ReadBuffersCallback callback) {
task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&ConsumerHost::ReadBuffers,
- base::Unretained(consumer_.get()),
- std::move(stream), std::move(callback)));
+ FROM_HERE,
+ base::BindOnce(
+ &ConsumerHost::TracingSession::ReadBuffers,
+ base::Unretained(consumer_.get()->tracing_session_for_testing()),
+ std::move(stream), std::move(callback)));
}
- void FreeBuffers() {
+ void FreeBuffers() { tracing_session_host_.reset(); }
+
+ void DisableTracing() {
base::RunLoop wait_for_call;
task_runner_->PostTaskAndReply(
FROM_HERE,
- base::BindOnce(&ConsumerHost::FreeBuffers,
- base::Unretained(consumer_.get())),
+ base::BindOnce(
+ &ConsumerHost::TracingSession::DisableTracing,
+ base::Unretained(consumer_.get()->tracing_session_for_testing())),
wait_for_call.QuitClosure());
wait_for_call.Run();
}
- void DisableTracing() {
+ void DisableTracingAndEmitJson(
+ mojo::ScopedDataPipeProducerHandle stream,
+ ConsumerHost::TracingSession::DisableTracingAndEmitJsonCallback
+ callback) {
base::RunLoop wait_for_call;
task_runner_->PostTaskAndReply(
FROM_HERE,
- base::BindOnce(&ConsumerHost::DisableTracing,
- base::Unretained(consumer_.get())),
+ base::BindOnce(
+ &ConsumerHost::TracingSession::DisableTracingAndEmitJson,
+ base::Unretained(consumer_.get()->tracing_session_for_testing()),
+ std::string(), std::move(stream), std::move(callback)),
wait_for_call.QuitClosure());
wait_for_call.Run();
}
@@ -177,14 +191,16 @@ class ThreadedPerfettoService : public mojom::TracingSession {
void Flush(base::OnceClosure on_flush_complete) {
task_runner_->PostTask(
FROM_HERE,
- base::BindOnce(&ConsumerHost::Flush, base::Unretained(consumer_.get()),
- 10000u,
- base::BindOnce(
- [](base::OnceClosure callback, bool success) {
- EXPECT_TRUE(success);
- std::move(callback).Run();
- },
- std::move(on_flush_complete))));
+ base::BindOnce(
+ &ConsumerHost::TracingSession::Flush,
+ base::Unretained(consumer_.get()->tracing_session_for_testing()),
+ 10000u,
+ base::BindOnce(
+ [](base::OnceClosure callback, bool success) {
+ EXPECT_TRUE(success);
+ std::move(callback).Run();
+ },
+ std::move(on_flush_complete))));
}
void ExpectPid(base::ProcessId pid) {
@@ -236,21 +252,32 @@ class ThreadedPerfettoService : public mojom::TracingSession {
perfetto::DataSourceConfig GetProducerClientConfig() {
perfetto::DataSourceConfig config;
base::RunLoop wait_loop;
+ task_runner_->PostTaskAndReply(FROM_HERE, base::BindLambdaForTesting([&]() {
+ config =
+ producer_->data_source()->config();
+ }),
+ wait_loop.QuitClosure());
+ wait_loop.Run();
+ return config;
+ }
+
+ void ClearConsumer() {
+ base::RunLoop wait_loop;
task_runner_->PostTaskAndReply(
- FROM_HERE, base::BindLambdaForTesting([&]() {
- config = producer_->producer_client()->data_source()->config();
- }),
+ FROM_HERE, base::BindLambdaForTesting([&]() { consumer_.reset(); }),
wait_loop.QuitClosure());
wait_loop.Run();
- return config;
}
+ PerfettoService* perfetto_service() const { return perfetto_service_.get(); }
+
private:
scoped_refptr<base::SequencedTaskRunner> task_runner_;
std::unique_ptr<PerfettoService> perfetto_service_;
std::unique_ptr<ConsumerHost> consumer_;
std::unique_ptr<MockProducer> producer_;
- std::unique_ptr<mojo::Binding<mojom::TracingSession>> binding_;
+ std::unique_ptr<mojo::Binding<mojom::TracingSessionClient>> binding_;
+ tracing::mojom::TracingSessionHostPtr tracing_session_host_;
bool tracing_enabled_ = false;
};
@@ -258,7 +285,7 @@ class TracingConsumerTest : public testing::Test,
public mojo::DataPipeDrainer::Client {
public:
void SetUp() override {
- ProducerClient::ResetTaskRunnerForTesting();
+ PerfettoTracedProcess::ResetTaskRunnerForTesting();
threaded_service_ = std::make_unique<ThreadedPerfettoService>();
matching_packet_count_ = 0;
@@ -277,14 +304,22 @@ class TracingConsumerTest : public testing::Test,
// mojo::DataPipeDrainer::Client
void OnDataComplete() override {
- auto proto = std::make_unique<perfetto::protos::Trace>();
- EXPECT_TRUE(
- proto->ParseFromArray(received_data_.data(), received_data_.size()));
-
- for (int i = 0; i < proto->packet_size(); ++i) {
- if (proto->packet(i).for_testing().str() == packet_testing_str_) {
+ if (expect_json_data_) {
+ std::string output(reinterpret_cast<const char*>(received_data_.data()),
+ received_data_.size());
+ if (output.find(packet_testing_str_) != std::string::npos) {
matching_packet_count_++;
}
+ } else {
+ auto proto = std::make_unique<perfetto::protos::Trace>();
+ EXPECT_TRUE(
+ proto->ParseFromArray(received_data_.data(), received_data_.size()));
+
+ for (int i = 0; i < proto->packet_size(); ++i) {
+ if (proto->packet(i).for_testing().str() == packet_testing_str_) {
+ matching_packet_count_++;
+ }
+ }
}
if (on_data_complete_) {
@@ -300,11 +335,27 @@ class TracingConsumerTest : public testing::Test,
}
void ReadBuffers() {
- mojo::DataPipe data_pipe;
- threaded_service_->ReadBuffers(std::move(data_pipe.producer_handle),
- base::OnceClosure());
- drainer_.reset(
- new mojo::DataPipeDrainer(this, std::move(data_pipe.consumer_handle)));
+ MojoCreateDataPipeOptions options = {sizeof(MojoCreateDataPipeOptions),
+ MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 0};
+ mojo::ScopedDataPipeProducerHandle producer;
+ mojo::ScopedDataPipeConsumerHandle consumer;
+ MojoResult rv = mojo::CreateDataPipe(&options, &producer, &consumer);
+ ASSERT_EQ(MOJO_RESULT_OK, rv);
+ threaded_service_->ReadBuffers(std::move(producer), base::OnceClosure());
+ drainer_.reset(new mojo::DataPipeDrainer(this, std::move(consumer)));
+ }
+
+ void DisableTracingAndEmitJson(base::OnceClosure write_callback) {
+ expect_json_data_ = true;
+ MojoCreateDataPipeOptions options = {sizeof(MojoCreateDataPipeOptions),
+ MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 0};
+ mojo::ScopedDataPipeProducerHandle producer;
+ mojo::ScopedDataPipeConsumerHandle consumer;
+ MojoResult rv = mojo::CreateDataPipe(&options, &producer, &consumer);
+ ASSERT_EQ(MOJO_RESULT_OK, rv);
+ threaded_service_->DisableTracingAndEmitJson(std::move(producer),
+ std::move(write_callback));
+ drainer_.reset(new mojo::DataPipeDrainer(this, std::move(consumer)));
}
perfetto::TraceConfig GetDefaultTraceConfig(
@@ -356,6 +407,7 @@ class TracingConsumerTest : public testing::Test,
std::string packet_testing_str_;
size_t matching_packet_count_ = 0;
size_t total_bytes_received_ = 0;
+ bool expect_json_data_ = false;
};
TEST_F(TracingConsumerTest, EnableAndDisableTracing) {
@@ -393,6 +445,26 @@ TEST_F(TracingConsumerTest, ReceiveTestPackets) {
EXPECT_EQ(10u, matching_packet_count());
}
+TEST_F(TracingConsumerTest, DeleteConsumerWhenReceiving) {
+ EnableTracingWithDataSourceName(mojom::kTraceEventDataSourceName);
+
+ base::RunLoop wait_for_tracing_start;
+ threaded_perfetto_service()->CreateProducer(
+ mojom::kTraceEventDataSourceName, 100u,
+ wait_for_tracing_start.QuitClosure());
+
+ wait_for_tracing_start.Run();
+
+ base::RunLoop no_more_data;
+ ExpectPackets(kPerfettoTestString, no_more_data.QuitClosure());
+
+ threaded_perfetto_service()->DisableTracing();
+ ReadBuffers();
+
+ threaded_perfetto_service()->ClearConsumer();
+ no_more_data.Run();
+}
+
TEST_F(TracingConsumerTest, FlushProducers) {
EnableTracingWithDataSourceName(mojom::kTraceEventDataSourceName);
@@ -547,4 +619,128 @@ TEST_F(TracingConsumerTest, PrivacyFilterConfig) {
.privacy_filtering_enabled());
}
+TEST_F(TracingConsumerTest, PrivacyFilterConfigInJson) {
+ EnableTracingWithDataSourceName(mojom::kTraceEventDataSourceName,
+ /* enable_privacy_filtering =*/true);
+
+ base::RunLoop wait_for_tracing_start;
+ threaded_perfetto_service()->CreateProducer(
+ mojom::kTraceEventDataSourceName, 10u,
+ wait_for_tracing_start.QuitClosure());
+
+ wait_for_tracing_start.Run();
+
+ EXPECT_TRUE(threaded_perfetto_service()
+ ->GetProducerClientConfig()
+ .chrome_config()
+ .privacy_filtering_enabled());
+
+ base::RunLoop no_more_data;
+ ExpectPackets("\"perfetto_trace_stats\":\"__stripped__\"",
+ no_more_data.QuitClosure());
+
+ base::RunLoop write_done;
+ DisableTracingAndEmitJson(write_done.QuitClosure());
+
+ no_more_data.Run();
+ write_done.Run();
+
+ EXPECT_EQ(1u, matching_packet_count());
+}
+
+class MockConsumerHost : public mojom::TracingSessionClient {
+ public:
+ MockConsumerHost(PerfettoService* service)
+ : consumer_host_(std::make_unique<ConsumerHost>(service)) {}
+
+ void EnableTracing(const perfetto::TraceConfig& config,
+ mojom::TracingClientPriority priority) {
+ tracing::mojom::TracingSessionClientPtr tracing_session_client;
+ binding_.Bind(mojo::MakeRequest(&tracing_session_client));
+
+ binding_.set_connection_error_handler(base::BindOnce(
+ &MockConsumerHost::OnConnectionLost, base::Unretained(this)));
+
+ consumer_host_->EnableTracing(mojo::MakeRequest(&tracing_session_host_),
+ std::move(tracing_session_client), config,
+ priority);
+ tracing_session_host_.set_connection_error_handler(base::BindOnce(
+ &MockConsumerHost::OnConnectionLost, base::Unretained(this)));
+ }
+
+ void DisableTracing() { tracing_session_host_->DisableTracing(); }
+
+ void OnConnectionLost() {
+ CloseTracingSession();
+ wait_for_connection_lost_.Quit();
+ }
+
+ void CloseTracingSession() {
+ tracing_session_host_.reset();
+ binding_.Close();
+ }
+
+ // mojom::TracingSessionClient implementation:
+ void OnTracingEnabled() override { wait_for_tracing_enabled_.Quit(); }
+
+ void OnTracingDisabled() override { wait_for_tracing_disabled_.Quit(); }
+
+ void WaitForConnectionLost() { wait_for_connection_lost_.Run(); }
+
+ void WaitForTracingEnabled() { wait_for_tracing_enabled_.Run(); }
+
+ void WaitForTracingDisabled() { wait_for_tracing_disabled_.Run(); }
+
+ private:
+ tracing::mojom::TracingSessionHostPtr tracing_session_host_;
+ mojo::Binding<mojom::TracingSessionClient> binding_{this};
+ std::unique_ptr<ConsumerHost> consumer_host_;
+ base::RunLoop wait_for_connection_lost_;
+ base::RunLoop wait_for_tracing_enabled_;
+ base::RunLoop wait_for_tracing_disabled_;
+};
+
+TEST_F(TracingConsumerTest, TestConsumerPriority) {
+ // auto perfetto_service = std::make_unique<PerfettoService>(nullptr);
+ PerfettoService::GetInstance()->SetActiveServicePidsInitialized();
+ auto trace_config = GetDefaultTraceConfig(mojom::kTraceEventDataSourceName);
+
+ MockConsumerHost background_consumer_1(PerfettoService::GetInstance());
+ background_consumer_1.EnableTracing(
+ trace_config, tracing::mojom::TracingClientPriority::kBackground);
+ background_consumer_1.WaitForTracingEnabled();
+
+ // Second consumer of the same priority should cause the first one to
+ // be disabled and the second to start.
+ MockConsumerHost background_consumer_2(PerfettoService::GetInstance());
+ background_consumer_2.EnableTracing(
+ trace_config, tracing::mojom::TracingClientPriority::kBackground);
+ background_consumer_1.WaitForTracingDisabled();
+ background_consumer_2.WaitForTracingEnabled();
+
+ // Third consumer will have a higher priority, and should kill the second
+ // one.
+ MockConsumerHost user_initiated_consumer(PerfettoService::GetInstance());
+ user_initiated_consumer.EnableTracing(
+ trace_config, tracing::mojom::TracingClientPriority::kUserInitiated);
+ background_consumer_2.WaitForTracingDisabled();
+ user_initiated_consumer.WaitForTracingEnabled();
+
+ // Fourth consumer will be another background consumer, and should be
+ // itself killed as the third consumer is still running.
+ MockConsumerHost background_consumer_3(PerfettoService::GetInstance());
+ background_consumer_3.EnableTracing(
+ trace_config, tracing::mojom::TracingClientPriority::kBackground);
+ background_consumer_3.WaitForConnectionLost();
+
+ // If we close the user initiated consumer, the third background consumer
+ // should now be able to trace.
+ user_initiated_consumer.DisableTracing();
+ user_initiated_consumer.WaitForTracingDisabled();
+ user_initiated_consumer.CloseTracingSession();
+ background_consumer_3.EnableTracing(
+ trace_config, tracing::mojom::TracingClientPriority::kBackground);
+ background_consumer_3.WaitForTracingEnabled();
+}
+
} // namespace tracing
diff --git a/chromium/services/tracing/perfetto/json_exporter_main.cc b/chromium/services/tracing/perfetto/json_exporter_main.cc
new file mode 100644
index 00000000000..ff2ba4de1df
--- /dev/null
+++ b/chromium/services/tracing/perfetto/json_exporter_main.cc
@@ -0,0 +1,77 @@
+// Copyright 2019 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 "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "services/tracing/perfetto/json_trace_exporter.h"
+#include "services/tracing/perfetto/track_event_json_exporter.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/trace_packet.h"
+#include "third_party/perfetto/protos/perfetto/trace/trace.pbzero.h"
+
+// Tool to convert a given proto trace into json.
+//
+// Usage:
+// trace_json_exporter [input_file] [output_file]
+// Both the arguments are required.
+//
+// Parses the given input file which contains a serialized perfetto::Trace
+// proto, converts the trace to JSON and writes to output file.
+
+namespace tracing {
+
+void OnJsonData(base::File* output_file,
+ std::string* json,
+ base::DictionaryValue* metadata,
+ bool has_more) {
+ CHECK_EQ(output_file->WriteAtCurrentPos(json->data(), json->size()),
+ static_cast<int>(json->size()));
+ LOG(ERROR) << "Finished writing " << json->size() << " bytes to file.";
+}
+
+void WriteJsonTrace(const std::string& data, base::File* output_file) {
+ TrackEventJSONExporter exporter(
+ JSONTraceExporter::ArgumentFilterPredicate(),
+ JSONTraceExporter::MetadataFilterPredicate(),
+ base::BindRepeating(&OnJsonData, base::Unretained(output_file)));
+ perfetto::protos::pbzero::Trace::Decoder decoder(
+ reinterpret_cast<const uint8_t*>(data.data()), data.size());
+ std::vector<perfetto::TracePacket> packets;
+ for (auto it = decoder.packet(); !!it; ++it) {
+ perfetto::TracePacket trace_packet;
+ trace_packet.AddSlice(it->data(), it->size());
+ packets.emplace_back(std::move(trace_packet));
+ }
+ exporter.OnTraceData(std::move(packets), false);
+}
+
+} // namespace tracing
+
+int main(int argc, char* argv[]) {
+ base::AtExitManager at_exit_manager;
+ base::CommandLine::Init(argc, argv);
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+ base::CommandLine::StringVector args = command_line.GetArgs();
+ if (args.size() < 2u) {
+ LOG(ERROR) << "Enter input and output path. Usage:"
+ "trace_json_exporter [input] [output]";
+ return -1;
+ }
+
+ base::FilePath input_path(args[0]);
+ base::FilePath output_path(args[1]);
+
+ std::string contents;
+ CHECK(base::ReadFileToString(input_path, &contents));
+
+ base::File output_file(
+ output_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+ tracing::WriteJsonTrace(contents, &output_file);
+ return 0;
+}
diff --git a/chromium/services/tracing/perfetto/json_trace_exporter.cc b/chromium/services/tracing/perfetto/json_trace_exporter.cc
index f86102cc09d..cf6dc4c209a 100644
--- a/chromium/services/tracing/perfetto/json_trace_exporter.cc
+++ b/chromium/services/tracing/perfetto/json_trace_exporter.cc
@@ -440,10 +440,11 @@ void JSONTraceExporter::StringBuffer::EscapeJSONAndAppend(
void JSONTraceExporter::StringBuffer::Flush(base::DictionaryValue* metadata,
bool has_more) {
- callback_.Run(out_, metadata, has_more);
+ callback_.Run(&out_, metadata, has_more);
if (has_more) {
// We clear |out_| because we've processed all the current data in |out_|
- // and we don't want any data to be repeated. We have to protect this by
+ // and we don't want any data to be repeated. The callback should have moved
+ // all the contents, but clear it to be safe. We have to protect this by
// checking |has_more| because the callback could have deleted |this| in
// which cause |out_| is a destroyed as well.
out_.clear();
diff --git a/chromium/services/tracing/perfetto/json_trace_exporter.h b/chromium/services/tracing/perfetto/json_trace_exporter.h
index 9e96cba5a3e..b682dd2e161 100644
--- a/chromium/services/tracing/perfetto/json_trace_exporter.h
+++ b/chromium/services/tracing/perfetto/json_trace_exporter.h
@@ -55,10 +55,8 @@ class JSONTraceExporter {
using MetadataFilterPredicate =
base::RepeatingCallback<bool(const std::string& metadata_name)>;
- using OnTraceEventJSONCallback =
- base::RepeatingCallback<void(const std::string& json,
- base::DictionaryValue* metadata,
- bool has_more)>;
+ using OnTraceEventJSONCallback = base::RepeatingCallback<
+ void(std::string* json, base::DictionaryValue* metadata, bool has_more)>;
JSONTraceExporter(ArgumentFilterPredicate argument_filter_predicate,
MetadataFilterPredicate metadata_filter_predicate,
diff --git a/chromium/services/tracing/perfetto/json_trace_exporter_unittest.cc b/chromium/services/tracing/perfetto/json_trace_exporter_unittest.cc
index 8a55cd296de..9da5bb202c5 100644
--- a/chromium/services/tracing/perfetto/json_trace_exporter_unittest.cc
+++ b/chromium/services/tracing/perfetto/json_trace_exporter_unittest.cc
@@ -195,11 +195,12 @@ class JsonTraceExporterTest : public testing::Test {
base::BindRepeating(&JsonTraceExporterTest::OnTraceEventJSON,
base::Unretained(this)))) {}
- void OnTraceEventJSON(const std::string& json,
+ void OnTraceEventJSON(std::string* json,
base::DictionaryValue* metadata,
bool has_more) {
- unparsed_trace_data_ += json;
- unparsed_trace_data_sequence_.push_back(json);
+ unparsed_trace_data_ += *json;
+ unparsed_trace_data_sequence_.push_back(std::string());
+ unparsed_trace_data_sequence_.back().swap(*json);
if (has_more) {
return;
}
@@ -207,7 +208,7 @@ class JsonTraceExporterTest : public testing::Test {
base::JSONReader::ReadDeprecated(unparsed_trace_data_));
EXPECT_TRUE(parsed_trace_data_);
if (!parsed_trace_data_) {
- LOG(ERROR) << "Couldn't parse json: \n" << json;
+ LOG(ERROR) << "Couldn't parse json: \n" << unparsed_trace_data_;
}
// The TraceAnalyzer expects the raw trace output, without the
diff --git a/chromium/services/tracing/perfetto/perfetto_integration_unittest.cc b/chromium/services/tracing/perfetto/perfetto_integration_unittest.cc
index bec94c0f452..a7da62c1981 100644
--- a/chromium/services/tracing/perfetto/perfetto_integration_unittest.cc
+++ b/chromium/services/tracing/perfetto/perfetto_integration_unittest.cc
@@ -4,6 +4,7 @@
#include <memory>
#include <string>
+#include <thread>
#include <utility>
#include "base/bind.h"
@@ -22,14 +23,17 @@ namespace {
const char kPerfettoTestDataSourceName[] =
"org.chromium.chrome_integration_unittest";
-const char kPerfettoProducerName[] = "chrome_producer_test";
+const char kPerfettoProducerName[] = "org.chromium.perfetto_producer.123";
class PerfettoIntegrationTest : public testing::Test {
public:
void SetUp() override {
+ PerfettoTracedProcess::Get()->ClearDataSourcesForTesting();
+ data_source_ =
+ std::make_unique<TestDataSource>(kPerfettoTestDataSourceName, 0);
perfetto_service_ = std::make_unique<PerfettoService>();
RunUntilIdle();
- ProducerClient::ResetTaskRunnerForTesting();
+ PerfettoTracedProcess::ResetTaskRunnerForTesting();
}
void TearDown() override { perfetto_service_.reset(); }
@@ -37,14 +41,14 @@ class PerfettoIntegrationTest : public testing::Test {
PerfettoService* perfetto_service() const { return perfetto_service_.get(); }
void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
- private:
+ protected:
+ std::unique_ptr<TestDataSource> data_source_;
std::unique_ptr<PerfettoService> perfetto_service_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
};
TEST_F(PerfettoIntegrationTest, ProducerDatasourceInitialized) {
- auto dummy_client =
- std::make_unique<MockProducerClient>(0 /* send_packet_count */);
+ auto dummy_client = std::make_unique<MockProducerClient>();
base::RunLoop producer_initialized_runloop;
auto new_producer = std::make_unique<MockProducerHost>(
@@ -69,12 +73,13 @@ TEST_F(PerfettoIntegrationTest, ClientEnabledAndDisabled) {
base::RunLoop client_enabled_callback;
base::RunLoop client_disabled_callback;
auto client = std::make_unique<MockProducerClient>(
- 0 /* send_packet_count */, client_enabled_callback.QuitClosure(),
+ client_enabled_callback.QuitClosure(),
client_disabled_callback.QuitClosure());
auto producer = std::make_unique<MockProducerHost>(
kPerfettoProducerName, kPerfettoTestDataSourceName,
perfetto_service()->GetService(), client.get());
+
client_enabled_callback.Run();
RunUntilIdle();
@@ -91,11 +96,12 @@ TEST_F(PerfettoIntegrationTest, ClientEnabledAndDisabled) {
TEST_F(PerfettoIntegrationTest, PacketsEndToEndProducerFirst) {
const size_t kNumPackets = 10;
+ data_source_->set_send_packet_count(kNumPackets);
base::RunLoop client_enabled_callback;
base::RunLoop client_disabled_callback;
auto client = std::make_unique<MockProducerClient>(
- kNumPackets, client_enabled_callback.QuitClosure(),
+ client_enabled_callback.QuitClosure(),
client_disabled_callback.QuitClosure());
auto producer = std::make_unique<MockProducerHost>(
@@ -127,6 +133,7 @@ TEST_F(PerfettoIntegrationTest, PacketsEndToEndProducerFirst) {
TEST_F(PerfettoIntegrationTest, PacketsEndToEndConsumerFirst) {
const size_t kNumPackets = 10;
+ data_source_->set_send_packet_count(kNumPackets);
base::RunLoop no_more_packets_runloop;
MockConsumer consumer(kPerfettoTestDataSourceName,
@@ -139,7 +146,7 @@ TEST_F(PerfettoIntegrationTest, PacketsEndToEndConsumerFirst) {
base::RunLoop client_enabled_callback;
auto client = std::make_unique<MockProducerClient>(
- kNumPackets, client_enabled_callback.QuitClosure());
+ client_enabled_callback.QuitClosure());
auto new_producer = std::make_unique<MockProducerHost>(
kPerfettoProducerName, kPerfettoTestDataSourceName,
@@ -159,6 +166,7 @@ TEST_F(PerfettoIntegrationTest, PacketsEndToEndConsumerFirst) {
TEST_F(PerfettoIntegrationTest, CommitDataRequestIsMaybeComplete) {
const size_t kNumPackets = 100;
+ data_source_->set_send_packet_count(kNumPackets);
base::RunLoop no_more_packets_runloop;
MockConsumer consumer(kPerfettoTestDataSourceName,
@@ -171,7 +179,7 @@ TEST_F(PerfettoIntegrationTest, CommitDataRequestIsMaybeComplete) {
base::RunLoop client_enabled_callback;
auto client = std::make_unique<MockProducerClient>(
- kNumPackets, client_enabled_callback.QuitClosure());
+ client_enabled_callback.QuitClosure());
auto new_producer = std::make_unique<MockProducerHost>(
kPerfettoProducerName, kPerfettoTestDataSourceName,
perfetto_service()->GetService(), client.get());
@@ -179,11 +187,13 @@ TEST_F(PerfettoIntegrationTest, CommitDataRequestIsMaybeComplete) {
client_enabled_callback.Run();
base::RunLoop wait_for_packet_write;
- client->GetTaskRunner()->task_runner()->PostTaskAndReply(
- FROM_HERE,
- base::BindOnce(&TestDataSource::WritePacketBigly,
- base::Unretained(client->data_source())),
- wait_for_packet_write.QuitClosure());
+ PerfettoTracedProcess::Get()
+ ->GetTaskRunner()
+ ->GetOrCreateTaskRunner()
+ ->PostTaskAndReply(FROM_HERE,
+ base::BindOnce(&TestDataSource::WritePacketBigly,
+ base::Unretained(data_source_.get())),
+ wait_for_packet_write.QuitClosure());
wait_for_packet_write.Run();
RunUntilIdle();
@@ -200,6 +210,7 @@ TEST_F(PerfettoIntegrationTest, CommitDataRequestIsMaybeComplete) {
TEST_F(PerfettoIntegrationTest, TracingRestarted) {
const size_t kNumPackets = 10;
+ data_source_->set_send_packet_count(kNumPackets);
base::RunLoop no_more_packets_runloop;
MockConsumer consumer(kPerfettoTestDataSourceName,
@@ -212,7 +223,7 @@ TEST_F(PerfettoIntegrationTest, TracingRestarted) {
base::RunLoop client_enabled_callback;
auto client = std::make_unique<MockProducerClient>(
- kNumPackets, client_enabled_callback.QuitClosure());
+ client_enabled_callback.QuitClosure());
auto new_producer = std::make_unique<MockProducerHost>(
kPerfettoProducerName, kPerfettoTestDataSourceName,
@@ -254,11 +265,12 @@ TEST_F(PerfettoIntegrationTest, TracingRestarted) {
TEST_F(PerfettoIntegrationTest, NoPacketsReceivedOnWrongSourceName) {
const size_t kNumPackets = 10;
+ data_source_->set_send_packet_count(kNumPackets);
base::RunLoop client_enabled_callback;
base::RunLoop client_disabled_callback;
auto client = std::make_unique<MockProducerClient>(
- kNumPackets, client_enabled_callback.QuitClosure(),
+ client_enabled_callback.QuitClosure(),
client_disabled_callback.QuitClosure());
base::RunLoop producer_initialized_runloop;
@@ -267,8 +279,7 @@ TEST_F(PerfettoIntegrationTest, NoPacketsReceivedOnWrongSourceName) {
perfetto_service()->GetService(), client.get());
base::RunLoop no_more_packets_runloop;
- MockConsumer consumer(kPerfettoTestDataSourceName,
- perfetto_service()->GetService(),
+ MockConsumer consumer("fake_data_source", perfetto_service()->GetService(),
[&no_more_packets_runloop](bool has_more) {
if (!has_more) {
no_more_packets_runloop.Quit();
@@ -290,22 +301,27 @@ TEST_F(PerfettoIntegrationTest,
base::RunLoop client1_enabled_callback;
base::RunLoop client2_enabled_callback;
auto client1 = std::make_unique<MockProducerClient>(
- 0 /* send_packet_count */, client1_enabled_callback.QuitClosure());
- auto client2 = std::make_unique<MockProducerClient>(
- 0 /* send_packet_count */, client2_enabled_callback.QuitClosure());
-
+ client1_enabled_callback.QuitClosure());
auto producer1 = std::make_unique<MockProducerHost>(
kPerfettoProducerName, kPerfettoTestDataSourceName,
perfetto_service()->GetService(), client1.get());
- auto producer2 = std::make_unique<MockProducerHost>(
- kPerfettoProducerName, kPerfettoTestDataSourceName,
- perfetto_service()->GetService(), client2.get());
-
+ // Start the trace here, this is because we need to send the EnableTracing
+ // call to client1, but constructing client2 will override the
+ // |producer_client_| pointer in PerfettoTracedProcess::Get() so we wait until
+ // client1 has been enabled before constructing the second producer client.
MockConsumer consumer(kPerfettoTestDataSourceName,
perfetto_service()->GetService(), nullptr);
client1_enabled_callback.Run();
+
+ auto client2 = std::make_unique<MockProducerClient>(
+ client2_enabled_callback.QuitClosure());
+
+ auto producer2 = std::make_unique<MockProducerHost>(
+ kPerfettoProducerName, kPerfettoTestDataSourceName,
+ perfetto_service()->GetService(), client2.get());
+
client2_enabled_callback.Run();
EXPECT_TRUE(client1->shared_memory());
diff --git a/chromium/services/tracing/perfetto/perfetto_service.cc b/chromium/services/tracing/perfetto/perfetto_service.cc
index eb87096932a..980aec90ae9 100644
--- a/chromium/services/tracing/perfetto/perfetto_service.cc
+++ b/chromium/services/tracing/perfetto/perfetto_service.cc
@@ -19,6 +19,33 @@
namespace tracing {
+namespace {
+
+bool StringToProcessId(const std::string& input, base::ProcessId* output) {
+ // Pid is encoded as uint in the string.
+ return base::StringToUint(input, reinterpret_cast<uint32_t*>(output));
+}
+
+} // namespace
+
+// static
+bool PerfettoService::ParsePidFromProducerName(const std::string& producer_name,
+ base::ProcessId* pid) {
+ if (!base::StartsWith(producer_name, mojom::kPerfettoProducerNamePrefix,
+ base::CompareCase::SENSITIVE)) {
+ LOG(DFATAL) << "Unexpected producer name: " << producer_name;
+ return false;
+ }
+
+ static const size_t kPrefixLength =
+ strlen(mojom::kPerfettoProducerNamePrefix);
+ if (!StringToProcessId(producer_name.substr(kPrefixLength), pid)) {
+ LOG(DFATAL) << "Unexpected producer name: " << producer_name;
+ return false;
+ }
+ return true;
+}
+
// static
PerfettoService* PerfettoService::GetInstance() {
static base::NoDestructor<PerfettoService> perfetto_service;
@@ -63,31 +90,63 @@ void PerfettoService::ConnectToProducerHost(
void PerfettoService::AddActiveServicePid(base::ProcessId pid) {
active_service_pids_.insert(pid);
- for (auto* consumer_host : consumer_hosts_) {
- consumer_host->OnActiveServicePidAdded(pid);
+ for (auto* tracing_session : tracing_sessions_) {
+ tracing_session->OnActiveServicePidAdded(pid);
}
}
void PerfettoService::RemoveActiveServicePid(base::ProcessId pid) {
active_service_pids_.erase(pid);
- for (auto* consumer_host : consumer_hosts_) {
- consumer_host->OnActiveServicePidRemoved(pid);
+ for (auto* tracing_session : tracing_sessions_) {
+ tracing_session->OnActiveServicePidRemoved(pid);
}
}
void PerfettoService::SetActiveServicePidsInitialized() {
active_service_pids_initialized_ = true;
- for (auto* consumer_host : consumer_hosts_) {
- consumer_host->OnActiveServicePidsInitialized();
+ for (auto* tracing_session : tracing_sessions_) {
+ tracing_session->OnActiveServicePidsInitialized();
}
}
-void PerfettoService::RegisterConsumerHost(ConsumerHost* consumer_host) {
- consumer_hosts_.insert(consumer_host);
+void PerfettoService::RegisterTracingSession(
+ ConsumerHost::TracingSession* tracing_session) {
+ tracing_sessions_.insert(tracing_session);
}
-void PerfettoService::UnregisterConsumerHost(ConsumerHost* consumer_host) {
- consumer_hosts_.erase(consumer_host);
+void PerfettoService::UnregisterTracingSession(
+ ConsumerHost::TracingSession* tracing_session) {
+ tracing_sessions_.erase(tracing_session);
+}
+
+void PerfettoService::RequestTracingSession(
+ mojom::TracingClientPriority priority,
+ base::OnceClosure callback) {
+ // TODO(oysteine): This currently assumes we only have one concurrent tracing
+ // session, which is enforced by all ConsumerHost::BeginTracing calls routing
+ // through RequestTracingSession before creating a new TracingSession.
+ // Not running the callback means we'll drop any connection requests and deny
+ // the creation of the tracing session.
+ for (auto* tracing_session : tracing_sessions_) {
+ if (!tracing_session->tracing_enabled()) {
+ continue;
+ }
+
+ if (tracing_session->tracing_priority() > priority) {
+ return;
+ }
+
+ // If the currently active session is the same or lower priority and it's
+ // tracing, then we'll disable it and re-try the request once it's shut
+ // down.
+ tracing_session->RequestDisableTracing(
+ base::BindOnce(&PerfettoService::RequestTracingSession,
+ base::Unretained(PerfettoService::GetInstance()),
+ priority, std::move(callback)));
+ return;
+ }
+
+ std::move(callback).Run();
}
} // namespace tracing
diff --git a/chromium/services/tracing/perfetto/perfetto_service.h b/chromium/services/tracing/perfetto/perfetto_service.h
index f611ec309a3..aae5ede388c 100644
--- a/chromium/services/tracing/perfetto/perfetto_service.h
+++ b/chromium/services/tracing/perfetto/perfetto_service.h
@@ -12,6 +12,7 @@
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/strong_binding_set.h"
#include "services/service_manager/public/cpp/identity.h"
+#include "services/tracing/perfetto/consumer_host.h"
#include "services/tracing/public/cpp/perfetto/task_runner.h"
#include "services/tracing/public/mojom/perfetto_service.mojom.h"
@@ -21,8 +22,6 @@ class TracingService;
namespace tracing {
-class ConsumerHost;
-
// This class serves two purposes: It wraps the use of the system-wide
// perfetto::TracingService instance, and serves as the main Mojo interface for
// connecting per-process ProducerClient with corresponding service-side
@@ -34,6 +33,8 @@ class PerfettoService : public mojom::PerfettoService {
~PerfettoService() override;
static PerfettoService* GetInstance();
+ static bool ParsePidFromProducerName(const std::string& producer_name,
+ base::ProcessId* pid);
void BindRequest(mojom::PerfettoServiceRequest request, uint32_t pid);
@@ -43,10 +44,17 @@ class PerfettoService : public mojom::PerfettoService {
perfetto::TracingService* GetService() const;
- // Called when a ConsumerHost is created/destroyed (i.e. when a consumer
- // connects/disconnects).
- void RegisterConsumerHost(ConsumerHost* consumer_host);
- void UnregisterConsumerHost(ConsumerHost* consumer_host);
+ // Called when a ConsumerHost::TracingSession is created/destroyed (i.e. when
+ // a consumer starts/finishes tracing.
+ void RegisterTracingSession(ConsumerHost::TracingSession* consumer_host);
+ void UnregisterTracingSession(ConsumerHost::TracingSession* consumer_host);
+
+ // Make a request of the service for whether or not a TracingSession
+ // should be allowed to start tracing, in case of pre-existing sessions.
+ // |callback| will eventually be called once a session is allowed, or it
+ // will be destroyed.
+ void RequestTracingSession(mojom::TracingClientPriority priority,
+ base::OnceClosure callback);
// Called by TracingService to notify the perfetto service of the PIDs of
// actively running services (whenever a service starts or stops).
@@ -70,7 +78,7 @@ class PerfettoService : public mojom::PerfettoService {
std::unique_ptr<perfetto::TracingService> service_;
mojo::BindingSet<mojom::PerfettoService, uint32_t> bindings_;
mojo::StrongBindingSet<mojom::ProducerHost> producer_bindings_;
- std::set<ConsumerHost*> consumer_hosts_; // Not owned.
+ std::set<ConsumerHost::TracingSession*> tracing_sessions_; // Not owned.
std::set<base::ProcessId> active_service_pids_;
bool active_service_pids_initialized_ = false;
diff --git a/chromium/services/tracing/perfetto/perfetto_tracing_coordinator.cc b/chromium/services/tracing/perfetto/perfetto_tracing_coordinator.cc
index 591727e5a65..f12f6a13a7d 100644
--- a/chromium/services/tracing/perfetto/perfetto_tracing_coordinator.cc
+++ b/chromium/services/tracing/perfetto/perfetto_tracing_coordinator.cc
@@ -84,7 +84,7 @@ class PerfettoTracingCoordinator::TracingSession : public perfetto::Consumer {
~TracingSession() override {
if (!stop_and_flush_callback_.is_null()) {
- base::ResetAndReturn(&stop_and_flush_callback_)
+ std::move(stop_and_flush_callback_)
.Run(base::Value(base::Value::Type::DICTIONARY));
}
@@ -124,16 +124,16 @@ class PerfettoTracingCoordinator::TracingSession : public perfetto::Consumer {
consumer_endpoint_->DisableTracing();
}
- void OnJSONTraceEventCallback(const std::string& json,
+ void OnJSONTraceEventCallback(std::string* json,
base::DictionaryValue* metadata,
bool has_more) {
if (stream_.is_valid()) {
- mojo::BlockingCopyFromString(json, stream_);
+ mojo::BlockingCopyFromString(*json, stream_);
}
if (!has_more) {
DCHECK(!stop_and_flush_callback_.is_null());
- base::ResetAndReturn(&stop_and_flush_callback_)
+ std::move(stop_and_flush_callback_)
.Run(/*metadata=*/std::move(*metadata));
std::move(tracing_over_callback_).Run();
@@ -208,8 +208,8 @@ class PerfettoTracingCoordinator::TracingSession : public perfetto::Consumer {
// Attempt to parse the PID out of the producer name.
base::ProcessId pid;
- if (!ConsumerHost::ParsePidFromProducerName(state_change.producer_name(),
- &pid)) {
+ if (!PerfettoService::ParsePidFromProducerName(
+ state_change.producer_name(), &pid)) {
continue;
}
diff --git a/chromium/services/tracing/perfetto/privacy_filtered_fields-inl.h b/chromium/services/tracing/perfetto/privacy_filtered_fields-inl.h
new file mode 100644
index 00000000000..9ec02336839
--- /dev/null
+++ b/chromium/services/tracing/perfetto/privacy_filtered_fields-inl.h
@@ -0,0 +1,98 @@
+// Copyright 2019 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.
+
+#ifndef SERVICES_TRACING_PERFETTO_PRIVACY_FILTERED_FIELDS_INL_H_
+#define SERVICES_TRACING_PERFETTO_PRIVACY_FILTERED_FIELDS_INL_H_
+
+// This file is auto generated from internal copy of the TracePacket proto, that
+// does not contain any privacy sensitive fields. Updates to this file should be
+// made by changing internal copy and then running the generator script. Follow
+// instructions at:
+// https://goto.google.com/chrome-trace-privacy-filtered-fields
+
+namespace tracing {
+
+// A MessageInfo node created from a tree of TracePacket proto messages.
+struct MessageInfo {
+ // List of accepted field ids in the output for this message. The end of list
+ // is marked by a -1.
+ const int* accepted_field_ids;
+
+ // List of sub messages that correspond to the accepted field ids list. There
+ // is no end of list marker and the length is this list is equal to length of
+ // |accepted_field_ids| - 1.
+ const MessageInfo* const* const sub_messages;
+};
+
+// Proto Message: TaskExecution
+constexpr int kTaskExecutionIndices[] = {1, -1};
+constexpr MessageInfo kTaskExecution = {kTaskExecutionIndices, nullptr};
+
+// Proto Message: LegacyEvent
+constexpr int kLegacyEventIndices[] = {1, 2, 3, 4, 6, 8, 9, 10,
+ 11, 12, 13, 14, 18, 19, -1};
+constexpr MessageInfo kLegacyEvent = {kLegacyEventIndices, nullptr};
+
+// Proto Message: TrackEvent
+constexpr int kTrackEventIndices[] = {1, 2, 3, 5, 6, 16, 17, -1};
+constexpr MessageInfo const* kTrackEventComplexMessages[] = {
+ nullptr, nullptr, nullptr, &kTaskExecution,
+ &kLegacyEvent, nullptr, nullptr};
+constexpr MessageInfo kTrackEvent = {kTrackEventIndices,
+ kTrackEventComplexMessages};
+
+// Proto Message: EventCategory
+constexpr int kEventCategoryIndices[] = {1, 2, -1};
+constexpr MessageInfo kEventCategory = {kEventCategoryIndices, nullptr};
+
+// Proto Message: LegacyEventName
+constexpr int kLegacyEventNameIndices[] = {1, 2, -1};
+constexpr MessageInfo kLegacyEventName = {kLegacyEventNameIndices, nullptr};
+
+// Proto Message: SourceLocation
+constexpr int kSourceLocationIndices[] = {1, 2, 3, -1};
+constexpr MessageInfo kSourceLocation = {kSourceLocationIndices, nullptr};
+
+// Proto Message: InternedData
+constexpr int kInternedDataIndices[] = {1, 2, 4, -1};
+constexpr MessageInfo const* kInternedDataComplexMessages[] = {
+ &kEventCategory, &kLegacyEventName, &kSourceLocation};
+constexpr MessageInfo kInternedData = {kInternedDataIndices,
+ kInternedDataComplexMessages};
+
+// Proto Message: BufferStats
+constexpr int kBufferStatsIndices[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, -1};
+constexpr MessageInfo kBufferStats = {kBufferStatsIndices, nullptr};
+
+// Proto Message: TraceStats
+constexpr int kTraceStatsIndices[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, -1};
+constexpr MessageInfo const* kTraceStatsComplexMessages[] = {
+ &kBufferStats, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr};
+constexpr MessageInfo kTraceStats = {kTraceStatsIndices,
+ kTraceStatsComplexMessages};
+
+// Proto Message: ProcessDescriptor
+constexpr int kProcessDescriptorIndices[] = {1, 4, -1};
+constexpr MessageInfo kProcessDescriptor = {kProcessDescriptorIndices, nullptr};
+
+// Proto Message: ThreadDescriptor
+constexpr int kThreadDescriptorIndices[] = {1, 2, 4, 6, 7, -1};
+constexpr MessageInfo kThreadDescriptor = {kThreadDescriptorIndices, nullptr};
+
+// EDIT: Contains field numbers: {3} which are not autogenerated.
+
+// Proto Message: TracePacket
+constexpr int kTracePacketIndices[] = {3, 10, 11, 12, 35, 36,
+ 41, 42, 43, 44, -1};
+constexpr MessageInfo const* kTracePacketComplexMessages[] = {
+ nullptr, nullptr, &kTrackEvent, &kInternedData, &kTraceStats,
+ nullptr, nullptr, nullptr, &kProcessDescriptor, &kThreadDescriptor};
+constexpr MessageInfo kTracePacket = {kTracePacketIndices,
+ kTracePacketComplexMessages};
+
+} // namespace tracing
+
+#endif // SERVICES_TRACING_PERFETTO_PRIVACY_FILTERED_FIELDS_INL_H_
diff --git a/chromium/services/tracing/perfetto/privacy_filtering_check.cc b/chromium/services/tracing/perfetto/privacy_filtering_check.cc
new file mode 100644
index 00000000000..cebb3cd0262
--- /dev/null
+++ b/chromium/services/tracing/perfetto/privacy_filtering_check.cc
@@ -0,0 +1,101 @@
+// Copyright 2019 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/tracing/perfetto/privacy_filtering_check.h"
+
+#include <sstream>
+
+#include "base/logging.h"
+#include "services/tracing/perfetto/privacy_filtered_fields-inl.h"
+#include "third_party/perfetto/protos/perfetto/trace/interned_data/interned_data.pbzero.h"
+#include "third_party/perfetto/protos/perfetto/trace/trace.pbzero.h"
+#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
+#include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
+
+namespace tracing {
+namespace {
+
+using perfetto::protos::pbzero::InternedData;
+using perfetto::protos::pbzero::TracePacket;
+using perfetto::protos::pbzero::TrackEvent;
+using protozero::ProtoDecoder;
+
+int FindIndexOfValue(const int* const arr, uint32_t value) {
+ for (unsigned i = 0; arr[i] != -1; ++i) {
+ if (static_cast<int>(value) == arr[i])
+ return i;
+ }
+ return -1;
+}
+
+// Recursively verifies that the |proto| contains only accepted field IDs
+// including all sub messages. Keeps track of |parent_ids| for printing error
+// message.
+void VerifyProtoRecursive(const MessageInfo* root,
+ ProtoDecoder* proto,
+ std::vector<uint32_t>* parent_ids) {
+ proto->Reset();
+ for (auto f = proto->ReadField(); f.valid(); f = proto->ReadField()) {
+ int index = FindIndexOfValue(root->accepted_field_ids, f.id());
+ if (index == -1) {
+ std::stringstream error;
+ error << " Unexpected field in TracePacket proto. IDs from root to child";
+ for (int a : *parent_ids) {
+ error << " : " << a;
+ }
+ error << " : " << f.id();
+ LOG(DFATAL) << error.rdbuf();
+ continue;
+ }
+ if (root->sub_messages && root->sub_messages[index] != nullptr) {
+ ProtoDecoder decoder(f.data(), f.size());
+ parent_ids->push_back(f.id());
+ VerifyProtoRecursive(root->sub_messages[index], &decoder, parent_ids);
+ parent_ids->pop_back();
+ }
+ }
+}
+
+// Verifies that the |proto| contains only accepted fields.
+void VerifyProto(const MessageInfo* root, ProtoDecoder* proto) {
+ std::vector<uint32_t> parent_ids;
+ VerifyProtoRecursive(root, proto, &parent_ids);
+}
+
+} // namespace
+
+PrivacyFilteringCheck::PrivacyFilteringCheck() = default;
+PrivacyFilteringCheck::~PrivacyFilteringCheck() = default;
+
+// static
+void PrivacyFilteringCheck::CheckProtoForUnexpectedFields(
+ const std::string& serialized_trace_proto) {
+ perfetto::protos::pbzero::Trace::Decoder trace(
+ reinterpret_cast<const uint8_t*>(serialized_trace_proto.data()),
+ serialized_trace_proto.size());
+
+ for (auto it = trace.packet(); !!it; ++it) {
+ TracePacket::Decoder packet(it->data(), it->size());
+ const MessageInfo* root = &kTracePacket;
+ VerifyProto(root, &packet);
+
+ if (packet.has_track_event()) {
+ ++stats_.track_event;
+ } else if (packet.has_process_descriptor()) {
+ ++stats_.process_desc;
+ } else if (packet.has_thread_descriptor()) {
+ ++stats_.thread_desc;
+ }
+ if (packet.has_interned_data()) {
+ InternedData::Decoder interned_data(packet.interned_data().data,
+ packet.interned_data().size);
+ stats_.has_interned_names |= interned_data.has_legacy_event_names();
+ stats_.has_interned_categories |= interned_data.has_event_categories();
+ stats_.has_interned_source_locations |=
+ interned_data.has_source_locations();
+ }
+ }
+}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/perfetto/privacy_filtering_check.h b/chromium/services/tracing/perfetto/privacy_filtering_check.h
new file mode 100644
index 00000000000..fc76da7c1ae
--- /dev/null
+++ b/chromium/services/tracing/perfetto/privacy_filtering_check.h
@@ -0,0 +1,41 @@
+// Copyright 2019 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.
+
+#ifndef SERVICES_TRACING_PERFETTO_PRIVACY_FILTERING_CHECK_H_
+#define SERVICES_TRACING_PERFETTO_PRIVACY_FILTERING_CHECK_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+namespace tracing {
+
+class PrivacyFilteringCheck {
+ public:
+ struct TraceStats {
+ size_t track_event = 0;
+ size_t process_desc = 0;
+ size_t thread_desc = 0;
+
+ size_t has_interned_names = 0;
+ size_t has_interned_categories = 0;
+ size_t has_interned_source_locations = 0;
+ };
+
+ PrivacyFilteringCheck();
+ ~PrivacyFilteringCheck();
+
+ void CheckProtoForUnexpectedFields(const std::string& serialized_trace_proto);
+
+ const TraceStats& stats() const { return stats_; }
+
+ private:
+ TraceStats stats_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrivacyFilteringCheck);
+};
+
+} // namespace tracing
+
+#endif // SERVICES_TRACING_PERFETTO_PRIVACY_FILTERING_CHECK_H_
diff --git a/chromium/services/tracing/perfetto/producer_host.cc b/chromium/services/tracing/perfetto/producer_host.cc
index 0cc87619b00..12da7a6296d 100644
--- a/chromium/services/tracing/perfetto/producer_host.cc
+++ b/chromium/services/tracing/perfetto/producer_host.cc
@@ -7,7 +7,11 @@
#include <utility>
#include "base/bind.h"
+#include "base/process/process.h"
+#include "services/tracing/perfetto/perfetto_service.h"
+#include "services/tracing/public/cpp/perfetto/producer_client.h"
#include "services/tracing/public/cpp/perfetto/shared_memory.h"
+#include "services/tracing/public/cpp/tracing_features.h"
#include "third_party/perfetto/include/perfetto/tracing/core/commit_data_request.h"
#include "third_party/perfetto/include/perfetto/tracing/core/data_source_descriptor.h"
#include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h"
@@ -30,11 +34,32 @@ void ProducerHost::Initialize(mojom::ProducerClientPtr producer_client,
producer_client_ = std::move(producer_client);
+ // Attempt to parse the PID out of the producer name.
+ // If the Producer is in-process, we:
+ // * Signal Perfetto that it should create and manage its own
+ // SharedMemoryArbiter
+ // when we call ConnectProducer.
+ // * Set the local ProducerClient instance to use this SMA instead of passing
+ // an SMB handle over Mojo and letting it create its own.
+ // * After that point, any TraceWriter created by TraceEventDataSource will
+ // use this in-process SMA, and hence be able to synchronously flush full
+ // SMB chunks if we're running on the same sequence as the Perfetto service,
+ // hence we avoid any deadlocking occurring from trace events emitted from
+ // the Perfetto sequence filling up the SMB and stalling while waiting for
+ // Perfetto to free the chunks.
+ if (!base::FeatureList::IsEnabled(
+ features::kPerfettoForceOutOfProcessProducer)) {
+ base::ProcessId pid;
+ if (PerfettoService::ParsePidFromProducerName(name, &pid)) {
+ is_in_process_ = (pid == base::Process::Current().Pid());
+ }
+ }
+
// TODO(oysteine): Figure out an uid once we need it.
// TODO(oysteine): Figure out a good buffer size.
producer_endpoint_ = service->ConnectProducer(
this, 0 /* uid */, name,
- 4 * 1024 * 1024 /* shared_memory_size_hint_bytes */);
+ 4 * 1024 * 1024 /* shared_memory_size_hint_bytes */, is_in_process_);
DCHECK(producer_endpoint_);
}
@@ -47,6 +72,14 @@ void ProducerHost::OnDisconnect() {
}
void ProducerHost::OnTracingSetup() {
+ if (is_in_process_) {
+ PerfettoTracedProcess::Get()
+ ->producer_client()
+ ->set_in_process_shmem_arbiter(
+ producer_endpoint_->GetInProcessShmemArbiter());
+ return;
+ }
+
MojoSharedMemory* shared_memory =
static_cast<MojoSharedMemory*>(producer_endpoint_->shared_memory());
DCHECK(shared_memory);
@@ -98,6 +131,9 @@ void ProducerHost::Flush(
producer_client_->Flush(id, data_source_ids);
}
+void ProducerHost::ClearIncrementalState(const perfetto::DataSourceInstanceID*,
+ size_t) {}
+
// This data can come from a malicious child process. We don't do any
// sanitization here because ProducerEndpoint::CommitData() (And any other
// ProducerEndpoint methods) are designed to deal with malformed / malicious
diff --git a/chromium/services/tracing/perfetto/producer_host.h b/chromium/services/tracing/perfetto/producer_host.h
index 1637a7bde5a..9fe46160602 100644
--- a/chromium/services/tracing/perfetto/producer_host.h
+++ b/chromium/services/tracing/perfetto/producer_host.h
@@ -61,6 +61,9 @@ class ProducerHost : public tracing::mojom::ProducerHost,
void Flush(perfetto::FlushRequestID,
const perfetto::DataSourceInstanceID* raw_data_source_ids,
size_t num_data_sources) override;
+ void ClearIncrementalState(
+ const perfetto::DataSourceInstanceID* data_source_ids,
+ size_t num_data_sources) override;
// mojom::ProducerHost implementation.
// This interface gets called by the per-process ProducerClients
@@ -85,6 +88,7 @@ class ProducerHost : public tracing::mojom::ProducerHost,
private:
mojom::ProducerClientPtr producer_client_;
+ bool is_in_process_ = false;
protected:
// Perfetto guarantees that no OnXX callbacks are invoked on |this|
diff --git a/chromium/services/tracing/perfetto/test_utils.cc b/chromium/services/tracing/perfetto/test_utils.cc
index c5bc6fbd68b..9ba987d9c8d 100644
--- a/chromium/services/tracing/perfetto/test_utils.cc
+++ b/chromium/services/tracing/perfetto/test_utils.cc
@@ -1,11 +1,12 @@
// Copyright 2018 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/tracing/perfetto/test_utils.h"
+
#include <utility>
#include "base/bind.h"
#include "base/run_loop.h"
-#include "services/tracing/perfetto/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/perfetto/include/perfetto/tracing/core/commit_data_request.h"
#include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h"
@@ -20,7 +21,9 @@ namespace tracing {
TestDataSource::TestDataSource(const std::string& data_source_name,
size_t send_packet_count)
- : DataSourceBase(data_source_name), send_packet_count_(send_packet_count) {}
+ : DataSourceBase(data_source_name), send_packet_count_(send_packet_count) {
+ PerfettoTracedProcess::Get()->AddDataSource(this);
+}
TestDataSource::~TestDataSource() = default;
@@ -30,7 +33,7 @@ void TestDataSource::WritePacketBigly() {
payload.get()[kLargeMessageSize - 1] = 0;
std::unique_ptr<perfetto::TraceWriter> writer =
- producer_client_->CreateTraceWriter(config_.target_buffer());
+ producer_->CreateTraceWriter(config_.target_buffer());
CHECK(writer);
writer->NewTracePacket()->set_for_testing()->set_str(payload.get(),
@@ -38,14 +41,14 @@ void TestDataSource::WritePacketBigly() {
}
void TestDataSource::StartTracing(
- ProducerClient* producer_client,
+ PerfettoProducer* producer,
const perfetto::DataSourceConfig& data_source_config) {
- producer_client_ = producer_client;
+ producer_ = producer;
config_ = data_source_config;
if (send_packet_count_ > 0) {
std::unique_ptr<perfetto::TraceWriter> writer =
- producer_client_->CreateTraceWriter(config_.target_buffer());
+ producer_->CreateTraceWriter(config_.target_buffer());
CHECK(writer);
for (size_t i = 0; i < send_packet_count_; i++) {
@@ -65,21 +68,30 @@ void TestDataSource::Flush(base::RepeatingClosure flush_complete_callback) {
}
MockProducerClient::MockProducerClient(
- size_t send_packet_count,
base::OnceClosure client_enabled_callback,
base::OnceClosure client_disabled_callback)
- : client_enabled_callback_(std::move(client_enabled_callback)),
- client_disabled_callback_(std::move(client_disabled_callback)),
- send_packet_count_(send_packet_count) {}
-
-MockProducerClient::~MockProducerClient() = default;
+ : ProducerClient(PerfettoTracedProcess::Get()->GetTaskRunner()),
+ client_enabled_callback_(std::move(client_enabled_callback)),
+ client_disabled_callback_(std::move(client_disabled_callback)) {
+ // We want to set the ProducerClient to this mock, but that 'requires' passing
+ // ownership of ourselves to PerfettoTracedProcess. Since someone else manages
+ // our deletion we need to be careful in the deconstructor to not double free
+ // ourselves.
+ std::unique_ptr<MockProducerClient> client;
+ client.reset(this);
+ old_producer_ = PerfettoTracedProcess::Get()->SetProducerClientForTesting(
+ std::move(client));
+}
-void MockProducerClient::SetupDataSource(const std::string& data_source_name) {
- enabled_data_source_ =
- std::make_unique<TestDataSource>(data_source_name, send_packet_count_);
- AddDataSource(enabled_data_source_.get());
+MockProducerClient::~MockProducerClient() {
+ // See comment in the constructor. This prevents a double free.
+ auto client = PerfettoTracedProcess::Get()->SetProducerClientForTesting(
+ std::move(old_producer_));
+ client.release();
}
+void MockProducerClient::SetupDataSource(const std::string& data_source_name) {}
+
void MockProducerClient::StartDataSource(
uint64_t id,
const perfetto::DataSourceConfig& data_source_config,
@@ -192,21 +204,14 @@ MockProducerHost::MockProducerHost(
: producer_name_(producer_name),
datasource_registered_callback_(
std::move(datasource_registered_callback)) {
- auto on_mojo_connected_callback =
- [](MockProducerClient* producer_client,
- const std::string& data_source_name, MockProducerHost* producer_host,
- perfetto::TracingService* service,
- mojom::ProducerClientPtr producer_client_pipe,
- mojom::ProducerHostRequest producer_host_pipe) {
- producer_host->OnMessagepipesReadyCallback(
- service, std::move(producer_client_pipe),
- std::move(producer_host_pipe));
- producer_client->SetupDataSource(data_source_name);
- };
-
- producer_client->CreateMojoMessagepipes(base::BindOnce(
- on_mojo_connected_callback, base::Unretained(producer_client),
- data_source_name, base::Unretained(this), base::Unretained(service)));
+ mojom::ProducerClientPtr client;
+ mojom::ProducerHostPtrInfo host_info;
+ auto client_request = mojo::MakeRequest(&client);
+ Initialize(std::move(client), service, producer_name_);
+ binding_.Bind(mojo::MakeRequest(&host_info));
+ producer_client->BindClientAndHostPipesForTesting(std::move(client_request),
+ std::move(host_info));
+ producer_client->SetupDataSource(data_source_name);
}
MockProducerHost::~MockProducerHost() = default;
@@ -239,23 +244,16 @@ void MockProducerHost::OnCommit(
all_host_commit_data_requests_ += proto_string;
}
-void MockProducerHost::OnMessagepipesReadyCallback(
- perfetto::TracingService* perfetto_service,
- mojom::ProducerClientPtr producer_client_pipe,
- mojom::ProducerHostRequest producer_host_pipe) {
- Initialize(std::move(producer_client_pipe), perfetto_service, producer_name_);
- binding_ = std::make_unique<mojo::Binding<mojom::ProducerHost>>(
- this, std::move(producer_host_pipe));
-}
-
MockProducer::MockProducer(const std::string& producer_name,
const std::string& data_source_name,
perfetto::TracingService* service,
base::OnceClosure on_datasource_registered,
base::OnceClosure on_tracing_started,
size_t num_packets) {
- producer_client_ = std::make_unique<MockProducerClient>(
- num_packets, std::move(on_tracing_started));
+ data_source_ =
+ std::make_unique<TestDataSource>(data_source_name, num_packets);
+ producer_client_ =
+ std::make_unique<MockProducerClient>(std::move(on_tracing_started));
producer_host_ = std::make_unique<MockProducerHost>(
producer_name, data_source_name, service, producer_client_.get(),
@@ -267,11 +265,13 @@ MockProducer::~MockProducer() {
}
void MockProducer::WritePacketBigly(base::OnceClosure on_write_complete) {
- producer_client_->GetTaskRunner()->task_runner()->PostTaskAndReply(
- FROM_HERE,
- base::BindOnce(&TestDataSource::WritePacketBigly,
- base::Unretained(producer_client_->data_source())),
- std::move(on_write_complete));
+ PerfettoTracedProcess::Get()
+ ->GetTaskRunner()
+ ->GetOrCreateTaskRunner()
+ ->PostTaskAndReply(FROM_HERE,
+ base::BindOnce(&TestDataSource::WritePacketBigly,
+ base::Unretained(data_source())),
+ std::move(on_write_complete));
}
} // namespace tracing
diff --git a/chromium/services/tracing/perfetto/test_utils.h b/chromium/services/tracing/perfetto/test_utils.h
index 2e4486ef726..48385073f67 100644
--- a/chromium/services/tracing/perfetto/test_utils.h
+++ b/chromium/services/tracing/perfetto/test_utils.h
@@ -9,7 +9,9 @@
#include <string>
#include <vector>
+#include "mojo/public/cpp/bindings/binding.h"
#include "services/tracing/perfetto/producer_host.h"
+#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
#include "services/tracing/public/cpp/perfetto/producer_client.h"
#include "third_party/perfetto/include/perfetto/tracing/core/consumer.h"
@@ -18,7 +20,7 @@ namespace tracing {
const char kPerfettoTestString[] = "d00df00d";
const size_t kLargeMessageSize = 1 * 1024 * 1024;
-class TestDataSource : public ProducerClient::DataSourceBase {
+class TestDataSource : public PerfettoTracedProcess::DataSourceBase {
public:
TestDataSource(const std::string& data_source_name, size_t send_packet_count);
~TestDataSource() override;
@@ -27,7 +29,7 @@ class TestDataSource : public ProducerClient::DataSourceBase {
// DataSourceBase implementation
void StartTracing(
- ProducerClient* producer_client,
+ PerfettoProducer* producer,
const perfetto::DataSourceConfig& data_source_config) override;
void StopTracing(
base::OnceClosure stop_complete_callback = base::OnceClosure()) override;
@@ -35,16 +37,17 @@ class TestDataSource : public ProducerClient::DataSourceBase {
const perfetto::DataSourceConfig& config() { return config_; }
+ void set_send_packet_count(size_t count) { send_packet_count_ = count; }
+
private:
- ProducerClient* producer_client_ = nullptr;
- const size_t send_packet_count_;
+ PerfettoProducer* producer_ = nullptr;
+ size_t send_packet_count_;
perfetto::DataSourceConfig config_;
};
class MockProducerClient : public ProducerClient {
public:
MockProducerClient(
- size_t send_packet_count,
base::OnceClosure client_enabled_callback = base::OnceClosure(),
base::OnceClosure client_disabled_callback = base::OnceClosure());
~MockProducerClient() override;
@@ -68,14 +71,12 @@ class MockProducerClient : public ProducerClient {
return all_client_commit_data_requests_;
}
- TestDataSource* data_source() { return enabled_data_source_.get(); }
private:
base::OnceClosure client_enabled_callback_;
base::OnceClosure client_disabled_callback_;
- size_t send_packet_count_;
std::string all_client_commit_data_requests_;
- std::unique_ptr<TestDataSource> enabled_data_source_;
+ std::unique_ptr<ProducerClient> old_producer_;
};
class MockConsumer : public perfetto::Consumer {
@@ -133,11 +134,6 @@ class MockProducerHost : public ProducerHost {
void OnCommit(const perfetto::CommitDataRequest& commit_data_request);
- void OnMessagepipesReadyCallback(
- perfetto::TracingService* perfetto_service,
- mojom::ProducerClientPtr producer_client_pipe,
- mojom::ProducerHostRequest producer_host_pipe);
-
const std::string& all_host_commit_data_requests() const {
return all_host_commit_data_requests_;
}
@@ -146,7 +142,7 @@ class MockProducerHost : public ProducerHost {
const std::string producer_name_;
base::OnceClosure datasource_registered_callback_;
std::string all_host_commit_data_requests_;
- std::unique_ptr<mojo::Binding<mojom::ProducerHost>> binding_;
+ mojo::Binding<mojom::ProducerHost> binding_{this};
};
class MockProducer {
@@ -163,7 +159,10 @@ class MockProducer {
MockProducerClient* producer_client() { return producer_client_.get(); }
+ TestDataSource* data_source() { return data_source_.get(); }
+
private:
+ std::unique_ptr<TestDataSource> data_source_;
std::unique_ptr<MockProducerClient> producer_client_;
std::unique_ptr<MockProducerHost> producer_host_;
};
diff --git a/chromium/services/tracing/perfetto/track_event_json_exporter_unittest.cc b/chromium/services/tracing/perfetto/track_event_json_exporter_unittest.cc
index 704867fad4d..6524eecd79f 100644
--- a/chromium/services/tracing/perfetto/track_event_json_exporter_unittest.cc
+++ b/chromium/services/tracing/perfetto/track_event_json_exporter_unittest.cc
@@ -54,15 +54,16 @@ class TrackEventJsonExporterTest : public testing::Test {
void TearDown() override { json_trace_exporter_.reset(); }
- void OnTraceEventJson(const std::string& json,
+ void OnTraceEventJson(std::string* json,
base::DictionaryValue* metadata,
bool has_more) {
CHECK(!has_more);
- unparsed_trace_data_ = json;
- parsed_trace_data_ =
- base::DictionaryValue::From(base::JSONReader::ReadDeprecated(json));
- ASSERT_TRUE(parsed_trace_data_) << "Couldn't parse json: \n" << json;
+ unparsed_trace_data_.swap(*json);
+ parsed_trace_data_ = base::DictionaryValue::From(
+ base::JSONReader::ReadDeprecated(unparsed_trace_data_));
+ ASSERT_TRUE(parsed_trace_data_) << "Couldn't parse json: \n"
+ << unparsed_trace_data_;
// The TraceAnalyzer expects the raw trace output, without the
// wrapping root-node.
diff --git a/chromium/services/tracing/public/cpp/BUILD.gn b/chromium/services/tracing/public/cpp/BUILD.gn
index 3094241434c..90ed03cf395 100644
--- a/chromium/services/tracing/public/cpp/BUILD.gn
+++ b/chromium/services/tracing/public/cpp/BUILD.gn
@@ -26,13 +26,21 @@ if (!is_nacl && !is_ios) {
sources = [
"base_agent.cc",
"base_agent.h",
+ "perfetto/dummy_producer.cc",
+ "perfetto/dummy_producer.h",
"perfetto/interning_index.h",
"perfetto/perfetto_config.cc",
"perfetto/perfetto_config.h",
+ "perfetto/perfetto_producer.cc",
+ "perfetto/perfetto_producer.h",
+ "perfetto/perfetto_traced_process.cc",
+ "perfetto/perfetto_traced_process.h",
"perfetto/producer_client.cc",
"perfetto/producer_client.h",
"perfetto/shared_memory.cc",
"perfetto/shared_memory.h",
+ "perfetto/system_producer.cc",
+ "perfetto/system_producer.h",
"perfetto/task_runner.cc",
"perfetto/task_runner.h",
"perfetto/thread_local_event_sink.cc",
diff --git a/chromium/services/tracing/public/cpp/perfetto/dummy_producer.cc b/chromium/services/tracing/public/cpp/perfetto/dummy_producer.cc
new file mode 100644
index 00000000000..6558054f589
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/perfetto/dummy_producer.cc
@@ -0,0 +1,65 @@
+// Copyright 2019 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/tracing/public/cpp/perfetto/dummy_producer.h"
+
+namespace tracing {
+
+DummyProducer::DummyProducer(PerfettoTaskRunner* task_runner)
+ : SystemProducer(task_runner) {}
+DummyProducer::~DummyProducer() {}
+
+// perfetto::Producer functions.
+void DummyProducer::OnConnect() {}
+void DummyProducer::OnDisconnect() {}
+void DummyProducer::OnTracingSetup() {}
+void DummyProducer::SetupDataSource(perfetto::DataSourceInstanceID,
+ const perfetto::DataSourceConfig&) {}
+void DummyProducer::StartDataSource(perfetto::DataSourceInstanceID,
+ const perfetto::DataSourceConfig&) {}
+void DummyProducer::StopDataSource(perfetto::DataSourceInstanceID) {}
+void DummyProducer::Flush(perfetto::FlushRequestID,
+ const perfetto::DataSourceInstanceID* data_source_ids,
+ size_t num_data_sources) {}
+void DummyProducer::ClearIncrementalState(
+ const perfetto::DataSourceInstanceID* data_source_ids,
+ size_t num_data_sources) {}
+
+// perfetto::TracingService::ProducerEndpoint functions.
+void DummyProducer::RegisterDataSource(const perfetto::DataSourceDescriptor&) {}
+void DummyProducer::UnregisterDataSource(const std::string& name) {}
+
+void DummyProducer::RegisterTraceWriter(uint32_t writer_id,
+ uint32_t target_buffer) {}
+void DummyProducer::UnregisterTraceWriter(uint32_t writer_id) {}
+
+void DummyProducer::CommitData(const perfetto::CommitDataRequest& commit,
+ CommitDataCallback callback) {}
+perfetto::SharedMemory* DummyProducer::shared_memory() const {
+ return nullptr;
+}
+size_t DummyProducer::shared_buffer_page_size_kb() const {
+ return 0;
+}
+perfetto::SharedMemoryArbiter* DummyProducer::GetSharedMemoryArbiter() {
+ return nullptr;
+}
+perfetto::SharedMemoryArbiter* DummyProducer::GetInProcessShmemArbiter() {
+ return nullptr;
+}
+void DummyProducer::NotifyFlushComplete(perfetto::FlushRequestID) {}
+
+void DummyProducer::NotifyDataSourceStarted(perfetto::DataSourceInstanceID) {}
+void DummyProducer::NotifyDataSourceStopped(perfetto::DataSourceInstanceID) {}
+
+void DummyProducer::ActivateTriggers(const std::vector<std::string>&) {}
+
+// tracing::PerfettoProducer functions.
+void DummyProducer::NewDataSourceAdded(
+ const PerfettoTracedProcess::DataSourceBase* const data_source) {}
+
+// Functions expected for SystemProducer
+void DummyProducer::Disconnect() {}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/perfetto/dummy_producer.h b/chromium/services/tracing/public/cpp/perfetto/dummy_producer.h
new file mode 100644
index 00000000000..a79383f465c
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/perfetto/dummy_producer.h
@@ -0,0 +1,59 @@
+// Copyright 2019 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.
+
+#ifndef SERVICES_TRACING_PUBLIC_CPP_PERFETTO_DUMMY_PRODUCER_H_
+#define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_DUMMY_PRODUCER_H_
+
+#include "services/tracing/public/cpp/perfetto/system_producer.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/producer.h"
+
+namespace tracing {
+
+class COMPONENT_EXPORT(TRACING_CPP) DummyProducer : public SystemProducer {
+ public:
+ DummyProducer(PerfettoTaskRunner* task_runner);
+ ~DummyProducer() override;
+
+ // perfetto::Producer functions.
+ void OnConnect() override;
+ void OnDisconnect() override;
+ void OnTracingSetup() override;
+ void SetupDataSource(perfetto::DataSourceInstanceID,
+ const perfetto::DataSourceConfig&) override;
+ void StartDataSource(perfetto::DataSourceInstanceID,
+ const perfetto::DataSourceConfig&) override;
+ void StopDataSource(perfetto::DataSourceInstanceID) override;
+ void Flush(perfetto::FlushRequestID,
+ const perfetto::DataSourceInstanceID* data_source_ids,
+ size_t num_data_sources) override;
+ void ClearIncrementalState(
+ const perfetto::DataSourceInstanceID* data_source_ids,
+ size_t num_data_sources) override;
+
+ // perfetto::TracingService::ProducerEndpoint functions.
+ void RegisterDataSource(const perfetto::DataSourceDescriptor&) override;
+ void UnregisterDataSource(const std::string& name) override;
+ void RegisterTraceWriter(uint32_t writer_id, uint32_t target_buffer) override;
+ void UnregisterTraceWriter(uint32_t writer_id) override;
+ void CommitData(const perfetto::CommitDataRequest& commit,
+ CommitDataCallback callback) override;
+ perfetto::SharedMemory* shared_memory() const override;
+ size_t shared_buffer_page_size_kb() const override;
+ perfetto::SharedMemoryArbiter* GetSharedMemoryArbiter() override;
+ perfetto::SharedMemoryArbiter* GetInProcessShmemArbiter() override;
+ void NotifyFlushComplete(perfetto::FlushRequestID) override;
+ void NotifyDataSourceStarted(perfetto::DataSourceInstanceID) override;
+ void NotifyDataSourceStopped(perfetto::DataSourceInstanceID) override;
+ void ActivateTriggers(const std::vector<std::string>&) override;
+
+ // tracing::PerfettoProducer functions.
+ void NewDataSourceAdded(
+ const PerfettoTracedProcess::DataSourceBase* const data_source) override;
+
+ // Functions expected for SystemProducer
+ void Disconnect() override;
+};
+} // namespace tracing
+
+#endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_DUMMY_PRODUCER_H_
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_config.cc b/chromium/services/tracing/public/cpp/perfetto/perfetto_config.cc
index b21ba02a792..84fbef75bd0 100644
--- a/chromium/services/tracing/public/cpp/perfetto/perfetto_config.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_config.cc
@@ -14,8 +14,28 @@
namespace tracing {
+namespace {
+
+perfetto::TraceConfig::DataSource* AddDataSourceConfig(
+ perfetto::TraceConfig* perfetto_config,
+ const char* name,
+ const std::string& chrome_config_string,
+ bool privacy_filtering_enabled) {
+ auto* data_source = perfetto_config->add_data_sources();
+ auto* source_config = data_source->mutable_config();
+ source_config->set_name(name);
+ source_config->set_target_buffer(0);
+ auto* chrome_config = source_config->mutable_chrome_config();
+ chrome_config->set_trace_config(chrome_config_string);
+ chrome_config->set_privacy_filtering_enabled(privacy_filtering_enabled);
+ return data_source;
+}
+
+} // namespace
+
perfetto::TraceConfig GetDefaultPerfettoConfig(
- const base::trace_event::TraceConfig& chrome_config) {
+ const base::trace_event::TraceConfig& chrome_config,
+ bool privacy_filtering_enabled) {
perfetto::TraceConfig perfetto_config;
size_t size_limit = chrome_config.GetTraceBufferSizeInKb();
@@ -26,16 +46,10 @@ perfetto::TraceConfig GetDefaultPerfettoConfig(
// Perfetto uses clock_gettime for its internal snapshotting, which gets
// blocked by the sandboxed and isn't needed for Chrome regardless.
- perfetto_config.set_disable_clock_snapshotting(true);
-
- // Capture actual trace events.
- auto* trace_event_data_source = perfetto_config.add_data_sources();
- for (auto& enabled_pid :
- chrome_config.process_filter_config().included_process_ids()) {
- *trace_event_data_source->add_producer_name_filter() = base::StrCat(
- {mojom::kPerfettoProducerNamePrefix,
- base::NumberToString(static_cast<uint32_t>(enabled_pid))});
- }
+ auto* builtin_data_sources = perfetto_config.mutable_builtin_data_sources();
+ builtin_data_sources->set_disable_clock_snapshotting(true);
+ builtin_data_sources->set_disable_trace_config(privacy_filtering_enabled);
+ builtin_data_sources->set_disable_system_info(privacy_filtering_enabled);
// We strip the process filter from the config string we send to Perfetto,
// so perfetto doesn't reject it from a future
@@ -46,39 +60,33 @@ perfetto::TraceConfig GetDefaultPerfettoConfig(
base::trace_event::TraceConfig::ProcessFilterConfig());
std::string chrome_config_string = processfilter_stripped_config.ToString();
- auto* trace_event_config = trace_event_data_source->mutable_config();
- trace_event_config->set_name(tracing::mojom::kTraceEventDataSourceName);
- trace_event_config->set_target_buffer(0);
- auto* chrome_proto_config = trace_event_config->mutable_chrome_config();
- chrome_proto_config->set_trace_config(chrome_config_string);
+ // Capture actual trace events.
+ auto* trace_event_data_source = AddDataSourceConfig(
+ &perfetto_config, tracing::mojom::kTraceEventDataSourceName,
+ chrome_config_string, privacy_filtering_enabled);
+ for (auto& enabled_pid :
+ chrome_config.process_filter_config().included_process_ids()) {
+ *trace_event_data_source->add_producer_name_filter() = base::StrCat(
+ {mojom::kPerfettoProducerNamePrefix,
+ base::NumberToString(static_cast<uint32_t>(enabled_pid))});
+ }
// Capture system trace events if supported and enabled. The datasources will
// only emit events if system tracing is enabled in |chrome_config|.
#if defined(OS_CHROMEOS) || (defined(IS_CHROMECAST) && defined(OS_LINUX))
- auto* system_trace_config =
- perfetto_config.add_data_sources()->mutable_config();
- system_trace_config->set_name(tracing::mojom::kSystemTraceDataSourceName);
- system_trace_config->set_target_buffer(0);
- auto* system_chrome_config = system_trace_config->mutable_chrome_config();
- system_chrome_config->set_trace_config(chrome_config_string);
+ AddDataSourceConfig(&perfetto_config,
+ tracing::mojom::kSystemTraceDataSourceName,
+ chrome_config_string, privacy_filtering_enabled);
#endif
#if defined(OS_CHROMEOS)
- auto* arc_trace_config = perfetto_config.add_data_sources()->mutable_config();
- arc_trace_config->set_name(tracing::mojom::kArcTraceDataSourceName);
- arc_trace_config->set_target_buffer(0);
- auto* arc_chrome_config = arc_trace_config->mutable_chrome_config();
- arc_chrome_config->set_trace_config(chrome_config_string);
+ AddDataSourceConfig(&perfetto_config, tracing::mojom::kArcTraceDataSourceName,
+ chrome_config_string, privacy_filtering_enabled);
#endif
// Also capture global metadata.
- auto* trace_metadata_config =
- perfetto_config.add_data_sources()->mutable_config();
- trace_metadata_config->set_name(tracing::mojom::kMetaDataSourceName);
- trace_metadata_config->set_target_buffer(0);
- auto* metadata_chrome_config = trace_metadata_config->mutable_chrome_config();
- metadata_chrome_config->set_trace_config(chrome_config_string);
- // TODO(ssid): Also set privacy_filtering_enabled here.
+ AddDataSourceConfig(&perfetto_config, tracing::mojom::kMetaDataSourceName,
+ chrome_config_string, privacy_filtering_enabled);
return perfetto_config;
}
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_config.h b/chromium/services/tracing/public/cpp/perfetto/perfetto_config.h
index 84fef0f9065..b4616787278 100644
--- a/chromium/services/tracing/public/cpp/perfetto/perfetto_config.h
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_config.h
@@ -17,7 +17,8 @@ class TraceConfig;
namespace tracing {
perfetto::TraceConfig COMPONENT_EXPORT(TRACING_CPP) GetDefaultPerfettoConfig(
- const base::trace_event::TraceConfig& chrome_config);
+ const base::trace_event::TraceConfig& chrome_config,
+ bool privacy_filtering_enabled = false);
} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_producer.cc b/chromium/services/tracing/public/cpp/perfetto/perfetto_producer.cc
new file mode 100644
index 00000000000..f5a59521a6d
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_producer.cc
@@ -0,0 +1,44 @@
+// Copyright 2019 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/tracing/public/cpp/perfetto/perfetto_producer.h"
+
+#include "third_party/perfetto/include/perfetto/tracing/core/shared_memory_arbiter.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/startup_trace_writer_registry.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/trace_writer.h"
+
+namespace tracing {
+
+PerfettoProducer::PerfettoProducer(PerfettoTaskRunner* task_runner)
+ : task_runner_(task_runner) {
+ DCHECK(task_runner_);
+}
+
+PerfettoProducer::~PerfettoProducer() {}
+
+void PerfettoProducer::BindStartupTraceWriterRegistry(
+ std::unique_ptr<perfetto::StartupTraceWriterRegistry> registry,
+ perfetto::BufferID target_buffer) {
+ DCHECK(GetSharedMemoryArbiter());
+ return GetSharedMemoryArbiter()->BindStartupTraceWriterRegistry(
+ std::move(registry), target_buffer);
+}
+
+std::unique_ptr<perfetto::TraceWriter> PerfettoProducer::CreateTraceWriter(
+ perfetto::BufferID target_buffer) {
+ DCHECK(GetSharedMemoryArbiter());
+ return GetSharedMemoryArbiter()->CreateTraceWriter(target_buffer);
+}
+
+PerfettoTaskRunner* PerfettoProducer::task_runner() {
+ return task_runner_;
+}
+
+void PerfettoProducer::DeleteSoonForTesting(
+ std::unique_ptr<PerfettoProducer> perfetto_producer) {
+ PerfettoTracedProcess::GetTaskRunner()->GetOrCreateTaskRunner()->DeleteSoon(
+ FROM_HERE, std::move(perfetto_producer));
+}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_producer.h b/chromium/services/tracing/public/cpp/perfetto/perfetto_producer.h
new file mode 100644
index 00000000000..d5a18aafd5f
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_producer.h
@@ -0,0 +1,73 @@
+// Copyright 2019 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.
+
+#ifndef SERVICES_TRACING_PUBLIC_CPP_PERFETTO_PERFETTO_PRODUCER_H_
+#define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_PERFETTO_PRODUCER_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/tracing_service.h"
+
+namespace perfetto {
+class SharedMemoryArbiter;
+class StartupTraceWriterRegistry;
+} // namespace perfetto
+
+namespace tracing {
+
+// This class represents the perfetto producer endpoint which is used for
+// producers to talk to the Perfetto service. It also provides methods to
+// interact with the shared memory buffer by binding and creating TraceWriters.
+//
+// In addition to the PerfettoProducers' pure virtual methods, subclasses must
+// implement the remaining methods of the ProducerEndpoint interface.
+class COMPONENT_EXPORT(TRACING_CPP) PerfettoProducer
+ : public perfetto::TracingService::ProducerEndpoint {
+ public:
+ PerfettoProducer(PerfettoTaskRunner* task_runner);
+
+ ~PerfettoProducer() override;
+
+ // Binds the registry and its trace writers to the ProducerClient's SMB, to
+ // write into the given target buffer. The ownership of |registry| is
+ // transferred to PerfettoProducer (and its SharedMemoryArbiter).
+ //
+ // Should only be called while a tracing session is active and a
+ // SharedMemoryArbiter exists.
+ void BindStartupTraceWriterRegistry(
+ std::unique_ptr<perfetto::StartupTraceWriterRegistry> registry,
+ perfetto::BufferID target_buffer);
+
+ // Used by the DataSource implementations to create TraceWriters
+ // for writing their protobufs, and respond to flushes.
+ //
+ // Should only be called while a tracing session is active and a
+ // SharedMemoryArbiter exists.
+ std::unique_ptr<perfetto::TraceWriter> CreateTraceWriter(
+ perfetto::BufferID target_buffer) override;
+
+ // Informs the PerfettoProducer a new Data Source was added. This instance
+ // will also be found in |data_sources| having just be inserted before this
+ // method is called by PerfettoTracedProcess. This enables the
+ // PerfettoProducer to perform initialization on new data sources.
+ virtual void NewDataSourceAdded(
+ const PerfettoTracedProcess::DataSourceBase* const data_source) = 0;
+
+ static void DeleteSoonForTesting(
+ std::unique_ptr<PerfettoProducer> perfetto_producer);
+
+ protected:
+ // Returns the SMA of the SharedMemory from the perfetto service or nullptr if
+ // not initialized (no trace has ever been started).
+ virtual perfetto::SharedMemoryArbiter* GetSharedMemoryArbiter() = 0;
+
+ PerfettoTaskRunner* task_runner();
+
+ private:
+ PerfettoTaskRunner* const task_runner_;
+};
+} // namespace tracing
+#endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_PERFETTO_PRODUCER_H_
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc b/chromium/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc
new file mode 100644
index 00000000000..96cdf91440e
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc
@@ -0,0 +1,105 @@
+// Copyright 2019 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/tracing/public/cpp/perfetto/perfetto_traced_process.h"
+
+#include "base/no_destructor.h"
+#include "base/task/post_task.h"
+#include "services/tracing/public/cpp/perfetto/producer_client.h"
+
+#include "services/tracing/public/cpp/perfetto/dummy_producer.h"
+
+namespace tracing {
+namespace {
+std::unique_ptr<SystemProducer> NewSystemProducer(PerfettoTaskRunner* runner) {
+ return std::make_unique<DummyProducer>(runner);
+}
+} // namespace
+
+PerfettoTracedProcess::DataSourceBase::DataSourceBase(const std::string& name)
+ : name_(name) {
+ DCHECK(!name.empty());
+}
+
+PerfettoTracedProcess::DataSourceBase::~DataSourceBase() = default;
+
+void PerfettoTracedProcess::DataSourceBase::StartTracingWithID(
+ uint64_t data_source_id,
+ PerfettoProducer* producer_client,
+ const perfetto::DataSourceConfig& data_source_config) {
+ data_source_id_ = data_source_id;
+ StartTracing(producer_client, data_source_config);
+}
+
+// static
+PerfettoTracedProcess* PerfettoTracedProcess::Get() {
+ static base::NoDestructor<PerfettoTracedProcess> traced_process;
+ return traced_process.get();
+}
+
+PerfettoTracedProcess::PerfettoTracedProcess()
+ : producer_client_(std::make_unique<ProducerClient>(GetTaskRunner())),
+ system_producer_endpoint_(NewSystemProducer(GetTaskRunner())),
+ weak_ptr_factory_(this) {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+PerfettoTracedProcess::~PerfettoTracedProcess() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void PerfettoTracedProcess::ClearDataSourcesForTesting() {
+ data_sources_.clear();
+}
+
+std::unique_ptr<ProducerClient>
+PerfettoTracedProcess::SetProducerClientForTesting(
+ std::unique_ptr<ProducerClient> client) {
+ auto old_producer_client_for_testing = std::move(producer_client_);
+ producer_client_ = std::move(client);
+ return old_producer_client_for_testing;
+}
+
+// static
+void PerfettoTracedProcess::DeleteSoonForTesting(
+ std::unique_ptr<PerfettoTracedProcess> perfetto_traced_process) {
+ GetTaskRunner()->GetOrCreateTaskRunner()->DeleteSoon(
+ FROM_HERE, std::move(perfetto_traced_process));
+}
+
+// We never destroy the taskrunner as we may need it for cleanup
+// of TraceWriters in TLS, which could happen after the PerfettoTracedProcess
+// is deleted.
+// static
+PerfettoTaskRunner* PerfettoTracedProcess::GetTaskRunner() {
+ static base::NoDestructor<PerfettoTaskRunner> task_runner(nullptr);
+ return task_runner.get();
+}
+
+// static
+void PerfettoTracedProcess::ResetTaskRunnerForTesting() {
+ DETACH_FROM_SEQUENCE(PerfettoTracedProcess::Get()->sequence_checker_);
+ GetTaskRunner()->ResetTaskRunnerForTesting(nullptr);
+}
+
+void PerfettoTracedProcess::AddDataSource(DataSourceBase* data_source) {
+ GetTaskRunner()->GetOrCreateTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&PerfettoTracedProcess::AddDataSourceOnSequence,
+ base::Unretained(this), data_source));
+}
+
+ProducerClient* PerfettoTracedProcess::producer_client() {
+ return producer_client_.get();
+}
+
+void PerfettoTracedProcess::AddDataSourceOnSequence(
+ DataSourceBase* data_source) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (data_sources_.insert(data_source).second) {
+ producer_client_->NewDataSourceAdded(data_source);
+ system_producer_endpoint_->NewDataSourceAdded(data_source);
+ }
+}
+} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_traced_process.h b/chromium/services/tracing/public/cpp/perfetto/perfetto_traced_process.h
new file mode 100644
index 00000000000..abd7b7f5dcf
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_traced_process.h
@@ -0,0 +1,112 @@
+// Copyright 2019 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.
+
+#ifndef SERVICES_TRACING_PUBLIC_CPP_PERFETTO_PERFETTO_TRACED_PROCESS_H_
+#define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_PERFETTO_TRACED_PROCESS_H_
+
+#include "base/component_export.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "services/tracing/public/cpp/perfetto/task_runner.h"
+
+namespace tracing {
+
+class PerfettoProducer;
+class ProducerClient;
+class SystemProducer;
+
+// This represents global process level state that the Perfetto tracing system
+// expects to exist. This includes a single base implementation of DataSources
+// all implementors should use and the perfetto task runner that should be used
+// when talking to the tracing system to prevent deadlocks.
+//
+// Implementations of new DataSources should:
+// * Implement PerfettoTracedProcess::DataSourceBase.
+// * Add a new data source name in perfetto_service.mojom.
+// * Register the data source with Perfetto in ProducerHost::OnConnect.
+// * Construct the new implementation when requested to
+// in PerfettoProducer::StartDataSource.
+class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final {
+ public:
+ class DataSourceBase {
+ public:
+ explicit DataSourceBase(const std::string& name);
+ virtual ~DataSourceBase();
+
+ void StartTracingWithID(
+ uint64_t data_source_id,
+ PerfettoProducer* producer_client,
+ const perfetto::DataSourceConfig& data_source_config);
+
+ virtual void StartTracing(
+ PerfettoProducer* producer_client,
+ const perfetto::DataSourceConfig& data_source_config) = 0;
+ virtual void StopTracing(
+ base::OnceClosure stop_complete_callback = base::OnceClosure()) = 0;
+
+ // Flush the data source.
+ virtual void Flush(base::RepeatingClosure flush_complete_callback) = 0;
+
+ const std::string& name() const { return name_; }
+ uint64_t data_source_id() const { return data_source_id_; }
+
+ private:
+ uint64_t data_source_id_ = 0;
+ std::string name_;
+ };
+
+ // Returns the process-wide instance of the PerfettoTracedProcess.
+ static PerfettoTracedProcess* Get();
+
+ ProducerClient* producer_client();
+
+ ~PerfettoTracedProcess();
+
+ // Sets the ProducerClient and returns the old pointer. If tests want to
+ // restore the state of the world they should store the pointer and call this
+ // method again with it as the parameter.
+ std::unique_ptr<ProducerClient> SetProducerClientForTesting(
+ std::unique_ptr<ProducerClient> client);
+ void ClearDataSourcesForTesting();
+ static void DeleteSoonForTesting(std::unique_ptr<PerfettoTracedProcess>);
+
+ // Returns the taskrunner used by any Perfetto service.
+ static PerfettoTaskRunner* GetTaskRunner();
+
+ // Add a new data source to the PerfettoTracedProcess; the caller retains
+ // ownership and is responsible for making sure the data source outlives the
+ // PerfettoTracedProcess.
+ void AddDataSource(DataSourceBase*);
+ const std::set<DataSourceBase*>& data_sources() { return data_sources_; }
+
+ static void ResetTaskRunnerForTesting();
+
+ protected:
+ // protected for testing.
+ PerfettoTracedProcess();
+
+ private:
+ friend class base::NoDestructor<PerfettoTracedProcess>;
+
+ void AddDataSourceOnSequence(DataSourceBase* data_source);
+
+ // The canonical set of DataSourceBases alive in this process. These will be
+ // registered with the tracing service.
+ std::set<DataSourceBase*> data_sources_;
+ // A PerfettoProducer that connects to the chrome Perfetto service through
+ // mojo.
+ std::unique_ptr<ProducerClient> producer_client_;
+ // A PerfettoProducer that connects to the system Perfetto service. If there
+ // is no system Perfetto service this pointer will be valid, but all function
+ // calls will be noops.
+ std::unique_ptr<SystemProducer> system_producer_endpoint_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+ // NOTE: Weak pointers must be invalidated before all other member
+ // variables.
+ base::WeakPtrFactory<PerfettoTracedProcess> weak_ptr_factory_;
+ DISALLOW_COPY_AND_ASSIGN(PerfettoTracedProcess);
+};
+} // namespace tracing
+#endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_PERFETTO_TRACED_PROCESS_H_
diff --git a/chromium/services/tracing/public/cpp/perfetto/producer_client.cc b/chromium/services/tracing/public/cpp/perfetto/producer_client.cc
index e416f855402..245624cfff6 100644
--- a/chromium/services/tracing/public/cpp/perfetto/producer_client.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/producer_client.cc
@@ -8,9 +8,10 @@
#include "base/bind.h"
#include "base/no_destructor.h"
+#include "base/process/process.h"
#include "base/task/post_task.h"
-#include "base/task/thread_pool/scheduler_lock_impl.h"
#include "services/tracing/public/cpp/perfetto/shared_memory.h"
+#include "services/tracing/public/cpp/perfetto/trace_event_data_source.h"
#include "services/tracing/public/mojom/constants.mojom.h"
#include "third_party/perfetto/include/perfetto/tracing/core/commit_data_request.h"
#include "third_party/perfetto/include/perfetto/tracing/core/shared_memory_arbiter.h"
@@ -19,52 +20,8 @@
namespace tracing {
-namespace {
-
-scoped_refptr<base::SequencedTaskRunner> CreateTaskRunner() {
- return base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::USER_BLOCKING});
-}
-
-} // namespace
-
-ScopedPerfettoPostTaskBlocker::ScopedPerfettoPostTaskBlocker(bool enable)
- : enabled_(enable) {
- if (enabled_) {
- ProducerClient::GetTaskRunner()->BlockPostTaskForThread();
- } else {
- base::internal::SchedulerLockImpl::AssertNoLockHeldOnCurrentThread();
- }
-}
-
-ScopedPerfettoPostTaskBlocker::~ScopedPerfettoPostTaskBlocker() {
- if (enabled_) {
- ProducerClient::GetTaskRunner()->UnblockPostTaskForThread();
- }
-}
-
-ProducerClient::DataSourceBase::DataSourceBase(const std::string& name)
- : name_(name) {
- DCHECK(!name.empty());
-}
-
-ProducerClient::DataSourceBase::~DataSourceBase() = default;
-
-void ProducerClient::DataSourceBase::StartTracingWithID(
- uint64_t data_source_id,
- ProducerClient* producer_client,
- const perfetto::DataSourceConfig& data_source_config) {
- data_source_id_ = data_source_id;
- StartTracing(producer_client, data_source_config);
-}
-
-// static
-ProducerClient* ProducerClient::Get() {
- static base::NoDestructor<ProducerClient> producer_client;
- return producer_client.get();
-}
-
-ProducerClient::ProducerClient() : weak_ptr_factory_(this) {
+ProducerClient::ProducerClient(PerfettoTaskRunner* task_runner)
+ : PerfettoProducer(task_runner), weak_ptr_factory_(this) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
@@ -72,68 +29,36 @@ ProducerClient::~ProducerClient() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
-// static
-void ProducerClient::DeleteSoonForTesting(
- std::unique_ptr<ProducerClient> producer_client) {
- GetTaskRunner()->task_runner()->DeleteSoon(FROM_HERE,
- std::move(producer_client));
-}
-
-// We never destroy the taskrunner as we may need it for cleanup
-// of TraceWriters in TLS, which could happen after the ProducerClient
-// is deleted.
-// static
-PerfettoTaskRunner* ProducerClient::GetTaskRunner() {
- static base::NoDestructor<PerfettoTaskRunner> task_runner(CreateTaskRunner());
- return task_runner.get();
-}
-
-// static
-void ProducerClient::ResetTaskRunnerForTesting() {
- DETACH_FROM_SEQUENCE(ProducerClient::Get()->sequence_checker_);
- GetTaskRunner()->ResetTaskRunnerForTesting(CreateTaskRunner());
-}
-
void ProducerClient::Connect(mojom::PerfettoServicePtr perfetto_service) {
- CreateMojoMessagepipes(base::BindOnce(
- [](mojom::PerfettoServicePtr perfetto_service,
- mojom::ProducerClientPtr producer_client_pipe,
- mojom::ProducerHostRequest producer_host_pipe) {
- perfetto_service->ConnectToProducerHost(std::move(producer_client_pipe),
- std::move(producer_host_pipe));
- },
- std::move(perfetto_service)));
-}
-
-void ProducerClient::CreateMojoMessagepipes(
- MessagepipesReadyCallback callback) {
- auto origin_task_runner = base::SequencedTaskRunnerHandle::Get();
- DCHECK(origin_task_runner);
- mojom::ProducerClientPtr producer_client;
- GetTaskRunner()->task_runner()->PostTask(
+ mojom::ProducerClientPtr client;
+ auto client_request = mojo::MakeRequest(&client);
+ mojom::ProducerHostPtrInfo host_info;
+ perfetto_service->ConnectToProducerHost(std::move(client),
+ mojo::MakeRequest(&host_info));
+ task_runner()->GetOrCreateTaskRunner()->PostTask(
FROM_HERE,
- base::BindOnce(&ProducerClient::CreateMojoMessagepipesOnSequence,
- base::Unretained(this), origin_task_runner,
- std::move(callback), mojo::MakeRequest(&producer_client),
- std::move(producer_client)));
+ base::BindOnce(&ProducerClient::BindClientAndHostPipesOnSequence,
+ base::Unretained(this), std::move(client_request),
+ std::move(host_info)));
}
-void ProducerClient::BindStartupTraceWriterRegistry(
- std::unique_ptr<perfetto::StartupTraceWriterRegistry> registry,
- perfetto::BufferID target_buffer) {
- shared_memory_arbiter_->BindStartupTraceWriterRegistry(std::move(registry),
- target_buffer);
+void ProducerClient::BindClientAndHostPipesForTesting(
+ mojom::ProducerClientRequest producer_client_request,
+ mojom::ProducerHostPtrInfo producer_host_info) {
+ task_runner()->GetOrCreateTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ProducerClient::BindClientAndHostPipesOnSequence,
+ base::Unretained(this), std::move(producer_client_request),
+ std::move(producer_host_info)));
}
// The Mojo binding should run on the same sequence as the one we get
// callbacks from Perfetto on, to avoid additional PostTasks.
-void ProducerClient::CreateMojoMessagepipesOnSequence(
- scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
- MessagepipesReadyCallback callback,
+void ProducerClient::BindClientAndHostPipesOnSequence(
mojom::ProducerClientRequest producer_client_request,
- mojom::ProducerClientPtr producer_client) {
+ mojom::ProducerHostPtrInfo producer_host_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(!binding_ || !binding_->is_bound());
+ CHECK(!binding_ || !binding_->is_bound());
binding_ = std::make_unique<mojo::Binding<mojom::ProducerClient>>(
this, std::move(producer_client_request));
@@ -143,9 +68,7 @@ void ProducerClient::CreateMojoMessagepipesOnSequence(
},
base::Unretained(this)));
- origin_task_runner->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), std::move(producer_client),
- mojo::MakeRequest(&producer_host_)));
+ producer_host_.Bind(std::move(producer_host_info));
// TODO(oysteine) We register the data sources in reverse as a temporary
// workaround to make sure that the TraceEventDataSource is registered
@@ -154,28 +77,17 @@ void ProducerClient::CreateMojoMessagepipesOnSequence(
// be enabled, which is done by the TraceEventDataSource. We need to register
// the MetadataSource first to ensure that it's also ready. Once the
// Perfetto Observer interface is ready, we can remove this.
- for (auto it = data_sources_.rbegin(); it != data_sources_.rend(); ++it) {
- RegisterDataSourceWithHost(*it);
+ const auto& data_sources = PerfettoTracedProcess::Get()->data_sources();
+ for (auto it = data_sources.crbegin(); it != data_sources.crend(); ++it) {
+ NewDataSourceAdded(*it);
}
}
-void ProducerClient::AddDataSource(DataSourceBase* data_source) {
- GetTaskRunner()->task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&ProducerClient::AddDataSourceOnSequence,
- base::Unretained(this), data_source));
-}
-
-void ProducerClient::AddDataSourceOnSequence(DataSourceBase* data_source) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (data_sources_.insert(data_source).second) {
- if (producer_host_) {
- RegisterDataSourceWithHost(data_source);
- }
+void ProducerClient::NewDataSourceAdded(
+ const PerfettoTracedProcess::DataSourceBase* const data_source) {
+ if (!producer_host_) {
+ return;
}
-}
-
-void ProducerClient::RegisterDataSourceWithHost(DataSourceBase* data_source) {
perfetto::DataSourceDescriptor new_registration;
new_registration.set_name(data_source->name());
new_registration.set_will_notify_on_start(true);
@@ -183,8 +95,16 @@ void ProducerClient::RegisterDataSourceWithHost(DataSourceBase* data_source) {
producer_host_->RegisterDataSource(std::move(new_registration));
}
+perfetto::SharedMemoryArbiter* ProducerClient::GetSharedMemoryArbiter() {
+ return in_process_arbiter_ ? in_process_arbiter_
+ : shared_memory_arbiter_.get();
+}
+
void ProducerClient::OnTracingStart(
mojo::ScopedSharedBufferHandle shared_memory) {
+ // If we're using in-process mode, we don't need to set up our
+ // own SharedMemoryArbiter.
+ DCHECK(!in_process_arbiter_);
// TODO(oysteine): In next CLs plumb this through the service.
const size_t kShmemBufferPageSize = 4096;
@@ -195,7 +115,8 @@ void ProducerClient::OnTracingStart(
std::make_unique<MojoSharedMemory>(std::move(shared_memory));
shared_memory_arbiter_ = perfetto::SharedMemoryArbiter::CreateInstance(
- shared_memory_.get(), kShmemBufferPageSize, this, GetTaskRunner());
+ shared_memory_.get(), kShmemBufferPageSize, this,
+ PerfettoTracedProcess::GetTaskRunner());
} else {
// TODO(oysteine): This is assuming the SMB is the same, currently. Swapping
// out SharedMemoryBuffers would require more thread synchronization.
@@ -210,7 +131,7 @@ void ProducerClient::StartDataSource(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(oysteine): Support concurrent tracing sessions.
- for (auto* data_source : data_sources_) {
+ for (auto* data_source : PerfettoTracedProcess::Get()->data_sources()) {
if (data_source->name() == data_source_config.name()) {
data_source->StartTracingWithID(id, this, data_source_config);
// TODO(eseckler): Consider plumbing this callback through |data_source|.
@@ -224,7 +145,7 @@ void ProducerClient::StopDataSource(uint64_t id,
StopDataSourceCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- for (auto* data_source : data_sources_) {
+ for (auto* data_source : PerfettoTracedProcess::Get()->data_sources()) {
if (data_source->data_source_id() == id) {
data_source->StopTracing(std::move(callback));
return;
@@ -240,7 +161,7 @@ void ProducerClient::Flush(uint64_t flush_request_id,
data_source_ids.size()};
// N^2, optimize once there's more than a couple of possible data sources.
- for (auto* data_source : data_sources_) {
+ for (auto* data_source : PerfettoTracedProcess::Get()->data_sources()) {
if (std::find(data_source_ids.begin(), data_source_ids.end(),
data_source->data_source_id()) != data_source_ids.end()) {
data_source->Flush(base::BindRepeating(
@@ -278,6 +199,17 @@ void ProducerClient::ActivateTriggers(const std::vector<std::string>&) {
void ProducerClient::CommitData(const perfetto::CommitDataRequest& commit,
CommitDataCallback callback) {
+ // We need to make sure the CommitData IPC is sent off without triggering any
+ // trace events, as that could stall waiting for SMB chunks to be freed up
+ // which requires the tracing service to receive the IPC.
+ if (!TraceEventDataSource::GetThreadIsInTraceEventTLS()->Get()) {
+ AutoThreadLocalBoolean thread_is_in_trace_event(
+ TraceEventDataSource::GetThreadIsInTraceEventTLS());
+
+ producer_host_->CommitData(commit);
+ return;
+ }
+
producer_host_->CommitData(commit);
}
@@ -310,15 +242,10 @@ void ProducerClient::NotifyFlushComplete(perfetto::FlushRequestID id) {
DCHECK_NE(pending_replies_for_latest_flush_.second, 0u);
if (--pending_replies_for_latest_flush_.second == 0) {
- shared_memory_arbiter_->NotifyFlushComplete(id);
+ GetSharedMemoryArbiter()->NotifyFlushComplete(id);
}
}
-std::unique_ptr<perfetto::TraceWriter> ProducerClient::CreateTraceWriter(
- perfetto::BufferID target_buffer) {
- return shared_memory_arbiter_->CreateTraceWriter(target_buffer);
-}
-
void ProducerClient::RegisterTraceWriter(uint32_t writer_id,
uint32_t target_buffer) {
producer_host_->RegisterTraceWriter(writer_id, target_buffer);
diff --git a/chromium/services/tracing/public/cpp/perfetto/producer_client.h b/chromium/services/tracing/public/cpp/perfetto/producer_client.h
index 8370a219346..2322307f3ea 100644
--- a/chromium/services/tracing/public/cpp/perfetto/producer_client.h
+++ b/chromium/services/tracing/public/cpp/perfetto/producer_client.h
@@ -17,102 +17,38 @@
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/tracing/public/cpp/perfetto/perfetto_producer.h"
#include "services/tracing/public/cpp/perfetto/task_runner.h"
#include "services/tracing/public/mojom/perfetto_service.mojom.h"
-#include "third_party/perfetto/include/perfetto/tracing/core/tracing_service.h"
namespace perfetto {
class SharedMemoryArbiter;
-class StartupTraceWriterRegistry;
} // namespace perfetto
namespace tracing {
class MojoSharedMemory;
-class ScopedPerfettoPostTaskBlocker {
- public:
- explicit ScopedPerfettoPostTaskBlocker(bool enable);
- ~ScopedPerfettoPostTaskBlocker();
-
- private:
- const bool enabled_;
-};
-
// This class is the per-process client side of the Perfetto
// producer, and is responsible for creating specific kinds
// of DataSources (like ChromeTracing) on demand, and provide
// them with TraceWriters and a configuration to start logging.
-
-// Implementations of new DataSources should:
-// * Implement ProducerClient::DataSourceBase.
-// * Add a new data source name in perfetto_service.mojom.
-// * Register the data source with Perfetto in ProducerHost::OnConnect.
-// * Construct the new implementation when requested to
-// in ProducerClient::StartDataSource.
class COMPONENT_EXPORT(TRACING_CPP) ProducerClient
- : public mojom::ProducerClient,
- public perfetto::TracingService::ProducerEndpoint {
+ : public PerfettoProducer,
+ public mojom::ProducerClient {
public:
- class DataSourceBase {
- public:
- explicit DataSourceBase(const std::string& name);
- virtual ~DataSourceBase();
-
- void StartTracingWithID(
- uint64_t data_source_id,
- ProducerClient* producer_client,
- const perfetto::DataSourceConfig& data_source_config);
-
- virtual void StartTracing(
- ProducerClient* producer_client,
- const perfetto::DataSourceConfig& data_source_config) = 0;
- virtual void StopTracing(
- base::OnceClosure stop_complete_callback = base::OnceClosure()) = 0;
-
- // Flush the data source.
- virtual void Flush(base::RepeatingClosure flush_complete_callback) = 0;
-
- const std::string& name() const { return name_; }
- uint64_t data_source_id() const { return data_source_id_; }
-
- private:
- uint64_t data_source_id_ = 0;
- std::string name_;
- };
-
- // Returns the process-wide instance of the ProducerClient.
- static ProducerClient* Get();
-
+ ProducerClient(PerfettoTaskRunner* task_runner);
~ProducerClient() override;
- static void DeleteSoonForTesting(std::unique_ptr<ProducerClient>);
-
- // Returns the taskrunner used by Perfetto.
- static PerfettoTaskRunner* GetTaskRunner();
+ void NewDataSourceAdded(
+ const PerfettoTracedProcess::DataSourceBase* const data_source) override;
void Connect(mojom::PerfettoServicePtr perfetto_service);
- // Create the messagepipes that'll be used to connect
- // to the service-side ProducerHost, on the correct
- // sequence. The callback will be called on same sequence
- // as CreateMojoMessagepipes() got called on.
- using MessagepipesReadyCallback =
- base::OnceCallback<void(mojom::ProducerClientPtr,
- mojom::ProducerHostRequest)>;
- void CreateMojoMessagepipes(MessagepipesReadyCallback);
-
- // Binds the registry and its trace writers to the ProducerClient's SMB, to
- // write into the given target buffer. The ownership of |registry| is
- // transferred to ProducerClient (and its SharedMemoryArbiter).
- void BindStartupTraceWriterRegistry(
- std::unique_ptr<perfetto::StartupTraceWriterRegistry> registry,
- perfetto::BufferID target_buffer);
-
- // Add a new data source to the ProducerClient; the caller
- // retains ownership and is responsible for making sure
- // the data source outlives the ProducerClient.
- void AddDataSource(DataSourceBase*);
+ void set_in_process_shmem_arbiter(perfetto::SharedMemoryArbiter* arbiter) {
+ DCHECK(!in_process_arbiter_);
+ in_process_arbiter_ = arbiter;
+ }
// mojom::ProducerClient implementation.
// Called through Mojo by the ProducerHost on the service-side to control
@@ -134,8 +70,6 @@ class COMPONENT_EXPORT(TRACING_CPP) ProducerClient
CommitDataCallback callback) override;
// Used by the DataSource implementations to create TraceWriters
// for writing their protobufs, and respond to flushes.
- std::unique_ptr<perfetto::TraceWriter> CreateTraceWriter(
- perfetto::BufferID target_buffer) override;
void NotifyFlushComplete(perfetto::FlushRequestID) override;
perfetto::SharedMemory* shared_memory() const override;
void RegisterTraceWriter(uint32_t writer_id, uint32_t target_buffer) override;
@@ -151,32 +85,24 @@ class COMPONENT_EXPORT(TRACING_CPP) ProducerClient
size_t shared_buffer_page_size_kb() const override;
perfetto::SharedMemoryArbiter* GetInProcessShmemArbiter() override;
- static void ResetTaskRunnerForTesting();
+ void BindClientAndHostPipesForTesting(mojom::ProducerClientRequest,
+ mojom::ProducerHostPtrInfo);
protected:
- // protected for testing.
- ProducerClient();
+ perfetto::SharedMemoryArbiter* GetSharedMemoryArbiter() override;
private:
friend class base::NoDestructor<ProducerClient>;
void CommitDataOnSequence(const perfetto::CommitDataRequest& request);
- void AddDataSourceOnSequence(DataSourceBase*);
- void RegisterDataSourceWithHost(DataSourceBase* data_source);
-
- // The callback will be run on the |origin_task_runner|, meaning
- // the same sequence as CreateMojoMessagePipes() got called on.
- void CreateMojoMessagepipesOnSequence(
- scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
- MessagepipesReadyCallback,
- mojom::ProducerClientRequest,
- mojom::ProducerClientPtr);
+ void BindClientAndHostPipesOnSequence(mojom::ProducerClientRequest,
+ mojom::ProducerHostPtrInfo);
std::unique_ptr<mojo::Binding<mojom::ProducerClient>> binding_;
- std::unique_ptr<perfetto::SharedMemoryArbiter> shared_memory_arbiter_;
mojom::ProducerHostPtr producer_host_;
std::unique_ptr<MojoSharedMemory> shared_memory_;
- std::set<DataSourceBase*> data_sources_;
+ std::unique_ptr<perfetto::SharedMemoryArbiter> shared_memory_arbiter_;
+ perfetto::SharedMemoryArbiter* in_process_arbiter_ = nullptr;
// First value is the flush ID, the second is the number of
// replies we're still waiting for.
std::pair<uint64_t, size_t> pending_replies_for_latest_flush_;
diff --git a/chromium/services/tracing/public/cpp/perfetto/system_producer.cc b/chromium/services/tracing/public/cpp/perfetto/system_producer.cc
new file mode 100644
index 00000000000..f1ffbf294c0
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/perfetto/system_producer.cc
@@ -0,0 +1,10 @@
+// Copyright 2019 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/tracing/public/cpp/perfetto/system_producer.h"
+
+namespace tracing {
+SystemProducer::SystemProducer(PerfettoTaskRunner* task_runner)
+ : PerfettoProducer(task_runner) {}
+} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/perfetto/system_producer.h b/chromium/services/tracing/public/cpp/perfetto/system_producer.h
new file mode 100644
index 00000000000..e37274c42d2
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/perfetto/system_producer.h
@@ -0,0 +1,23 @@
+// Copyright 2019 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.
+
+#ifndef SERVICES_TRACING_PUBLIC_CPP_PERFETTO_SYSTEM_PRODUCER_H_
+#define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_SYSTEM_PRODUCER_H_
+
+#include "services/tracing/public/cpp/perfetto/perfetto_producer.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/producer.h"
+
+namespace tracing {
+
+class SystemProducer : public PerfettoProducer, public perfetto::Producer {
+ public:
+ SystemProducer(PerfettoTaskRunner* task_runner);
+ // Since Chrome does not support concurrent tracing sessions, and system
+ // tracing is always lower priority than human or DevTools initiated tracing,
+ // all system producers must be able to disconnect and stop tracing.
+ virtual void Disconnect() = 0;
+};
+} // namespace tracing
+
+#endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_SYSTEM_PRODUCER_H_
diff --git a/chromium/services/tracing/public/cpp/perfetto/task_runner.cc b/chromium/services/tracing/public/cpp/perfetto/task_runner.cc
index 7c7838f34f4..1eecec0c9bc 100644
--- a/chromium/services/tracing/public/cpp/perfetto/task_runner.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/task_runner.cc
@@ -8,8 +8,15 @@
#include <utility>
#include "base/bind.h"
+#include "base/no_destructor.h"
+#include "base/task/common/checked_lock_impl.h"
+#include "base/task/common/scoped_defer_task_posting.h"
+#include "base/task/post_task.h"
+#include "base/task/thread_pool/thread_pool.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_local.h"
#include "base/threading/thread_local_storage.h"
+#include "services/tracing/public/cpp/perfetto/trace_event_data_source.h"
namespace tracing {
@@ -20,29 +27,25 @@ PerfettoTaskRunner::PerfettoTaskRunner(
PerfettoTaskRunner::~PerfettoTaskRunner() = default;
void PerfettoTaskRunner::PostTask(std::function<void()> task) {
- // If we're blocked from PostTasking, we defer the task until
- // later. If we're not blocked, but there's tasks that have previously been
- // deferred, we PostTask them now; this is important to preserve ordering,
- // in case the previously deferred tasks have been posted from the same
- // sequence as we're now posting a new task from.
- {
- base::AutoLock lock(lock_);
- if (posttask_is_blocked_for_thread_.Get()) {
- deferred_tasks_.emplace_back(std::move(task));
- return;
- }
-
- while (!deferred_tasks_.empty()) {
- task_runner_->PostTask(
- FROM_HERE, base::BindOnce([](std::function<void()> task) { task(); },
- deferred_tasks_.front()));
- deferred_tasks_.pop_front();
- }
- }
-
- task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce([](std::function<void()> task) { task(); }, task));
+ base::ScopedDeferTaskPosting::PostOrDefer(
+ GetOrCreateTaskRunner(), FROM_HERE,
+ base::BindOnce(
+ [](std::function<void()> task) {
+ // We block any trace events that happens while any
+ // Perfetto task is running, or we'll get deadlocks in
+ // situations where the StartupTraceWriterRegistry tries
+ // to bind a writer which in turn causes a PostTask where
+ // a trace event can be emitted, which then deadlocks as
+ // it needs a new chunk from the same StartupTraceWriter
+ // which we're trying to bind and are keeping the lock
+ // to.
+ // TODO(oysteine): Try to see if we can be more selective
+ // about this.
+ AutoThreadLocalBoolean thread_is_in_trace_event(
+ TraceEventDataSource::GetThreadIsInTraceEventTLS());
+ task();
+ },
+ task));
}
void PerfettoTaskRunner::PostDelayedTask(std::function<void()> task,
@@ -55,14 +58,15 @@ void PerfettoTaskRunner::PostDelayedTask(std::function<void()> task,
// There's currently nothing which uses PostDelayedTask on the ProducerClient
// side, where PostTask sometimes requires blocking. If this DCHECK ever
// triggers, support for deferring delayed tasks need to be added.
- DCHECK(!posttask_is_blocked_for_thread_.Get());
- task_runner_->PostDelayedTask(
+ DCHECK(!base::ScopedDeferTaskPosting::IsPresent());
+ GetOrCreateTaskRunner()->PostDelayedTask(
FROM_HERE,
base::BindOnce([](std::function<void()> task) { task(); }, task),
base::TimeDelta::FromMilliseconds(delay_ms));
}
bool PerfettoTaskRunner::RunsTasksOnCurrentThread() const {
+ DCHECK(task_runner_);
return task_runner_->RunsTasksInCurrentSequence();
}
@@ -79,44 +83,21 @@ void PerfettoTaskRunner::ResetTaskRunnerForTesting(
task_runner_ = std::move(task_runner);
}
-void PerfettoTaskRunner::BlockPostTaskForThread() {
- DCHECK(!posttask_is_blocked_for_thread_.Get());
- posttask_is_blocked_for_thread_.Set(true);
-}
-
-void PerfettoTaskRunner::UnblockPostTaskForThread() {
- DCHECK(posttask_is_blocked_for_thread_.Get());
- posttask_is_blocked_for_thread_.Set(false);
-}
-
-void PerfettoTaskRunner::StartDeferredTasksDrainTimer() {
- DCHECK(!posttask_is_blocked_for_thread_.Get());
- // The deferred tasks will generally be posted by another task being
- // posted when PostTask isn't blocked; this timer is a fallback for the
- // rare case where we're *only* getting trace events when PostTask is
- // blocked, and hence doesn't need to run very often (just often enough so
- // the SMB doesn't get filled up with uncommitted chunks).
- deferred_tasks_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), this,
- &PerfettoTaskRunner::OnDeferredTasksDrainTimer);
-}
-
-void PerfettoTaskRunner::StopDeferredTasksDrainTimer() {
- DCHECK(!posttask_is_blocked_for_thread_.Get());
-
- deferred_tasks_timer_.Stop();
- OnDeferredTasksDrainTimer();
+void PerfettoTaskRunner::SetTaskRunner(
+ scoped_refptr<base::SequencedTaskRunner> task_runner) {
+ DCHECK(!task_runner_);
+ task_runner_ = std::move(task_runner);
}
-void PerfettoTaskRunner::OnDeferredTasksDrainTimer() {
- DCHECK(!posttask_is_blocked_for_thread_.Get());
-
- base::AutoLock lock(lock_);
- while (!deferred_tasks_.empty()) {
- task_runner_->PostTask(
- FROM_HERE, base::BindOnce([](std::function<void()> task) { task(); },
- deferred_tasks_.front()));
- deferred_tasks_.pop_front();
+scoped_refptr<base::SequencedTaskRunner>
+PerfettoTaskRunner::GetOrCreateTaskRunner() {
+ if (!task_runner_) {
+ DCHECK(base::ThreadPoolInstance::Get());
+ task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::USER_BLOCKING});
}
+
+ return task_runner_;
}
} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/perfetto/task_runner.h b/chromium/services/tracing/public/cpp/perfetto/task_runner.h
index d8193e461d0..1221bc68670 100644
--- a/chromium/services/tracing/public/cpp/perfetto/task_runner.h
+++ b/chromium/services/tracing/public/cpp/perfetto/task_runner.h
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "base/sequenced_task_runner.h"
#include "base/synchronization/lock.h"
-#include "base/threading/thread_local.h"
#include "base/timer/timer.h"
#include "services/tracing/public/mojom/perfetto_service.mojom.h"
#include "third_party/perfetto/include/perfetto/base/task_runner.h"
@@ -37,36 +36,24 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTaskRunner
// use case.
bool RunsTasksOnCurrentThread() const override;
+ void SetTaskRunner(scoped_refptr<base::SequencedTaskRunner> task_runner);
+ scoped_refptr<base::SequencedTaskRunner> GetOrCreateTaskRunner();
+ bool HasTaskRunner() const { return !!task_runner_; }
+
// Not used in Chrome.
void AddFileDescriptorWatch(int fd, std::function<void()>) override;
void RemoveFileDescriptorWatch(int fd) override;
- base::SequencedTaskRunner* task_runner() { return task_runner_.get(); }
// Tests will shut down all task runners in between runs, so we need
// to re-create any static instances on each SetUp();
void ResetTaskRunnerForTesting(
scoped_refptr<base::SequencedTaskRunner> task_runner);
- // Sometimes we have to temporarily defer any posted tasks, like
- // when trace events are added when the taskqueue is locked. For this purpose
- // we keep a timer running when tracing is enabled, which will periodically
- // drain these posted tasks.
- void StartDeferredTasksDrainTimer();
- void StopDeferredTasksDrainTimer();
-
- void BlockPostTaskForThread();
- void UnblockPostTaskForThread();
-
private:
void OnDeferredTasksDrainTimer();
scoped_refptr<base::SequencedTaskRunner> task_runner_;
- base::ThreadLocalBoolean posttask_is_blocked_for_thread_;
-
- base::Lock lock_; // Protects deferred_tasks_;
- std::list<std::function<void()>> deferred_tasks_;
- base::RepeatingTimer deferred_tasks_timer_;
DISALLOW_COPY_AND_ASSIGN(PerfettoTaskRunner);
};
diff --git a/chromium/services/tracing/public/cpp/perfetto/task_runner_unittest.cc b/chromium/services/tracing/public/cpp/perfetto/task_runner_unittest.cc
index 9739ca7fb2d..d0af6fea754 100644
--- a/chromium/services/tracing/public/cpp/perfetto/task_runner_unittest.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/task_runner_unittest.cc
@@ -72,8 +72,6 @@ class PosterThread : public base::SimpleThread {
void BeforeJoin() override {}
void Run() override {
- task_runner_->BlockPostTaskForThread();
-
for (int i = 0; i < n_; ++i) {
auto weak_ptr = weak_ptr_;
auto sequence_number = sequence_number_;
@@ -81,8 +79,6 @@ class PosterThread : public base::SimpleThread {
weak_ptr->TestTask(i, sequence_number);
});
}
-
- task_runner_->UnblockPostTaskForThread();
}
private:
@@ -132,70 +128,6 @@ TEST_F(PerfettoTaskRunnerTest, SequentialTasks) {
wait_for_tasks.Run();
}
-TEST_F(PerfettoTaskRunnerTest, SequentialDeferredTasks) {
- base::RunLoop wait_for_tasks;
- SetTaskExpectations(wait_for_tasks.QuitClosure(), 3);
-
- task_runner()->BlockPostTaskForThread();
- auto weak_ptr = destination()->GetWeakPtr();
- task_runner()->PostTask([weak_ptr]() { weak_ptr->TestTask(1); });
- task_runner()->PostTask([weak_ptr]() { weak_ptr->TestTask(2); });
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0u, destination()->tasks_run());
- task_runner()->UnblockPostTaskForThread();
- // Posting an unblocked task should post the earlier deferred ones,
- // in the right order.
- task_runner()->PostTask([weak_ptr]() { weak_ptr->TestTask(3); });
-
- wait_for_tasks.Run();
-}
-
-TEST_F(PerfettoTaskRunnerTest, SequentialDeferredTasksByTimer) {
- base::RunLoop wait_for_tasks;
- SetTaskExpectations(wait_for_tasks.QuitClosure(), 3);
-
- task_runner()->BlockPostTaskForThread();
- auto weak_ptr = destination()->GetWeakPtr();
- task_runner()->PostTask([weak_ptr]() { weak_ptr->TestTask(1); });
- task_runner()->PostTask([weak_ptr]() { weak_ptr->TestTask(2); });
- task_runner()->PostTask([weak_ptr]() { weak_ptr->TestTask(3); });
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0u, destination()->tasks_run());
-
- // Start the timer which eventually will tick and post the previously
- // deferred tasks. Note that this is posted directly to the taskqueue
- // rather than the Perfetto wrapper, so it won't be deferred.
- task_runner()->task_runner()->PostTask(
- FROM_HERE,
- base::BindOnce(&PerfettoTaskRunner::StartDeferredTasksDrainTimer,
- base::Unretained(task_runner())));
-
- wait_for_tasks.Run();
-}
-
-TEST_F(PerfettoTaskRunnerTest, SequentialByMultipleSequences) {
- base::RunLoop wait_for_tasks;
- SetTaskExpectations(wait_for_tasks.QuitClosure(), 2001, 3);
-
- auto weak_ptr = destination()->GetWeakPtr();
-
- PosterThread first_thread(task_runner(), weak_ptr, 1000, 1);
- PosterThread second_thread(task_runner(), weak_ptr, 1000, 2);
- first_thread.Start();
- second_thread.Start();
- first_thread.Join();
- second_thread.Join();
-
- // Both threads set the taskrunner to defer new tasks, so none
- // should have run at this point.
- EXPECT_EQ(0u, destination()->tasks_run());
-
- // Posting an unblocked task should post the earlier deferred ones,
- // in the right order.
- task_runner()->PostTask([weak_ptr]() { weak_ptr->TestTask(1, 0); });
- wait_for_tasks.Run();
-}
-
} // namespace
} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.cc b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
index e388ed6d321..2a8f262dfdf 100644
--- a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
@@ -83,6 +83,9 @@ TraceEventMetadataSource::GenerateTraceConfigMetadataDict() {
void TraceEventMetadataSource::GenerateMetadata(
std::unique_ptr<perfetto::TraceWriter> trace_writer) {
+ if (privacy_filtering_enabled_) {
+ return;
+ }
DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
auto trace_packet = trace_writer->NewTracePacket();
@@ -114,7 +117,7 @@ void TraceEventMetadataSource::GenerateMetadata(
}
void TraceEventMetadataSource::StartTracing(
- ProducerClient* producer_client,
+ PerfettoProducer* producer,
const perfetto::DataSourceConfig& data_source_config) {
// TODO(eseckler): Once we support streaming of trace data, it would make
// sense to emit the metadata on startup, so the UI can display it right away.
@@ -122,7 +125,7 @@ void TraceEventMetadataSource::StartTracing(
data_source_config.chrome_config().privacy_filtering_enabled();
chrome_config_ = data_source_config.chrome_config().trace_config();
trace_writer_ =
- producer_client->CreateTraceWriter(data_source_config.target_buffer());
+ producer->CreateTraceWriter(data_source_config.target_buffer());
}
void TraceEventMetadataSource::StopTracing(
@@ -150,31 +153,11 @@ void TraceEventMetadataSource::Flush(
namespace {
-class AutoThreadLocalBoolean {
- public:
- explicit AutoThreadLocalBoolean(
- base::ThreadLocalBoolean* thread_local_boolean)
- : thread_local_boolean_(thread_local_boolean) {
- DCHECK(!thread_local_boolean_->Get());
- thread_local_boolean_->Set(true);
- }
- ~AutoThreadLocalBoolean() { thread_local_boolean_->Set(false); }
-
- private:
- base::ThreadLocalBoolean* thread_local_boolean_;
- DISALLOW_COPY_AND_ASSIGN(AutoThreadLocalBoolean);
-};
-
-base::ThreadLocalBoolean* GetThreadIsInTraceEventTLS() {
- static base::NoDestructor<base::ThreadLocalBoolean> thread_is_in_trace_event;
- return thread_is_in_trace_event.get();
-}
-
base::ThreadLocalStorage::Slot* ThreadLocalEventSinkSlot() {
static base::NoDestructor<base::ThreadLocalStorage::Slot>
thread_local_event_sink_tls([](void* event_sink) {
AutoThreadLocalBoolean thread_is_in_trace_event(
- GetThreadIsInTraceEventTLS());
+ TraceEventDataSource::GetThreadIsInTraceEventTLS());
delete static_cast<ThreadLocalEventSink*>(event_sink);
});
@@ -192,6 +175,12 @@ TraceEventDataSource* TraceEventDataSource::GetInstance() {
}
// static
+base::ThreadLocalBoolean* TraceEventDataSource::GetThreadIsInTraceEventTLS() {
+ static base::NoDestructor<base::ThreadLocalBoolean> thread_is_in_trace_event;
+ return thread_is_in_trace_event.get();
+}
+
+// static
void TraceEventDataSource::ResetForTesting() {
if (!g_trace_event_data_source_for_testing)
return;
@@ -221,15 +210,17 @@ void TraceEventDataSource::UnregisterFromTraceLog() {
TraceLog::GetInstance()->SetAddTraceEventOverrides(nullptr, nullptr, nullptr);
}
-void TraceEventDataSource::SetupStartupTracing() {
+void TraceEventDataSource::SetupStartupTracing(bool privacy_filtering_enabled) {
{
base::AutoLock lock(lock_);
// No need to do anything if startup tracing has already been set,
// or we know Perfetto has already been setup.
if (startup_writer_registry_ || producer_client_) {
+ DCHECK(!privacy_filtering_enabled || privacy_filtering_enabled_);
return;
}
+ privacy_filtering_enabled_ = privacy_filtering_enabled;
startup_writer_registry_ =
std::make_unique<perfetto::StartupTraceWriterRegistry>();
}
@@ -237,34 +228,36 @@ void TraceEventDataSource::SetupStartupTracing() {
}
void TraceEventDataSource::StartTracing(
- ProducerClient* producer_client,
+ PerfettoProducer* producer,
const perfetto::DataSourceConfig& data_source_config) {
- privacy_filtering_enabled_ =
- data_source_config.chrome_config().privacy_filtering_enabled();
-
std::unique_ptr<perfetto::StartupTraceWriterRegistry> unbound_writer_registry;
{
base::AutoLock lock(lock_);
+ bool should_enable_filtering =
+ data_source_config.chrome_config().privacy_filtering_enabled();
+ if (should_enable_filtering) {
+ CHECK(!startup_writer_registry_ || privacy_filtering_enabled_)
+ << "Unexpected StartTracing received when startup tracing is "
+ "running.";
+ }
+ privacy_filtering_enabled_ = should_enable_filtering;
+
DCHECK(!producer_client_);
- producer_client_ = producer_client;
+ producer_client_ = producer;
target_buffer_ = data_source_config.target_buffer();
// Reduce lock contention by binding the registry without holding the lock.
unbound_writer_registry = std::move(startup_writer_registry_);
- trace_writers_from_registry_.clear();
}
session_id_.fetch_add(1u, std::memory_order_relaxed);
if (unbound_writer_registry) {
- // TODO(ssid): Startup tracing should know about filtering output.
- CHECK(!privacy_filtering_enabled_);
-
// TODO(oysteine): Investigate why trace events emitted by something in
// BindStartupTraceWriterRegistry() causes deadlocks.
AutoThreadLocalBoolean thread_is_in_trace_event(
GetThreadIsInTraceEventTLS());
- producer_client->BindStartupTraceWriterRegistry(
+ producer->BindStartupTraceWriterRegistry(
std::move(unbound_writer_registry), data_source_config.target_buffer());
} else {
RegisterWithTraceLog();
@@ -274,7 +267,6 @@ void TraceEventDataSource::StartTracing(
TraceConfig(data_source_config.chrome_config().trace_config());
TraceLog::GetInstance()->SetEnabled(trace_config, TraceLog::RECORDING_MODE);
ResetHistograms(trace_config);
- ProducerClient::GetTaskRunner()->StartDeferredTasksDrainTimer();
}
void TraceEventDataSource::StopTracing(
@@ -289,12 +281,6 @@ void TraceEventDataSource::StopTracing(
return;
}
- // It's extremely unlikely any threads are still in mid-trace-event
- // at this point and end up posting new tasks to the PerfettoTaskRunner
- // which end up not getting run until the next tracing session; worst
- // case is we lose some chunk commit messages and Perfetto will
- // scrape the chunks.
- ProducerClient::GetTaskRunner()->StopDeferredTasksDrainTimer();
data_source->UnregisterFromTraceLog();
if (data_source->stop_complete_callback_) {
@@ -399,7 +385,6 @@ ThreadLocalEventSink* TraceEventDataSource::CreateThreadLocalEventSink(
uint32_t session_id = session_id_.load(std::memory_order_relaxed);
if (startup_writer_registry_) {
trace_writer = startup_writer_registry_->CreateUnboundTraceWriter();
- trace_writers_from_registry_.insert(trace_writer.get());
} else if (producer_client_) {
trace_writer = std::make_unique<perfetto::StartupTraceWriter>(
producer_client_->CreateTraceWriter(target_buffer_));
@@ -456,20 +441,13 @@ void TraceEventDataSource::OnAddTraceEvent(
// events emitted while the taskqueue is locked), we can't reset the
// sink as the TraceWriter deletion is done through PostTask.
if (new_session_id > kFirstSessionID &&
- new_session_id != thread_local_event_sink->session_id() &&
- !(trace_event->flags() & TRACE_EVENT_FLAG_DISALLOW_POSTTASK)) {
+ new_session_id != thread_local_event_sink->session_id()) {
delete thread_local_event_sink;
thread_local_event_sink = nullptr;
}
}
if (!thread_local_event_sink) {
- // Trace events emitted by the task queue itself can happen while the task
- // queue is locked, posting to it reentrantly would deadlock so these events
- // need to be flagged so we can avoid PostTasks while they're being emitted.
- ScopedPerfettoPostTaskBlocker post_task_blocker(
- !!(trace_event->flags() & TRACE_EVENT_FLAG_DISALLOW_POSTTASK));
-
thread_local_event_sink =
GetInstance()->CreateThreadLocalEventSink(thread_will_flush);
ThreadLocalEventSinkSlot()->Set(thread_local_event_sink);
@@ -518,28 +496,42 @@ void TraceEventDataSource::FlushCurrentThread() {
void TraceEventDataSource::ReturnTraceWriter(
std::unique_ptr<perfetto::StartupTraceWriter> trace_writer) {
+ // Prevent concurrent binding of the registry.
base::AutoLock lock(lock_);
- // It's possible that the returned trace writer was created by a former
- // StartupTraceWriterRegistry. In this case, we should not attempt to return
- // it to the current registry, so we need to verify first that it was indeed
- // created by the current registry.
- if (startup_writer_registry_ &&
- trace_writers_from_registry_.find(trace_writer.get()) !=
- trace_writers_from_registry_.end()) {
- // If the writer is still unbound, the registry will keep it alive until it
- // was bound and its buffered data was copied. This ensures that we don't
- // lose data from threads that are shut down during startup.
- trace_writers_from_registry_.erase(trace_writer.get());
- startup_writer_registry_->ReturnUnboundTraceWriter(std::move(trace_writer));
- } else {
- // Delete the TraceWriter on the sequence that Perfetto runs on, needed
- // as the ThreadLocalEventSink gets deleted on thread
- // shutdown and we can't safely call TaskRunnerHandle::Get() at that point
- // (which can happen as the TraceWriter destructor might make a Mojo call
- // and trigger it).
- ProducerClient::GetTaskRunner()->task_runner()->DeleteSoon(
- FROM_HERE, std::move(trace_writer));
+
+ // If we don't have a task runner yet, we must be attempting to return a
+ // writer before the (very first) registry was bound. We cannot create the
+ // task runner safely in this case, because the thread pool may not have been
+ // brought up yet.
+ if (!PerfettoTracedProcess::GetTaskRunner()->HasTaskRunner()) {
+ DCHECK(startup_writer_registry_);
+ // It's safe to call ReturnToRegistry on the current sequence, as it won't
+ // destroy the writer since the registry was not bound yet. Will keep
+ // |trace_writer| alive until the registry is bound later.
+ perfetto::StartupTraceWriter::ReturnToRegistry(std::move(trace_writer));
+ return;
}
+
+ // Return the TraceWriter on the sequence that Perfetto runs on. Needed as the
+ // ThreadLocalEventSink gets deleted on thread shutdown and we can't safely
+ // call TaskRunnerHandle::Get() at that point (which can happen as the
+ // TraceWriter destructor might make a Mojo call and trigger it).
+ PerfettoTracedProcess::GetTaskRunner()->GetOrCreateTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ // Pass writer as raw pointer so that we leak it if task posting fails
+ // (during shutdown).
+ [](perfetto::StartupTraceWriter* raw_trace_writer) {
+ std::unique_ptr<perfetto::StartupTraceWriter> trace_writer(
+ raw_trace_writer);
+ // May destroy |trace_writer|. If the writer is still unbound, the
+ // registry will keep it alive until it was bound and its buffered
+ // data was copied. This ensures that we don't lose data from
+ // threads that are shut down during startup.
+ perfetto::StartupTraceWriter::ReturnToRegistry(
+ std::move(trace_writer));
+ },
+ trace_writer.release()));
}
} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.h b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.h
index 4550cb0283c..b350726f91a 100644
--- a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.h
+++ b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.h
@@ -16,6 +16,7 @@
#include "base/threading/thread_local.h"
#include "base/time/time.h"
#include "base/trace_event/trace_config.h"
+#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
#include "services/tracing/public/cpp/perfetto/producer_client.h"
namespace perfetto {
@@ -28,10 +29,25 @@ namespace tracing {
class ThreadLocalEventSink;
+class AutoThreadLocalBoolean {
+ public:
+ explicit AutoThreadLocalBoolean(
+ base::ThreadLocalBoolean* thread_local_boolean)
+ : thread_local_boolean_(thread_local_boolean) {
+ DCHECK(!thread_local_boolean_->Get());
+ thread_local_boolean_->Set(true);
+ }
+ ~AutoThreadLocalBoolean() { thread_local_boolean_->Set(false); }
+
+ private:
+ base::ThreadLocalBoolean* thread_local_boolean_;
+ DISALLOW_COPY_AND_ASSIGN(AutoThreadLocalBoolean);
+};
+
// This class is a data source that clients can use to provide
// global metadata in dictionary form, by registering callbacks.
class COMPONENT_EXPORT(TRACING_CPP) TraceEventMetadataSource
- : public ProducerClient::DataSourceBase {
+ : public PerfettoTracedProcess::DataSourceBase {
public:
TraceEventMetadataSource();
~TraceEventMetadataSource() override;
@@ -41,10 +57,10 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventMetadataSource
// Any callbacks passed here will be called when tracing starts.
void AddGeneratorFunction(MetadataGeneratorFunction generator);
- // ProducerClient::DataSourceBase implementation, called by
+ // PerfettoTracedProcess::DataSourceBase implementation, called by
// ProducerClent.
void StartTracing(
- ProducerClient* producer_client,
+ PerfettoProducer* producer_client,
const perfetto::DataSourceConfig& data_source_config) override;
void StopTracing(base::OnceClosure stop_complete_callback) override;
void Flush(base::RepeatingClosure flush_complete_callback) override;
@@ -63,11 +79,11 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventMetadataSource
};
// This class acts as a bridge between the TraceLog and
-// the Perfetto ProducerClient. It converts incoming
+// the PerfettoProducer. It converts incoming
// trace events to ChromeTraceEvent protos and writes
// them into the Perfetto shared memory.
class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource
- : public ProducerClient::DataSourceBase {
+ : public PerfettoTracedProcess::DataSourceBase {
public:
static TraceEventDataSource* GetInstance();
@@ -77,21 +93,23 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource
// Flushes and deletes the TraceWriter for the current thread, if any.
static void FlushCurrentThread();
+ static base::ThreadLocalBoolean* GetThreadIsInTraceEventTLS();
+
// Installs TraceLog overrides for tracing during Chrome startup. Trace data
// is locally buffered until connection to the perfetto service is
// established. Expects a later call to StartTracing() to bind to the perfetto
// service. Should only be called once.
- void SetupStartupTracing();
+ void SetupStartupTracing(bool privacy_filtering_enabled);
- // The ProducerClient is responsible for calling StopTracing
+ // The PerfettoProducer is responsible for calling StopTracing
// which will clear the stored pointer to it, before it
- // gets destroyed. ProducerClient::CreateTraceWriter can be
+ // gets destroyed. PerfettoProducer::CreateTraceWriter can be
// called by the TraceEventDataSource on any thread.
void StartTracing(
- ProducerClient* producer_client,
+ PerfettoProducer* producer_client,
const perfetto::DataSourceConfig& data_source_config) override;
- // Called from the ProducerClient.
+ // Called from the PerfettoProducer.
void StopTracing(base::OnceClosure stop_complete_callback) override;
void Flush(base::RepeatingClosure flush_complete_callback) override;
@@ -132,7 +150,6 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource
void LogHistogram(base::HistogramBase* histogram);
bool disable_interning_ = false;
- bool privacy_filtering_enabled_ = false;
base::OnceClosure stop_complete_callback_;
// Incremented and accessed atomically but without memory order guarantees.
@@ -143,17 +160,14 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource
base::Lock lock_; // Protects subsequent members.
uint32_t target_buffer_ = 0;
- ProducerClient* producer_client_ = nullptr;
+ PerfettoProducer* producer_client_ = nullptr;
// We own the registry during startup, but transfer its ownership to the
- // ProducerClient once the perfetto service is available. Only set if
+ // PerfettoProducer once the perfetto service is available. Only set if
// SetupStartupTracing() is called.
std::unique_ptr<perfetto::StartupTraceWriterRegistry>
startup_writer_registry_;
- // Unbound writers created by the current |startup_writer_registry_|. We track
- // these writers to ensure that we only return the correct ones back to the
- // registry.
- std::set<perfetto::StartupTraceWriter*> trace_writers_from_registry_;
std::vector<std::string> histograms_;
+ bool privacy_filtering_enabled_ = false;
DISALLOW_COPY_AND_ASSIGN(TraceEventDataSource);
};
diff --git a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
index 4f1bf3c3b5c..02ce6c010d1 100644
--- a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
@@ -37,8 +37,9 @@ constexpr const char kCategoryGroup[] = "foo";
class MockProducerClient : public ProducerClient {
public:
explicit MockProducerClient(
- scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner)
- : delegate_(perfetto::base::kPageSize),
+ std::unique_ptr<PerfettoTaskRunner> main_thread_task_runner)
+ : ProducerClient(main_thread_task_runner.get()),
+ delegate_(perfetto::base::kPageSize),
stream_(&delegate_),
main_thread_task_runner_(std::move(main_thread_task_runner)) {
trace_packet_.Reset(&stream_);
@@ -109,7 +110,7 @@ class MockProducerClient : public ProducerClient {
perfetto::protos::pbzero::TracePacket trace_packet_;
protozero::ScatteredStreamWriterNullDelegate delegate_;
protozero::ScatteredStreamWriter stream_;
- scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner_;
+ std::unique_ptr<PerfettoTaskRunner> main_thread_task_runner_;
};
// For sequences/threads other than our own, we just want to ignore
@@ -169,7 +170,8 @@ std::unique_ptr<perfetto::TraceWriter> MockProducerClient::CreateTraceWriter(
// but there's no guarantee that this will succeed if that taskrunner is also
// shut down.
ANNOTATE_SCOPED_MEMORY_LEAK;
- if (main_thread_task_runner_->RunsTasksInCurrentSequence()) {
+ if (main_thread_task_runner_->GetOrCreateTaskRunner()
+ ->RunsTasksInCurrentSequence()) {
return std::make_unique<MockTraceWriter>(this);
} else {
return std::make_unique<DummyTraceWriter>();
@@ -179,9 +181,12 @@ std::unique_ptr<perfetto::TraceWriter> MockProducerClient::CreateTraceWriter(
class TraceEventDataSourceTest : public testing::Test {
public:
void SetUp() override {
- ProducerClient::ResetTaskRunnerForTesting();
- producer_client_ = std::make_unique<MockProducerClient>(
+ PerfettoTracedProcess::ResetTaskRunnerForTesting();
+ PerfettoTracedProcess::GetTaskRunner()->GetOrCreateTaskRunner();
+ auto perfetto_wrapper = std::make_unique<PerfettoTaskRunner>(
scoped_task_environment_.GetMainThreadTaskRunner());
+ producer_client_ =
+ std::make_unique<MockProducerClient>(std::move(perfetto_wrapper));
}
void TearDown() override {
diff --git a/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc b/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
index 7b97f5ceabe..dd0a5971e29 100644
--- a/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
@@ -9,6 +9,7 @@
#include "base/trace_event/trace_buffer.h"
#include "base/trace_event/trace_log.h"
#include "build/build_config.h"
+#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
#include "services/tracing/public/cpp/perfetto/producer_client.h"
#include "services/tracing/public/cpp/perfetto/traced_value_proto_writer.h"
#include "third_party/perfetto/include/perfetto/tracing/core/startup_trace_writer.h"
@@ -175,9 +176,6 @@ void TrackEventThreadLocalEventSink::AddTraceEvent(
bool copy_strings = flags & TRACE_EVENT_FLAG_COPY;
bool explicit_timestamp = flags & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP;
- ScopedPerfettoPostTaskBlocker post_task_blocker(
- !!(flags & TRACE_EVENT_FLAG_DISALLOW_POSTTASK));
-
if (reset_incremental_state_) {
interned_event_categories_.ResetEmittedState();
interned_event_names_.ResetEmittedState();
diff --git a/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h b/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h
index 54d4f042064..80d122738ee 100644
--- a/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h
+++ b/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h
@@ -64,7 +64,7 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink
base::trace_event::TraceEvent complete_event_stack_[kMaxCompleteEventDepth];
uint32_t current_stack_depth_ = 0;
- bool privacy_filtering_enabled_;
+ const bool privacy_filtering_enabled_;
};
} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/trace_event_agent.cc b/chromium/services/tracing/public/cpp/trace_event_agent.cc
index 510cb9d3a8d..684355de1f9 100644
--- a/chromium/services/tracing/public/cpp/trace_event_agent.cc
+++ b/chromium/services/tracing/public/cpp/trace_event_agent.cc
@@ -18,7 +18,7 @@
#include "base/trace_event/trace_log.h"
#include "base/values.h"
#include "build/build_config.h"
-#include "services/tracing/public/cpp/perfetto/producer_client.h"
+#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
#include "services/tracing/public/cpp/perfetto/trace_event_data_source.h"
#include "services/tracing/public/cpp/trace_event_args_whitelist.h"
#include "services/tracing/public/cpp/tracing_features.h"
@@ -56,7 +56,8 @@ TraceEventAgent::TraceEventAgent()
base::BindRepeating(&IsMetadataWhitelisted));
}
- ProducerClient::Get()->AddDataSource(TraceEventDataSource::GetInstance());
+ PerfettoTracedProcess::Get()->AddDataSource(
+ TraceEventDataSource::GetInstance());
}
TraceEventAgent::~TraceEventAgent() = default;
@@ -77,7 +78,7 @@ void TraceEventAgent::AddMetadataGeneratorFunction(
// call.
static TraceEventMetadataSource* metadata_source = []() {
static base::NoDestructor<TraceEventMetadataSource> instance;
- ProducerClient::Get()->AddDataSource(instance.get());
+ PerfettoTracedProcess::Get()->AddDataSource(instance.get());
return instance.get();
}();
diff --git a/chromium/services/tracing/public/cpp/trace_event_agent_unittest.cc b/chromium/services/tracing/public/cpp/trace_event_agent_unittest.cc
index 8578b723266..27ddafefc4c 100644
--- a/chromium/services/tracing/public/cpp/trace_event_agent_unittest.cc
+++ b/chromium/services/tracing/public/cpp/trace_event_agent_unittest.cc
@@ -83,7 +83,7 @@ class MockRecorder : public mojom::Recorder {
class TraceEventAgentTest : public testing::Test {
public:
- void SetUp() override { ProducerClient::ResetTaskRunnerForTesting(); }
+ void SetUp() override { PerfettoTracedProcess::ResetTaskRunnerForTesting(); }
void TearDown() override {
base::trace_event::TraceLog::GetInstance()->SetDisabled();
diff --git a/chromium/services/tracing/public/cpp/trace_event_args_whitelist.cc b/chromium/services/tracing/public/cpp/trace_event_args_whitelist.cc
index 2e622d8222e..3d1de85a037 100644
--- a/chromium/services/tracing/public/cpp/trace_event_args_whitelist.cc
+++ b/chromium/services/tracing/public/cpp/trace_event_args_whitelist.cc
@@ -29,12 +29,14 @@ const char* const kScopedBlockingCallAllowedArgs[] = {"file_name",
const char* const kGetFallbackFontsAllowedArgs[] = {"script", nullptr};
const char* const kGPUAllowedArgs[] = {nullptr};
const char* const kInputLatencyAllowedArgs[] = {"data", nullptr};
-const char* const kMemoryDumpAllowedArgs[] = {"dumps", nullptr};
+const char* const kMemoryDumpAllowedArgs[] = {"dumps", "top_queued_message_tag",
+ "count", nullptr};
const char* const kRendererHostAllowedArgs[] = {
"class", "line", "should_background", "has_pending_views",
"bytes_allocated", nullptr};
const char* const kV8GCAllowedArgs[] = {"num_items", "num_tasks", nullptr};
const char* const kTopLevelFlowAllowedArgs[] = {"task_queue_name", nullptr};
+const char* const kTopLevelIpcRunTaskAllowedArgs[] = {"ipc_hash", nullptr};
const WhitelistEntry kEventArgsWhitelist[] = {
{"__metadata", "thread_name", nullptr},
@@ -56,6 +58,7 @@ const WhitelistEntry kEventArgsWhitelist[] = {
{"startup", "PrefProvider::PrefProvider", nullptr},
{"task_scheduler", "*", nullptr},
{"toplevel", "*", nullptr},
+ {"toplevel.ipc", "TaskAnnotator::RunTask", kTopLevelIpcRunTaskAllowedArgs},
{TRACE_DISABLED_BY_DEFAULT("cpu_profiler"), "*", nullptr},
// Redefined the string since MemoryDumpManager::kTraceCategory causes
// static initialization of this struct.
diff --git a/chromium/services/tracing/public/cpp/trace_startup.cc b/chromium/services/tracing/public/cpp/trace_startup.cc
index 13a382f4f2e..f11df229dca 100644
--- a/chromium/services/tracing/public/cpp/trace_startup.cc
+++ b/chromium/services/tracing/public/cpp/trace_startup.cc
@@ -15,6 +15,11 @@
namespace tracing {
+namespace {
+using base::trace_event::TraceConfig;
+using base::trace_event::TraceLog;
+} // namespace
+
void EnableStartupTracingIfNeeded() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
@@ -27,29 +32,31 @@ void EnableStartupTracingIfNeeded() {
// Ensure TraceLog is initialized first.
// https://crbug.com/764357
- base::trace_event::TraceLog::GetInstance();
+ auto* trace_log = TraceLog::GetInstance();
+ auto* startup_config = TraceStartupConfig::GetInstance();
+
+ if (startup_config->IsEnabled()) {
+ if (TracingUsesPerfettoBackend()) {
+ TraceEventDataSource::GetInstance()->SetupStartupTracing(
+ startup_config->GetBackgroundStartupTracingEnabled());
+ }
- if (TraceStartupConfig::GetInstance()->IsEnabled()) {
- const base::trace_event::TraceConfig& trace_config =
- TraceStartupConfig::GetInstance()->GetTraceConfig();
- uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
+ const TraceConfig& trace_config = startup_config->GetTraceConfig();
+ uint8_t modes = TraceLog::RECORDING_MODE;
if (!trace_config.event_filters().empty())
- modes |= base::trace_event::TraceLog::FILTERING_MODE;
- if (TracingUsesPerfettoBackend())
- TraceEventDataSource::GetInstance()->SetupStartupTracing();
- base::trace_event::TraceLog::GetInstance()->SetEnabled(
- TraceStartupConfig::GetInstance()->GetTraceConfig(), modes);
+ modes |= TraceLog::FILTERING_MODE;
+ trace_log->SetEnabled(startup_config->GetTraceConfig(), modes);
} else if (command_line.HasSwitch(switches::kTraceToConsole)) {
// TODO(eseckler): Remove ability to trace to the console, perfetto doesn't
// support this and noone seems to use it.
- base::trace_event::TraceConfig trace_config = GetConfigForTraceToConsole();
+ TraceConfig trace_config = GetConfigForTraceToConsole();
LOG(ERROR) << "Start " << switches::kTraceToConsole
<< " with CategoryFilter '"
<< trace_config.ToCategoryFilterString() << "'.";
if (TracingUsesPerfettoBackend())
- TraceEventDataSource::GetInstance()->SetupStartupTracing();
- base::trace_event::TraceLog::GetInstance()->SetEnabled(
- trace_config, base::trace_event::TraceLog::RECORDING_MODE);
+ TraceEventDataSource::GetInstance()->SetupStartupTracing(
+ /*privacy_filtering_enabled=*/false);
+ trace_log->SetEnabled(trace_config, TraceLog::RECORDING_MODE);
}
}
diff --git a/chromium/services/tracing/public/cpp/traced_process_impl.cc b/chromium/services/tracing/public/cpp/traced_process_impl.cc
index 1824f7c5adb..ba11a2cdd24 100644
--- a/chromium/services/tracing/public/cpp/traced_process_impl.cc
+++ b/chromium/services/tracing/public/cpp/traced_process_impl.cc
@@ -45,6 +45,7 @@ void TracedProcessImpl::OnTracedProcessRequest(
return;
}
+ DETACH_FROM_SEQUENCE(sequence_checker_);
binding_.Bind(std::move(request));
}
@@ -73,12 +74,17 @@ void TracedProcessImpl::UnregisterAgent(BaseAgent* agent) {
}
void TracedProcessImpl::ConnectToTracingService(
- mojom::ConnectToTracingRequestPtr request) {
+ mojom::ConnectToTracingRequestPtr request,
+ ConnectToTracingServiceCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Acknowledge this message so the tracing service knows it was dispatched in
+ // this process.
+ std::move(callback).Run();
+
// Tracing requires a running ThreadPool; disable tracing
// for processes without it.
- if (!base::ThreadPool::GetInstance()) {
+ if (!base::ThreadPoolInstance::Get()) {
return;
}
@@ -102,7 +108,7 @@ void TracedProcessImpl::ConnectToTracingService(
agent->Connect(agent_registry_.get());
}
- ProducerClient::Get()->Connect(
+ PerfettoTracedProcess::Get()->producer_client()->Connect(
tracing::mojom::PerfettoServicePtr(std::move(request->perfetto_service)));
}
diff --git a/chromium/services/tracing/public/cpp/traced_process_impl.h b/chromium/services/tracing/public/cpp/traced_process_impl.h
index efd5f313710..a67e2ca61cd 100644
--- a/chromium/services/tracing/public/cpp/traced_process_impl.h
+++ b/chromium/services/tracing/public/cpp/traced_process_impl.h
@@ -46,7 +46,8 @@ class COMPONENT_EXPORT(TRACING_CPP) TracedProcessImpl
// tracing::mojom::TracedProcess:
void ConnectToTracingService(
- mojom::ConnectToTracingRequestPtr request) override;
+ mojom::ConnectToTracingRequestPtr request,
+ ConnectToTracingServiceCallback callback) override;
// Lock protecting binding_.
base::Lock lock_;
diff --git a/chromium/services/tracing/public/cpp/tracing_features.cc b/chromium/services/tracing/public/cpp/tracing_features.cc
index ee6a39798d8..9a20fc7860c 100644
--- a/chromium/services/tracing/public/cpp/tracing_features.cc
+++ b/chromium/services/tracing/public/cpp/tracing_features.cc
@@ -19,10 +19,19 @@ namespace features {
const base::Feature kTracingPerfettoBackend{"TracingPerfettoBackend",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Causes the BackgroundTracingManager to upload proto messages via UMA,
+// rather than JSON via the crash frontend.
+const base::Feature kBackgroundTracingProtoOutput{
+ "BackgroundTracingProtoOutput", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Causes Perfetto to run in-process mode for in-process tracing producers.
+const base::Feature kPerfettoForceOutOfProcessProducer{
+ "PerfettoForceOutOfProcessProducer", base::FEATURE_ENABLED_BY_DEFAULT};
+
// Runs the tracing service as an in-process browser service.
const base::Feature kTracingServiceInProcess {
"TracingServiceInProcess",
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(IS_CHROMECAST)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/chromium/services/tracing/public/cpp/tracing_features.h b/chromium/services/tracing/public/cpp/tracing_features.h
index fca060e4ab8..ef0bbe85b3c 100644
--- a/chromium/services/tracing/public/cpp/tracing_features.h
+++ b/chromium/services/tracing/public/cpp/tracing_features.h
@@ -21,6 +21,12 @@ extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature
extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature
kTracingServiceInProcess;
+extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature
+ kBackgroundTracingProtoOutput;
+
+extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature
+ kPerfettoForceOutOfProcessProducer;
+
} // namespace features
namespace tracing {
diff --git a/chromium/services/tracing/public/mojom/perfetto_service.mojom b/chromium/services/tracing/public/mojom/perfetto_service.mojom
index 97b707f7a92..799b2c4997c 100644
--- a/chromium/services/tracing/public/mojom/perfetto_service.mojom
+++ b/chromium/services/tracing/public/mojom/perfetto_service.mojom
@@ -149,42 +149,77 @@ struct DataSource {
array<string> producer_name_filter;
};
+struct PerfettoBuiltinDataSource {
+ bool disable_clock_snapshotting;
+ bool disable_trace_config;
+ bool disable_system_info;
+};
+
// The configuration provided by a Consumer to the Perfetto service which
// primarily configures which named data sources it would like to enable and
// receive tracing data from, and how large the destination buffers should be.
struct TraceConfig {
array<DataSource> data_sources;
+ PerfettoBuiltinDataSource perfetto_builtin_data_source;
array<BufferConfig> buffers;
uint32 duration_ms;
};
+// The priority of the incoming EnableTracing request, used to determine
+// whether the session should take precedence over another existing session,
+// and/or whether a later session should abort the current one. Ordered in
+// ascending priority.
+enum TracingClientPriority {
+ kUnknown,
+ kBackground,
+ kUserInitiated
+};
+
// The ConsumerHost interface is a privileged interface which is implemented
// within the tracing service, and connected to by privileged services
// (i.e. content_browser) to receive tracing data.
interface ConsumerHost {
- // Enable Perfetto tracing with the given TracingSession interface for
+ // Enable Perfetto tracing with the given TracingSessionClient interface for
// signaling lifespan of the tracing session, and any future callbacks.
- EnableTracing(TracingSession tracing_session, TraceConfig config);
+ // The given TracingSessionHost is used to control the tracing session and
+ // closing it will disable tracing and free the session's trace buffers.
+ // Note: Right now only a single concurrent tracing session is supported,
+ // as there's no support for multiplexing enabled trace events to multiple
+ // consumers. If a new tracing session is attempted while there's an existing
+ // one in progress, the relative priorities will be used to figure out which
+ // one to be able to (keep) tracing; if the priorities are the same, the new
+ // session will take precedence.
+ EnableTracing(TracingSessionHost& tracing_session_host,
+ TracingSessionClient tracing_session_client,
+ TraceConfig config,
+ TracingClientPriority priority);
+};
+// Represents the host side of an active tracing session. Closing this
+// will disable tracing.
+interface TracingSessionHost {
// Update the trace config for the active tracing session. Currently, only
// (additive) updates to the |producer_name_filter| of a data source are
// supported.
ChangeTraceConfig(TraceConfig config);
- // Stop tracing for the active tracing session. The host will disconnect the
- // TracingSession once tracing was disabled. Note that tracing may also stop
- // without an explicit call to DisableTracing(), e.g. when a tracing duration
- // is specified in the TraceConfig.
+ // Stop tracing for the active tracing session. Note that tracing may also
+ // stop without an explicit call to DisableTracing(), e.g. when a tracing
+ // duration is specified in the TraceConfig.
DisableTracing();
// Tell Perfetto we're ready to receive data, over the given data pipe.
// The result callback will be called when there's no more data currently
- // available. If the TracingSession is still active after the callback,
+ // available. If the TracingSessionClient is still active after the callback,
// another call to ReadBuffers() needs to be made to receive any new
// tracing data.
ReadBuffers(handle<data_pipe_producer> stream) => ();
+ // Request current trace buffer usage of the active session. Will be returned
+ // as percentage value between 0.0f and 1.0f.
+ RequestBufferUsage() => (bool success, float percent_full);
+
// Disables tracing and converts the collected trace data converted into the
// legacy JSON format before returning it via the data pipe. If
// |agent_label_filter| is not empty, only data pertaining to the specified
@@ -194,20 +229,17 @@ interface ConsumerHost {
// streaming proto format via ReadBuffers.
DisableTracingAndEmitJson(string agent_label_filter,
handle<data_pipe_producer> stream) => ();
-
- // Request current trace buffer usage of the active session. Will be returned
- // as percentage value between 0.0f and 1.0f.
- RequestBufferUsage() => (bool success, float percent_full);
};
-// Any client connecting to ConsumerHost should implement this
-// interface which represents the lifetime of an active tracing
-// session. The ConsumerHost will disconnect it when tracing
-// is stopped, at which point the client can know that one
-// more ReadBuffers() call will receive any remaining tracing
-// data from the session (in addition to any calls it may have
-// made while the session is active, to stream out data).
-interface TracingSession {
+// Any client connecting to ConsumerHost should implement this interface which
+// represents the lifetime of an active tracing session, i.e. from the point
+// where tracing is enabled, to the point where all tracing data has been
+// received by the client.
+interface TracingSessionClient {
// Called when all processes have begun tracing.
OnTracingEnabled();
+ // Called when tracing is disabled; initiated either by a call to
+ // TracingSessionHost::DisableTracing or by the service itself if a timeout is
+ // specified in the tracing config.
+ OnTracingDisabled();
};
diff --git a/chromium/services/tracing/public/mojom/perfetto_service.typemap b/chromium/services/tracing/public/mojom/perfetto_service.typemap
index 5bec6e49054..2671fac9069 100644
--- a/chromium/services/tracing/public/mojom/perfetto_service.typemap
+++ b/chromium/services/tracing/public/mojom/perfetto_service.typemap
@@ -36,5 +36,6 @@ type_mappings = [
"tracing.mojom.DataSourceConfig=perfetto::DataSourceConfig",
"tracing.mojom.ChromeConfig=perfetto::ChromeConfig",
"tracing.mojom.DataSourceRegistration=perfetto::DataSourceDescriptor",
+ "tracing.mojom.PerfettoBuiltinDataSource=perfetto::TraceConfig::BuiltinDataSource",
"tracing.mojom.TraceConfig=perfetto::TraceConfig",
]
diff --git a/chromium/services/tracing/public/mojom/trace_config_mojom_traits.cc b/chromium/services/tracing/public/mojom/trace_config_mojom_traits.cc
index 649fbe92b05..9e78d913d50 100644
--- a/chromium/services/tracing/public/mojom/trace_config_mojom_traits.cc
+++ b/chromium/services/tracing/public/mojom/trace_config_mojom_traits.cc
@@ -45,11 +45,24 @@ bool StructTraits<tracing::mojom::DataSourceDataView,
}
// static
+bool StructTraits<tracing::mojom::PerfettoBuiltinDataSourceDataView,
+ perfetto::TraceConfig::BuiltinDataSource>::
+ Read(tracing::mojom::PerfettoBuiltinDataSourceDataView data,
+ perfetto::TraceConfig::BuiltinDataSource* out) {
+ out->set_disable_clock_snapshotting(data.disable_clock_snapshotting());
+ out->set_disable_trace_config(data.disable_trace_config());
+ out->set_disable_system_info(data.disable_system_info());
+ return true;
+}
+
+// static
bool StructTraits<tracing::mojom::TraceConfigDataView, perfetto::TraceConfig>::
Read(tracing::mojom::TraceConfigDataView data, perfetto::TraceConfig* out) {
std::vector<perfetto::TraceConfig::DataSource> data_sources;
std::vector<perfetto::TraceConfig::BufferConfig> buffers;
- if (!data.ReadDataSources(&data_sources) || !data.ReadBuffers(&buffers)) {
+ if (!data.ReadDataSources(&data_sources) || !data.ReadBuffers(&buffers) ||
+ !data.ReadPerfettoBuiltinDataSource(
+ out->mutable_builtin_data_sources())) {
return false;
}
diff --git a/chromium/services/tracing/public/mojom/trace_config_mojom_traits.h b/chromium/services/tracing/public/mojom/trace_config_mojom_traits.h
index 018d1bd1896..bb274ef4057 100644
--- a/chromium/services/tracing/public/mojom/trace_config_mojom_traits.h
+++ b/chromium/services/tracing/public/mojom/trace_config_mojom_traits.h
@@ -49,6 +49,30 @@ class StructTraits<tracing::mojom::DataSourceDataView,
perfetto::TraceConfig::DataSource* out);
};
+// perfetto::TraceConfig::BuiltinDataSource
+template <>
+class StructTraits<tracing::mojom::PerfettoBuiltinDataSourceDataView,
+ perfetto::TraceConfig::BuiltinDataSource> {
+ public:
+ static bool disable_clock_snapshotting(
+ const perfetto::TraceConfig::BuiltinDataSource& src) {
+ return src.disable_clock_snapshotting();
+ }
+
+ static bool disable_trace_config(
+ const perfetto::TraceConfig::BuiltinDataSource& src) {
+ return src.disable_trace_config();
+ }
+
+ static bool disable_system_info(
+ const perfetto::TraceConfig::BuiltinDataSource& src) {
+ return src.disable_system_info();
+ }
+
+ static bool Read(tracing::mojom::PerfettoBuiltinDataSourceDataView data,
+ perfetto::TraceConfig::BuiltinDataSource* out);
+};
+
// perfetto::TraceConfig
template <>
class StructTraits<tracing::mojom::TraceConfigDataView, perfetto::TraceConfig> {
@@ -58,6 +82,11 @@ class StructTraits<tracing::mojom::TraceConfigDataView, perfetto::TraceConfig> {
return src.data_sources();
}
+ static const perfetto::TraceConfig::BuiltinDataSource&
+ perfetto_builtin_data_source(const perfetto::TraceConfig& src) {
+ return src.builtin_data_sources();
+ }
+
static const std::vector<perfetto::TraceConfig::BufferConfig>& buffers(
const perfetto::TraceConfig& src) {
return src.buffers();
diff --git a/chromium/services/tracing/public/mojom/traced_process.mojom b/chromium/services/tracing/public/mojom/traced_process.mojom
index b1d8040907e..7b443cee6ac 100644
--- a/chromium/services/tracing/public/mojom/traced_process.mojom
+++ b/chromium/services/tracing/public/mojom/traced_process.mojom
@@ -20,7 +20,7 @@ struct ConnectToTracingRequest {
// and pass it pointers to the interfaces within the tracing service
// that the other services should register themselves with.
interface TracedProcess {
- ConnectToTracingService(ConnectToTracingRequest request);
+ ConnectToTracingService(ConnectToTracingRequest request) => ();
};
diff --git a/chromium/services/tracing/tracing_service.cc b/chromium/services/tracing/tracing_service.cc
index 6d04bca0b47..4ab07c9645d 100644
--- a/chromium/services/tracing/tracing_service.cc
+++ b/chromium/services/tracing/tracing_service.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/stl_util.h"
#include "base/timer/timer.h"
#include "services/service_manager/public/mojom/service_manager.mojom.h"
#include "services/tracing/agent_registry.h"
@@ -29,8 +30,7 @@ class ServiceListener : public service_manager::mojom::ServiceManagerListener {
ServiceListener(service_manager::Connector* connector,
AgentRegistry* agent_registry,
Coordinator* coordinator)
- : binding_(this),
- connector_(connector),
+ : connector_(connector),
agent_registry_(agent_registry),
coordinator_(coordinator) {
service_manager::mojom::ServiceManagerPtr service_manager;
@@ -45,25 +45,31 @@ class ServiceListener : public service_manager::mojom::ServiceManagerListener {
size_t CountServicesWithPID(uint32_t pid) {
return std::count_if(service_pid_map_.begin(), service_pid_map_.end(),
- [pid](decltype(service_pid_map_)::value_type p) {
- return p.second == pid;
- });
+ [pid](const auto& p) { return p.second == pid; });
}
void ServiceAddedWithPID(const service_manager::Identity& identity,
uint32_t pid) {
service_pid_map_[identity] = pid;
- // Not the first service added, so we're already sent it a connection
- // request.
- if (CountServicesWithPID(pid) > 1) {
+
+ // Not the first service added for this PID, and the process has already
+ // accepted a connection request.
+ if (base::ContainsKey(connected_pids_, pid))
return;
- }
// Let the Coordinator and the perfetto service know it should be expecting
// a connection from this process.
coordinator_->AddExpectedPID(pid);
PerfettoService::GetInstance()->AddActiveServicePid(pid);
+ // NOTE: If multiple service instances are running in the same process, we
+ // may send multiple ConnectToTracingService calls to the same process in
+ // the time it takes the first call to be received and acknowledged. This is
+ // OK, because any given client process will only bind a single
+ // TracedProcess endpoint as long as this instance of the tracing service
+ // remains alive. Subsequent TracedProcess endpoints will be dropped and
+ // their calls will never be processed.
+
mojom::TracedProcessPtr traced_process;
connector_->BindInterface(
service_manager::ServiceFilter::ForExactIdentity(identity),
@@ -71,14 +77,17 @@ class ServiceListener : public service_manager::mojom::ServiceManagerListener {
service_manager::mojom::BindInterfacePriority::kBestEffort);
auto new_connection_request = mojom::ConnectToTracingRequest::New();
-
- PerfettoService::GetInstance()->BindRequest(
- mojo::MakeRequest(&new_connection_request->perfetto_service), pid);
-
- agent_registry_->BindAgentRegistryRequest(
- mojo::MakeRequest(&new_connection_request->agent_registry));
-
- traced_process->ConnectToTracingService(std::move(new_connection_request));
+ auto service_request =
+ mojo::MakeRequest(&new_connection_request->perfetto_service);
+ auto registry_request =
+ mojo::MakeRequest(&new_connection_request->agent_registry);
+ mojom::TracedProcess* raw_traced_process = traced_process.get();
+ raw_traced_process->ConnectToTracingService(
+ std::move(new_connection_request),
+ base::BindOnce(&ServiceListener::OnProcessConnected,
+ base::Unretained(this), std::move(traced_process), pid,
+ std::move(service_request),
+ std::move(registry_request)));
}
void ServiceRemoved(const service_manager::Identity& identity) {
@@ -91,6 +100,7 @@ class ServiceListener : public service_manager::mojom::ServiceManagerListener {
if (CountServicesWithPID(pid) == 0) {
coordinator_->RemoveExpectedPID(pid);
PerfettoService::GetInstance()->RemoveActiveServicePid(pid);
+ connected_pids_.erase(pid);
}
}
}
@@ -130,11 +140,30 @@ class ServiceListener : public service_manager::mojom::ServiceManagerListener {
service_manager::mojom::RunningServiceInfoPtr service) override {}
private:
- mojo::Binding<service_manager::mojom::ServiceManagerListener> binding_;
- service_manager::Connector* connector_;
- AgentRegistry* agent_registry_;
- Coordinator* coordinator_;
+ void OnProcessConnected(mojom::TracedProcessPtr traced_process,
+ uint32_t pid,
+ mojom::PerfettoServiceRequest service_request,
+ mojom::AgentRegistryRequest registry_request) {
+ auto result = connected_pids_.insert(pid);
+ if (!result.second) {
+ // The PID was already connected. Nothing more to do.
+ return;
+ }
+
+ connected_pids_.insert(pid);
+ PerfettoService::GetInstance()->BindRequest(std::move(service_request),
+ pid);
+ agent_registry_->BindAgentRegistryRequest(std::move(registry_request));
+ }
+
+ mojo::Binding<service_manager::mojom::ServiceManagerListener> binding_{this};
+ service_manager::Connector* const connector_;
+ AgentRegistry* const agent_registry_;
+ Coordinator* const coordinator_;
std::map<service_manager::Identity, uint32_t> service_pid_map_;
+ std::set<uint32_t> connected_pids_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceListener);
};
TracingService::TracingService(service_manager::mojom::ServiceRequest request)