15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/tracing/tracing_ui.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <vector>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/base64.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/command_line.h"
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/debug/trace_event.h"
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/format_macros.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/json/json_reader.h"
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/json/json_writer.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/string_split.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/stringprintf.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "content/browser/tracing/grit/tracing_resources.h"
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/tracing/trace_uploader.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/browser/tracing/tracing_controller_impl.h"
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/browser/browser_context.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/tracing_controller.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_ui.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_ui_data_source.h"
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/common/content_client.h"
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/common/content_switches.h"
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/common/url_constants.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst char kUploadURL[] = "https://clients2.google.com/cr/staging_report";
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void OnGotCategories(const WebUIDataSource::GotDataCallback& callback,
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                     const std::set<std::string>& categorySet) {
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<base::ListValue> category_list(new base::ListValue());
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (std::set<std::string>::const_iterator it = categorySet.begin();
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       it != categorySet.end(); it++) {
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    category_list->AppendString(*it);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::RefCountedString* res = new base::RefCountedString();
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::JSONWriter::Write(category_list.get(), &res->data());
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  callback.Run(res);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GetTracingOptions(const std::string& data64,
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       base::debug::CategoryFilter* category_filter,
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       base::debug::TraceOptions* tracing_options) {
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string data;
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!base::Base64Decode(data64, &data)) {
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(ERROR) << "Options were not base64 encoded.";
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<base::Value> optionsRaw(base::JSONReader::Read(data));
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!optionsRaw) {
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(ERROR) << "Options were not valid JSON";
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::DictionaryValue* options;
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!optionsRaw->GetAsDictionary(&options)) {
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(ERROR) << "Options must be dict";
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!category_filter) {
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "category_filter can't be passed as NULL";
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!tracing_options) {
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "tracing_options can't be passed as NULL";
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool options_ok = true;
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string category_filter_string;
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  options_ok &= options->GetString("categoryFilter", &category_filter_string);
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  *category_filter = base::debug::CategoryFilter(category_filter_string);
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  options_ok &= options->GetBoolean("useSystemTracing",
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                    &tracing_options->enable_systrace);
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  options_ok &=
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      options->GetBoolean("useSampling", &tracing_options->enable_sampling);
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool use_continuous_tracing;
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  options_ok &=
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      options->GetBoolean("useContinuousTracing", &use_continuous_tracing);
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (use_continuous_tracing)
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    tracing_options->record_mode = base::debug::RECORD_CONTINUOUSLY;
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  else
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    tracing_options->record_mode = base::debug::RECORD_UNTIL_FULL;
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!options_ok) {
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(ERROR) << "Malformed options";
107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback);
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool BeginRecording(const std::string& data64,
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    const WebUIDataSource::GotDataCallback& callback) {
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::debug::CategoryFilter category_filter("");
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::debug::TraceOptions tracing_options;
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!GetTracingOptions(data64, &category_filter, &tracing_options))
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return TracingController::GetInstance()->EnableRecording(
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      category_filter,
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      tracing_options,
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&OnRecordingEnabledAck, callback));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::RefCountedString* res = new base::RefCountedString();
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  callback.Run(res);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void OnTraceBufferPercentFullResult(
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const WebUIDataSource::GotDataCallback& callback, float result) {
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string str = base::DoubleToString(result);
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  callback.Run(base::RefCountedString::TakeString(&str));
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback);
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool EnableMonitoring(const std::string& data64,
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      const WebUIDataSource::GotDataCallback& callback) {
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::debug::TraceOptions tracing_options;
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::debug::CategoryFilter category_filter("");
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!GetTracingOptions(data64, &category_filter, &tracing_options))
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return TracingController::GetInstance()->EnableMonitoring(
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      category_filter,
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      tracing_options,
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(OnMonitoringEnabledAck, callback));
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::RefCountedString* res = new base::RefCountedString();
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(res);
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void OnMonitoringDisabled(const WebUIDataSource::GotDataCallback& callback) {
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::RefCountedString* res = new base::RefCountedString();
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(res);
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GetMonitoringStatus(const WebUIDataSource::GotDataCallback& callback) {
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool is_monitoring;
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::debug::CategoryFilter category_filter("");
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::debug::TraceOptions options;
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TracingController::GetInstance()->GetMonitoringStatus(
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &is_monitoring, &category_filter, &options);
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::DictionaryValue>
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    monitoring_options(new base::DictionaryValue());
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  monitoring_options->SetBoolean("isMonitoring", is_monitoring);
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  monitoring_options->SetString("categoryFilter", category_filter.ToString());
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  monitoring_options->SetBoolean("useSystemTracing", options.enable_systrace);
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  monitoring_options->SetBoolean(
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "useContinuousTracing",
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      options.record_mode == base::debug::RECORD_CONTINUOUSLY);
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  monitoring_options->SetBoolean("useSampling", options.enable_sampling);
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string monitoring_options_json;
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::JSONWriter::Write(monitoring_options.get(), &monitoring_options_json);
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::RefCountedString* monitoring_options_base64 =
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    new base::RefCountedString();
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Base64Encode(monitoring_options_json,
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     &monitoring_options_base64->data());
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(monitoring_options_base64);
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid TracingCallbackWrapper(const WebUIDataSource::GotDataCallback& callback,
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            base::RefCountedString* data) {
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback.Run(data);
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool OnBeginJSONRequest(const std::string& path,
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        const WebUIDataSource::GotDataCallback& callback) {
197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (path == "json/categories") {
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return TracingController::GetInstance()->GetCategories(
199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        base::Bind(OnGotCategories, callback));
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const char* beginRecordingPath = "json/begin_recording?";
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (StartsWithASCII(path, beginRecordingPath, true)) {
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string data = path.substr(strlen(beginRecordingPath));
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return BeginRecording(data, callback);
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (path == "json/get_buffer_percent_full") {
208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return TracingController::GetInstance()->GetTraceBufferPercentFull(
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        base::Bind(OnTraceBufferPercentFullResult, callback));
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (path == "json/end_recording") {
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return TracingController::GetInstance()->DisableRecording(
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        TracingControllerImpl::CreateStringSink(
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            base::Bind(TracingCallbackWrapper, callback)));
215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char* enableMonitoringPath = "json/begin_monitoring?";
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (path.find(enableMonitoringPath) == 0) {
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string data = path.substr(strlen(enableMonitoringPath));
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return EnableMonitoring(data, callback);
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (path == "json/end_monitoring") {
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return TracingController::GetInstance()->DisableMonitoring(
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(OnMonitoringDisabled, callback));
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (path == "json/capture_monitoring") {
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TracingController::GetInstance()->CaptureMonitoringSnapshot(
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        TracingControllerImpl::CreateStringSink(
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            base::Bind(TracingCallbackWrapper, callback)));
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (path == "json/get_monitoring_status") {
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GetMonitoringStatus(callback);
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Unhandled request to " << path;
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool OnTracingRequest(const std::string& path,
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      const WebUIDataSource::GotDataCallback& callback) {
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (StartsWithASCII(path, "json/", true)) {
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!OnBeginJSONRequest(path, callback)) {
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::string error("##ERROR##");
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      callback.Run(base::RefCountedString::TakeString(&error));
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return false;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TracingUI
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262116680a4aac90f2aa7413d9095a592090648e557Ben MurdochTracingUI::TracingUI(WebUI* web_ui)
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : WebUIController(web_ui),
264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      weak_factory_(this) {
265116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  web_ui->RegisterMessageCallback(
266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        "doUpload",
267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::Bind(&TracingUI::DoUpload, base::Unretained(this)));
268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up the chrome://tracing/ source.
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserContext* browser_context =
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      web_ui->GetWebContents()->GetBrowserContext();
272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  WebUIDataSource* source = WebUIDataSource::Create(kChromeUITracingHost);
274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  source->SetJsonPath("strings.js");
275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  source->SetDefaultResource(IDR_TRACING_HTML);
276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  source->AddResourcePath("tracing.js", IDR_TRACING_JS);
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  source->SetRequestFilter(base::Bind(OnTracingRequest));
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  WebUIDataSource::Add(browser_context, source);
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TracingControllerImpl::GetInstance()->RegisterTracingUI(this);
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TracingUI::~TracingUI() {
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TracingControllerImpl::GetInstance()->UnregisterTracingUI(this);
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TracingUI::OnMonitoringStateChanged(bool is_monitoring) {
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  web_ui()->CallJavascriptFunction(
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "onMonitoringStateChanged", base::FundamentalValue(is_monitoring));
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TracingUI::DoUpload(const base::ListValue* args) {
2926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  const base::CommandLine& command_line =
2936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      *base::CommandLine::ForCurrentProcess();
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string upload_url = kUploadURL;
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (command_line.HasSwitch(switches::kTraceUploadURL)) {
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    upload_url =
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        command_line.GetSwitchValueASCII(switches::kTraceUploadURL);
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!GURL(upload_url).is_valid()) {
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    upload_url.clear();
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (upload_url.empty()) {
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    web_ui()->CallJavascriptFunction("onUploadError",
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::StringValue("Upload URL empty or invalid"));
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string file_contents;
310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!args || args->empty() || !args->GetString(0, &file_contents)) {
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    web_ui()->CallJavascriptFunction("onUploadError",
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     base::StringValue("Missing data"));
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  TraceUploader::UploadProgressCallback progress_callback =
317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&TracingUI::OnTraceUploadProgress,
318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      weak_factory_.GetWeakPtr());
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  TraceUploader::UploadDoneCallback done_callback =
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&TracingUI::OnTraceUploadComplete,
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      weak_factory_.GetWeakPtr());
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(OS_WIN)
324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char product[] = "Chrome";
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#elif defined(OS_MACOSX)
326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char product[] = "Chrome_Mac";
327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#elif defined(OS_LINUX)
328116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char product[] = "Chrome_Linux";
329116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#elif defined(OS_ANDROID)
330116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char product[] = "Chrome_Android";
331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#elif defined(OS_CHROMEOS)
332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char product[] = "Chrome_ChromeOS";
333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#else
334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#error Platform not supported.
335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
336116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
337116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // the part before the "/".
339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<std::string> product_components;
340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::SplitString(content::GetContentClient()->GetProduct(), '/',
341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                    &product_components);
342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(2U, product_components.size());
343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string version;
344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (product_components.size() == 2U) {
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    version = product_components[1];
346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    version = "unknown";
348116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  BrowserContext* browser_context =
351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      web_ui()->GetWebContents()->GetBrowserContext();
352116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  TraceUploader* uploader = new TraceUploader(
353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      product, version, upload_url, browser_context->GetRequestContext());
354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch     &TraceUploader::DoUpload,
357116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch     base::Unretained(uploader),
358116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch     file_contents,
359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch     progress_callback,
360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch     done_callback));
361116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // TODO(mmandlis): Add support for stopping the upload in progress.
362116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
363116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
364116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TracingUI::OnTraceUploadProgress(int64 current, int64 total) {
365116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(current <= total);
366116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int percent = (current / total) * 100;
367116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  web_ui()->CallJavascriptFunction(
368116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        "onUploadProgress",
369116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::FundamentalValue(percent),
370116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::StringValue(base::StringPrintf("%" PRId64, current)),
371116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::StringValue(base::StringPrintf("%" PRId64, total)));
372116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
373116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
374116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TracingUI::OnTraceUploadComplete(bool success,
375116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      const std::string& report_id,
376116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      const std::string& error_message) {
377116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (success) {
378116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    web_ui()->CallJavascriptFunction("onUploadComplete",
379116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     base::StringValue(report_id));
380116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
381116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    web_ui()->CallJavascriptFunction("onUploadError",
382116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     base::StringValue(error_message));
383116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
384116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
387