Home | History | Annotate | Download | only in tracing
      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/tracing/tracing_ui.h"
      6 
      7 #include <string>
      8 
      9 #include "base/base64.h"
     10 #include "base/bind.h"
     11 #include "base/bind_helpers.h"
     12 #include "base/file_util.h"
     13 #include "base/json/json_reader.h"
     14 #include "base/json/json_writer.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "base/strings/string_number_conversions.h"
     17 #include "base/strings/string_util.h"
     18 #include "base/values.h"
     19 #include "content/public/browser/browser_thread.h"
     20 #include "content/public/browser/tracing_controller.h"
     21 #include "content/public/browser/web_contents.h"
     22 #include "content/public/browser/web_ui.h"
     23 #include "content/public/browser/web_ui_data_source.h"
     24 #include "content/public/common/url_constants.h"
     25 #include "grit/tracing_resources.h"
     26 
     27 namespace content {
     28 namespace {
     29 
     30 void OnGotCategories(const WebUIDataSource::GotDataCallback& callback,
     31                      const std::set<std::string>& categorySet) {
     32 
     33   scoped_ptr<base::ListValue> category_list(new base::ListValue());
     34   for (std::set<std::string>::const_iterator it = categorySet.begin();
     35        it != categorySet.end(); it++) {
     36     category_list->AppendString(*it);
     37   }
     38 
     39   base::RefCountedString* res = new base::RefCountedString();
     40   base::JSONWriter::Write(category_list.get(), &res->data());
     41   callback.Run(res);
     42 }
     43 
     44 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback);
     45 
     46 bool OnBeginRecording(const std::string& data64,
     47                       const WebUIDataSource::GotDataCallback& callback) {
     48   std::string data;
     49   if (!base::Base64Decode(data64, &data)) {
     50     LOG(ERROR) << "Options were not base64 encoded.";
     51     return false;
     52   }
     53 
     54   scoped_ptr<base::Value> optionsRaw(base::JSONReader::Read(data));
     55   if (!optionsRaw) {
     56     LOG(ERROR) << "Options were not valid JSON";
     57     return false;
     58   }
     59   base::DictionaryValue* options;
     60   if (!optionsRaw->GetAsDictionary(&options)) {
     61     LOG(ERROR) << "Options must be dict";
     62     return false;
     63   }
     64 
     65   std::string category_filter_string;
     66   bool use_system_tracing;
     67   bool use_continuous_tracing;
     68   bool use_sampling;
     69 
     70   bool options_ok = true;
     71   options_ok &= options->GetString("categoryFilter", &category_filter_string);
     72   options_ok &= options->GetBoolean("useSystemTracing", &use_system_tracing);
     73   options_ok &= options->GetBoolean("useContinuousTracing",
     74                                     &use_continuous_tracing);
     75   options_ok &= options->GetBoolean("useSampling", &use_sampling);
     76   if (!options_ok) {
     77     LOG(ERROR) << "Malformed options";
     78     return false;
     79   }
     80 
     81   int tracing_options = 0;
     82   if (use_system_tracing)
     83     tracing_options |= TracingController::ENABLE_SYSTRACE;
     84   if (use_sampling)
     85     tracing_options |= TracingController::ENABLE_SAMPLING;
     86   if (use_continuous_tracing)
     87     tracing_options |= TracingController::RECORD_CONTINUOUSLY;
     88 
     89   return TracingController::GetInstance()->EnableRecording(
     90       category_filter_string,
     91       static_cast<TracingController::Options>(tracing_options),
     92       base::Bind(&OnRecordingEnabledAck, callback));
     93 }
     94 
     95 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
     96   base::RefCountedString* res = new base::RefCountedString();
     97   callback.Run(res);
     98 }
     99 
    100 void OnTraceBufferPercentFullResult(
    101     const WebUIDataSource::GotDataCallback& callback, float result) {
    102   std::string str = base::DoubleToString(result);
    103   callback.Run(base::RefCountedString::TakeString(&str));
    104 }
    105 
    106 void ReadRecordingResult(const WebUIDataSource::GotDataCallback& callback,
    107                          const base::FilePath& path) {
    108   std::string tmp;
    109   if (!base::ReadFileToString(path, &tmp))
    110     LOG(ERROR) << "Failed to read file " << path.value();
    111   base::DeleteFile(path, false);
    112   callback.Run(base::RefCountedString::TakeString(&tmp));
    113 }
    114 
    115 void BeginReadingRecordingResult(
    116     const WebUIDataSource::GotDataCallback& callback,
    117     const base::FilePath& path) {
    118   BrowserThread::PostTask(
    119       BrowserThread::FILE, FROM_HERE,
    120       base::Bind(ReadRecordingResult, callback, path));
    121 }
    122 
    123 bool OnBeginRequest(const std::string& path,
    124                     const WebUIDataSource::GotDataCallback& callback) {
    125   if (path == "json/categories") {
    126     TracingController::GetInstance()->GetCategories(
    127         base::Bind(OnGotCategories, callback));
    128     return true;
    129   }
    130   const char* beginRecordingPath = "json/begin_recording?";
    131   if (path.find(beginRecordingPath) == 0) {
    132     std::string data = path.substr(strlen(beginRecordingPath));
    133     return OnBeginRecording(data, callback);
    134   }
    135   if (path == "json/get_buffer_percent_full") {
    136     return TracingController::GetInstance()->GetTraceBufferPercentFull(
    137         base::Bind(OnTraceBufferPercentFullResult, callback));
    138   }
    139   if (path == "json/end_recording") {
    140     return TracingController::GetInstance()->DisableRecording(
    141         base::FilePath(), base::Bind(BeginReadingRecordingResult, callback));
    142   }
    143   if (StartsWithASCII(path, "json/", true))
    144     LOG(ERROR) << "Unhandled request to " << path;
    145   return false;
    146 }
    147 
    148 }  // namespace
    149 
    150 
    151 ////////////////////////////////////////////////////////////////////////////////
    152 //
    153 // TracingUI
    154 //
    155 ////////////////////////////////////////////////////////////////////////////////
    156 
    157 TracingUI::TracingUI(WebUI* web_ui) : WebUIController(web_ui) {
    158   // Set up the chrome://tracing/ source.
    159   BrowserContext* browser_context =
    160       web_ui->GetWebContents()->GetBrowserContext();
    161 
    162   WebUIDataSource* source = WebUIDataSource::Create(kChromeUITracingHost);
    163   source->SetJsonPath("strings.js");
    164   source->SetDefaultResource(IDR_TRACING_HTML);
    165   source->AddResourcePath("tracing.js", IDR_TRACING_JS);
    166   source->SetRequestFilter(base::Bind(OnBeginRequest));
    167   WebUIDataSource::Add(browser_context, source);
    168 }
    169 
    170 }  // namespace content
    171