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