| Index: content/browser/tracing/tracing_ui.cc
|
| ===================================================================
|
| --- content/browser/tracing/tracing_ui.cc (revision 180281)
|
| +++ content/browser/tracing/tracing_ui.cc (working copy)
|
| @@ -1,492 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "content/browser/tracing/tracing_ui.h"
|
| -
|
| -#include <string>
|
| -
|
| -#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/memory/scoped_ptr.h"
|
| -#include "base/string_number_conversions.h"
|
| -#include "base/stringprintf.h"
|
| -#include "base/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/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/content_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(chrome::kChromeUITracingHost);
|
| -
|
| - source->SetJsonPath("strings.js");
|
| - source->SetDefaultResource(IDR_TRACING_HTML);
|
| - source->AddResourcePath("tracing.js", IDR_TRACING_JS);
|
| - source->AddLocalizedString("tracingTitle", IDS_TRACING_TITLE);
|
| - 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();
|
| -
|
| - // SelectFileDialog::Listener implementation
|
| - virtual void FileSelected(const FilePath& path, int index, void* params);
|
| - virtual void FileSelectionCanceled(void* params);
|
| -
|
| - // TraceSubscriber implementation.
|
| - virtual void OnEndTracingComplete();
|
| - virtual void OnTraceDataCollected(
|
| - const scoped_refptr<base::RefCountedString>& trace_fragment);
|
| - virtual void OnTraceBufferPercentFullReply(float percent_full);
|
| -
|
| - // Messages.
|
| - void OnTracingControllerInitialized(const ListValue* list);
|
| - void OnBeginTracing(const ListValue* list);
|
| - void OnEndTracingAsync(const ListValue* list);
|
| - void OnBeginRequestBufferPercentFull(const ListValue* list);
|
| - void OnLoadTraceFile(const ListValue* list);
|
| - void OnSaveTraceFile(const ListValue* list);
|
| -
|
| - // Callbacks.
|
| - void LoadTraceFileComplete(string16* file_contents);
|
| - void SaveTraceFileComplete();
|
| -
|
| - 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) {
|
| - if (handler_)
|
| - handler_->LoadTraceFileComplete(file_contents);
|
| - delete file_contents;
|
| - }
|
| -
|
| - void SaveTraceFileCompleteProxy() {
|
| - if (handler_)
|
| - handler_->SaveTraceFileComplete();
|
| - }
|
| -
|
| - 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) {
|
| -}
|
| -
|
| -TracingMessageHandler::~TracingMessageHandler() {
|
| - if (select_trace_file_dialog_)
|
| - 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)));
|
| -}
|
| -
|
| -void TracingMessageHandler::OnTracingControllerInitialized(
|
| - const ListValue* args) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - // Send the client info to the tracingController
|
| - {
|
| - scoped_ptr<DictionaryValue> dict(new DictionaryValue());
|
| - dict->SetString("version", GetContentClient()->GetProduct());
|
| -
|
| - dict->SetString("command_line",
|
| - CommandLine::ForCurrentProcess()->GetCommandLineString());
|
| -
|
| - web_ui()->CallJavascriptFunction("tracingController.onClientInfoUpdate",
|
| - *dict);
|
| - }
|
| -}
|
| -
|
| -void TracingMessageHandler::OnBeginRequestBufferPercentFull(
|
| - const 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 FilePath& path) {
|
| - std::string file_contents;
|
| - if (!file_util::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 < ' ') {
|
| - escaped_contents += base::StringPrintf("\\u%04x", c);
|
| - continue;
|
| - }
|
| - if (c == '\\' || c == '\'')
|
| - escaped_contents.push_back('\\');
|
| - escaped_contents.push_back(c);
|
| - }
|
| - 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()));
|
| -}
|
| -
|
| -// A callback used for asynchronously writing a file from a string. Calls the
|
| -// TaskProxy callback when writing is complete.
|
| -void WriteTraceFileCallback(TaskProxy* proxy,
|
| - const FilePath& path,
|
| - std::string* contents) {
|
| - if (!file_util::WriteFile(path, contents->c_str(), contents->size()))
|
| - return;
|
| -
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&TaskProxy::SaveTraceFileCompleteProxy, proxy));
|
| -}
|
| -
|
| -void TracingMessageHandler::FileSelected(
|
| - const 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()));
|
| - }
|
| -
|
| - 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");
|
| - }
|
| -}
|
| -
|
| -void TracingMessageHandler::OnLoadTraceFile(const 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(),
|
| - FilePath(),
|
| - NULL, 0, FILE_PATH_LITERAL(""),
|
| - web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(), NULL);
|
| -}
|
| -
|
| -void TracingMessageHandler::LoadTraceFileComplete(string16* contents) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - // 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.
|
| - // IPC::Channel::kMaximumMessageSize is in bytes, and we need to account for
|
| - // overhead.
|
| - const size_t kMaxSize = IPC::Channel::kMaximumMessageSize / 2 - 128;
|
| - string16 first_prefix = UTF8ToUTF16("window.traceData = '");
|
| - string16 prefix = UTF8ToUTF16("window.traceData += '");
|
| - string16 suffix = UTF8ToUTF16("';");
|
| -
|
| - RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
|
| - for (size_t i = 0; i < contents->size(); i += kMaxSize) {
|
| - string16 javascript = i == 0 ? first_prefix : prefix;
|
| - javascript += contents->substr(i, kMaxSize) + suffix;
|
| - rvh->ExecuteJavascriptInWebFrame(string16(), javascript);
|
| - }
|
| - rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(
|
| - "tracingController.onLoadTraceFileComplete(JSON.parse(window.traceData));"
|
| - "delete window.traceData;"));
|
| -}
|
| -
|
| -void TracingMessageHandler::OnSaveTraceFile(const ListValue* list) {
|
| - // Only allow a single dialog at a time.
|
| - if (select_trace_file_dialog_.get())
|
| - return;
|
| -
|
| - DCHECK(list->GetSize() == 1);
|
| -
|
| - 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(),
|
| - FilePath(),
|
| - NULL, 0, FILE_PATH_LITERAL(""),
|
| - web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(), NULL);
|
| -}
|
| -
|
| -void TracingMessageHandler::SaveTraceFileComplete() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - web_ui()->CallJavascriptFunction("tracingController.onSaveTraceFileComplete");
|
| -}
|
| -
|
| -void TracingMessageHandler::OnBeginTracing(const ListValue* args) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - DCHECK_EQ(args->GetSize(), (size_t) 2);
|
| -
|
| - 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);
|
| -
|
| - 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);
|
| -
|
| - 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 TracingMessageHandler::OnEndTracingAsync(const ListValue* list) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - // 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 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
|
| - }
|
| - web_ui()->CallJavascriptFunction("tracingController.onEndTracingComplete");
|
| -}
|
| -
|
| -void TracingMessageHandler::OnEndSystemTracingAck(
|
| - const scoped_refptr<base::RefCountedString>& events_str_ptr) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - web_ui()->CallJavascriptFunction(
|
| - "tracingController.onSystemTraceDataCollected",
|
| - *scoped_ptr<Value>(Value::CreateStringValue(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));
|
| -
|
| - base::debug::TraceResultBuffer::SimpleOutput output;
|
| - base::debug::TraceResultBuffer trace_buffer;
|
| - trace_buffer.SetOutputCallback(output.GetCallback());
|
| - output.Append("tracingController.onTraceDataCollected(");
|
| - trace_buffer.Start();
|
| - trace_buffer.AddFragment(trace_fragment->data());
|
| - trace_buffer.Finish();
|
| - output.Append(");");
|
| -
|
| - web_ui()->GetWebContents()->GetRenderViewHost()->
|
| - ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(output.json_output));
|
| -}
|
| -
|
| -void TracingMessageHandler::OnTraceBufferPercentFullReply(float percent_full) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - web_ui()->CallJavascriptFunction(
|
| - "tracingController.onRequestBufferPercentFullComplete",
|
| - *scoped_ptr<Value>(Value::CreateDoubleValue(percent_full)));
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -//
|
| -// TracingUI
|
| -//
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -
|
| -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());
|
| -}
|
| -
|
| -} // namespace content
|
|
|