1 // Copyright 2014 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 "components/feedback/tracing_manager.h" 6 7 #include "base/bind.h" 8 #include "base/memory/ref_counted_memory.h" 9 #include "base/message_loop/message_loop_proxy.h" 10 #include "components/feedback/feedback_util.h" 11 #include "content/public/browser/tracing_controller.h" 12 13 namespace { 14 15 // Only once trace manager can exist at a time. 16 TracingManager* g_tracing_manager = NULL; 17 // Trace IDs start at 1 and increase. 18 int g_next_trace_id = 1; 19 // Name of the file to store the tracing data as. 20 const base::FilePath::CharType kTracingFilename[] = 21 FILE_PATH_LITERAL("tracing.json"); 22 } 23 24 TracingManager::TracingManager() 25 : current_trace_id_(0), 26 weak_ptr_factory_(this) { 27 DCHECK(!g_tracing_manager); 28 g_tracing_manager = this; 29 StartTracing(); 30 } 31 32 TracingManager::~TracingManager() { 33 DCHECK(g_tracing_manager == this); 34 g_tracing_manager = NULL; 35 } 36 37 int TracingManager::RequestTrace() { 38 // Return the current trace if one is being collected. 39 if (current_trace_id_) 40 return current_trace_id_; 41 42 current_trace_id_ = g_next_trace_id; 43 ++g_next_trace_id; 44 content::TracingController::GetInstance()->DisableRecording( 45 content::TracingController::CreateStringSink( 46 base::Bind(&TracingManager::OnTraceDataCollected, 47 weak_ptr_factory_.GetWeakPtr()))); 48 return current_trace_id_; 49 } 50 51 bool TracingManager::GetTraceData(int id, const TraceDataCallback& callback) { 52 // If a trace is being collected currently, send it via callback when 53 // complete. 54 if (current_trace_id_) { 55 // Only allow one trace data request at a time. 56 if (trace_callback_.is_null()) { 57 trace_callback_ = callback; 58 return true; 59 } else { 60 return false; 61 } 62 } else { 63 std::map<int, scoped_refptr<base::RefCountedString> >::iterator data = 64 trace_data_.find(id); 65 if (data == trace_data_.end()) 66 return false; 67 68 // Always return the data asychronously, so the behavior is consistant. 69 base::MessageLoopProxy::current()->PostTask( 70 FROM_HERE, 71 base::Bind(callback, data->second)); 72 return true; 73 } 74 } 75 76 void TracingManager::DiscardTraceData(int id) { 77 trace_data_.erase(id); 78 79 // If the trace is discarded before it is complete, clean up the accumulators. 80 if (id == current_trace_id_) { 81 current_trace_id_ = 0; 82 83 // If the trace has already been requested, provide an empty string. 84 if (!trace_callback_.is_null()) { 85 trace_callback_.Run(scoped_refptr<base::RefCountedString>()); 86 trace_callback_.Reset(); 87 } 88 } 89 } 90 91 void TracingManager::StartTracing() { 92 content::TracingController::GetInstance()->EnableRecording( 93 base::debug::CategoryFilter(), 94 base::debug::TraceOptions(), 95 content::TracingController::EnableRecordingDoneCallback()); 96 } 97 98 void TracingManager::OnTraceDataCollected(base::RefCountedString* trace_data) { 99 if (!current_trace_id_) 100 return; 101 102 std::string output_val; 103 feedback_util::ZipString( 104 base::FilePath(kTracingFilename), trace_data->data(), &output_val); 105 106 scoped_refptr<base::RefCountedString> output( 107 base::RefCountedString::TakeString(&output_val)); 108 109 trace_data_[current_trace_id_] = output; 110 111 if (!trace_callback_.is_null()) { 112 trace_callback_.Run(output); 113 trace_callback_.Reset(); 114 } 115 116 current_trace_id_ = 0; 117 118 // Tracing has to be restarted asynchronous, so the TracingController can 119 // clean up. 120 base::MessageLoopProxy::current()->PostTask( 121 FROM_HERE, 122 base::Bind(&TracingManager::StartTracing, 123 weak_ptr_factory_.GetWeakPtr())); 124 } 125 126 // static 127 scoped_ptr<TracingManager> TracingManager::Create() { 128 if (g_tracing_manager) 129 return scoped_ptr<TracingManager>(); 130 return scoped_ptr<TracingManager>(new TracingManager()); 131 } 132 133 TracingManager* TracingManager::Get() { 134 return g_tracing_manager; 135 } 136