content_tracing_manager.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // Copyright 2021 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. #include "components/feedback/content/content_tracing_manager.h"
  5. #include "base/bind.h"
  6. #include "base/location.h"
  7. #include "base/memory/ptr_util.h"
  8. #include "base/memory/ref_counted_memory.h"
  9. #include "base/task/single_thread_task_runner.h"
  10. #include "base/threading/thread_task_runner_handle.h"
  11. #include "base/trace_event/trace_config.h"
  12. #include "components/feedback/feedback_util.h"
  13. #include "content/public/browser/browser_thread.h"
  14. #include "content/public/browser/tracing_controller.h"
  15. namespace {
  16. // Only once trace manager can exist at a time.
  17. ContentTracingManager* g_tracing_manager = nullptr;
  18. // Trace IDs start at 1 and increase.
  19. int g_next_trace_id = 1;
  20. // Name of the file to store the tracing data as.
  21. const base::FilePath::CharType kTracingFilename[] =
  22. FILE_PATH_LITERAL("tracing.json");
  23. } // namespace
  24. ContentTracingManager::ContentTracingManager() {
  25. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  26. DCHECK(!g_tracing_manager);
  27. g_tracing_manager = this;
  28. StartTracing();
  29. }
  30. ContentTracingManager::~ContentTracingManager() {
  31. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  32. DCHECK(g_tracing_manager == this);
  33. g_tracing_manager = nullptr;
  34. }
  35. int ContentTracingManager::RequestTrace() {
  36. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  37. // Return the current trace if one is being collected.
  38. if (current_trace_id_)
  39. return current_trace_id_;
  40. current_trace_id_ = g_next_trace_id;
  41. ++g_next_trace_id;
  42. content::TracingController::GetInstance()->StopTracing(
  43. content::TracingController::CreateStringEndpoint(
  44. base::BindOnce(&ContentTracingManager::OnTraceDataCollected,
  45. weak_ptr_factory_.GetWeakPtr())));
  46. return current_trace_id_;
  47. }
  48. bool ContentTracingManager::GetTraceData(int id, TraceDataCallback callback) {
  49. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  50. // If a trace is being collected currently, send it via callback when
  51. // complete.
  52. if (current_trace_id_) {
  53. // Only allow one trace data request at a time.
  54. if (!trace_callback_) {
  55. trace_callback_ = std::move(callback);
  56. return true;
  57. } else {
  58. return false;
  59. }
  60. } else {
  61. auto data = trace_data_.find(id);
  62. if (data == trace_data_.end())
  63. return false;
  64. // Always return the data asynchronously, so the behavior is consistent.
  65. base::ThreadTaskRunnerHandle::Get()->PostTask(
  66. FROM_HERE, base::BindOnce(std::move(callback), data->second));
  67. return true;
  68. }
  69. }
  70. void ContentTracingManager::DiscardTraceData(int id) {
  71. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  72. trace_data_.erase(id);
  73. // If the trace is discarded before it is complete, clean up the accumulators.
  74. if (id == current_trace_id_) {
  75. current_trace_id_ = 0;
  76. // If the trace has already been requested, provide an empty string.
  77. if (trace_callback_)
  78. std::move(trace_callback_).Run(scoped_refptr<base::RefCountedString>());
  79. }
  80. }
  81. void ContentTracingManager::StartTracing() {
  82. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  83. content::TracingController::GetInstance()->StartTracing(
  84. base::trace_event::TraceConfig(),
  85. content::TracingController::StartTracingDoneCallback());
  86. }
  87. void ContentTracingManager::OnTraceDataCollected(
  88. std::unique_ptr<std::string> trace_data) {
  89. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  90. if (!current_trace_id_)
  91. return;
  92. std::string output_val;
  93. feedback_util::ZipString(base::FilePath(kTracingFilename), *trace_data,
  94. &output_val);
  95. scoped_refptr<base::RefCountedString> output(
  96. base::RefCountedString::TakeString(&output_val));
  97. trace_data_[current_trace_id_] = output;
  98. if (trace_callback_)
  99. std::move(trace_callback_).Run(output);
  100. current_trace_id_ = 0;
  101. // Tracing has to be restarted asynchronous, so the ContentTracingManager can
  102. // clean up.
  103. base::ThreadTaskRunnerHandle::Get()->PostTask(
  104. FROM_HERE, base::BindOnce(&ContentTracingManager::StartTracing,
  105. weak_ptr_factory_.GetWeakPtr()));
  106. }
  107. // static
  108. std::unique_ptr<ContentTracingManager> ContentTracingManager::Create() {
  109. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  110. if (g_tracing_manager)
  111. return nullptr;
  112. return base::WrapUnique(new ContentTracingManager);
  113. }
  114. ContentTracingManager* ContentTracingManager::Get() {
  115. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  116. return g_tracing_manager;
  117. }