1 // Copyright (c) 2012 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/devtools/devtools_tracing_handler.h" 6 7 #include "base/bind.h" 8 #include "base/callback.h" 9 #include "base/file_util.h" 10 #include "base/json/json_reader.h" 11 #include "base/json/json_writer.h" 12 #include "base/location.h" 13 #include "base/memory/ref_counted_memory.h" 14 #include "base/strings/string_split.h" 15 #include "base/strings/stringprintf.h" 16 #include "base/values.h" 17 #include "content/browser/devtools/devtools_http_handler_impl.h" 18 #include "content/browser/devtools/devtools_protocol_constants.h" 19 #include "content/public/browser/browser_thread.h" 20 #include "content/public/browser/tracing_controller.h" 21 22 namespace content { 23 24 namespace { 25 26 const char kRecordUntilFull[] = "record-until-full"; 27 const char kRecordContinuously[] = "record-continuously"; 28 const char kEnableSampling[] = "enable-sampling"; 29 30 void ReadFile( 31 const base::FilePath& path, 32 const base::Callback<void(const scoped_refptr<base::RefCountedString>&)> 33 callback) { 34 std::string trace_data; 35 if (!base::ReadFileToString(path, &trace_data)) 36 LOG(ERROR) << "Failed to read file: " << path.value(); 37 base::DeleteFile(path, false); 38 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 39 base::Bind(callback, make_scoped_refptr( 40 base::RefCountedString::TakeString(&trace_data)))); 41 } 42 43 } // namespace 44 45 DevToolsTracingHandler::DevToolsTracingHandler() 46 : weak_factory_(this) { 47 RegisterCommandHandler(devtools::Tracing::start::kName, 48 base::Bind(&DevToolsTracingHandler::OnStart, 49 base::Unretained(this))); 50 RegisterCommandHandler(devtools::Tracing::end::kName, 51 base::Bind(&DevToolsTracingHandler::OnEnd, 52 base::Unretained(this))); 53 } 54 55 DevToolsTracingHandler::~DevToolsTracingHandler() { 56 } 57 58 void DevToolsTracingHandler::BeginReadingRecordingResult( 59 const base::FilePath& path) { 60 BrowserThread::PostTask( 61 BrowserThread::FILE, FROM_HERE, 62 base::Bind(&ReadFile, path, 63 base::Bind(&DevToolsTracingHandler::ReadRecordingResult, 64 weak_factory_.GetWeakPtr()))); 65 } 66 67 void DevToolsTracingHandler::ReadRecordingResult( 68 const scoped_refptr<base::RefCountedString>& trace_data) { 69 if (trace_data->data().size()) { 70 scoped_ptr<base::Value> trace_value(base::JSONReader::Read( 71 trace_data->data())); 72 DictionaryValue* dictionary = NULL; 73 bool ok = trace_value->GetAsDictionary(&dictionary); 74 DCHECK(ok); 75 ListValue* list = NULL; 76 ok = dictionary->GetList("traceEvents", &list); 77 DCHECK(ok); 78 std::string buffer; 79 for (size_t i = 0; i < list->GetSize(); ++i) { 80 std::string item; 81 base::Value* item_value; 82 list->Get(i, &item_value); 83 base::JSONWriter::Write(item_value, &item); 84 if (buffer.size()) 85 buffer.append(","); 86 buffer.append(item); 87 if (i % 1000 == 0) { 88 OnTraceDataCollected(buffer); 89 buffer.clear(); 90 } 91 } 92 if (buffer.size()) 93 OnTraceDataCollected(buffer); 94 } 95 96 SendNotification(devtools::Tracing::tracingComplete::kName, NULL); 97 } 98 99 void DevToolsTracingHandler::OnTraceDataCollected( 100 const std::string& trace_fragment) { 101 // Hand-craft protocol notification message so we can substitute JSON 102 // that we already got as string as a bare object, not a quoted string. 103 std::string message = base::StringPrintf( 104 "{ \"method\": \"%s\", \"params\": { \"%s\": [ %s ] } }", 105 devtools::Tracing::dataCollected::kName, 106 devtools::Tracing::dataCollected::kParamValue, 107 trace_fragment.c_str()); 108 SendRawMessage(message); 109 } 110 111 TracingController::Options DevToolsTracingHandler::TraceOptionsFromString( 112 const std::string& options) { 113 std::vector<std::string> split; 114 std::vector<std::string>::iterator iter; 115 int ret = 0; 116 117 base::SplitString(options, ',', &split); 118 for (iter = split.begin(); iter != split.end(); ++iter) { 119 if (*iter == kRecordUntilFull) { 120 ret &= ~TracingController::RECORD_CONTINUOUSLY; 121 } else if (*iter == kRecordContinuously) { 122 ret |= TracingController::RECORD_CONTINUOUSLY; 123 } else if (*iter == kEnableSampling) { 124 ret |= TracingController::ENABLE_SAMPLING; 125 } 126 } 127 return static_cast<TracingController::Options>(ret); 128 } 129 130 scoped_refptr<DevToolsProtocol::Response> 131 DevToolsTracingHandler::OnStart( 132 scoped_refptr<DevToolsProtocol::Command> command) { 133 std::string categories; 134 base::DictionaryValue* params = command->params(); 135 if (params) 136 params->GetString(devtools::Tracing::start::kParamCategories, &categories); 137 138 TracingController::Options options = TracingController::DEFAULT_OPTIONS; 139 if (params && params->HasKey(devtools::Tracing::start::kParamOptions)) { 140 std::string options_param; 141 params->GetString(devtools::Tracing::start::kParamOptions, &options_param); 142 options = TraceOptionsFromString(options_param); 143 } 144 145 TracingController::GetInstance()->EnableRecording( 146 categories, options, 147 TracingController::EnableRecordingDoneCallback()); 148 return command->SuccessResponse(NULL); 149 } 150 151 scoped_refptr<DevToolsProtocol::Response> 152 DevToolsTracingHandler::OnEnd( 153 scoped_refptr<DevToolsProtocol::Command> command) { 154 TracingController::GetInstance()->DisableRecording( 155 base::FilePath(), 156 base::Bind(&DevToolsTracingHandler::BeginReadingRecordingResult, 157 weak_factory_.GetWeakPtr())); 158 return command->SuccessResponse(NULL); 159 } 160 161 } // namespace content 162