1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/tracing/public/cpp/trace_startup.h"
6
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/task/thread_pool/thread_pool_instance.h"
10 #include "base/trace_event/trace_log.h"
11 #include "components/tracing/common/trace_startup_config.h"
12 #include "components/tracing/common/trace_to_console.h"
13 #include "components/tracing/common/tracing_switches.h"
14 #include "services/tracing/public/cpp/perfetto/producer_client.h"
15 #include "services/tracing/public/cpp/perfetto/system_producer.h"
16 #include "services/tracing/public/cpp/perfetto/trace_event_data_source.h"
17 #include "services/tracing/public/cpp/trace_event_agent.h"
18 #include "services/tracing/public/cpp/trace_event_args_whitelist.h"
19 #include "services/tracing/public/cpp/tracing_features.h"
20 #include "third_party/perfetto/include/perfetto/tracing/track.h"
21
22 namespace tracing {
23 namespace {
24
25 using base::trace_event::TraceConfig;
26 using base::trace_event::TraceLog;
27
28 } // namespace
29
30 bool g_tracing_initialized_after_threadpool_and_featurelist = false;
31
IsTracingInitialized()32 bool IsTracingInitialized() {
33 return g_tracing_initialized_after_threadpool_and_featurelist;
34 }
35
EnableStartupTracingIfNeeded()36 void EnableStartupTracingIfNeeded() {
37 const base::CommandLine& command_line =
38 *base::CommandLine::ForCurrentProcess();
39
40 TraceEventDataSource::GetInstance()->RegisterStartupHooks();
41 // TODO(eseckler): Initialize the entire perfetto client library instead.
42 perfetto::internal::TrackRegistry::InitializeInstance();
43
44 // TODO(oysteine): Support startup tracing to a perfetto protobuf trace. This
45 // should also enable TraceLog and call SetupStartupTracing().
46 if (command_line.HasSwitch(switches::kPerfettoOutputFile))
47 return;
48
49 // Ensure TraceLog is initialized first.
50 // https://crbug.com/764357
51 TraceLog::GetInstance();
52 auto* startup_config = TraceStartupConfig::GetInstance();
53
54 if (startup_config->IsEnabled()) {
55 // Ensure that data sources are created and registered.
56 TraceEventAgent::GetInstance();
57
58 TraceConfig trace_config = startup_config->GetTraceConfig();
59
60 PerfettoProducer* producer =
61 PerfettoTracedProcess::Get()->producer_client();
62 if (startup_config->GetSessionOwner() ==
63 TraceStartupConfig::SessionOwner::kSystemTracing) {
64 producer = PerfettoTracedProcess::Get()->system_producer();
65 }
66
67 bool privacy_filtering_enabled =
68 startup_config->GetSessionOwner() ==
69 TraceStartupConfig::SessionOwner::kBackgroundTracing ||
70 command_line.HasSwitch(switches::kTraceStartupEnablePrivacyFiltering);
71
72 if (!PerfettoTracedProcess::Get()->SetupStartupTracing(
73 producer, trace_config, privacy_filtering_enabled)) {
74 startup_config->SetDisabled();
75 }
76 }
77 }
78
EnableStartupTracingForProcess(const base::trace_event::TraceConfig & trace_config,bool privacy_filtering_enabled)79 bool EnableStartupTracingForProcess(
80 const base::trace_event::TraceConfig& trace_config,
81 bool privacy_filtering_enabled) {
82 return PerfettoTracedProcess::Get()->SetupStartupTracing(
83 PerfettoTracedProcess::Get()->producer_client(), trace_config,
84 privacy_filtering_enabled);
85 }
86
InitTracingPostThreadPoolStartAndFeatureList()87 void InitTracingPostThreadPoolStartAndFeatureList() {
88 if (g_tracing_initialized_after_threadpool_and_featurelist)
89 return;
90 g_tracing_initialized_after_threadpool_and_featurelist = true;
91 // TODO(nuskos): We should switch these to DCHECK once we're reasonably
92 // confident we've ensured this is called properly in all processes. Probably
93 // after M78 release has been cut (since we'll verify in the rollout of M78).
94 CHECK(base::ThreadPoolInstance::Get());
95 CHECK(base::FeatureList::GetInstance());
96
97 PerfettoTracedProcess::Get()->OnThreadPoolAvailable();
98
99 if (ShouldSetupSystemTracing()) {
100 // Ensure that data sources are created and registered.
101 TraceEventAgent::GetInstance();
102 // Connect to system service if available (currently a no-op except on
103 // Posix). Has to happen on the producer's sequence, as all communication
104 // with the system Perfetto service should occur on a single sequence.
105 PerfettoTracedProcess::Get()
106 ->GetTaskRunner()
107 ->GetOrCreateTaskRunner()
108 ->PostTask(FROM_HERE, base::BindOnce([]() {
109 PerfettoTracedProcess::Get()
110 ->system_producer()
111 ->ConnectToSystemService();
112 }));
113 }
114 }
115
PropagateTracingFlagsToChildProcessCmdLine(base::CommandLine * cmd_line)116 void PropagateTracingFlagsToChildProcessCmdLine(base::CommandLine* cmd_line) {
117 base::trace_event::TraceLog* trace_log =
118 base::trace_event::TraceLog::GetInstance();
119
120 if (!trace_log->IsEnabled())
121 return;
122
123 // It's possible that tracing is enabled only for atrace, in which case the
124 // TraceEventDataSource isn't registered. In that case, there's no reason to
125 // enable startup tracing in the child process (and we wouldn't know the
126 // correct value for privacy_filtering_enabled below).
127 if (!TraceEventDataSource::GetInstance()->IsEnabled())
128 return;
129
130 // (Posix)SystemProducer doesn't currently support startup tracing, so don't
131 // attempt to enable startup tracing in child processes if system tracing is
132 // active.
133 if (PerfettoTracedProcess::Get()->system_producer()->IsTracingActive())
134 return;
135
136 // The child process startup may race with a concurrent disabling of the
137 // tracing session by the tracing service. To avoid being stuck in startup
138 // tracing mode forever, the child process will discard the startup session
139 // after a timeout (|startup_tracing_timer_| in TraceEventDataSource).
140 //
141 // Note that we disregard the config's process filter, since it's possible
142 // that the trace consumer will update the config to include the process
143 // shortly. Otherwise, the startup tracing timeout in the child will
144 // eventually disable tracing for the process.
145
146 const auto trace_config = trace_log->GetCurrentTraceConfig();
147
148 // We can't currently propagate event filter options, memory dump configs, or
149 // trace buffer sizes via command line flags (they only support categories,
150 // trace options, record mode). If event filters are set, we bail out here to
151 // avoid recording events that we shouldn't in the child process. Even if
152 // memory dump config is set, it's OK to propagate the remaining config,
153 // because the child won't record events it shouldn't without it and will
154 // adopt the memory dump config once it connects to the tracing service.
155 // Buffer sizes configure the tracing service's central buffer, so also don't
156 // affect local tracing.
157 //
158 // TODO(eseckler): Support propagating the full config via command line flags
159 // somehow (--trace-config?). This will also need some rethinking to support
160 // multiple concurrent tracing sessions in the future.
161 if (!trace_config.event_filters().empty())
162 return;
163
164 // Make sure that the startup session uses privacy filtering mode if it's
165 // enabled for the browser's session.
166 if (TraceEventDataSource::GetInstance()->privacy_filtering_enabled())
167 cmd_line->AppendSwitch(switches::kTraceStartupEnablePrivacyFiltering);
168
169 cmd_line->AppendSwitchASCII(switches::kTraceStartup,
170 trace_config.ToCategoryFilterString());
171 // The argument filtering setting is passed via trace options as part of
172 // --trace-startup-record-mode.
173 cmd_line->AppendSwitchASCII(switches::kTraceStartupRecordMode,
174 trace_config.ToTraceOptionsString());
175 }
176
177 } // namespace tracing
178