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