summaryrefslogtreecommitdiffstats
path: root/content/browser/tracing
diff options
context:
space:
mode:
authorwangxianzhu@chromium.org <wangxianzhu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-21 06:10:34 +0000
committerwangxianzhu@chromium.org <wangxianzhu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-21 06:10:34 +0000
commit4a0a8f968b0d60b5ffc23ccdcb15c443b93ec559 (patch)
treeb551f4cf9636c95181e29e0dcca77891cdea1b23 /content/browser/tracing
parent2bb3b8e022870b6ae42abed5d8a921b6b08f1c8c (diff)
downloadchromium_src-4a0a8f968b0d60b5ffc23ccdcb15c443b93ec559.zip
chromium_src-4a0a8f968b0d60b5ffc23ccdcb15c443b93ec559.tar.gz
chromium_src-4a0a8f968b0d60b5ffc23ccdcb15c443b93ec559.tar.bz2
Overhaul tracing_ui to use XHR and new tracing_controller
Based on https://codereview.chromium.org/24355002/ Pairs with https://codereview.appspot.com/23860046/ Roll trace-viewer to r1063 to include the paired change. BUG=trace-viewer:420 Review URL: https://codereview.chromium.org/64553013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@236404 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/tracing')
-rw-r--r--content/browser/tracing/trace_message_filter.cc2
-rw-r--r--content/browser/tracing/tracing_controller_impl.cc71
-rw-r--r--content/browser/tracing/tracing_controller_impl.h16
-rw-r--r--content/browser/tracing/tracing_ui.cc622
4 files changed, 188 insertions, 523 deletions
diff --git a/content/browser/tracing/trace_message_filter.cc b/content/browser/tracing/trace_message_filter.cc
index 8f96a40..00fffb9 100644
--- a/content/browser/tracing/trace_message_filter.cc
+++ b/content/browser/tracing/trace_message_filter.cc
@@ -166,6 +166,8 @@ void TraceMessageFilter::OnTraceBufferPercentFullReply(float percent_full) {
is_awaiting_buffer_percent_full_ack_ = false;
TraceControllerImpl::GetInstance()->OnTraceBufferPercentFullReply(
percent_full);
+ TracingControllerImpl::GetInstance()->OnTraceBufferPercentFullReply(
+ percent_full);
} else {
NOTREACHED();
}
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index 78cb93f..1340b67 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -113,6 +113,8 @@ void TracingControllerImpl::ResultFile::CloseTask(
TracingControllerImpl::TracingControllerImpl() :
pending_disable_recording_ack_count_(0),
pending_capture_monitoring_snapshot_ack_count_(0),
+ pending_trace_buffer_percent_full_ack_count_(0),
+ maximum_trace_buffer_percent_full_(0),
// Tracing may have been enabled by ContentMainRunner if kTraceStartup
// is specified in command line.
is_recording_(TraceLog::GetInstance()->IsEnabled()),
@@ -158,9 +160,15 @@ bool TracingControllerImpl::EnableRecording(
TraceLog::GetInstance()->AddClockSyncMetadataEvent();
#endif
- TraceLog::Options trace_options = TraceLog::GetInstance()->trace_options();
- TraceLog::GetInstance()->SetEnabled(filter, trace_options);
+ TraceLog::Options trace_options = (options & RECORD_CONTINUOUSLY) ?
+ TraceLog::RECORD_CONTINUOUSLY : TraceLog::RECORD_UNTIL_FULL;
+ if (options & ENABLE_SAMPLING) {
+ trace_options = static_cast<TraceLog::Options>(
+ trace_options | TraceLog::ENABLE_SAMPLING);
+ }
+ // TODO(haraken): How to handle ENABLE_SYSTRACE?
+ TraceLog::GetInstance()->SetEnabled(filter, trace_options);
is_recording_ = true;
category_filter_ = TraceLog::GetInstance()->GetCurrentCategoryFilter();
@@ -320,6 +328,34 @@ void TracingControllerImpl::CaptureMonitoringSnapshot(
#endif
}
+bool TracingControllerImpl::GetTraceBufferPercentFull(
+ const GetTraceBufferPercentFullCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!can_get_trace_buffer_percent_full() || callback.is_null())
+ return false;
+
+ pending_trace_buffer_percent_full_callback_ = callback;
+
+ // Count myself in pending_trace_buffer_percent_full_ack_count_, acked below.
+ pending_trace_buffer_percent_full_ack_count_ = filters_.size() + 1;
+ maximum_trace_buffer_percent_full_ = 0;
+
+ // Handle special case of zero child processes.
+ if (pending_trace_buffer_percent_full_ack_count_ == 1) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
+ base::Unretained(this),
+ TraceLog::GetInstance()->GetBufferPercentFull()));
+ }
+
+ // Notify all child processes.
+ for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
+ it->get()->SendGetTraceBufferPercentFull();
+ }
+ return true;
+}
+
void TracingControllerImpl::AddFilter(TraceMessageFilter* filter) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
@@ -502,4 +538,35 @@ void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
OnCaptureMonitoringSnapshotAcked();
}
+void TracingControllerImpl::OnTraceBufferPercentFullReply(float percent_full) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
+ base::Unretained(this), percent_full));
+ return;
+ }
+
+ if (pending_trace_buffer_percent_full_ack_count_ == 0)
+ return;
+
+ maximum_trace_buffer_percent_full_ =
+ std::max(maximum_trace_buffer_percent_full_, percent_full);
+
+ if (--pending_trace_buffer_percent_full_ack_count_ == 0) {
+ // Trigger callback if one is set.
+ pending_trace_buffer_percent_full_callback_.Run(
+ maximum_trace_buffer_percent_full_);
+ pending_trace_buffer_percent_full_callback_.Reset();
+ }
+
+ if (pending_trace_buffer_percent_full_ack_count_ == 1) {
+ // The last ack represents local trace, so we need to ack it now. Note that
+ // this code only executes if there were child processes.
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
+ base::Unretained(this),
+ TraceLog::GetInstance()->GetBufferPercentFull()));
+ }
+}
+
} // namespace content
diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h
index 299adf4..7eab907 100644
--- a/content/browser/tracing/tracing_controller_impl.h
+++ b/content/browser/tracing/tracing_controller_impl.h
@@ -44,6 +44,8 @@ class TracingControllerImpl : public TracingController {
virtual void CaptureMonitoringSnapshot(
const base::FilePath& result_file_path,
const TracingFileResultCallback& callback) OVERRIDE;
+ virtual bool GetTraceBufferPercentFull(
+ const GetTraceBufferPercentFullCallback& callback) OVERRIDE;
private:
typedef std::set<scoped_refptr<TraceMessageFilter> > FilterMap;
@@ -71,6 +73,10 @@ class TracingControllerImpl : public TracingController {
return is_monitoring_ && !monitoring_snapshot_file_;
}
+ bool can_get_trace_buffer_percent_full() const {
+ return pending_trace_buffer_percent_full_callback_.is_null();
+ }
+
// Methods for use by TraceMessageFilter.
void AddFilter(TraceMessageFilter* filter);
void RemoveFilter(TraceMessageFilter* filter);
@@ -96,16 +102,26 @@ class TracingControllerImpl : public TracingController {
void OnCaptureMonitoringSnapshotAcked();
void OnMonitoringSnapshotFileClosed();
+ void OnTraceNotification(int notification);
+ void OnTraceBufferPercentFullReply(float percent_full);
+
FilterMap filters_;
// Pending acks for DisableRecording.
int pending_disable_recording_ack_count_;
// Pending acks for CaptureMonitoringSnapshot.
int pending_capture_monitoring_snapshot_ack_count_;
+ // Pending acks for GetTraceBufferPercentFull.
+ int pending_trace_buffer_percent_full_ack_count_;
+ float maximum_trace_buffer_percent_full_;
+
bool is_recording_;
bool is_monitoring_;
+
GetCategoriesDoneCallback pending_get_categories_done_callback_;
TracingFileResultCallback pending_disable_recording_done_callback_;
TracingFileResultCallback pending_capture_monitoring_snapshot_done_callback_;
+ GetTraceBufferPercentFullCallback pending_trace_buffer_percent_full_callback_;
+
std::set<std::string> known_category_groups_;
base::debug::CategoryFilter category_filter_;
scoped_ptr<ResultFile> result_file_;
diff --git a/content/browser/tracing/tracing_ui.cc b/content/browser/tracing/tracing_ui.cc
index 0609e19..6e471c2 100644
--- a/content/browser/tracing/tracing_ui.cc
+++ b/content/browser/tracing/tracing_ui.cc
@@ -6,568 +6,144 @@
#include <string>
+#include "base/base64.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/file_util.h"
-#include "base/json/string_escape.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
#include "base/memory/scoped_ptr.h"
-#include "base/safe_numerics.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/trace_controller.h"
-#include "content/public/browser/trace_subscriber.h"
+#include "content/public/browser/tracing_controller.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
-#include "content/public/browser/web_ui_message_handler.h"
#include "content/public/common/url_constants.h"
#include "grit/tracing_resources.h"
-#include "ipc/ipc_channel.h"
-#include "ui/shell_dialogs/select_file_dialog.h"
-
-#if defined(OS_CHROMEOS)
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/debug_daemon_client.h"
-#endif
namespace content {
namespace {
-WebUIDataSource* CreateTracingHTMLSource() {
- WebUIDataSource* source = WebUIDataSource::Create(kChromeUITracingHost);
-
- source->SetJsonPath("strings.js");
- source->SetDefaultResource(IDR_TRACING_HTML);
- source->AddResourcePath("tracing.js", IDR_TRACING_JS);
- return source;
-}
-
-// This class receives javascript messages from the renderer.
-// Note that the WebUI infrastructure runs on the UI thread, therefore all of
-// this class's methods are expected to run on the UI thread.
-class TracingMessageHandler
- : public WebUIMessageHandler,
- public ui::SelectFileDialog::Listener,
- public base::SupportsWeakPtr<TracingMessageHandler>,
- public TraceSubscriber {
- public:
- TracingMessageHandler();
- virtual ~TracingMessageHandler();
-
- // WebUIMessageHandler implementation.
- virtual void RegisterMessages() OVERRIDE;
-
- // SelectFileDialog::Listener implementation
- virtual void FileSelected(const base::FilePath& path,
- int index,
- void* params) OVERRIDE;
- virtual void FileSelectionCanceled(void* params) OVERRIDE;
-
- // TraceSubscriber implementation.
- virtual void OnEndTracingComplete() OVERRIDE;
- virtual void OnTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE;
- virtual void OnTraceBufferPercentFullReply(float percent_full) OVERRIDE;
- virtual void OnKnownCategoriesCollected(
- const std::set<std::string>& known_categories) OVERRIDE;
-
- // Messages.
- void OnTracingControllerInitialized(const base::ListValue* list);
- void OnBeginTracing(const base::ListValue* list);
- void OnEndTracingAsync(const base::ListValue* list);
- void OnBeginRequestBufferPercentFull(const base::ListValue* list);
- void OnLoadTraceFile(const base::ListValue* list);
- void OnSaveTraceFile(const base::ListValue* list);
- void OnGetKnownCategories(const base::ListValue* list);
-
- // Callbacks.
- void LoadTraceFileComplete(string16* file_contents,
- const base::FilePath &path);
- void SaveTraceFileComplete();
+void OnGotCategories(const WebUIDataSource::GotDataCallback& callback,
+ const std::set<std::string>& categorySet) {
- private:
- // The file dialog to select a file for loading or saving traces.
- scoped_refptr<ui::SelectFileDialog> select_trace_file_dialog_;
-
- // The type of the file dialog as the same one is used for loading or saving
- // traces.
- ui::SelectFileDialog::Type select_trace_file_dialog_type_;
-
- // The trace data that is to be written to the file on saving.
- scoped_ptr<std::string> trace_data_to_save_;
-
- // True while tracing is active.
- bool trace_enabled_;
-
- // True while system tracing is active.
- bool system_trace_in_progress_;
-
- void OnEndSystemTracingAck(
- const scoped_refptr<base::RefCountedString>& events_str_ptr);
-
- DISALLOW_COPY_AND_ASSIGN(TracingMessageHandler);
-};
-
-// A proxy passed to the Read and Write tasks used when loading or saving trace
-// data.
-class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
- public:
- explicit TaskProxy(const base::WeakPtr<TracingMessageHandler>& handler)
- : handler_(handler) {}
- void LoadTraceFileCompleteProxy(string16* file_contents,
- const base::FilePath& path) {
- if (handler_.get())
- handler_->LoadTraceFileComplete(file_contents, path);
- delete file_contents;
- }
-
- void SaveTraceFileCompleteProxy() {
- if (handler_.get())
- handler_->SaveTraceFileComplete();
+ scoped_ptr<base::ListValue> category_list(new base::ListValue());
+ for (std::set<std::string>::const_iterator it = categorySet.begin();
+ it != categorySet.end(); it++) {
+ category_list->AppendString(*it);
}
- private:
- friend class base::RefCountedThreadSafe<TaskProxy>;
- ~TaskProxy() {}
-
- // The message handler to call callbacks on.
- base::WeakPtr<TracingMessageHandler> handler_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskProxy);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// TracingMessageHandler
-//
-////////////////////////////////////////////////////////////////////////////////
-
-TracingMessageHandler::TracingMessageHandler()
- : select_trace_file_dialog_type_(ui::SelectFileDialog::SELECT_NONE),
- trace_enabled_(false),
- system_trace_in_progress_(false) {
+ base::RefCountedString* res = new base::RefCountedString();
+ base::JSONWriter::Write(category_list.get(), &res->data());
+ callback.Run(res);
}
-TracingMessageHandler::~TracingMessageHandler() {
- if (select_trace_file_dialog_.get())
- select_trace_file_dialog_->ListenerDestroyed();
-
- // If we are the current subscriber, this will result in ending tracing.
- TraceController::GetInstance()->CancelSubscriber(this);
-
- // Shutdown any system tracing too.
- if (system_trace_in_progress_) {
-#if defined(OS_CHROMEOS)
- chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
- RequestStopSystemTracing(
- chromeos::DebugDaemonClient::EmptyStopSystemTracingCallback());
-#endif
- }
-}
-
-void TracingMessageHandler::RegisterMessages() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- web_ui()->RegisterMessageCallback("tracingControllerInitialized",
- base::Bind(&TracingMessageHandler::OnTracingControllerInitialized,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("beginTracing",
- base::Bind(&TracingMessageHandler::OnBeginTracing,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("endTracingAsync",
- base::Bind(&TracingMessageHandler::OnEndTracingAsync,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("beginRequestBufferPercentFull",
- base::Bind(&TracingMessageHandler::OnBeginRequestBufferPercentFull,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("loadTraceFile",
- base::Bind(&TracingMessageHandler::OnLoadTraceFile,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("saveTraceFile",
- base::Bind(&TracingMessageHandler::OnSaveTraceFile,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("getKnownCategories",
- base::Bind(&TracingMessageHandler::OnGetKnownCategories,
- base::Unretained(this)));
-}
-
-void TracingMessageHandler::OnTracingControllerInitialized(
- const base::ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Send the client info to the tracingController
- {
- scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetString("version", GetContentClient()->GetProduct());
+void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback);
- dict->SetString("command_line",
- CommandLine::ForCurrentProcess()->GetCommandLineString());
-
- web_ui()->CallJavascriptFunction("tracingController.onClientInfoUpdate",
- *dict);
+bool OnBeginRecording(const std::string& data64,
+ const WebUIDataSource::GotDataCallback& callback) {
+ std::string data;
+ if (!base::Base64Decode(data64, &data)) {
+ LOG(ERROR) << "Options were not base64 encoded.";
+ return false;
}
-}
-
-void TracingMessageHandler::OnBeginRequestBufferPercentFull(
- const base::ListValue* list) {
- TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this);
-}
-
-// A callback used for asynchronously reading a file to a string. Calls the
-// TaskProxy callback when reading is complete.
-void ReadTraceFileCallback(TaskProxy* proxy, const base::FilePath& path) {
- std::string file_contents;
- if (!base::ReadFileToString(path, &file_contents))
- return;
- // We need to escape the file contents, because it will go into a javascript
- // quoted string in TracingMessageHandler::LoadTraceFileComplete. We need to
- // escape control characters (to have well-formed javascript statements), as
- // well as \ and ' (the only special characters in a ''-quoted string).
- // Do the escaping on this thread, it may take a little while for big files
- // and we don't want to block the UI during that time. Also do the UTF-16
- // conversion here.
- // Note: we're using UTF-16 because we'll need to cut the string into slices
- // to give to Javascript, and it's easier to cut than UTF-8 (since JS strings
- // are arrays of 16-bit values, UCS-2 really, whereas we can't cut inside of a
- // multibyte UTF-8 codepoint).
- size_t size = file_contents.size();
- std::string escaped_contents;
- escaped_contents.reserve(size);
- for (size_t i = 0; i < size; ++i) {
- char c = file_contents[i];
- if (c < ' ' || c == 0x7f) {
- escaped_contents += base::StringPrintf("\\u%04x",
- static_cast<uint8_t>(c));
- continue;
- }
- if (c == '\\' || c == '\'')
- escaped_contents.push_back('\\');
- escaped_contents.push_back(c);
+ scoped_ptr<base::Value> optionsRaw(base::JSONReader::Read(data));
+ if (!optionsRaw) {
+ LOG(ERROR) << "Options were not valid JSON";
+ return false;
}
- file_contents.clear();
-
- scoped_ptr<string16> contents16(new string16);
- UTF8ToUTF16(escaped_contents).swap(*contents16);
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&TaskProxy::LoadTraceFileCompleteProxy, proxy,
- contents16.release(),
- path));
-}
-
-// A callback used for asynchronously writing a file from a string. Calls the
-// TaskProxy callback when writing is complete.
-void WriteTraceFileCallback(TaskProxy* proxy,
- const base::FilePath& path,
- std::string* contents) {
- int size = base::checked_numeric_cast<int>(contents->size());
- if (file_util::WriteFile(path, contents->c_str(), size) != size)
- return;
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&TaskProxy::SaveTraceFileCompleteProxy, proxy));
-}
-
-void TracingMessageHandler::FileSelected(
- const base::FilePath& path, int index, void* params) {
- if (select_trace_file_dialog_type_ ==
- ui::SelectFileDialog::SELECT_OPEN_FILE) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&ReadTraceFileCallback,
- make_scoped_refptr(new TaskProxy(AsWeakPtr())), path));
- } else {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&WriteTraceFileCallback,
- make_scoped_refptr(new TaskProxy(AsWeakPtr())), path,
- trace_data_to_save_.release()));
+ base::DictionaryValue* options;
+ if (!optionsRaw->GetAsDictionary(&options)) {
+ LOG(ERROR) << "Options must be dict";
+ return false;
}
- select_trace_file_dialog_ = NULL;
-}
-
-void TracingMessageHandler::FileSelectionCanceled(void* params) {
- select_trace_file_dialog_ = NULL;
- if (select_trace_file_dialog_type_ ==
- ui::SelectFileDialog::SELECT_OPEN_FILE) {
- web_ui()->CallJavascriptFunction(
- "tracingController.onLoadTraceFileCanceled");
- } else {
- web_ui()->CallJavascriptFunction(
- "tracingController.onSaveTraceFileCanceled");
+ std::string category_filter_string;
+ bool use_system_tracing;
+ bool use_continuous_tracing;
+ bool use_sampling;
+
+ bool options_ok = true;
+ options_ok &= options->GetString("categoryFilter", &category_filter_string);
+ options_ok &= options->GetBoolean("useSystemTracing", &use_system_tracing);
+ options_ok &= options->GetBoolean("useContinuousTracing",
+ &use_continuous_tracing);
+ options_ok &= options->GetBoolean("useSampling", &use_sampling);
+ if (!options_ok) {
+ LOG(ERROR) << "Malformed options";
+ return false;
}
-}
-
-void TracingMessageHandler::OnLoadTraceFile(const base::ListValue* list) {
- // Only allow a single dialog at a time.
- if (select_trace_file_dialog_.get())
- return;
- select_trace_file_dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE;
- select_trace_file_dialog_ = ui::SelectFileDialog::Create(
- this,
- GetContentClient()->browser()->CreateSelectFilePolicy(
- web_ui()->GetWebContents()));
- select_trace_file_dialog_->SelectFile(
- ui::SelectFileDialog::SELECT_OPEN_FILE,
- string16(),
- base::FilePath(),
- NULL,
- 0,
- base::FilePath::StringType(),
- web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
- NULL);
-}
-void TracingMessageHandler::LoadTraceFileComplete(string16* contents,
- const base::FilePath& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ int tracing_options = 0;
+ if (use_system_tracing)
+ tracing_options |= TracingController::ENABLE_SYSTRACE;
+ if (use_sampling)
+ tracing_options |= TracingController::ENABLE_SAMPLING;
+ if (use_continuous_tracing)
+ tracing_options |= TracingController::RECORD_CONTINUOUSLY;
- // We need to pass contents to tracingController.onLoadTraceFileComplete, but
- // that may be arbitrarily big, and IPCs messages are limited in size. So we
- // need to cut it into pieces and rebuild the string in Javascript.
- // |contents| has already been escaped in ReadTraceFileCallback, so we need to
- // avoid splitting escape sequences (e.g., \' or \u1234) to keep the data
- // intact. IPC::Channel::kMaximumMessageSize is in bytes, and we need to
- // account for overhead.
- const size_t kMaxSize = IPC::Channel::kMaximumMessageSize / 2 - 128;
- const size_t kControlCharEscapeSequenceSize = 5;
- string16 first_prefix = UTF8ToUTF16("window.traceData = '");
- string16 prefix = UTF8ToUTF16("window.traceData += '");
- string16 suffix = UTF8ToUTF16("';");
-
- RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
-
- size_t flush_offset = 0;
- size_t token_start = 0;
- while (flush_offset < contents->size()) {
- size_t token_end = token_start;
- if ((*contents)[token_end] == '\\') {
- token_end++;
- DCHECK(token_end < contents->size());
- if (token_end < contents->size() && (*contents)[token_end] == 'u') {
- token_end += kControlCharEscapeSequenceSize;
- } else {
- token_end++;
- }
- } else {
- token_end++;
- }
- token_end = std::min(contents->size(), token_end);
- size_t token_size = token_end - token_start;
- size_t flush_size = token_start - flush_offset;
- if (token_end == contents->size()) {
- flush_size = contents->size() - flush_offset;
- } else if (flush_size + token_size < kMaxSize) {
- token_start += token_size;
- continue;
- }
- string16 javascript = flush_offset == 0 ? first_prefix : prefix;
- javascript += contents->substr(flush_offset, flush_size) + suffix;
- rvh->ExecuteJavascriptInWebFrame(string16(), javascript);
- flush_offset += flush_size;
- }
-
- // The CallJavascriptFunction is not used because we need to pass
- // the first param |window.traceData| through as an un-quoted string.
- rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(
- "tracingController.onLoadTraceFileComplete(window.traceData," +
- base::GetDoubleQuotedJson(path.value()) + ");" +
- "delete window.traceData;"));
+ base::debug::CategoryFilter category_filter(category_filter_string);
+ return TracingController::GetInstance()->EnableRecording(
+ category_filter,
+ static_cast<TracingController::Options>(tracing_options),
+ base::Bind(OnRecordingEnabledAck, callback));
}
-void TracingMessageHandler::OnSaveTraceFile(const base::ListValue* list) {
- // Only allow a single dialog at a time.
- if (select_trace_file_dialog_.get())
- return;
-
- DCHECK_EQ(1U, list->GetSize());
-
- std::string* trace_data = new std::string();
- bool ok = list->GetString(0, trace_data);
- DCHECK(ok);
- trace_data_to_save_.reset(trace_data);
-
- select_trace_file_dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
- select_trace_file_dialog_ = ui::SelectFileDialog::Create(
- this,
- GetContentClient()->browser()->CreateSelectFilePolicy(
- web_ui()->GetWebContents()));
- select_trace_file_dialog_->SelectFile(
- ui::SelectFileDialog::SELECT_SAVEAS_FILE,
- string16(),
- base::FilePath(),
- NULL,
- 0,
- base::FilePath::StringType(),
- web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
- NULL);
+void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
+ base::RefCountedString* res = new base::RefCountedString();
+ callback.Run(res);
}
-void TracingMessageHandler::SaveTraceFileComplete() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- web_ui()->CallJavascriptFunction("tracingController.onSaveTraceFileComplete");
+void OnTraceBufferPercentFullResult(
+ const WebUIDataSource::GotDataCallback& callback, float result) {
+ std::string str = base::DoubleToString(result);
+ callback.Run(base::RefCountedString::TakeString(&str));
}
-void TracingMessageHandler::OnBeginTracing(const base::ListValue* args) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK_GE(args->GetSize(), (size_t) 2);
- DCHECK_LE(args->GetSize(), (size_t) 3);
-
- bool system_tracing_requested = false;
- bool ok = args->GetBoolean(0, &system_tracing_requested);
- DCHECK(ok);
-
- std::string chrome_categories;
- ok = args->GetString(1, &chrome_categories);
- DCHECK(ok);
-
- base::debug::TraceLog::Options options =
- base::debug::TraceLog::RECORD_UNTIL_FULL;
- if (args->GetSize() >= 3) {
- std::string options_;
- ok = args->GetString(2, &options_);
- DCHECK(ok);
- options = base::debug::TraceLog::TraceOptionsFromString(options_);
- }
-
- trace_enabled_ = true;
- // TODO(jbates) This may fail, but that's OK for current use cases.
- // Ex: Multiple about:gpu traces can not trace simultaneously.
- // TODO(nduca) send feedback to javascript about whether or not BeginTracing
- // was successful.
- TraceController::GetInstance()->BeginTracing(this, chrome_categories,
- options);
-
- if (system_tracing_requested) {
-#if defined(OS_CHROMEOS)
- DCHECK(!system_trace_in_progress_);
- chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
- StartSystemTracing();
- // TODO(sleffler) async, could wait for completion
- system_trace_in_progress_ = true;
-#endif
- }
+void ReadRecordingResult(const WebUIDataSource::GotDataCallback& callback,
+ const base::FilePath& path) {
+ std::string tmp;
+ if (!base::ReadFileToString(path, &tmp))
+ LOG(ERROR) << "Failed to read file " << path.value();
+ base::DeleteFile(path, false);
+ callback.Run(base::RefCountedString::TakeString(&tmp));
}
-void TracingMessageHandler::OnEndTracingAsync(const base::ListValue* list) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // This is really us beginning to end tracing, rather than tracing being truly
- // over. When this function yields, we expect to get some number of
- // OnTraceDataCollected callbacks, which will append data to window.traceData.
- // To set up for this, set window.traceData to the empty string.
- web_ui()->GetWebContents()->GetRenderViewHost()->
- ExecuteJavascriptInWebFrame(string16(),
- UTF8ToUTF16("window.traceData = '';"));
-
- // TODO(nduca): fix javascript code to make sure trace_enabled_ is always true
- // here. triggered a false condition by just clicking stop
- // trace a few times when it was going slow, and maybe switching
- // between tabs.
- if (trace_enabled_ &&
- !TraceController::GetInstance()->EndTracingAsync(this)) {
- // Set to false now, since it turns out we never were the trace subscriber.
- OnEndTracingComplete();
- }
+void BeginReadingRecordingResult(
+ const WebUIDataSource::GotDataCallback& callback,
+ const base::FilePath& path) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(ReadRecordingResult, callback, path));
}
-void TracingMessageHandler::OnEndTracingComplete() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- trace_enabled_ = false;
- if (system_trace_in_progress_) {
- // Disable system tracing now that the local trace has shutdown.
- // This must be done last because we potentially need to push event
- // records into the system event log for synchronizing system event
- // timestamps with chrome event timestamps--and since the system event
- // log is a ring-buffer (on linux) adding them at the end is the only
- // way we're confident we'll have them in the final result.
- system_trace_in_progress_ = false;
-#if defined(OS_CHROMEOS)
- chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
- RequestStopSystemTracing(
- base::Bind(&TracingMessageHandler::OnEndSystemTracingAck,
- base::Unretained(this)));
- return;
-#endif
+bool OnBeginRequest(const std::string& path,
+ const WebUIDataSource::GotDataCallback& callback) {
+ if (path == "json/categories") {
+ TracingController::GetInstance()->GetCategories(
+ base::Bind(OnGotCategories, callback));
+ return true;
}
-
- RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
- rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(
- "tracingController.onEndTracingComplete(window.traceData);"
- "delete window.traceData;"));
-}
-
-void TracingMessageHandler::OnEndSystemTracingAck(
- const scoped_refptr<base::RefCountedString>& events_str_ptr) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- web_ui()->CallJavascriptFunction(
- "tracingController.onSystemTraceDataCollected",
- *scoped_ptr<base::Value>(new base::StringValue(events_str_ptr->data())));
- DCHECK(!system_trace_in_progress_);
-
- OnEndTracingComplete();
-}
-
-void TracingMessageHandler::OnTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& trace_fragment) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- std::string javascript;
- javascript.reserve(trace_fragment->size() * 2);
- javascript.append("window.traceData += \"");
- base::JsonDoubleQuote(trace_fragment->data(), false, &javascript);
-
- // Intentionally append a , to the traceData. This technically causes all
- // traceData that we pass back to JS to end with a comma, but that is actually
- // something the JS side strips away anyway
- javascript.append(",\";");
-
- web_ui()->GetWebContents()->GetRenderViewHost()->
- ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(javascript));
-}
-
-void TracingMessageHandler::OnTraceBufferPercentFullReply(float percent_full) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- web_ui()->CallJavascriptFunction(
- "tracingController.onRequestBufferPercentFullComplete",
- *scoped_ptr<base::Value>(new base::FundamentalValue(percent_full)));
-}
-
-void TracingMessageHandler::OnGetKnownCategories(const base::ListValue* list) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!TraceController::GetInstance()->GetKnownCategoryGroupsAsync(this)) {
- std::set<std::string> ret;
- OnKnownCategoriesCollected(ret);
+ const char* beginRecordingPath = "json/begin_recording?";
+ if (path.find(beginRecordingPath) == 0) {
+ std::string data = path.substr(strlen(beginRecordingPath));
+ return OnBeginRecording(data, callback);
}
-}
-
-void TracingMessageHandler::OnKnownCategoriesCollected(
- const std::set<std::string>& known_categories) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- scoped_ptr<base::ListValue> categories(new base::ListValue());
- for (std::set<std::string>::const_iterator iter = known_categories.begin();
- iter != known_categories.end();
- ++iter) {
- categories->AppendString(*iter);
+ if (path == "json/get_buffer_percent_full") {
+ return TracingController::GetInstance()->GetTraceBufferPercentFull(
+ base::Bind(OnTraceBufferPercentFullResult, callback));
}
-
- web_ui()->CallJavascriptFunction(
- "tracingController.onKnownCategoriesCollected", *categories);
+ if (path == "json/end_recording") {
+ return TracingController::GetInstance()->DisableRecording(
+ base::FilePath(), base::Bind(BeginReadingRecordingResult, callback));
+ }
+ if (StartsWithASCII(path, "json/", true))
+ LOG(ERROR) << "Unhandled request to " << path;
+ return false;
}
} // namespace
@@ -580,12 +156,16 @@ void TracingMessageHandler::OnKnownCategoriesCollected(
////////////////////////////////////////////////////////////////////////////////
TracingUI::TracingUI(WebUI* web_ui) : WebUIController(web_ui) {
- web_ui->AddMessageHandler(new TracingMessageHandler());
-
// Set up the chrome://tracing/ source.
BrowserContext* browser_context =
web_ui->GetWebContents()->GetBrowserContext();
- WebUIDataSource::Add(browser_context, CreateTracingHTMLSource());
+
+ WebUIDataSource* source = WebUIDataSource::Create(kChromeUITracingHost);
+ source->SetJsonPath("strings.js");
+ source->SetDefaultResource(IDR_TRACING_HTML);
+ source->AddResourcePath("tracing.js", IDR_TRACING_JS);
+ source->SetRequestFilter(base::Bind(OnBeginRequest));
+ WebUIDataSource::Add(browser_context, source);
}
} // namespace content