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