summaryrefslogtreecommitdiff
path: root/chromium/content/browser/tracing
diff options
context:
space:
mode:
authorAndras Becsi <andras.becsi@digia.com>2014-03-18 13:16:26 +0100
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-03-20 15:55:39 +0100
commit3f0f86b0caed75241fa71c95a5d73bc0164348c5 (patch)
tree92b9fb00f2e9e90b0be2262093876d4f43b6cd13 /chromium/content/browser/tracing
parente90d7c4b152c56919d963987e2503f9909a666d2 (diff)
downloadqtwebengine-chromium-3f0f86b0caed75241fa71c95a5d73bc0164348c5.tar.gz
Update to new stable branch 1750
This also includes an updated ninja and chromium dependencies needed on Windows. Change-Id: Icd597d80ed3fa4425933c9f1334c3c2e31291c42 Reviewed-by: Zoltan Arvai <zarvai@inf.u-szeged.hu> Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'chromium/content/browser/tracing')
-rw-r--r--chromium/content/browser/tracing/trace_controller_impl.cc417
-rw-r--r--chromium/content/browser/tracing/trace_controller_impl.h109
-rw-r--r--chromium/content/browser/tracing/trace_message_filter.cc79
-rw-r--r--chromium/content/browser/tracing/trace_message_filter.h13
-rw-r--r--chromium/content/browser/tracing/trace_subscriber_stdio.cc201
-rw-r--r--chromium/content/browser/tracing/trace_subscriber_stdio.h57
-rw-r--r--chromium/content/browser/tracing/trace_subscriber_stdio_unittest.cc132
-rw-r--r--chromium/content/browser/tracing/tracing_controller_browsertest.cc205
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl.cc531
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl.h107
-rw-r--r--chromium/content/browser/tracing/tracing_ui.cc593
11 files changed, 881 insertions, 1563 deletions
diff --git a/chromium/content/browser/tracing/trace_controller_impl.cc b/chromium/content/browser/tracing/trace_controller_impl.cc
deleted file mode 100644
index fe08639876d..00000000000
--- a/chromium/content/browser/tracing/trace_controller_impl.cc
+++ /dev/null
@@ -1,417 +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/trace_controller_impl.h"
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/strings/string_number_conversions.h"
-#include "content/browser/tracing/trace_message_filter.h"
-#include "content/browser/tracing/trace_subscriber_stdio.h"
-#include "content/common/child_process_messages.h"
-#include "content/public/browser/browser_message_filter.h"
-#include "content/public/common/content_switches.h"
-
-using base::debug::TraceLog;
-
-namespace content {
-
-namespace {
-
-base::LazyInstance<TraceControllerImpl>::Leaky g_controller =
- LAZY_INSTANCE_INITIALIZER;
-
-class AutoStopTraceSubscriberStdio : public TraceSubscriberStdio {
- public:
- AutoStopTraceSubscriberStdio(const base::FilePath& file_path)
- : TraceSubscriberStdio(file_path,
- FILE_TYPE_PROPERTY_LIST,
- false) {}
-
- static void EndStartupTrace(AutoStopTraceSubscriberStdio* subscriber) {
- if (!TraceControllerImpl::GetInstance()->EndTracingAsync(subscriber))
- delete subscriber;
- // else, the tracing will end asynchronously in OnEndTracingComplete().
- }
-
- virtual void OnEndTracingComplete() OVERRIDE {
- TraceSubscriberStdio::OnEndTracingComplete();
- delete this;
- // TODO(joth): this would be the time to automatically open up
- // chrome://tracing/ and load up the trace data collected.
- }
-};
-
-} // namespace
-
-TraceController* TraceController::GetInstance() {
- return TraceControllerImpl::GetInstance();
-}
-
-TraceControllerImpl::TraceControllerImpl() :
- subscriber_(NULL),
- pending_end_ack_count_(0),
- pending_bpf_ack_count_(0),
- maximum_bpf_(0.0f),
- is_tracing_(false),
- is_get_category_groups_(false),
- category_filter_(
- base::debug::CategoryFilter::kDefaultCategoryFilterString) {
- TraceLog::GetInstance()->SetNotificationCallback(
- base::Bind(&TraceControllerImpl::OnTraceNotification,
- base::Unretained(this)));
-}
-
-TraceControllerImpl::~TraceControllerImpl() {
- // No need to SetNotificationCallback(nil) on the TraceLog since this is a
- // Leaky instance.
- NOTREACHED();
-}
-
-TraceControllerImpl* TraceControllerImpl::GetInstance() {
- return g_controller.Pointer();
-}
-
-void TraceControllerImpl::InitStartupTracing(const CommandLine& command_line) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- base::FilePath trace_file = command_line.GetSwitchValuePath(
- switches::kTraceStartupFile);
- // trace_file = "none" means that startup events will show up for the next
- // begin/end tracing (via about:tracing or AutomationProxy::BeginTracing/
- // EndTracing, for example).
- if (trace_file == base::FilePath().AppendASCII("none"))
- return;
-
- if (trace_file.empty()) {
- // Default to saving the startup trace into the current dir.
- trace_file = base::FilePath().AppendASCII("chrometrace.log");
- }
- scoped_ptr<AutoStopTraceSubscriberStdio> subscriber(
- new AutoStopTraceSubscriberStdio(trace_file));
- DCHECK(can_begin_tracing(subscriber.get()));
-
- std::string delay_str = command_line.GetSwitchValueASCII(
- switches::kTraceStartupDuration);
- int delay_secs = 5;
- if (!delay_str.empty() && !base::StringToInt(delay_str, &delay_secs)) {
- DLOG(WARNING) << "Could not parse --" << switches::kTraceStartupDuration
- << "=" << delay_str << " defaulting to 5 (secs)";
- delay_secs = 5;
- }
-
- OnTracingBegan(subscriber.get());
- BrowserThread::PostDelayedTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&AutoStopTraceSubscriberStdio::EndStartupTrace,
- base::Unretained(subscriber.release())),
- base::TimeDelta::FromSeconds(delay_secs));
-}
-
-bool TraceControllerImpl::GetKnownCategoryGroupsAsync(
- TraceSubscriber* subscriber) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Known categories come back from child processes with the EndTracingAck
- // message. So to get known categories, just begin and end tracing immediately
- // afterwards. This will ping all the child processes for categories.
- is_get_category_groups_ = true;
- bool success = BeginTracing(subscriber, "*",
- TraceLog::GetInstance()->trace_options()) &&
- EndTracingAsync(subscriber);
- is_get_category_groups_ = success;
- return success;
-}
-
-bool TraceControllerImpl::BeginTracing(TraceSubscriber* subscriber,
- const std::string& category_patterns,
- base::debug::TraceLog::Options options) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (!can_begin_tracing(subscriber))
- return false;
-
- // Enable tracing
- TraceLog::GetInstance()->SetEnabled(
- base::debug::CategoryFilter(category_patterns), options);
-
- OnTracingBegan(subscriber);
-
- return true;
-}
-
-bool TraceControllerImpl::EndTracingAsync(TraceSubscriber* subscriber) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (!can_end_tracing() || subscriber != subscriber_)
- return false;
-
- // Disable local trace early to avoid traces during end-tracing process from
- // interfering with the process.
- TraceLog::GetInstance()->SetDisabled();
-
- // There could be a case where there are no child processes and filters_
- // is empty. In that case we can immediately tell the subscriber that tracing
- // has ended. To avoid recursive calls back to the subscriber, we will just
- // use the existing asynchronous OnEndTracingAck code.
- // Count myself (local trace) in pending_end_ack_count_, acked below.
- pending_end_ack_count_ = filters_.size() + 1;
-
- // Handle special case of zero child processes.
- if (pending_end_ack_count_ == 1) {
- // Ack asynchronously now, because we don't have any children to wait for.
- std::vector<std::string> category_groups;
- TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TraceControllerImpl::OnEndTracingAck,
- base::Unretained(this), category_groups));
- }
-
- // Notify all child processes.
- for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
- it->get()->SendEndTracing();
- }
-
- return true;
-}
-
-bool TraceControllerImpl::GetTraceBufferPercentFullAsync(
- TraceSubscriber* subscriber) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (!can_get_buffer_percent_full() || subscriber != subscriber_)
- return false;
-
- maximum_bpf_ = 0.0f;
- pending_bpf_ack_count_ = filters_.size() + 1;
-
- // Handle special case of zero child processes.
- if (pending_bpf_ack_count_ == 1) {
- // Ack asynchronously now, because we don't have any children to wait for.
- float bpf = TraceLog::GetInstance()->GetBufferPercentFull();
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TraceControllerImpl::OnTraceBufferPercentFullReply,
- base::Unretained(this), bpf));
- }
-
- // Message all child processes.
- for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
- it->get()->SendGetTraceBufferPercentFull();
- }
-
- return true;
-}
-
-bool TraceControllerImpl::SetWatchEvent(TraceSubscriber* subscriber,
- const std::string& category_name,
- const std::string& event_name) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (subscriber != subscriber_)
- return false;
-
- watch_category_ = category_name;
- watch_name_ = event_name;
-
- TraceLog::GetInstance()->SetWatchEvent(category_name, event_name);
- for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it)
- it->get()->SendSetWatchEvent(category_name, event_name);
-
- return true;
-}
-
-bool TraceControllerImpl::CancelWatchEvent(TraceSubscriber* subscriber) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (subscriber != subscriber_)
- return false;
-
- watch_category_.clear();
- watch_name_.clear();
-
- TraceLog::GetInstance()->CancelWatchEvent();
- for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it)
- it->get()->SendCancelWatchEvent();
-
- return true;
-}
-
-void TraceControllerImpl::CancelSubscriber(TraceSubscriber* subscriber) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (subscriber == subscriber_) {
- subscriber_ = NULL;
- // End tracing if necessary.
- if (is_tracing_ && pending_end_ack_count_ == 0)
- EndTracingAsync(NULL);
- }
-}
-
-void TraceControllerImpl::AddFilter(TraceMessageFilter* filter) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TraceControllerImpl::AddFilter, base::Unretained(this),
- make_scoped_refptr(filter)));
- return;
- }
-
- filters_.insert(filter);
- if (is_tracing_enabled()) {
- std::string cf_str = category_filter_.ToString();
- filter->SendBeginTracing(cf_str, trace_options_);
- if (!watch_category_.empty())
- filter->SendSetWatchEvent(watch_category_, watch_name_);
- }
-}
-
-void TraceControllerImpl::RemoveFilter(TraceMessageFilter* filter) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TraceControllerImpl::RemoveFilter, base::Unretained(this),
- make_scoped_refptr(filter)));
- return;
- }
-
- filters_.erase(filter);
-}
-
-void TraceControllerImpl::OnTracingBegan(TraceSubscriber* subscriber) {
- is_tracing_ = true;
-
- subscriber_ = subscriber;
-
- category_filter_ = TraceLog::GetInstance()->GetCurrentCategoryFilter();
- trace_options_ = TraceLog::GetInstance()->trace_options();
-
- // Notify all child processes.
- for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
- it->get()->SendBeginTracing(category_filter_.ToString(), trace_options_);
- }
-}
-
-void TraceControllerImpl::OnEndTracingAck(
- const std::vector<std::string>& known_category_groups) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TraceControllerImpl::OnEndTracingAck,
- base::Unretained(this), known_category_groups));
- return;
- }
-
- // Merge known_category_groups with known_category_groups_
- known_category_groups_.insert(known_category_groups.begin(),
- known_category_groups.end());
-
- if (pending_end_ack_count_ == 0)
- return;
-
-
- if (--pending_end_ack_count_ == 1) {
- // All acks from subprocesses have been received. Now flush the local trace.
- // During or after this call, our OnLocalTraceDataCollected will be
- // called with the last of the local trace data.
- TraceLog::GetInstance()->Flush(
- base::Bind(&TraceControllerImpl::OnLocalTraceDataCollected,
- base::Unretained(this)));
- }
-
- if (pending_end_ack_count_ == 0) {
- // All acks (including from the subprocesses and the local trace) have been
- // received.
- is_tracing_ = false;
-
- // Trigger callback if one is set.
- if (subscriber_) {
- if (is_get_category_groups_)
- subscriber_->OnKnownCategoriesCollected(known_category_groups_);
- else
- subscriber_->OnEndTracingComplete();
- // Clear subscriber so that others can use TraceController.
- subscriber_ = NULL;
- }
-
- is_get_category_groups_ = false;
- }
-}
-
-void TraceControllerImpl::OnTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& events_str_ptr) {
- // OnTraceDataCollected may be called from any browser thread, either by the
- // local event trace system or from child processes via TraceMessageFilter.
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TraceControllerImpl::OnTraceDataCollected,
- base::Unretained(this), events_str_ptr));
- return;
- }
-
- // Drop trace events if we are just getting categories.
- if (subscriber_ && !is_get_category_groups_)
- subscriber_->OnTraceDataCollected(events_str_ptr);
-}
-
-void TraceControllerImpl::OnLocalTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& events_str_ptr,
- bool has_more_events) {
- if (events_str_ptr->data().size())
- OnTraceDataCollected(events_str_ptr);
-
- if (!has_more_events) {
- // Simulate an EndTrackingAck for the local trace.
- std::vector<std::string> category_groups;
- TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
- OnEndTracingAck(category_groups);
- }
-}
-
-void TraceControllerImpl::OnTraceNotification(int notification) {
- // OnTraceNotification may be called from any browser thread, either by the
- // local event trace system or from child processes via TraceMessageFilter.
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TraceControllerImpl::OnTraceNotification,
- base::Unretained(this), notification));
- return;
- }
-
- if (notification & base::debug::TraceLog::TRACE_BUFFER_FULL) {
- // EndTracingAsync may return false if tracing is already in the process
- // of being ended. That is ok.
- EndTracingAsync(subscriber_);
- }
- if (notification & base::debug::TraceLog::EVENT_WATCH_NOTIFICATION) {
- if (subscriber_)
- subscriber_->OnEventWatchNotification();
- }
-}
-
-void TraceControllerImpl::OnTraceBufferPercentFullReply(float percent_full) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TraceControllerImpl::OnTraceBufferPercentFullReply,
- base::Unretained(this), percent_full));
- return;
- }
-
- if (pending_bpf_ack_count_ == 0)
- return;
-
- maximum_bpf_ = (maximum_bpf_ > percent_full)? maximum_bpf_ : percent_full;
-
- if (--pending_bpf_ack_count_ == 0) {
- // Trigger callback if one is set.
- if (subscriber_)
- subscriber_->OnTraceBufferPercentFullReply(maximum_bpf_);
- }
-
- if (pending_bpf_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.
- float bpf = TraceLog::GetInstance()->GetBufferPercentFull();
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TraceControllerImpl::OnTraceBufferPercentFullReply,
- base::Unretained(this), bpf));
- }
-}
-
-} // namespace content
diff --git a/chromium/content/browser/tracing/trace_controller_impl.h b/chromium/content/browser/tracing/trace_controller_impl.h
deleted file mode 100644
index 6f2ccb5d481..00000000000
--- a/chromium/content/browser/tracing/trace_controller_impl.h
+++ /dev/null
@@ -1,109 +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.
-
-#ifndef CONTENT_BROWSER_TRACING_TRACE_CONTROLLER_IMPL_H_
-#define CONTENT_BROWSER_TRACING_TRACE_CONTROLLER_IMPL_H_
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/debug/trace_event.h"
-#include "base/lazy_instance.h"
-#include "content/public/browser/trace_controller.h"
-
-class CommandLine;
-
-namespace content {
-class TraceMessageFilter;
-
-class TraceControllerImpl : public TraceController {
- public:
- static TraceControllerImpl* GetInstance();
-
- // Called on the main thread of the browser process to initialize
- // startup tracing.
- void InitStartupTracing(const CommandLine& command_line);
-
- // TraceController implementation:
- virtual bool BeginTracing(TraceSubscriber* subscriber,
- const std::string& category_patterns,
- base::debug::TraceLog::Options options) OVERRIDE;
- virtual bool EndTracingAsync(TraceSubscriber* subscriber) OVERRIDE;
- virtual bool GetTraceBufferPercentFullAsync(
- TraceSubscriber* subscriber) OVERRIDE;
- virtual bool SetWatchEvent(TraceSubscriber* subscriber,
- const std::string& category_name,
- const std::string& event_name) OVERRIDE;
- virtual bool CancelWatchEvent(TraceSubscriber* subscriber) OVERRIDE;
- virtual void CancelSubscriber(TraceSubscriber* subscriber) OVERRIDE;
- virtual bool GetKnownCategoryGroupsAsync(TraceSubscriber* subscriber)
- OVERRIDE;
-
- private:
- typedef std::set<scoped_refptr<TraceMessageFilter> > FilterMap;
-
- friend struct base::DefaultLazyInstanceTraits<TraceControllerImpl>;
- friend class TraceMessageFilter;
-
- TraceControllerImpl();
- virtual ~TraceControllerImpl();
-
- bool is_tracing_enabled() const {
- return can_end_tracing();
- }
-
- bool can_end_tracing() const {
- return is_tracing_ && pending_end_ack_count_ == 0;
- }
-
- // Can get Buffer Percent Full
- bool can_get_buffer_percent_full() const {
- return is_tracing_ &&
- pending_end_ack_count_ == 0 &&
- pending_bpf_ack_count_ == 0;
- }
-
- bool can_begin_tracing(TraceSubscriber* subscriber) const {
- return !is_tracing_ &&
- (subscriber_ == NULL || subscriber == subscriber_);
- }
-
- // Methods for use by TraceMessageFilter.
-
- void AddFilter(TraceMessageFilter* filter);
- void RemoveFilter(TraceMessageFilter* filter);
- void OnTracingBegan(TraceSubscriber* subscriber);
- void OnEndTracingAck(const std::vector<std::string>& known_category_groups);
- void OnTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& events_str_ptr);
- void OnTraceNotification(int notification);
- void OnTraceBufferPercentFullReply(float percent_full);
-
- // Callback of TraceLog::Flush() for the local trace.
- void OnLocalTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& events_str_ptr,
- bool has_more_events);
-
- FilterMap filters_;
- TraceSubscriber* subscriber_;
- // Pending acks for EndTracingAsync:
- int pending_end_ack_count_;
- // Pending acks for GetTraceBufferPercentFullAsync:
- int pending_bpf_ack_count_;
- float maximum_bpf_;
- bool is_tracing_;
- bool is_get_category_groups_;
- std::set<std::string> known_category_groups_;
- std::string watch_category_;
- std::string watch_name_;
- base::debug::TraceLog::Options trace_options_;
- base::debug::CategoryFilter category_filter_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceControllerImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_TRACING_TRACE_CONTROLLER_IMPL_H_
diff --git a/chromium/content/browser/tracing/trace_message_filter.cc b/chromium/content/browser/tracing/trace_message_filter.cc
index e75d786142d..35f23dc1025 100644
--- a/chromium/content/browser/tracing/trace_message_filter.cc
+++ b/chromium/content/browser/tracing/trace_message_filter.cc
@@ -5,33 +5,31 @@
#include "content/browser/tracing/trace_message_filter.h"
#include "components/tracing/tracing_messages.h"
-#include "content/browser/tracing/trace_controller_impl.h"
+#include "content/browser/tracing/tracing_controller_impl.h"
namespace content {
TraceMessageFilter::TraceMessageFilter() :
has_child_(false),
is_awaiting_end_ack_(false),
+ is_awaiting_capture_monitoring_snapshot_ack_(false),
is_awaiting_buffer_percent_full_ack_(false) {
}
-void TraceMessageFilter::OnFilterAdded(IPC::Channel* channel) {
- // Always on IO thread (BrowserMessageFilter guarantee).
- BrowserMessageFilter::OnFilterAdded(channel);
-}
+TraceMessageFilter::~TraceMessageFilter() {}
void TraceMessageFilter::OnChannelClosing() {
- // Always on IO thread (BrowserMessageFilter guarantee).
- BrowserMessageFilter::OnChannelClosing();
-
if (has_child_) {
if (is_awaiting_end_ack_)
OnEndTracingAck(std::vector<std::string>());
+ if (is_awaiting_capture_monitoring_snapshot_ack_)
+ OnCaptureMonitoringSnapshotAcked();
+
if (is_awaiting_buffer_percent_full_ack_)
OnTraceBufferPercentFullReply(0.0f);
- TraceControllerImpl::GetInstance()->RemoveFilter(this);
+ TracingControllerImpl::GetInstance()->RemoveTraceMessageFilter(this);
}
}
@@ -43,10 +41,14 @@ bool TraceMessageFilter::OnMessageReceived(const IPC::Message& message,
IPC_MESSAGE_HANDLER(TracingHostMsg_ChildSupportsTracing,
OnChildSupportsTracing)
IPC_MESSAGE_HANDLER(TracingHostMsg_EndTracingAck, OnEndTracingAck)
+ IPC_MESSAGE_HANDLER(TracingHostMsg_CaptureMonitoringSnapshotAck,
+ OnCaptureMonitoringSnapshotAcked)
IPC_MESSAGE_HANDLER(TracingHostMsg_TraceDataCollected,
OnTraceDataCollected)
- IPC_MESSAGE_HANDLER(TracingHostMsg_TraceNotification,
- OnTraceNotification)
+ IPC_MESSAGE_HANDLER(TracingHostMsg_MonitoringTraceDataCollected,
+ OnMonitoringTraceDataCollected)
+ IPC_MESSAGE_HANDLER(TracingHostMsg_WatchEventMatched,
+ OnWatchEventMatched)
IPC_MESSAGE_HANDLER(TracingHostMsg_TraceBufferPercentFullReply,
OnTraceBufferPercentFullReply)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -70,6 +72,27 @@ void TraceMessageFilter::SendEndTracing() {
Send(new TracingMsg_EndTracing);
}
+void TraceMessageFilter::SendEnableMonitoring(
+ const std::string& category_filter_str,
+ base::debug::TraceLog::Options options) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ Send(new TracingMsg_EnableMonitoring(category_filter_str,
+ base::TimeTicks::NowFromSystemTraceTime(),
+ options));
+}
+
+void TraceMessageFilter::SendDisableMonitoring() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ Send(new TracingMsg_DisableMonitoring);
+}
+
+void TraceMessageFilter::SendCaptureMonitoringSnapshot() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(!is_awaiting_capture_monitoring_snapshot_ack_);
+ is_awaiting_capture_monitoring_snapshot_ack_ = true;
+ Send(new TracingMsg_CaptureMonitoringSnapshot);
+}
+
void TraceMessageFilter::SendGetTraceBufferPercentFull() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!is_awaiting_buffer_percent_full_ack_);
@@ -86,11 +109,9 @@ void TraceMessageFilter::SendCancelWatchEvent() {
Send(new TracingMsg_CancelWatchEvent);
}
-TraceMessageFilter::~TraceMessageFilter() {}
-
void TraceMessageFilter::OnChildSupportsTracing() {
has_child_ = true;
- TraceControllerImpl::GetInstance()->AddFilter(this);
+ TracingControllerImpl::GetInstance()->AddTraceMessageFilter(this);
}
void TraceMessageFilter::OnEndTracingAck(
@@ -99,7 +120,19 @@ void TraceMessageFilter::OnEndTracingAck(
// child process is compromised.
if (is_awaiting_end_ack_) {
is_awaiting_end_ack_ = false;
- TraceControllerImpl::GetInstance()->OnEndTracingAck(known_categories);
+ TracingControllerImpl::GetInstance()->OnDisableRecordingAcked(
+ known_categories);
+ } else {
+ NOTREACHED();
+ }
+}
+
+void TraceMessageFilter::OnCaptureMonitoringSnapshotAcked() {
+ // is_awaiting_capture_monitoring_snapshot_ack_ should always be true here,
+ // but check in case the child process is compromised.
+ if (is_awaiting_capture_monitoring_snapshot_ack_) {
+ is_awaiting_capture_monitoring_snapshot_ack_ = false;
+ TracingControllerImpl::GetInstance()->OnCaptureMonitoringSnapshotAcked();
} else {
NOTREACHED();
}
@@ -108,17 +141,25 @@ void TraceMessageFilter::OnEndTracingAck(
void TraceMessageFilter::OnTraceDataCollected(const std::string& data) {
scoped_refptr<base::RefCountedString> data_ptr(new base::RefCountedString());
data_ptr->data() = data;
- TraceControllerImpl::GetInstance()->OnTraceDataCollected(data_ptr);
+ TracingControllerImpl::GetInstance()->OnTraceDataCollected(data_ptr);
+}
+
+void TraceMessageFilter::OnMonitoringTraceDataCollected(
+ const std::string& data) {
+ scoped_refptr<base::RefCountedString> data_ptr(new base::RefCountedString());
+ data_ptr->data() = data;
+ TracingControllerImpl::GetInstance()->OnMonitoringTraceDataCollected(
+ data_ptr);
}
-void TraceMessageFilter::OnTraceNotification(int notification) {
- TraceControllerImpl::GetInstance()->OnTraceNotification(notification);
+void TraceMessageFilter::OnWatchEventMatched() {
+ TracingControllerImpl::GetInstance()->OnWatchEventMatched();
}
void TraceMessageFilter::OnTraceBufferPercentFullReply(float percent_full) {
if (is_awaiting_buffer_percent_full_ack_) {
is_awaiting_buffer_percent_full_ack_ = false;
- TraceControllerImpl::GetInstance()->OnTraceBufferPercentFullReply(
+ TracingControllerImpl::GetInstance()->OnTraceBufferPercentFullReply(
percent_full);
} else {
NOTREACHED();
diff --git a/chromium/content/browser/tracing/trace_message_filter.h b/chromium/content/browser/tracing/trace_message_filter.h
index 41fd017827f..0f9e18ed9c3 100644
--- a/chromium/content/browser/tracing/trace_message_filter.h
+++ b/chromium/content/browser/tracing/trace_message_filter.h
@@ -20,9 +20,6 @@ class TraceMessageFilter : public BrowserMessageFilter {
public:
TraceMessageFilter();
- // BrowserMessageFilter override.
- virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE;
-
// BrowserMessageFilter implementation.
virtual void OnChannelClosing() OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message,
@@ -31,6 +28,10 @@ class TraceMessageFilter : public BrowserMessageFilter {
void SendBeginTracing(const std::string& category_filter_str,
base::debug::TraceLog::Options options);
void SendEndTracing();
+ void SendEnableMonitoring(const std::string& category_filter_str,
+ base::debug::TraceLog::Options options);
+ void SendDisableMonitoring();
+ void SendCaptureMonitoringSnapshot();
void SendGetTraceBufferPercentFull();
void SendSetWatchEvent(const std::string& category_name,
const std::string& event_name);
@@ -43,15 +44,19 @@ class TraceMessageFilter : public BrowserMessageFilter {
// Message handlers.
void OnChildSupportsTracing();
void OnEndTracingAck(const std::vector<std::string>& known_categories);
- void OnTraceNotification(int notification);
+ void OnCaptureMonitoringSnapshotAcked();
+ void OnWatchEventMatched();
void OnTraceBufferPercentFullReply(float percent_full);
void OnTraceDataCollected(const std::string& data);
+ void OnMonitoringTraceDataCollected(const std::string& data);
// ChildTraceMessageFilter exists:
bool has_child_;
// Awaiting ack for previously sent SendEndTracing
bool is_awaiting_end_ack_;
+ // Awaiting ack for previously sent SendCaptureMonitoringSnapshot
+ bool is_awaiting_capture_monitoring_snapshot_ack_;
// Awaiting ack for previously sent SendGetTraceBufferPercentFull
bool is_awaiting_buffer_percent_full_ack_;
diff --git a/chromium/content/browser/tracing/trace_subscriber_stdio.cc b/chromium/content/browser/tracing/trace_subscriber_stdio.cc
deleted file mode 100644
index 2c6aede56ce..00000000000
--- a/chromium/content/browser/tracing/trace_subscriber_stdio.cc
+++ /dev/null
@@ -1,201 +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/trace_subscriber_stdio.h"
-
-#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace content {
-
-// All method calls on this class are done on a SequencedWorkerPool thread.
-class TraceSubscriberStdio::TraceSubscriberStdioWorker
- : public base::RefCountedThreadSafe<TraceSubscriberStdioWorker> {
- public:
- TraceSubscriberStdioWorker(const base::FilePath& path,
- FileType file_type,
- bool has_system_trace)
- : path_(path),
- file_type_(file_type),
- has_system_trace_(has_system_trace),
- file_(0),
- needs_comma_(false),
- wrote_trace_(false),
- has_pending_system_trace_(false),
- wrote_system_trace_(false) {}
-
- void OnTraceStart() {
- DCHECK(!file_);
- file_ = file_util::OpenFile(path_, "w+");
- if (!IsValid()) {
- LOG(ERROR) << "Failed to open performance trace file: " << path_.value();
- return;
- }
-
- LOG(INFO) << "Logging performance trace to file: " << path_.value();
- if (file_type_ == FILE_TYPE_PROPERTY_LIST)
- WriteString("{\"traceEvents\":");
- WriteString("[");
- }
-
- void OnTraceData(const scoped_refptr<base::RefCountedString>& data_ptr) {
- if (!IsValid())
- return;
- DCHECK(!data_ptr->data().empty());
- if (needs_comma_)
- WriteString(",");
- WriteString(data_ptr->data());
- needs_comma_ = true;
- }
-
- void OnSystemTraceData(
- const scoped_refptr<base::RefCountedString>& data_ptr) {
- if (wrote_trace_) {
- WriteSystemTrace(data_ptr);
- End();
- } else {
- pending_system_trace_ = data_ptr;
- has_pending_system_trace_ = true;
- }
- }
-
- void OnTraceEnd() {
- if (!IsValid())
- return;
- WriteString("]");
-
- wrote_trace_ = true;
-
- if (!has_system_trace_ || wrote_system_trace_) {
- End();
- return;
- }
-
- WriteString(",");
- if (has_pending_system_trace_) {
- WriteSystemTrace(pending_system_trace_);
- End();
- }
- }
-
- private:
- friend class base::RefCountedThreadSafe<TraceSubscriberStdioWorker>;
-
- ~TraceSubscriberStdioWorker() {
- CloseFile();
- }
-
- bool IsValid() const {
- return file_ && (0 == ferror(file_));
- }
-
- void CloseFile() {
- if (file_) {
- fclose(file_);
- file_ = 0;
-
- }
- }
-
- void End() {
- if (file_type_ == FILE_TYPE_PROPERTY_LIST)
- WriteString("}");
- CloseFile();
- }
-
- void WriteSystemTrace(const scoped_refptr<base::RefCountedString>& data_ptr) {
- // Newlines need to be replaced with the string "\n" to be parsed correctly.
- // Double quotes need to be replaced with the string "\"".
- // System logs are ASCII.
- const std::string& data = data_ptr->data();
- const char* chars = data.c_str();
- WriteString("\"systemTraceEvents\":\"");
- size_t old_index = 0;
- for (size_t new_index = data.find_first_of("\n\"");
- std::string::npos != new_index;
- old_index = new_index + 1,
- new_index = data.find_first_of("\n\"", old_index)) {
- WriteChars(chars + old_index, new_index - old_index);
- if (chars[new_index] == '\n')
- WriteChars("\\n", 2);
- else
- WriteChars("\\\"", 2);
- }
- WriteChars(chars + old_index, data.size() - old_index);
- WriteString("\"");
- wrote_system_trace_ = true;
- }
-
- void WriteChars(const char* output_chars, size_t size) {
- if (size == 0)
- return;
-
- if (IsValid()) {
- size_t written = fwrite(output_chars, 1, size, file_);
- if (written != size) {
- LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file";
- CloseFile();
- }
- }
- }
-
- void WriteString(const std::string& output_str) {
- WriteChars(output_str.data(), output_str.size());
- }
-
- base::FilePath path_;
- const FileType file_type_;
- const bool has_system_trace_;
- FILE* file_;
- bool needs_comma_;
- bool wrote_trace_;
- bool has_pending_system_trace_;
- bool wrote_system_trace_;
- scoped_refptr<base::RefCountedString> pending_system_trace_;
- DISALLOW_COPY_AND_ASSIGN(TraceSubscriberStdioWorker);
-};
-
-TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path,
- FileType file_type,
- bool has_system_trace)
- : worker_(new TraceSubscriberStdioWorker(path,
- file_type,
- has_system_trace)) {
- if (has_system_trace)
- CHECK_EQ(FILE_TYPE_PROPERTY_LIST, file_type);
- BrowserThread::PostBlockingPoolSequencedTask(
- __FILE__, FROM_HERE,
- base::Bind(&TraceSubscriberStdioWorker::OnTraceStart, worker_));
-}
-
-TraceSubscriberStdio::~TraceSubscriberStdio() {
-}
-
-void TraceSubscriberStdio::OnEndTracingComplete() {
- BrowserThread::PostBlockingPoolSequencedTask(
- __FILE__, FROM_HERE,
- base::Bind(&TraceSubscriberStdioWorker::OnTraceEnd, worker_));
-}
-
-void TraceSubscriberStdio::OnTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& data_ptr) {
- BrowserThread::PostBlockingPoolSequencedTask(
- __FILE__, FROM_HERE,
- base::Bind(&TraceSubscriberStdioWorker::OnTraceData, worker_, data_ptr));
-}
-
-void TraceSubscriberStdio::OnEndSystemTracing(
- const scoped_refptr<base::RefCountedString>& events_str_ptr) {
- BrowserThread::PostBlockingPoolSequencedTask(
- __FILE__, FROM_HERE,
- base::Bind(&TraceSubscriberStdioWorker::OnSystemTraceData,
- worker_,
- events_str_ptr));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/tracing/trace_subscriber_stdio.h b/chromium/content/browser/tracing/trace_subscriber_stdio.h
deleted file mode 100644
index b9fc4f74c19..00000000000
--- a/chromium/content/browser/tracing/trace_subscriber_stdio.h
+++ /dev/null
@@ -1,57 +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.
-
-#ifndef CONTENT_BROWSER_TRACING_TRACE_SUBSCRIBER_STDIO_H_
-#define CONTENT_BROWSER_TRACING_TRACE_SUBSCRIBER_STDIO_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "content/public/browser/trace_subscriber.h"
-#include "content/common/content_export.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace content {
-
-// Stdio implementation of TraceSubscriber. Use this to write traces to a file.
-class CONTENT_EXPORT TraceSubscriberStdio
- : NON_EXPORTED_BASE(public TraceSubscriber) {
- public:
- enum FileType {
- // Output file as array, representing trace events:
- // [event1, event2, ...]
- FILE_TYPE_ARRAY,
- // Output file as property list with one or two items:
- // {traceEvents: [event1, event2, ...],
- // systemTraceEvents: "event1\nevent2\n..." // optional}
- FILE_TYPE_PROPERTY_LIST
- };
-
- // has_system_trace indicates whether system trace events are expected.
- TraceSubscriberStdio(const base::FilePath& path,
- FileType file_type,
- bool has_system_trace);
- virtual ~TraceSubscriberStdio();
-
- // Implementation of TraceSubscriber
- virtual void OnEndTracingComplete() OVERRIDE;
- virtual void OnTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& data_ptr) OVERRIDE;
-
- // To be used as callback to DebugDaemonClient::RequestStopSystemTracing().
- virtual void OnEndSystemTracing(
- const scoped_refptr<base::RefCountedString>& events_str_ptr);
-
- private:
- class TraceSubscriberStdioWorker;
- scoped_refptr<TraceSubscriberStdioWorker> worker_;
- DISALLOW_COPY_AND_ASSIGN(TraceSubscriberStdio);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_TRACING_TRACE_SUBSCRIBER_STDIO_H_
diff --git a/chromium/content/browser/tracing/trace_subscriber_stdio_unittest.cc b/chromium/content/browser/tracing/trace_subscriber_stdio_unittest.cc
deleted file mode 100644
index 10e51a968df..00000000000
--- a/chromium/content/browser/tracing/trace_subscriber_stdio_unittest.cc
+++ /dev/null
@@ -1,132 +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/trace_subscriber_stdio.h"
-
-#include "base/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "content/public/browser/browser_thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-class TraceSubscriberStdioTest : public ::testing::Test {};
-
-TEST_F(TraceSubscriberStdioTest, CanWriteArray) {
- base::ScopedTempDir trace_dir;
- ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
- base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
- {
- TraceSubscriberStdio subscriber(trace_file,
- TraceSubscriberStdio::FILE_TYPE_ARRAY,
- false);
-
- std::string foo("foo");
- subscriber.OnTraceDataCollected(
- make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
-
- std::string bar("bar");
- subscriber.OnTraceDataCollected(
- make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
-
- subscriber.OnEndTracingComplete();
- }
- BrowserThread::GetBlockingPool()->FlushForTesting();
- std::string result;
- EXPECT_TRUE(base::ReadFileToString(trace_file, &result));
- EXPECT_EQ("[foo,bar]", result);
-}
-
-TEST_F(TraceSubscriberStdioTest, CanWritePropertyList) {
- base::ScopedTempDir trace_dir;
- ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
- base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
- {
- TraceSubscriberStdio subscriber(
- trace_file,
- TraceSubscriberStdio::FILE_TYPE_PROPERTY_LIST,
- false);
-
- std::string foo("foo");
- subscriber.OnTraceDataCollected(
- make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
-
- std::string bar("bar");
- subscriber.OnTraceDataCollected(
- make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
-
- subscriber.OnEndTracingComplete();
- }
- BrowserThread::GetBlockingPool()->FlushForTesting();
- std::string result;
- EXPECT_TRUE(base::ReadFileToString(trace_file, &result));
- EXPECT_EQ("{\"traceEvents\":[foo,bar]}", result);
-}
-
-TEST_F(TraceSubscriberStdioTest, CanWriteSystemDataFirst) {
- base::ScopedTempDir trace_dir;
- ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
- base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
- {
- TraceSubscriberStdio subscriber(
- trace_file,
- TraceSubscriberStdio::FILE_TYPE_PROPERTY_LIST,
- true);
-
- std::string foo("foo");
- subscriber.OnTraceDataCollected(
- make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
-
- std::string bar("bar");
- subscriber.OnTraceDataCollected(
- make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
-
- std::string systemTrace("event1\nev\"ent\"2\n");
- subscriber.OnEndSystemTracing(
- make_scoped_refptr(base::RefCountedString::TakeString(&systemTrace)));
- subscriber.OnEndTracingComplete();
- }
- BrowserThread::GetBlockingPool()->FlushForTesting();
- std::string result;
- EXPECT_TRUE(base::ReadFileToString(trace_file, &result));
- EXPECT_EQ(
- "{\"traceEvents\":[foo,bar],\""
- "systemTraceEvents\":\"event1\\nev\\\"ent\\\"2\\n\"}",
- result);
-}
-
-TEST_F(TraceSubscriberStdioTest, CanWriteSystemDataLast) {
- base::ScopedTempDir trace_dir;
- ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
- base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
- {
- TraceSubscriberStdio subscriber(
- trace_file,
- TraceSubscriberStdio::FILE_TYPE_PROPERTY_LIST,
- true);
-
- std::string foo("foo");
- subscriber.OnTraceDataCollected(
- make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
-
- std::string bar("bar");
- subscriber.OnTraceDataCollected(
- make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
-
- std::string systemTrace("event1\nev\"ent\"2\n");
- subscriber.OnEndTracingComplete();
- subscriber.OnEndSystemTracing(
- make_scoped_refptr(base::RefCountedString::TakeString(&systemTrace)));
- }
- BrowserThread::GetBlockingPool()->FlushForTesting();
- std::string result;
- EXPECT_TRUE(base::ReadFileToString(trace_file, &result));
- EXPECT_EQ(
- "{\"traceEvents\":[foo,bar],\""
- "systemTraceEvents\":\"event1\\nev\\\"ent\\\"2\\n\"}",
- result);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/tracing/tracing_controller_browsertest.cc b/chromium/content/browser/tracing/tracing_controller_browsertest.cc
index c88932e0597..bccf90af44a 100644
--- a/chromium/content/browser/tracing/tracing_controller_browsertest.cc
+++ b/chromium/content/browser/tracing/tracing_controller_browsertest.cc
@@ -20,6 +20,9 @@ class TracingControllerTest : public ContentBrowserTest {
get_categories_done_callback_count_ = 0;
enable_recording_done_callback_count_ = 0;
disable_recording_done_callback_count_ = 0;
+ enable_monitoring_done_callback_count_ = 0;
+ disable_monitoring_done_callback_count_ = 0;
+ capture_monitoring_snapshot_done_callback_count_ = 0;
ContentBrowserTest::SetUp();
}
@@ -44,10 +47,35 @@ class TracingControllerTest : public ContentBrowserTest {
}
void DisableRecordingDoneCallbackTest(base::Closure quit_callback,
- scoped_ptr<base::FilePath> file_path) {
+ const base::FilePath& file_path) {
disable_recording_done_callback_count_++;
- EXPECT_TRUE(PathExists(*file_path));
+ EXPECT_TRUE(PathExists(file_path));
+ int64 file_size;
+ base::GetFileSize(file_path, &file_size);
+ EXPECT_TRUE(file_size > 0);
quit_callback.Run();
+ last_actual_recording_file_path_ = file_path;
+ }
+
+ void EnableMonitoringDoneCallbackTest(base::Closure quit_callback) {
+ enable_monitoring_done_callback_count_++;
+ quit_callback.Run();
+ }
+
+ void DisableMonitoringDoneCallbackTest(base::Closure quit_callback) {
+ disable_monitoring_done_callback_count_++;
+ quit_callback.Run();
+ }
+
+ void CaptureMonitoringSnapshotDoneCallbackTest(
+ base::Closure quit_callback, const base::FilePath& file_path) {
+ capture_monitoring_snapshot_done_callback_count_++;
+ EXPECT_TRUE(PathExists(file_path));
+ int64 file_size;
+ base::GetFileSize(file_path, &file_size);
+ EXPECT_TRUE(file_size > 0);
+ quit_callback.Run();
+ last_actual_monitoring_file_path_ = file_path;
}
int get_categories_done_callback_count() const {
@@ -62,10 +90,111 @@ class TracingControllerTest : public ContentBrowserTest {
return disable_recording_done_callback_count_;
}
+ int enable_monitoring_done_callback_count() const {
+ return enable_monitoring_done_callback_count_;
+ }
+
+ int disable_monitoring_done_callback_count() const {
+ return disable_monitoring_done_callback_count_;
+ }
+
+ int capture_monitoring_snapshot_done_callback_count() const {
+ return capture_monitoring_snapshot_done_callback_count_;
+ }
+
+ base::FilePath last_actual_recording_file_path() const {
+ return last_actual_recording_file_path_;
+ }
+
+ base::FilePath last_actual_monitoring_file_path() const {
+ return last_actual_monitoring_file_path_;
+ }
+
+ void TestEnableAndDisableRecording(const base::FilePath& result_file_path) {
+ Navigate(shell());
+
+ TracingController* controller = TracingController::GetInstance();
+
+ {
+ base::RunLoop run_loop;
+ TracingController::EnableRecordingDoneCallback callback =
+ base::Bind(&TracingControllerTest::EnableRecordingDoneCallbackTest,
+ base::Unretained(this),
+ run_loop.QuitClosure());
+ bool result = controller->EnableRecording(
+ "", TracingController::DEFAULT_OPTIONS, callback);
+ ASSERT_TRUE(result);
+ run_loop.Run();
+ EXPECT_EQ(enable_recording_done_callback_count(), 1);
+ }
+
+ {
+ base::RunLoop run_loop;
+ TracingController::TracingFileResultCallback callback =
+ base::Bind(&TracingControllerTest::DisableRecordingDoneCallbackTest,
+ base::Unretained(this),
+ run_loop.QuitClosure());
+ bool result = controller->DisableRecording(result_file_path, callback);
+ ASSERT_TRUE(result);
+ run_loop.Run();
+ EXPECT_EQ(disable_recording_done_callback_count(), 1);
+ }
+ }
+
+ void TestEnableCaptureAndDisableMonitoring(
+ const base::FilePath& result_file_path) {
+ Navigate(shell());
+
+ TracingController* controller = TracingController::GetInstance();
+
+ {
+ base::RunLoop run_loop;
+ TracingController::EnableMonitoringDoneCallback callback =
+ base::Bind(&TracingControllerTest::EnableMonitoringDoneCallbackTest,
+ base::Unretained(this),
+ run_loop.QuitClosure());
+ bool result = controller->EnableMonitoring(
+ "", TracingController::ENABLE_SAMPLING, callback);
+ ASSERT_TRUE(result);
+ run_loop.Run();
+ EXPECT_EQ(enable_monitoring_done_callback_count(), 1);
+ }
+
+ {
+ base::RunLoop run_loop;
+ TracingController::TracingFileResultCallback callback =
+ base::Bind(&TracingControllerTest::
+ CaptureMonitoringSnapshotDoneCallbackTest,
+ base::Unretained(this),
+ run_loop.QuitClosure());
+ ASSERT_TRUE(controller->CaptureMonitoringSnapshot(result_file_path,
+ callback));
+ run_loop.Run();
+ EXPECT_EQ(capture_monitoring_snapshot_done_callback_count(), 1);
+ }
+
+ {
+ base::RunLoop run_loop;
+ TracingController::DisableMonitoringDoneCallback callback =
+ base::Bind(&TracingControllerTest::DisableMonitoringDoneCallbackTest,
+ base::Unretained(this),
+ run_loop.QuitClosure());
+ bool result = controller->DisableMonitoring(callback);
+ ASSERT_TRUE(result);
+ run_loop.Run();
+ EXPECT_EQ(disable_monitoring_done_callback_count(), 1);
+ }
+ }
+
private:
int get_categories_done_callback_count_;
int enable_recording_done_callback_count_;
int disable_recording_done_callback_count_;
+ int enable_monitoring_done_callback_count_;
+ int disable_monitoring_done_callback_count_;
+ int capture_monitoring_snapshot_done_callback_count_;
+ base::FilePath last_actual_recording_file_path_;
+ base::FilePath last_actual_monitoring_file_path_;
};
IN_PROC_BROWSER_TEST_F(TracingControllerTest, GetCategories) {
@@ -78,38 +207,64 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest, GetCategories) {
base::Bind(&TracingControllerTest::GetCategoriesDoneCallbackTest,
base::Unretained(this),
run_loop.QuitClosure());
- controller->GetCategories(callback);
+ ASSERT_TRUE(controller->GetCategories(callback));
run_loop.Run();
EXPECT_EQ(get_categories_done_callback_count(), 1);
}
IN_PROC_BROWSER_TEST_F(TracingControllerTest, EnableAndDisableRecording) {
+ TestEnableAndDisableRecording(base::FilePath());
+}
+
+IN_PROC_BROWSER_TEST_F(TracingControllerTest,
+ EnableAndDisableRecordingWithFilePath) {
+ base::FilePath file_path;
+ base::CreateTemporaryFile(&file_path);
+ TestEnableAndDisableRecording(file_path);
+ EXPECT_EQ(file_path.value(), last_actual_recording_file_path().value());
+}
+
+IN_PROC_BROWSER_TEST_F(TracingControllerTest,
+ EnableAndDisableRecordingWithEmptyFileAndNullCallback) {
Navigate(shell());
TracingController* controller = TracingController::GetInstance();
+ EXPECT_TRUE(controller->EnableRecording(
+ "", TracingController::DEFAULT_OPTIONS,
+ TracingController::EnableRecordingDoneCallback()));
+ EXPECT_TRUE(controller->DisableRecording(
+ base::FilePath(), TracingController::TracingFileResultCallback()));
+ base::RunLoop().RunUntilIdle();
+}
- {
- base::RunLoop run_loop;
- TracingController::EnableRecordingDoneCallback callback =
- base::Bind(&TracingControllerTest::EnableRecordingDoneCallbackTest,
- base::Unretained(this),
- run_loop.QuitClosure());
- controller->EnableRecording(base::debug::CategoryFilter("*"),
- TracingController::Options(), callback);
- run_loop.Run();
- EXPECT_EQ(enable_recording_done_callback_count(), 1);
- }
-
- {
- base::RunLoop run_loop;
- TracingController::TracingFileResultCallback callback =
- base::Bind(&TracingControllerTest::DisableRecordingDoneCallbackTest,
- base::Unretained(this),
- run_loop.QuitClosure());
- controller->DisableRecording(callback);
- run_loop.Run();
- EXPECT_EQ(disable_recording_done_callback_count(), 1);
- }
+IN_PROC_BROWSER_TEST_F(TracingControllerTest,
+ EnableCaptureAndDisableMonitoring) {
+ TestEnableCaptureAndDisableMonitoring(base::FilePath());
+}
+
+IN_PROC_BROWSER_TEST_F(TracingControllerTest,
+ EnableCaptureAndDisableMonitoringWithFilePath) {
+ base::FilePath file_path;
+ base::CreateTemporaryFile(&file_path);
+ TestEnableCaptureAndDisableMonitoring(file_path);
+ EXPECT_EQ(file_path.value(), last_actual_monitoring_file_path().value());
+}
+
+IN_PROC_BROWSER_TEST_F(
+ TracingControllerTest,
+ EnableCaptureAndDisableMonitoringWithEmptyFileAndNullCallback) {
+ Navigate(shell());
+
+ TracingController* controller = TracingController::GetInstance();
+ EXPECT_TRUE(controller->EnableMonitoring(
+ "", TracingController::ENABLE_SAMPLING,
+ TracingController::EnableMonitoringDoneCallback()));
+ controller->CaptureMonitoringSnapshot(
+ base::FilePath(), TracingController::TracingFileResultCallback());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(controller->DisableMonitoring(
+ TracingController::DisableMonitoringDoneCallback()));
+ base::RunLoop().RunUntilIdle();
}
} // namespace content
diff --git a/chromium/content/browser/tracing/tracing_controller_impl.cc b/chromium/content/browser/tracing/tracing_controller_impl.cc
index 1c1c43aabf9..bc7cee2f930 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl.cc
+++ b/chromium/content/browser/tracing/tracing_controller_impl.cc
@@ -5,6 +5,7 @@
#include "content/browser/tracing/tracing_controller_impl.h"
#include "base/bind.h"
+#include "base/debug/trace_event.h"
#include "base/file_util.h"
#include "base/json/string_escape.h"
#include "base/strings/string_number_conversions.h"
@@ -28,11 +29,97 @@ TracingController* TracingController::GetInstance() {
return TracingControllerImpl::GetInstance();
}
+class TracingControllerImpl::ResultFile {
+ public:
+ explicit ResultFile(const base::FilePath& path);
+ void Write(const scoped_refptr<base::RefCountedString>& events_str_ptr) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&TracingControllerImpl::ResultFile::WriteTask,
+ base::Unretained(this), events_str_ptr));
+ }
+ void Close(const base::Closure& callback) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&TracingControllerImpl::ResultFile::CloseTask,
+ base::Unretained(this), callback));
+ }
+ const base::FilePath& path() const { return path_; }
+
+ private:
+ void OpenTask();
+ void WriteTask(const scoped_refptr<base::RefCountedString>& events_str_ptr);
+ void CloseTask(const base::Closure& callback);
+
+ FILE* file_;
+ base::FilePath path_;
+ bool has_at_least_one_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResultFile);
+};
+
+TracingControllerImpl::ResultFile::ResultFile(const base::FilePath& path)
+ : file_(NULL),
+ path_(path),
+ has_at_least_one_result_(false) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&TracingControllerImpl::ResultFile::OpenTask,
+ base::Unretained(this)));
+}
+
+void TracingControllerImpl::ResultFile::OpenTask() {
+ if (path_.empty())
+ base::CreateTemporaryFile(&path_);
+ file_ = base::OpenFile(path_, "w");
+ if (!file_) {
+ LOG(ERROR) << "Failed to open " << path_.value();
+ return;
+ }
+ const char* preamble = "{\"traceEvents\": [";
+ size_t written = fwrite(preamble, strlen(preamble), 1, file_);
+ DCHECK(written == 1);
+}
+
+void TracingControllerImpl::ResultFile::WriteTask(
+ const scoped_refptr<base::RefCountedString>& events_str_ptr) {
+ if (!file_)
+ return;
+
+ // If there is already a result in the file, then put a commma
+ // before the next batch of results.
+ if (has_at_least_one_result_) {
+ size_t written = fwrite(",", 1, 1, file_);
+ DCHECK(written == 1);
+ }
+ has_at_least_one_result_ = true;
+ size_t written = fwrite(events_str_ptr->data().c_str(),
+ events_str_ptr->data().size(), 1,
+ file_);
+ DCHECK(written == 1);
+}
+
+void TracingControllerImpl::ResultFile::CloseTask(
+ const base::Closure& callback) {
+ if (!file_)
+ return;
+
+ const char* trailout = "]}";
+ size_t written = fwrite(trailout, strlen(trailout), 1, file_);
+ DCHECK(written == 1);
+ base::CloseFile(file_);
+ file_ = NULL;
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
+}
+
+
TracingControllerImpl::TracingControllerImpl() :
- pending_end_ack_count_(0),
- is_recording_(false),
- category_filter_(
- base::debug::CategoryFilter::kDefaultCategoryFilterString) {
+ 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()),
+ is_monitoring_(false) {
}
TracingControllerImpl::~TracingControllerImpl() {
@@ -44,7 +131,7 @@ TracingControllerImpl* TracingControllerImpl::GetInstance() {
return g_controller.Pointer();
}
-void TracingControllerImpl::GetCategories(
+bool TracingControllerImpl::GetCategories(
const GetCategoriesDoneCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -52,42 +139,61 @@ void TracingControllerImpl::GetCategories(
// message. So to get known categories, just begin and end tracing immediately
// afterwards. This will ping all the child processes for categories.
pending_get_categories_done_callback_ = callback;
- EnableRecording(base::debug::CategoryFilter("*"),
- TracingController::Options(),
- EnableRecordingDoneCallback());
- DisableRecording(TracingFileResultCallback());
+ if (!EnableRecording("*", TracingController::Options(),
+ EnableRecordingDoneCallback())) {
+ pending_get_categories_done_callback_.Reset();
+ return false;
+ }
+
+ bool ok = DisableRecording(base::FilePath(), TracingFileResultCallback());
+ DCHECK(ok);
+ return true;
}
-void TracingControllerImpl::EnableRecording(
- const base::debug::CategoryFilter& filter,
+bool TracingControllerImpl::EnableRecording(
+ const std::string& category_filter,
TracingController::Options options,
const EnableRecordingDoneCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!can_enable_recording())
- return;
-
- trace_options_ = TraceLog::GetInstance()->trace_options();
- TraceLog::GetInstance()->SetEnabled(filter, trace_options_);
+ return false;
+
+#if defined(OS_ANDROID)
+ if (pending_get_categories_done_callback_.is_null())
+ TraceLog::GetInstance()->AddClockSyncMetadataEvent();
+#endif
+
+ 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(
+ base::debug::CategoryFilter(category_filter), trace_options);
is_recording_ = true;
- category_filter_ = TraceLog::GetInstance()->GetCurrentCategoryFilter();
// Notify all child processes.
- for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
- it->get()->SendBeginTracing(category_filter_.ToString(), trace_options_);
+ for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
+ it != trace_message_filters_.end(); ++it) {
+ it->get()->SendBeginTracing(category_filter, trace_options);
}
if (!callback.is_null())
callback.Run();
+ return true;
}
-void TracingControllerImpl::DisableRecording(
+bool TracingControllerImpl::DisableRecording(
+ const base::FilePath& result_file_path,
const TracingFileResultCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!can_end_recording())
- return;
+ if (!can_disable_recording())
+ return false;
pending_disable_recording_done_callback_ = callback;
@@ -95,22 +201,22 @@ void TracingControllerImpl::DisableRecording(
// interfering with the process.
TraceLog::GetInstance()->SetDisabled();
- // We don't need to create a temporary file when getting categories.
- if (pending_get_categories_done_callback_.is_null()) {
- base::FilePath temporary_file;
- file_util::CreateTemporaryFile(&temporary_file);
- recording_result_file_.reset(new base::FilePath(temporary_file));
- }
+#if defined(OS_ANDROID)
+ if (pending_get_categories_done_callback_.is_null())
+ TraceLog::GetInstance()->AddClockSyncMetadataEvent();
+#endif
- // There could be a case where there are no child processes and filters_
- // is empty. In that case we can immediately tell the subscriber that tracing
- // has ended. To avoid recursive calls back to the subscriber, we will just
- // use the existing asynchronous OnDisableRecordingAcked code.
- // Count myself (local trace) in pending_end_ack_count_, acked below.
- pending_end_ack_count_ = filters_.size() + 1;
+ if (!callback.is_null() || !result_file_path.empty())
+ result_file_.reset(new ResultFile(result_file_path));
- // Handle special case of zero child processes.
- if (pending_end_ack_count_ == 1) {
+ // Count myself (local trace) in pending_disable_recording_ack_count_,
+ // acked below.
+ pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
+
+ // Handle special case of zero child processes by immediately telling the
+ // caller that tracing has ended. Use asynchronous OnDisableRecordingAcked
+ // to avoid recursive call back to the caller.
+ if (pending_disable_recording_ack_count_ == 1) {
// Ack asynchronously now, because we don't have any children to wait for.
std::vector<std::string> category_groups;
TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
@@ -120,59 +226,221 @@ void TracingControllerImpl::DisableRecording(
}
// Notify all child processes.
- for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
+ for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
+ it != trace_message_filters_.end(); ++it) {
it->get()->SendEndTracing();
}
+ return true;
}
-void TracingControllerImpl::EnableMonitoring(
- const base::debug::CategoryFilter& filter,
+bool TracingControllerImpl::EnableMonitoring(
+ const std::string& category_filter,
TracingController::Options options,
const EnableMonitoringDoneCallback& callback) {
- NOTIMPLEMENTED();
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!can_enable_monitoring())
+ return false;
+ is_monitoring_ = true;
+
+#if defined(OS_ANDROID)
+ TraceLog::GetInstance()->AddClockSyncMetadataEvent();
+#endif
+
+ int monitoring_tracing_options = 0;
+ if (options & ENABLE_SAMPLING)
+ monitoring_tracing_options |= base::debug::TraceLog::MONITOR_SAMPLING;
+
+ TraceLog::GetInstance()->SetEnabled(
+ base::debug::CategoryFilter(category_filter),
+ static_cast<TraceLog::Options>(monitoring_tracing_options));
+
+ // Notify all child processes.
+ for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
+ it != trace_message_filters_.end(); ++it) {
+ it->get()->SendEnableMonitoring(category_filter,
+ static_cast<TraceLog::Options>(monitoring_tracing_options));
+ }
+
+ if (!callback.is_null())
+ callback.Run();
+ return true;
}
-void TracingControllerImpl::DisableMonitoring(
+bool TracingControllerImpl::DisableMonitoring(
const DisableMonitoringDoneCallback& callback) {
- NOTIMPLEMENTED();
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!can_disable_monitoring())
+ return false;
+ is_monitoring_ = false;
+
+ TraceLog::GetInstance()->SetDisabled();
+
+ // Notify all child processes.
+ for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
+ it != trace_message_filters_.end(); ++it) {
+ it->get()->SendDisableMonitoring();
+ }
+
+ if (!callback.is_null())
+ callback.Run();
+ return true;
}
void TracingControllerImpl::GetMonitoringStatus(
bool* out_enabled,
- base::debug::CategoryFilter* out_filter,
+ std::string* out_category_filter,
TracingController::Options* out_options) {
NOTIMPLEMENTED();
}
-void TracingControllerImpl::CaptureCurrentMonitoringSnapshot(
+bool TracingControllerImpl::CaptureMonitoringSnapshot(
+ const base::FilePath& result_file_path,
const TracingFileResultCallback& callback) {
- NOTIMPLEMENTED();
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!can_disable_monitoring())
+ return false;
+
+ if (callback.is_null() && result_file_path.empty())
+ return false;
+
+ pending_capture_monitoring_snapshot_done_callback_ = callback;
+ monitoring_snapshot_file_.reset(new ResultFile(result_file_path));
+
+ // Count myself in pending_capture_monitoring_snapshot_ack_count_,
+ // acked below.
+ pending_capture_monitoring_snapshot_ack_count_ =
+ trace_message_filters_.size() + 1;
+
+ // Handle special case of zero child processes by immediately telling the
+ // caller that capturing snapshot has ended. Use asynchronous
+ // OnCaptureMonitoringSnapshotAcked to avoid recursive call back to the
+ // caller.
+ if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
+ // Ack asynchronously now, because we don't have any children to wait for.
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
+ base::Unretained(this)));
+ }
+
+ // Notify all child processes.
+ for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
+ it != trace_message_filters_.end(); ++it) {
+ it->get()->SendCaptureMonitoringSnapshot();
+ }
+
+#if defined(OS_ANDROID)
+ TraceLog::GetInstance()->AddClockSyncMetadataEvent();
+#endif
+
+ return true;
+}
+
+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_ =
+ trace_message_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 (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
+ it != trace_message_filters_.end(); ++it) {
+ it->get()->SendGetTraceBufferPercentFull();
+ }
+ return true;
+}
+
+bool TracingControllerImpl::SetWatchEvent(
+ const std::string& category_name,
+ const std::string& event_name,
+ const WatchEventCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (callback.is_null())
+ return false;
+
+ watch_category_name_ = category_name;
+ watch_event_name_ = event_name;
+ watch_event_callback_ = callback;
+
+ TraceLog::GetInstance()->SetWatchEvent(
+ category_name, event_name,
+ base::Bind(&TracingControllerImpl::OnWatchEventMatched,
+ base::Unretained(this)));
+
+ for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
+ it != trace_message_filters_.end(); ++it) {
+ it->get()->SendSetWatchEvent(category_name, event_name);
+ }
+ return true;
+}
+
+bool TracingControllerImpl::CancelWatchEvent() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!can_cancel_watch_event())
+ return false;
+
+ for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
+ it != trace_message_filters_.end(); ++it) {
+ it->get()->SendCancelWatchEvent();
+ }
+
+ watch_event_callback_.Reset();
+ return true;
}
-void TracingControllerImpl::AddFilter(TraceMessageFilter* filter) {
+void TracingControllerImpl::AddTraceMessageFilter(
+ TraceMessageFilter* trace_message_filter) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TracingControllerImpl::AddFilter, base::Unretained(this),
- make_scoped_refptr(filter)));
+ base::Bind(&TracingControllerImpl::AddTraceMessageFilter,
+ base::Unretained(this),
+ make_scoped_refptr(trace_message_filter)));
return;
}
- filters_.insert(filter);
- if (is_recording_enabled()) {
- std::string cf_str = category_filter_.ToString();
- filter->SendBeginTracing(cf_str, trace_options_);
+ trace_message_filters_.insert(trace_message_filter);
+ if (can_cancel_watch_event()) {
+ trace_message_filter->SendSetWatchEvent(watch_category_name_,
+ watch_event_name_);
+ }
+ if (can_disable_recording()) {
+ trace_message_filter->SendBeginTracing(
+ TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString(),
+ TraceLog::GetInstance()->trace_options());
}
}
-void TracingControllerImpl::RemoveFilter(TraceMessageFilter* filter) {
+void TracingControllerImpl::RemoveTraceMessageFilter(
+ TraceMessageFilter* trace_message_filter) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TracingControllerImpl::RemoveFilter, base::Unretained(this),
- make_scoped_refptr(filter)));
+ base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter,
+ base::Unretained(this),
+ make_scoped_refptr(trace_message_filter)));
return;
}
- filters_.erase(filter);
+ trace_message_filters_.erase(trace_message_filter);
}
void TracingControllerImpl::OnDisableRecordingAcked(
@@ -188,19 +456,20 @@ void TracingControllerImpl::OnDisableRecordingAcked(
known_category_groups_.insert(known_category_groups.begin(),
known_category_groups.end());
- if (pending_end_ack_count_ == 0)
+ if (pending_disable_recording_ack_count_ == 0)
return;
- if (--pending_end_ack_count_ == 1) {
+ if (--pending_disable_recording_ack_count_ == 1) {
// All acks from subprocesses have been received. Now flush the local trace.
// During or after this call, our OnLocalTraceDataCollected will be
// called with the last of the local trace data.
TraceLog::GetInstance()->Flush(
base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
base::Unretained(this)));
+ return;
}
- if (pending_end_ack_count_ != 0)
+ if (pending_disable_recording_ack_count_ != 0)
return;
// All acks (including from the subprocesses and the local trace) have been
@@ -211,17 +480,69 @@ void TracingControllerImpl::OnDisableRecordingAcked(
if (!pending_get_categories_done_callback_.is_null()) {
pending_get_categories_done_callback_.Run(known_category_groups_);
pending_get_categories_done_callback_.Reset();
- } else {
- OnEndTracingComplete();
+ } else if (result_file_) {
+ result_file_->Close(
+ base::Bind(&TracingControllerImpl::OnResultFileClosed,
+ base::Unretained(this)));
}
}
-void TracingControllerImpl::OnEndTracingComplete() {
- if (pending_disable_recording_done_callback_.is_null())
+void TracingControllerImpl::OnResultFileClosed() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!result_file_)
return;
- pending_disable_recording_done_callback_.Run(recording_result_file_.Pass());
- pending_disable_recording_done_callback_.Reset();
+ if (!pending_disable_recording_done_callback_.is_null()) {
+ pending_disable_recording_done_callback_.Run(result_file_->path());
+ pending_disable_recording_done_callback_.Reset();
+ }
+ result_file_.reset();
+}
+
+void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked() {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
+ base::Unretained(this)));
+ return;
+ }
+
+ if (pending_capture_monitoring_snapshot_ack_count_ == 0)
+ return;
+
+ if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
+ // All acks from subprocesses have been received. Now flush the local trace.
+ // During or after this call, our OnLocalMonitoringTraceDataCollected
+ // will be called with the last of the local trace data.
+ TraceLog::GetInstance()->FlushButLeaveBufferIntact(
+ base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
+ base::Unretained(this)));
+ return;
+ }
+
+ if (pending_capture_monitoring_snapshot_ack_count_ != 0)
+ return;
+
+ if (monitoring_snapshot_file_) {
+ monitoring_snapshot_file_->Close(
+ base::Bind(&TracingControllerImpl::OnMonitoringSnapshotFileClosed,
+ base::Unretained(this)));
+ }
+}
+
+void TracingControllerImpl::OnMonitoringSnapshotFileClosed() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!monitoring_snapshot_file_)
+ return;
+
+ if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) {
+ pending_capture_monitoring_snapshot_done_callback_.Run(
+ monitoring_snapshot_file_->path());
+ pending_capture_monitoring_snapshot_done_callback_.Reset();
+ }
+ monitoring_snapshot_file_.reset();
}
void TracingControllerImpl::OnTraceDataCollected(
@@ -235,21 +556,21 @@ void TracingControllerImpl::OnTraceDataCollected(
return;
}
- // Drop trace events if we are just getting categories.
- if (!pending_get_categories_done_callback_.is_null())
- return;
-
- std::string javascript;
- javascript.reserve(events_str_ptr->size() * 2);
- base::JsonDoubleQuote(events_str_ptr->data(), false, &javascript);
+ if (result_file_)
+ result_file_->Write(events_str_ptr);
+}
- // 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(",");
+void TracingControllerImpl::OnMonitoringTraceDataCollected(
+ const scoped_refptr<base::RefCountedString>& events_str_ptr) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
+ base::Unretained(this), events_str_ptr));
+ return;
+ }
- file_util::WriteFile(*recording_result_file_,
- javascript.c_str(), javascript.length());
+ if (monitoring_snapshot_file_)
+ monitoring_snapshot_file_->Write(events_str_ptr);
}
void TracingControllerImpl::OnLocalTraceDataCollected(
@@ -267,4 +588,60 @@ void TracingControllerImpl::OnLocalTraceDataCollected(
OnDisableRecordingAcked(category_groups);
}
+void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
+ const scoped_refptr<base::RefCountedString>& events_str_ptr,
+ bool has_more_events) {
+ if (events_str_ptr->data().size())
+ OnMonitoringTraceDataCollected(events_str_ptr);
+
+ if (has_more_events)
+ return;
+
+ // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
+ 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()));
+ }
+}
+
+void TracingControllerImpl::OnWatchEventMatched() {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnWatchEventMatched,
+ base::Unretained(this)));
+ return;
+ }
+
+ if (!watch_event_callback_.is_null())
+ watch_event_callback_.Run();
+}
+
} // namespace content
diff --git a/chromium/content/browser/tracing/tracing_controller_impl.h b/chromium/content/browser/tracing/tracing_controller_impl.h
index 22192255444..ed3c8fd6519 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl.h
+++ b/chromium/content/browser/tracing/tracing_controller_impl.h
@@ -9,42 +9,54 @@
#include <string>
#include <vector>
+#include "base/files/file_path.h"
#include "base/lazy_instance.h"
-#include "content/public/browser/trace_subscriber.h"
#include "content/public/browser/tracing_controller.h"
+namespace base {
+class RefCountedString;
+}
+
namespace content {
class TraceMessageFilter;
-class TracingControllerImpl :
- public TracingController, public TraceSubscriber {
+class TracingControllerImpl : public TracingController {
public:
static TracingControllerImpl* GetInstance();
// TracingController implementation.
- virtual void GetCategories(
+ virtual bool GetCategories(
const GetCategoriesDoneCallback& callback) OVERRIDE;
- virtual void EnableRecording(
- const base::debug::CategoryFilter& filter,
+ virtual bool EnableRecording(
+ const std::string& category_filter,
TracingController::Options options,
const EnableRecordingDoneCallback& callback) OVERRIDE;
- virtual void DisableRecording(
+ virtual bool DisableRecording(
+ const base::FilePath& result_file_path,
const TracingFileResultCallback& callback) OVERRIDE;
- virtual void EnableMonitoring(const base::debug::CategoryFilter& filter,
+ virtual bool EnableMonitoring(const std::string& category_filter,
TracingController::Options options,
const EnableMonitoringDoneCallback& callback) OVERRIDE;
- virtual void DisableMonitoring(
+ virtual bool DisableMonitoring(
const DisableMonitoringDoneCallback& callback) OVERRIDE;
virtual void GetMonitoringStatus(
bool* out_enabled,
- base::debug::CategoryFilter* out_filter,
+ std::string* out_category_filter,
TracingController::Options* out_options) OVERRIDE;
- virtual void CaptureCurrentMonitoringSnapshot(
+ virtual bool CaptureMonitoringSnapshot(
+ const base::FilePath& result_file_path,
const TracingFileResultCallback& callback) OVERRIDE;
+ virtual bool GetTraceBufferPercentFull(
+ const GetTraceBufferPercentFullCallback& callback) OVERRIDE;
+ virtual bool SetWatchEvent(const std::string& category_name,
+ const std::string& event_name,
+ const WatchEventCallback& callback) OVERRIDE;
+ virtual bool CancelWatchEvent() OVERRIDE;
private:
- typedef std::set<scoped_refptr<TraceMessageFilter> > FilterMap;
+ typedef std::set<scoped_refptr<TraceMessageFilter> > TraceMessageFilterMap;
+ class ResultFile;
friend struct base::DefaultLazyInstanceTraits<TracingControllerImpl>;
friend class TraceMessageFilter;
@@ -52,46 +64,83 @@ class TracingControllerImpl :
TracingControllerImpl();
virtual ~TracingControllerImpl();
- // TraceSubscriber implementation.
- virtual void OnEndTracingComplete() OVERRIDE;
- virtual void OnTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& events_str_ptr) OVERRIDE;
-
bool can_enable_recording() const {
return !is_recording_;
}
- bool can_end_recording() const {
- return is_recording_ && pending_end_ack_count_ == 0;
+ bool can_disable_recording() const {
+ return is_recording_ && !result_file_;
+ }
+
+ bool can_enable_monitoring() const {
+ return !is_monitoring_;
+ }
+
+ bool can_disable_monitoring() const {
+ return is_monitoring_ && !monitoring_snapshot_file_;
+ }
+
+ bool can_get_trace_buffer_percent_full() const {
+ return pending_trace_buffer_percent_full_callback_.is_null();
}
- bool is_recording_enabled() const {
- return can_end_recording();
+ bool can_cancel_watch_event() const {
+ return !watch_event_callback_.is_null();
}
// Methods for use by TraceMessageFilter.
- void AddFilter(TraceMessageFilter* filter);
- void RemoveFilter(TraceMessageFilter* filter);
+ void AddTraceMessageFilter(TraceMessageFilter* trace_message_filter);
+ void RemoveTraceMessageFilter(TraceMessageFilter* trace_message_filter);
+
+ void OnTraceDataCollected(
+ const scoped_refptr<base::RefCountedString>& events_str_ptr);
+ void OnMonitoringTraceDataCollected(
+ const scoped_refptr<base::RefCountedString>& events_str_ptr);
// Callback of TraceLog::Flush() for the local trace.
void OnLocalTraceDataCollected(
const scoped_refptr<base::RefCountedString>& events_str_ptr,
bool has_more_events);
+ // Callback of TraceLog::FlushMonitoring() for the local trace.
+ void OnLocalMonitoringTraceDataCollected(
+ const scoped_refptr<base::RefCountedString>& events_str_ptr,
+ bool has_more_events);
void OnDisableRecordingAcked(
const std::vector<std::string>& known_category_groups);
+ void OnResultFileClosed();
+
+ void OnCaptureMonitoringSnapshotAcked();
+ void OnMonitoringSnapshotFileClosed();
+
+ void OnTraceBufferPercentFullReply(float percent_full);
- FilterMap filters_;
+ void OnWatchEventMatched();
+
+ TraceMessageFilterMap trace_message_filters_;
// Pending acks for DisableRecording.
- int pending_end_ack_count_;
+ 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_;
- std::set<std::string> known_category_groups_;
- base::debug::TraceLog::Options trace_options_;
- base::debug::CategoryFilter category_filter_;
- scoped_ptr<base::FilePath> recording_result_file_;
+ TracingFileResultCallback pending_capture_monitoring_snapshot_done_callback_;
+ GetTraceBufferPercentFullCallback pending_trace_buffer_percent_full_callback_;
+ std::string watch_category_name_;
+ std::string watch_event_name_;
+ WatchEventCallback watch_event_callback_;
+
+ std::set<std::string> known_category_groups_;
+ scoped_ptr<ResultFile> result_file_;
+ scoped_ptr<ResultFile> monitoring_snapshot_file_;
DISALLOW_COPY_AND_ASSIGN(TracingControllerImpl);
};
diff --git a/chromium/content/browser/tracing/tracing_ui.cc b/chromium/content/browser/tracing/tracing_ui.cc
index 15bd2cf2590..e59f5667cb4 100644
--- a/chromium/content/browser/tracing/tracing_ui.cc
+++ b/chromium/content/browser/tracing/tracing_ui.cc
@@ -6,540 +6,143 @@
#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 < ' ') {
- escaped_contents += base::StringPrintf("\\u%04x", 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.
- // 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);
- }
-
- // 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;"));
+ return TracingController::GetInstance()->EnableRecording(
+ category_filter_string,
+ 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
@@ -552,12 +155,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