diff options
author | wangxianzhu@chromium.org <wangxianzhu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-21 06:10:34 +0000 |
---|---|---|
committer | wangxianzhu@chromium.org <wangxianzhu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-21 06:10:34 +0000 |
commit | 4a0a8f968b0d60b5ffc23ccdcb15c443b93ec559 (patch) | |
tree | b551f4cf9636c95181e29e0dcca77891cdea1b23 /content/browser/tracing | |
parent | 2bb3b8e022870b6ae42abed5d8a921b6b08f1c8c (diff) | |
download | chromium_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.cc | 2 | ||||
-rw-r--r-- | content/browser/tracing/tracing_controller_impl.cc | 71 | ||||
-rw-r--r-- | content/browser/tracing/tracing_controller_impl.h | 16 | ||||
-rw-r--r-- | content/browser/tracing/tracing_ui.cc | 622 |
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 |