1 // Copyright (c) 2013 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 "content/browser/tracing/tracing_controller_impl.h"
6 
7 #include <inttypes.h>
8 #include <memory>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/command_line.h"
15 #include "base/cpu.h"
16 #include "base/files/file_tracing.h"
17 #include "base/logging.h"
18 #include "base/run_loop.h"
19 #include "base/strings/string_split.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/system/sys_info.h"
22 #include "base/time/time.h"
23 #include "base/trace_event/trace_config.h"
24 #include "base/values.h"
25 #include "build/build_config.h"
26 #include "components/tracing/common/trace_startup_config.h"
27 #include "components/tracing/common/trace_to_console.h"
28 #include "components/tracing/common/tracing_switches.h"
29 #include "content/browser/gpu/gpu_data_manager_impl.h"
30 #include "content/browser/tracing/file_tracing_provider_impl.h"
31 #include "content/browser/tracing/perfetto_file_tracer.h"
32 #include "content/browser/tracing/tracing_ui.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/content_browser_client.h"
35 #include "content/public/browser/tracing_controller.h"
36 #include "content/public/browser/tracing_delegate.h"
37 #include "content/public/browser/tracing_service.h"
38 #include "content/public/common/content_client.h"
39 #include "gpu/config/gpu_info.h"
40 #include "mojo/public/cpp/system/data_pipe.h"
41 #include "net/base/network_change_notifier.h"
42 #include "services/tracing/public/cpp/perfetto/perfetto_config.h"
43 #include "services/tracing/public/cpp/trace_event_agent.h"
44 #include "services/tracing/public/cpp/traced_process_impl.h"
45 #include "services/tracing/public/cpp/tracing_features.h"
46 #include "services/tracing/public/mojom/constants.mojom.h"
47 #include "v8/include/v8-version-string.h"
48 
49 #if defined(OS_CHROMEOS)
50 #include "chromeos/dbus/dbus_thread_manager.h"
51 #include "chromeos/dbus/debug_daemon/debug_daemon_client.h"
52 #include "chromeos/system/statistics_provider.h"
53 #include "content/browser/tracing/cros_tracing_agent.h"
54 #endif
55 
56 #if defined(CAST_TRACING_AGENT)
57 #include "content/browser/tracing/cast_tracing_agent.h"
58 #endif
59 
60 #if defined(OS_WIN)
61 #include "base/win/registry.h"
62 #include "base/win/win_util.h"
63 #include "base/win/windows_version.h"
64 #endif
65 
66 #if defined(OS_ANDROID)
67 #include <sys/time.h>
68 #include "base/debug/elf_reader.h"
69 #include "content/browser/android/tracing_controller_android.h"
70 #include "services/tracing/public/cpp/perfetto/java_heap_profiler/java_heap_profiler_android.h"
71 
72 // Symbol with virtual address of the start of ELF header of the current binary.
73 extern char __ehdr_start;
74 #endif  // defined(OS_ANDROID)
75 
76 namespace content {
77 
78 namespace {
79 
80 TracingControllerImpl* g_tracing_controller = nullptr;
81 
GetNetworkTypeString()82 std::string GetNetworkTypeString() {
83   switch (net::NetworkChangeNotifier::GetConnectionType()) {
84     case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
85       return "Ethernet";
86     case net::NetworkChangeNotifier::CONNECTION_WIFI:
87       return "WiFi";
88     case net::NetworkChangeNotifier::CONNECTION_2G:
89       return "2G";
90     case net::NetworkChangeNotifier::CONNECTION_3G:
91       return "3G";
92     case net::NetworkChangeNotifier::CONNECTION_4G:
93       return "4G";
94     case net::NetworkChangeNotifier::CONNECTION_NONE:
95       return "None";
96     case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
97       return "Bluetooth";
98     case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
99     default:
100       break;
101   }
102   return "Unknown";
103 }
104 
GetClockString()105 std::string GetClockString() {
106   switch (base::TimeTicks::GetClock()) {
107     case base::TimeTicks::Clock::FUCHSIA_ZX_CLOCK_MONOTONIC:
108       return "FUCHSIA_ZX_CLOCK_MONOTONIC";
109     case base::TimeTicks::Clock::LINUX_CLOCK_MONOTONIC:
110       return "LINUX_CLOCK_MONOTONIC";
111     case base::TimeTicks::Clock::IOS_CF_ABSOLUTE_TIME_MINUS_KERN_BOOTTIME:
112       return "IOS_CF_ABSOLUTE_TIME_MINUS_KERN_BOOTTIME";
113     case base::TimeTicks::Clock::MAC_MACH_ABSOLUTE_TIME:
114       return "MAC_MACH_ABSOLUTE_TIME";
115     case base::TimeTicks::Clock::WIN_QPC:
116       return "WIN_QPC";
117     case base::TimeTicks::Clock::WIN_ROLLOVER_PROTECTED_TIME_GET_TIME:
118       return "WIN_ROLLOVER_PROTECTED_TIME_GET_TIME";
119   }
120 
121   NOTREACHED();
122   return std::string();
123 }
124 
125 #if defined(OS_ANDROID)
ConvertTimespecToMicros(const struct timespec & ts)126 int64_t ConvertTimespecToMicros(const struct timespec& ts) {
127   // On 32-bit systems, the calculation cannot overflow int64_t.
128   // 2**32 * 1000000 + 2**64 / 1000 < 2**63
129   if (sizeof(ts.tv_sec) <= 4 && sizeof(ts.tv_nsec) <= 8) {
130     int64_t result = ts.tv_sec;
131     result *= base::Time::kMicrosecondsPerSecond;
132     result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond);
133     return result;
134   }
135   base::CheckedNumeric<int64_t> result(ts.tv_sec);
136   result *= base::Time::kMicrosecondsPerSecond;
137   result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond);
138   return result.ValueOrDie();
139 }
140 
141 // This returns the offset between the monotonic clock and the realtime clock.
142 // We could read btime from /proc/status files; however, btime can be off by
143 // around 1s, which is too much. The following method should give us a better
144 // approximation of the offset.
GetClockOffsetSinceEpoch()145 std::string GetClockOffsetSinceEpoch() {
146   struct timespec realtime_before, monotonic, realtime_after;
147   clock_gettime(CLOCK_REALTIME, &realtime_before);
148   clock_gettime(CLOCK_MONOTONIC, &monotonic);
149   clock_gettime(CLOCK_REALTIME, &realtime_after);
150   return base::StringPrintf("%" PRId64,
151                             ConvertTimespecToMicros(realtime_before) / 2 +
152                                 ConvertTimespecToMicros(realtime_after) / 2 -
153                                 ConvertTimespecToMicros(monotonic));
154 }
155 #endif
156 
OnStoppedStartupTracing(const base::FilePath & trace_file)157 void OnStoppedStartupTracing(const base::FilePath& trace_file) {
158   VLOG(0) << "Completed startup tracing to " << trace_file.value();
159   tracing::TraceStartupConfig::GetInstance()->OnTraceToResultFileFinished();
160 }
161 
162 }  // namespace
163 
GetInstance()164 TracingController* TracingController::GetInstance() {
165   return TracingControllerImpl::GetInstance();
166 }
167 
TracingControllerImpl()168 TracingControllerImpl::TracingControllerImpl()
169     : delegate_(GetContentClient()->browser()->GetTracingDelegate()) {
170   DCHECK(!g_tracing_controller);
171   DCHECK_CURRENTLY_ON(BrowserThread::UI);
172   // Deliberately leaked, like this class.
173   base::FileTracing::SetProvider(new FileTracingProviderImpl);
174   AddAgents();
175   g_tracing_controller = this;
176 
177   // TODO(oysteine): Startup tracing using Perfetto
178   // is enabled by the Mojo consumer in content/browser
179   // for now; this is too late in the browser startup
180   // process however.
181   if (PerfettoFileTracer::ShouldEnable())
182     perfetto_file_tracer_ = std::make_unique<PerfettoFileTracer>();
183 
184 #if defined(OS_CHROMEOS)
185   // Bind hwclass once the statistics are available.
186   chromeos::system::StatisticsProvider::GetInstance()
187       ->ScheduleOnMachineStatisticsLoaded(
188           base::BindOnce(&TracingControllerImpl::OnMachineStatisticsLoaded,
189                          weak_ptr_factory_.GetWeakPtr()));
190 #endif
191 }
192 
193 TracingControllerImpl::~TracingControllerImpl() = default;
194 
AddAgents()195 void TracingControllerImpl::AddAgents() {
196   tracing::TracedProcessImpl::GetInstance()->SetTaskRunner(
197       base::SequencedTaskRunnerHandle::Get());
198 
199 #if defined(OS_CHROMEOS)
200   agents_.push_back(std::make_unique<CrOSTracingAgent>());
201 #elif defined(CAST_TRACING_AGENT)
202   agents_.push_back(std::make_unique<CastTracingAgent>());
203 #endif
204 
205   // For adding general CPU, network, OS, and other system information to the
206   // metadata.
207   auto* trace_event_agent = tracing::TraceEventAgent::GetInstance();
208   trace_event_agent->AddMetadataGeneratorFunction(base::BindRepeating(
209       &TracingControllerImpl::GenerateMetadataDict, base::Unretained(this)));
210   if (delegate_) {
211     trace_event_agent->AddMetadataGeneratorFunction(
212         base::BindRepeating(&TracingDelegate::GenerateMetadataDict,
213                             base::Unretained(delegate_.get())));
214   }
215 #if defined(OS_ANDROID)
216   tracing::PerfettoTracedProcess::Get()->AddDataSource(
217       tracing::JavaHeapProfiler::GetInstance());
218 #endif
219 }
220 
ConnectToServiceIfNeeded()221 void TracingControllerImpl::ConnectToServiceIfNeeded() {
222   if (!consumer_host_) {
223     GetTracingService().BindConsumerHost(
224         consumer_host_.BindNewPipeAndPassReceiver());
225     consumer_host_.reset_on_disconnect();
226   }
227 }
228 
229 // Can be called on any thread.
230 std::unique_ptr<base::DictionaryValue>
GenerateMetadataDict()231 TracingControllerImpl::GenerateMetadataDict() {
232   DCHECK_CURRENTLY_ON(BrowserThread::UI);
233   auto metadata_dict = std::make_unique<base::DictionaryValue>();
234 
235   metadata_dict->SetString("network-type", GetNetworkTypeString());
236   metadata_dict->SetString("product-version",
237                            GetContentClient()->browser()->GetProduct());
238   metadata_dict->SetString("v8-version", V8_VERSION_STRING);
239   metadata_dict->SetString("user-agent",
240                            GetContentClient()->browser()->GetUserAgent());
241 
242 #if defined(OS_ANDROID)
243   // The library name is used for symbolizing heap profiles. This cannot be
244   // obtained from process maps since library can be mapped from apk directly.
245   // This is not added as part of memory-infra os dumps since it is special case
246   // only for chrome library.
247   base::Optional<base::StringPiece> soname =
248       base::debug::ReadElfLibraryName(&__ehdr_start);
249   if (soname)
250     metadata_dict->SetString("chrome-library-name", *soname);
251   metadata_dict->SetString("clock-offset-since-epoch",
252                            GetClockOffsetSinceEpoch());
253 #endif  // defined(OS_ANDROID)
254   metadata_dict->SetInteger("chrome-bitness", 8 * sizeof(uintptr_t));
255 
256   // OS
257 #if defined(OS_CHROMEOS)
258   metadata_dict->SetString("os-name", "CrOS");
259   if (are_statistics_loaded_)
260     metadata_dict->SetString("hardware-class", hardware_class_);
261 #else
262   metadata_dict->SetString("os-name", base::SysInfo::OperatingSystemName());
263 #endif  // defined(OS_CHROMEOS)
264   metadata_dict->SetString("os-version",
265                            base::SysInfo::OperatingSystemVersion());
266 #if defined(OS_WIN)
267   if (base::win::OSInfo::GetArchitecture() ==
268       base::win::OSInfo::X64_ARCHITECTURE) {
269     if (base::win::OSInfo::GetInstance()->wow64_status() ==
270         base::win::OSInfo::WOW64_ENABLED) {
271       metadata_dict->SetString("os-wow64", "enabled");
272     } else {
273       metadata_dict->SetString("os-wow64", "disabled");
274     }
275   }
276 
277   metadata_dict->SetString(
278       "os-session", base::win::IsCurrentSessionRemote() ? "remote" : "local");
279 #endif
280 
281   metadata_dict->SetString("os-arch",
282                            base::SysInfo::OperatingSystemArchitecture());
283 
284   // CPU
285   base::CPU cpu;
286   metadata_dict->SetInteger("cpu-family", cpu.family());
287   metadata_dict->SetInteger("cpu-model", cpu.model());
288   metadata_dict->SetInteger("cpu-stepping", cpu.stepping());
289   metadata_dict->SetInteger("num-cpus", base::SysInfo::NumberOfProcessors());
290   metadata_dict->SetInteger("physical-memory",
291                             base::SysInfo::AmountOfPhysicalMemoryMB());
292 
293   metadata_dict->SetString("cpu-brand", cpu.cpu_brand());
294 
295   // GPU
296   const gpu::GPUInfo gpu_info =
297       content::GpuDataManagerImpl::GetInstance()->GetGPUInfo();
298   const gpu::GPUInfo::GPUDevice& active_gpu = gpu_info.active_gpu();
299 
300 #if !defined(OS_ANDROID)
301   metadata_dict->SetInteger("gpu-venid", active_gpu.vendor_id);
302   metadata_dict->SetInteger("gpu-devid", active_gpu.device_id);
303 #endif
304 
305   metadata_dict->SetString("gpu-driver", active_gpu.driver_version);
306   metadata_dict->SetString("gpu-psver", gpu_info.pixel_shader_version);
307   metadata_dict->SetString("gpu-vsver", gpu_info.vertex_shader_version);
308 
309 #if defined(OS_MACOSX)
310   metadata_dict->SetString("gpu-glver", gpu_info.gl_version);
311 #elif defined(OS_POSIX)
312   metadata_dict->SetString("gpu-gl-vendor", gpu_info.gl_vendor);
313   metadata_dict->SetString("gpu-gl-renderer", gpu_info.gl_renderer);
314 #endif
315 
316   metadata_dict->SetString("clock-domain", GetClockString());
317   metadata_dict->SetBoolean("highres-ticks",
318                             base::TimeTicks::IsHighResolution());
319 
320   metadata_dict->SetString(
321       "command_line",
322       base::CommandLine::ForCurrentProcess()->GetCommandLineString());
323 
324   base::Time::Exploded ctime;
325   TRACE_TIME_NOW().UTCExplode(&ctime);
326   std::string time_string = base::StringPrintf(
327       "%u-%u-%u %d:%d:%d", ctime.year, ctime.month, ctime.day_of_month,
328       ctime.hour, ctime.minute, ctime.second);
329   metadata_dict->SetString("trace-capture-datetime", time_string);
330 
331   // TODO(crbug.com/737049): The central controller doesn't know about
332   // metadata filters, so we temporarily filter here as the controller is
333   // what assembles the full trace data.
334   base::trace_event::MetadataFilterPredicate metadata_filter;
335   if (trace_config_ && trace_config_->IsArgumentFilterEnabled()) {
336     metadata_filter = base::trace_event::TraceLog::GetInstance()
337                           ->GetMetadataFilterPredicate();
338   }
339 
340   if (!metadata_filter.is_null()) {
341     for (base::DictionaryValue::Iterator it(*metadata_dict); !it.IsAtEnd();
342          it.Advance()) {
343       if (!metadata_filter.Run(it.key())) {
344         metadata_dict->SetString(it.key(), "__stripped__");
345       }
346     }
347   }
348 
349   return metadata_dict;
350 }
351 
GetInstance()352 TracingControllerImpl* TracingControllerImpl::GetInstance() {
353   DCHECK(g_tracing_controller);
354   return g_tracing_controller;
355 }
356 
GetCategories(GetCategoriesDoneCallback callback)357 bool TracingControllerImpl::GetCategories(GetCategoriesDoneCallback callback) {
358   std::set<std::string> category_set;
359   tracing::TracedProcessImpl::GetInstance()->GetCategories(&category_set);
360 
361   std::move(callback).Run(category_set);
362   return true;
363 }
364 
StartTracing(const base::trace_event::TraceConfig & trace_config,StartTracingDoneCallback callback)365 bool TracingControllerImpl::StartTracing(
366     const base::trace_event::TraceConfig& trace_config,
367     StartTracingDoneCallback callback) {
368   DCHECK_CURRENTLY_ON(BrowserThread::UI);
369   // TODO(chiniforooshan): The actual value should be received by callback and
370   // this function should return void.
371   if (IsTracing()) {
372     // Do not allow updating trace config when process filter is not used.
373     if (trace_config.process_filter_config().empty() ||
374         trace_config_->process_filter_config().empty()) {
375       return false;
376     }
377     // Make sure other parts of trace_config (besides process filter)
378     // did not change.
379     base::trace_event::TraceConfig old_config_copy(*trace_config_);
380     base::trace_event::TraceConfig new_config_copy(trace_config);
381     old_config_copy.SetProcessFilterConfig(
382         base::trace_event::TraceConfig::ProcessFilterConfig());
383     new_config_copy.SetProcessFilterConfig(
384         base::trace_event::TraceConfig::ProcessFilterConfig());
385     if (old_config_copy.ToString() != new_config_copy.ToString())
386       return false;
387   }
388   trace_config_ =
389       std::make_unique<base::trace_event::TraceConfig>(trace_config);
390 
391   DCHECK(!tracing_session_host_);
392   ConnectToServiceIfNeeded();
393 
394   perfetto::TraceConfig perfetto_config = tracing::GetDefaultPerfettoConfig(
395       trace_config, /*requires_anonymized_data=*/false);
396 
397   consumer_host_->EnableTracing(
398       tracing_session_host_.BindNewPipeAndPassReceiver(),
399       receiver_.BindNewPipeAndPassRemote(), std::move(perfetto_config),
400       tracing::mojom::TracingClientPriority::kUserInitiated);
401   receiver_.set_disconnect_handler(base::BindOnce(
402       &TracingControllerImpl::OnTracingFailed, base::Unretained(this)));
403   tracing_session_host_.set_disconnect_handler(base::BindOnce(
404       &TracingControllerImpl::OnTracingFailed, base::Unretained(this)));
405 
406   start_tracing_callback_ = std::move(callback);
407 
408   // TODO(chiniforooshan): The actual success value should be sent by the
409   // callback asynchronously.
410   return true;
411 }
412 
StartStartupTracingIfNeeded()413 void TracingControllerImpl::StartStartupTracingIfNeeded() {
414   auto* trace_startup_config = tracing::TraceStartupConfig::GetInstance();
415   if (trace_startup_config->AttemptAdoptBySessionOwner(
416           tracing::TraceStartupConfig::SessionOwner::kTracingController)) {
417     StartTracing(trace_startup_config->GetTraceConfig(),
418                  StartTracingDoneCallback());
419   } else if (base::CommandLine::ForCurrentProcess()->HasSwitch(
420                  switches::kTraceToConsole)) {
421     StartTracing(tracing::GetConfigForTraceToConsole(),
422                  StartTracingDoneCallback());
423   }
424 
425   if (trace_startup_config->IsTracingStartupForDuration()) {
426     TRACE_EVENT0("startup",
427                  "TracingControllerImpl::InitStartupTracingForDuration");
428     InitStartupTracingForDuration();
429   }
430 }
431 
GetStartupTraceFileName() const432 base::FilePath TracingControllerImpl::GetStartupTraceFileName() const {
433   base::FilePath trace_file;
434 
435   trace_file = tracing::TraceStartupConfig::GetInstance()->GetResultFile();
436   if (trace_file.empty()) {
437 #if defined(OS_ANDROID)
438     TracingControllerAndroid::GenerateTracingFilePath(&trace_file);
439 #else
440     // Default to saving the startup trace into the current dir.
441     trace_file = base::FilePath().AppendASCII("chrometrace.log");
442 #endif
443   }
444 
445   return trace_file;
446 }
447 
InitStartupTracingForDuration()448 void TracingControllerImpl::InitStartupTracingForDuration() {
449   DCHECK(tracing::TraceStartupConfig::GetInstance()
450              ->IsTracingStartupForDuration());
451 
452   startup_trace_file_ = GetStartupTraceFileName();
453 
454   startup_trace_timer_.Start(
455       FROM_HERE,
456       base::TimeDelta::FromSeconds(
457           tracing::TraceStartupConfig::GetInstance()->GetStartupDuration()),
458       this, &TracingControllerImpl::EndStartupTracing);
459 }
460 
EndStartupTracing()461 void TracingControllerImpl::EndStartupTracing() {
462   // Do nothing if startup tracing is already stopped.
463   if (!tracing::TraceStartupConfig::GetInstance()->IsEnabled())
464     return;
465 
466   // Use USER_VISIBLE priority because BEST_EFFORT tasks are not run at startup
467   // and we want the trace file to be written soon.
468   StopTracing(CreateFileEndpoint(
469       startup_trace_file_,
470       base::BindRepeating(OnStoppedStartupTracing, startup_trace_file_),
471       base::TaskPriority::USER_VISIBLE));
472 }
473 
FinalizeStartupTracingIfNeeded()474 void TracingControllerImpl::FinalizeStartupTracingIfNeeded() {
475   // There are two cases:
476   // 1. Startup duration is not reached.
477   // 2. Or if the trace should be saved to file for --trace-config-file flag.
478   base::Optional<base::FilePath> startup_trace_file;
479   if (startup_trace_timer_.IsRunning()) {
480     startup_trace_timer_.Stop();
481     if (startup_trace_file_ != base::FilePath().AppendASCII("none")) {
482       startup_trace_file = startup_trace_file_;
483     }
484   } else if (tracing::TraceStartupConfig::GetInstance()
485                  ->ShouldTraceToResultFile()) {
486     startup_trace_file = GetStartupTraceFileName();
487   }
488   if (!startup_trace_file)
489     return;
490   // Perfetto currently doesn't support tracing during shutdown as the trace
491   // buffer is lost when the service is shut down, so we wait until the trace is
492   // complete. See also crbug.com/944107.
493   // TODO(eseckler): Avoid the nestedRunLoop here somehow.
494   base::RunLoop run_loop;
495   // We may not have completed startup yet when we attempt to write the trace,
496   // and thus tasks with BEST_EFFORT may not be run. Choose a non-background
497   // priority to avoid blocking forever.
498   const base::TaskPriority kWritePriority = base::TaskPriority::USER_VISIBLE;
499   bool success = StopTracing(CreateFileEndpoint(
500       startup_trace_file.value(),
501       base::BindRepeating(
502           [](base::FilePath trace_file, base::OnceClosure quit_closure) {
503             OnStoppedStartupTracing(trace_file);
504             std::move(quit_closure).Run();
505           },
506           startup_trace_file.value(), run_loop.QuitClosure()),
507       kWritePriority));
508   if (!success)
509     return;
510   run_loop.Run();
511 }
512 
StopTracing(const scoped_refptr<TraceDataEndpoint> & trace_data_endpoint)513 bool TracingControllerImpl::StopTracing(
514     const scoped_refptr<TraceDataEndpoint>& trace_data_endpoint) {
515   return StopTracing(std::move(trace_data_endpoint), "");
516 }
517 
StopTracing(const scoped_refptr<TraceDataEndpoint> & trace_data_endpoint,const std::string & agent_label,bool privacy_filtering_enabled)518 bool TracingControllerImpl::StopTracing(
519     const scoped_refptr<TraceDataEndpoint>& trace_data_endpoint,
520     const std::string& agent_label,
521     bool privacy_filtering_enabled) {
522   if (!IsTracing() || drainer_ || !tracing_session_host_)
523     return false;
524   DCHECK_CURRENTLY_ON(BrowserThread::UI);
525 
526 #if defined(OS_ANDROID)
527   base::trace_event::TraceLog::GetInstance()->AddClockSyncMetadataEvent();
528 #endif
529 
530   // Setting the argument filter is no longer supported just in the TraceConfig;
531   // clients of the TracingController that need filtering need to pass that
532   // option to StopTracing directly as an argument. This is due to Perfetto-
533   // based tracing requiring this filtering to be done during serialization
534   // time and not during tracing time.
535   // TODO(oysteine): Remove the config option once the legacy IPC layer is
536   // removed.
537   CHECK(privacy_filtering_enabled || !trace_config_->IsArgumentFilterEnabled());
538 
539   tracing::TraceStartupConfig::GetInstance()->SetDisabled();
540   trace_data_endpoint_ = std::move(trace_data_endpoint);
541   is_data_complete_ = false;
542   read_buffers_complete_ = false;
543 
544   mojo::ScopedDataPipeProducerHandle producer_handle;
545   mojo::ScopedDataPipeConsumerHandle consumer_handle;
546   MojoResult result =
547       mojo::CreateDataPipe(nullptr, &producer_handle, &consumer_handle);
548   if (result != MOJO_RESULT_OK) {
549     CompleteFlush();
550     return true;
551   }
552 
553   drainer_.reset(new mojo::DataPipeDrainer(this, std::move(consumer_handle)));
554 
555   tracing_session_host_->DisableTracingAndEmitJson(
556       agent_label, std::move(producer_handle), privacy_filtering_enabled,
557       base::BindOnce(&TracingControllerImpl::OnReadBuffersComplete,
558                      base::Unretained(this)));
559 
560   // TODO(chiniforooshan): Is the return value used anywhere?
561   return true;
562 }
563 
GetTraceBufferUsage(GetTraceBufferUsageCallback callback)564 bool TracingControllerImpl::GetTraceBufferUsage(
565     GetTraceBufferUsageCallback callback) {
566   DCHECK_CURRENTLY_ON(BrowserThread::UI);
567 
568   if (!tracing_session_host_) {
569     std::move(callback).Run(0.0, 0);
570     return true;
571   }
572 
573   tracing_session_host_->RequestBufferUsage(base::BindOnce(
574       [](GetTraceBufferUsageCallback callback, bool success, float percent_full,
575          bool data_loss) { std::move(callback).Run(percent_full, 0); },
576       std::move(callback)));
577   // TODO(chiniforooshan): The actual success value should be sent by the
578   // callback asynchronously.
579   return true;
580 }
581 
IsTracing()582 bool TracingControllerImpl::IsTracing() {
583   return trace_config_ != nullptr;
584 }
585 
OnTracingEnabled()586 void TracingControllerImpl::OnTracingEnabled() {
587   if (start_tracing_callback_)
588     std::move(start_tracing_callback_).Run();
589 }
590 
OnTracingDisabled()591 void TracingControllerImpl::OnTracingDisabled() {}
592 
OnTracingFailed()593 void TracingControllerImpl::OnTracingFailed() {
594   CompleteFlush();
595 }
596 
OnDataAvailable(const void * data,size_t num_bytes)597 void TracingControllerImpl::OnDataAvailable(const void* data,
598                                             size_t num_bytes) {
599   if (trace_data_endpoint_) {
600     const std::string chunk(static_cast<const char*>(data), num_bytes);
601     trace_data_endpoint_->ReceiveTraceChunk(
602         std::make_unique<std::string>(chunk));
603   }
604 }
605 
CompleteFlush()606 void TracingControllerImpl::CompleteFlush() {
607   if (trace_data_endpoint_)
608     trace_data_endpoint_->ReceivedTraceFinalContents();
609 
610   trace_data_endpoint_ = nullptr;
611   trace_config_ = nullptr;
612   drainer_ = nullptr;
613   tracing_session_host_.reset();
614   receiver_.reset();
615 }
616 
OnDataComplete()617 void TracingControllerImpl::OnDataComplete() {
618   is_data_complete_ = true;
619   if (read_buffers_complete_)
620     CompleteFlush();
621 }
622 
OnReadBuffersComplete()623 void TracingControllerImpl::OnReadBuffersComplete() {
624   read_buffers_complete_ = true;
625   if (is_data_complete_)
626     CompleteFlush();
627 }
628 
629 #if defined(OS_CHROMEOS)
OnMachineStatisticsLoaded()630 void TracingControllerImpl::OnMachineStatisticsLoaded() {
631   chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
632       chromeos::system::kHardwareClassKey, &hardware_class_);
633   are_statistics_loaded_ = true;
634 }
635 #endif
636 
SetTracingDelegateForTesting(std::unique_ptr<TracingDelegate> delegate)637 void TracingControllerImpl::SetTracingDelegateForTesting(
638     std::unique_ptr<TracingDelegate> delegate) {
639   if (!delegate) {
640     delegate_.reset(GetContentClient()->browser()->GetTracingDelegate());
641   } else {
642     delegate_ = std::move(delegate);
643   }
644 }
645 
646 }  // namespace content
647