| Index: content/browser/devtools/protocol/tracing_handler.cc
|
| diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
|
| index f4ce95b8ce3505d5806b4cf73e4efe05bca0e00d..3db56293dda72f476847ff279f98a295a61eefa9 100644
|
| --- a/content/browser/devtools/protocol/tracing_handler.cc
|
| +++ b/content/browser/devtools/protocol/tracing_handler.cc
|
| @@ -4,13 +4,55 @@
|
|
|
| #include "content/browser/devtools/protocol/tracing_handler.h"
|
|
|
| +#include <cmath>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/debug/trace_event_impl.h"
|
| +#include "base/strings/string_split.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "base/time/time.h"
|
| +#include "base/timer/timer.h"
|
| +
|
| namespace content {
|
| namespace devtools {
|
| namespace tracing {
|
|
|
| typedef DevToolsProtocolClient::Response Response;
|
|
|
| -TracingHandler::TracingHandler() {
|
| +namespace {
|
| +
|
| +const char kRecordUntilFull[] = "record-until-full";
|
| +const char kRecordContinuously[] = "record-continuously";
|
| +const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
|
| +const char kEnableSampling[] = "enable-sampling";
|
| +const double kMinimumReportingInterval = 250.0;
|
| +
|
| +class DevToolsTraceSinkProxy : public TracingController::TraceDataSink {
|
| + public:
|
| + explicit DevToolsTraceSinkProxy(base::WeakPtr<TracingHandler> handler)
|
| + : tracing_handler_(handler) {}
|
| +
|
| + virtual void AddTraceChunk(const std::string& chunk) override {
|
| + if (TracingHandler* h = tracing_handler_.get())
|
| + h->OnTraceDataCollected(chunk);
|
| + }
|
| + virtual void Close() override {
|
| + if (TracingHandler* h = tracing_handler_.get())
|
| + h->OnTraceComplete();
|
| + }
|
| +
|
| + private:
|
| + virtual ~DevToolsTraceSinkProxy() {}
|
| +
|
| + base::WeakPtr<TracingHandler> tracing_handler_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +TracingHandler::TracingHandler(TracingHandler::Target target)
|
| + : target_(target),
|
| + is_recording_(false),
|
| + weak_factory_(this) {
|
| }
|
|
|
| TracingHandler::~TracingHandler() {
|
| @@ -20,30 +62,152 @@ void TracingHandler::SetClient(scoped_ptr<Client> client) {
|
| client_.swap(client);
|
| }
|
|
|
| -scoped_refptr<DevToolsProtocol::Response> TracingHandler::Start(
|
| - const std::string& categories,
|
| - const std::string& options,
|
| - const double* buffer_usage_reporting_interval,
|
| - scoped_refptr<DevToolsProtocol::Command> command) {
|
| - return NULL;
|
| +void TracingHandler::Detached() {
|
| + if (is_recording_)
|
| + DisableRecording(true);
|
| +}
|
| +
|
| +void TracingHandler::OnTraceDataCollected(const std::string& trace_fragment) {
|
| + // Hand-craft protocol notification message so we can substitute JSON
|
| + // that we already got as string as a bare object, not a quoted string.
|
| + std::string message(
|
| + "{ \"method\": \"Tracing.dataCollected\", \"params\": { \"value\": [");
|
| + const size_t messageSuffixSize = 10;
|
| + message.reserve(message.size() + trace_fragment.size() + messageSuffixSize);
|
| + message += trace_fragment;
|
| + message += "] } }";
|
| + client_->SendRawMessage(message);
|
| +}
|
| +
|
| +void TracingHandler::OnTraceComplete() {
|
| + TracingCompleteParams params;
|
| + client_->TracingComplete(params);
|
| }
|
|
|
| scoped_refptr<DevToolsProtocol::Response> TracingHandler::Start(
|
| const std::string* categories,
|
| - const std::string* options,
|
| + const std::string* options_str,
|
| const double* buffer_usage_reporting_interval,
|
| scoped_refptr<DevToolsProtocol::Command> command) {
|
| - return NULL;
|
| + if (is_recording_)
|
| + return command->InternalErrorResponse("Tracing is already started");
|
| + is_recording_ = true;
|
| +
|
| + base::debug::TraceOptions options = TraceOptionsFromString(options_str);
|
| + base::debug::CategoryFilter filter(categories ? *categories : std::string());
|
| + if (buffer_usage_reporting_interval)
|
| + SetupTimer(*buffer_usage_reporting_interval);
|
| +
|
| + // If inspected target is a render process Tracing.start will be handled by
|
| + // tracing agent in the renderer.
|
| + if (target_ == Renderer) {
|
| + TracingController::GetInstance()->EnableRecording(
|
| + filter,
|
| + options,
|
| + TracingController::EnableRecordingDoneCallback());
|
| + return nullptr;
|
| + }
|
| +
|
| + TracingController::GetInstance()->EnableRecording(
|
| + filter,
|
| + options,
|
| + base::Bind(&TracingHandler::OnRecordingEnabled,
|
| + weak_factory_.GetWeakPtr(),
|
| + command));
|
| + return command->AsyncResponsePromise();
|
| }
|
|
|
| scoped_refptr<DevToolsProtocol::Response> TracingHandler::End(
|
| scoped_refptr<DevToolsProtocol::Command> command) {
|
| - return NULL;
|
| + if (!is_recording_)
|
| + return command->InternalErrorResponse("Tracing is not started");
|
| + DisableRecording(false);
|
| + // If inspected target is a render process Tracing.end will be handled by
|
| + // tracing agent in the renderer.
|
| + if (target_ == Renderer)
|
| + return nullptr;
|
| + return command->SuccessResponse(nullptr);
|
| }
|
|
|
| scoped_refptr<DevToolsProtocol::Response> TracingHandler::GetCategories(
|
| scoped_refptr<DevToolsProtocol::Command> command) {
|
| - return NULL;
|
| + TracingController::GetInstance()->GetCategories(
|
| + base::Bind(&TracingHandler::OnCategoriesReceived,
|
| + weak_factory_.GetWeakPtr(),
|
| + command));
|
| + return command->AsyncResponsePromise();
|
| +}
|
| +
|
| +void TracingHandler::OnRecordingEnabled(
|
| + scoped_refptr<DevToolsProtocol::Command> command) {
|
| + StartResponse response;
|
| + client_->SendStartResponse(command, response);
|
| +}
|
| +
|
| +void TracingHandler::OnBufferUsage(float usage) {
|
| + BufferUsageParams params;
|
| + params.set_value(usage);
|
| + client_->BufferUsage(params);
|
| +}
|
| +
|
| +void TracingHandler::OnCategoriesReceived(
|
| + scoped_refptr<DevToolsProtocol::Command> command,
|
| + const std::set<std::string>& category_set) {
|
| + std::vector<std::string> categories(category_set.begin(), category_set.end());
|
| + GetCategoriesResponse response;
|
| + response.set_categories(categories);
|
| + client_->SendGetCategoriesResponse(command, response);
|
| +}
|
| +
|
| +base::debug::TraceOptions TracingHandler::TraceOptionsFromString(
|
| + const std::string* options) {
|
| + base::debug::TraceOptions ret;
|
| + if (!options)
|
| + return ret;
|
| +
|
| + std::vector<std::string> split;
|
| + std::vector<std::string>::iterator iter;
|
| +
|
| + base::SplitString(*options, ',', &split);
|
| + for (iter = split.begin(); iter != split.end(); ++iter) {
|
| + if (*iter == kRecordUntilFull) {
|
| + ret.record_mode = base::debug::RECORD_UNTIL_FULL;
|
| + } else if (*iter == kRecordContinuously) {
|
| + ret.record_mode = base::debug::RECORD_CONTINUOUSLY;
|
| + } else if (*iter == kRecordAsMuchAsPossible) {
|
| + ret.record_mode = base::debug::RECORD_AS_MUCH_AS_POSSIBLE;
|
| + } else if (*iter == kEnableSampling) {
|
| + ret.enable_sampling = true;
|
| + }
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +void TracingHandler::SetupTimer(double usage_reporting_interval) {
|
| + if (usage_reporting_interval == 0) return;
|
| +
|
| + if (usage_reporting_interval < kMinimumReportingInterval)
|
| + usage_reporting_interval = kMinimumReportingInterval;
|
| +
|
| + base::TimeDelta interval = base::TimeDelta::FromMilliseconds(
|
| + std::ceil(usage_reporting_interval));
|
| + buffer_usage_poll_timer_.reset(new base::Timer(
|
| + FROM_HERE,
|
| + interval,
|
| + base::Bind(
|
| + base::IgnoreResult(&TracingController::GetTraceBufferPercentFull),
|
| + base::Unretained(TracingController::GetInstance()),
|
| + base::Bind(&TracingHandler::OnBufferUsage,
|
| + weak_factory_.GetWeakPtr())),
|
| + true));
|
| + buffer_usage_poll_timer_->Reset();
|
| +}
|
| +
|
| +void TracingHandler::DisableRecording(bool abort) {
|
| + is_recording_ = false;
|
| + buffer_usage_poll_timer_.reset();
|
| + TracingController::GetInstance()->DisableRecording(
|
| + abort ? nullptr : new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr()));
|
| }
|
|
|
| } // namespace tracing
|
|
|