Home | History | Annotate | Download | only in devtools
      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