OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/devtools/protocol/tracing_handler.h" | 5 #include "content/browser/devtools/protocol/tracing_handler.h" |
6 | 6 |
| 7 #include <cmath> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/debug/trace_event_impl.h" |
| 11 #include "base/strings/string_split.h" |
| 12 #include "base/strings/stringprintf.h" |
| 13 #include "base/time/time.h" |
| 14 #include "base/timer/timer.h" |
| 15 |
7 namespace content { | 16 namespace content { |
8 namespace devtools { | 17 namespace devtools { |
9 namespace tracing { | 18 namespace tracing { |
10 | 19 |
11 typedef DevToolsProtocolClient::Response Response; | 20 typedef DevToolsProtocolClient::Response Response; |
12 | 21 |
13 TracingHandler::TracingHandler() { | 22 namespace { |
| 23 |
| 24 const char kRecordUntilFull[] = "record-until-full"; |
| 25 const char kRecordContinuously[] = "record-continuously"; |
| 26 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible"; |
| 27 const char kEnableSampling[] = "enable-sampling"; |
| 28 const double kMinimumReportingInterval = 250.0; |
| 29 |
| 30 class DevToolsTraceSinkProxy : public TracingController::TraceDataSink { |
| 31 public: |
| 32 explicit DevToolsTraceSinkProxy(base::WeakPtr<TracingHandler> handler) |
| 33 : tracing_handler_(handler) {} |
| 34 |
| 35 virtual void AddTraceChunk(const std::string& chunk) override { |
| 36 if (TracingHandler* h = tracing_handler_.get()) |
| 37 h->OnTraceDataCollected(chunk); |
| 38 } |
| 39 virtual void Close() override { |
| 40 if (TracingHandler* h = tracing_handler_.get()) |
| 41 h->OnTraceComplete(); |
| 42 } |
| 43 |
| 44 private: |
| 45 virtual ~DevToolsTraceSinkProxy() {} |
| 46 |
| 47 base::WeakPtr<TracingHandler> tracing_handler_; |
| 48 }; |
| 49 |
| 50 } // namespace |
| 51 |
| 52 TracingHandler::TracingHandler(TracingHandler::Target target) |
| 53 : target_(target), |
| 54 is_recording_(false), |
| 55 weak_factory_(this) { |
14 } | 56 } |
15 | 57 |
16 TracingHandler::~TracingHandler() { | 58 TracingHandler::~TracingHandler() { |
17 } | 59 } |
18 | 60 |
19 void TracingHandler::SetClient(scoped_ptr<Client> client) { | 61 void TracingHandler::SetClient(scoped_ptr<Client> client) { |
20 client_.swap(client); | 62 client_.swap(client); |
21 } | 63 } |
22 | 64 |
23 scoped_refptr<DevToolsProtocol::Response> TracingHandler::Start( | 65 void TracingHandler::Detached() { |
24 const std::string& categories, | 66 if (is_recording_) |
25 const std::string& options, | 67 DisableRecording(true); |
26 const double* buffer_usage_reporting_interval, | 68 } |
27 scoped_refptr<DevToolsProtocol::Command> command) { | 69 |
28 return NULL; | 70 void TracingHandler::OnTraceDataCollected(const std::string& trace_fragment) { |
| 71 // Hand-craft protocol notification message so we can substitute JSON |
| 72 // that we already got as string as a bare object, not a quoted string. |
| 73 std::string message( |
| 74 "{ \"method\": \"Tracing.dataCollected\", \"params\": { \"value\": ["); |
| 75 const size_t messageSuffixSize = 10; |
| 76 message.reserve(message.size() + trace_fragment.size() + messageSuffixSize); |
| 77 message += trace_fragment; |
| 78 message += "] } }"; |
| 79 client_->SendRawMessage(message); |
| 80 } |
| 81 |
| 82 void TracingHandler::OnTraceComplete() { |
| 83 TracingCompleteParams params; |
| 84 client_->TracingComplete(params); |
29 } | 85 } |
30 | 86 |
31 scoped_refptr<DevToolsProtocol::Response> TracingHandler::Start( | 87 scoped_refptr<DevToolsProtocol::Response> TracingHandler::Start( |
32 const std::string* categories, | 88 const std::string* categories, |
33 const std::string* options, | 89 const std::string* options_str, |
34 const double* buffer_usage_reporting_interval, | 90 const double* buffer_usage_reporting_interval, |
35 scoped_refptr<DevToolsProtocol::Command> command) { | 91 scoped_refptr<DevToolsProtocol::Command> command) { |
36 return NULL; | 92 if (is_recording_) |
| 93 return command->InternalErrorResponse("Tracing is already started"); |
| 94 is_recording_ = true; |
| 95 |
| 96 base::debug::TraceOptions options = TraceOptionsFromString(options_str); |
| 97 base::debug::CategoryFilter filter(categories ? *categories : std::string()); |
| 98 if (buffer_usage_reporting_interval) |
| 99 SetupTimer(*buffer_usage_reporting_interval); |
| 100 |
| 101 // If inspected target is a render process Tracing.start will be handled by |
| 102 // tracing agent in the renderer. |
| 103 if (target_ == Renderer) { |
| 104 TracingController::GetInstance()->EnableRecording( |
| 105 filter, |
| 106 options, |
| 107 TracingController::EnableRecordingDoneCallback()); |
| 108 return nullptr; |
| 109 } |
| 110 |
| 111 TracingController::GetInstance()->EnableRecording( |
| 112 filter, |
| 113 options, |
| 114 base::Bind(&TracingHandler::OnRecordingEnabled, |
| 115 weak_factory_.GetWeakPtr(), |
| 116 command)); |
| 117 return command->AsyncResponsePromise(); |
37 } | 118 } |
38 | 119 |
39 scoped_refptr<DevToolsProtocol::Response> TracingHandler::End( | 120 scoped_refptr<DevToolsProtocol::Response> TracingHandler::End( |
40 scoped_refptr<DevToolsProtocol::Command> command) { | 121 scoped_refptr<DevToolsProtocol::Command> command) { |
41 return NULL; | 122 if (!is_recording_) |
| 123 return command->InternalErrorResponse("Tracing is not started"); |
| 124 DisableRecording(false); |
| 125 // If inspected target is a render process Tracing.end will be handled by |
| 126 // tracing agent in the renderer. |
| 127 if (target_ == Renderer) |
| 128 return nullptr; |
| 129 return command->SuccessResponse(nullptr); |
42 } | 130 } |
43 | 131 |
44 scoped_refptr<DevToolsProtocol::Response> TracingHandler::GetCategories( | 132 scoped_refptr<DevToolsProtocol::Response> TracingHandler::GetCategories( |
45 scoped_refptr<DevToolsProtocol::Command> command) { | 133 scoped_refptr<DevToolsProtocol::Command> command) { |
46 return NULL; | 134 TracingController::GetInstance()->GetCategories( |
| 135 base::Bind(&TracingHandler::OnCategoriesReceived, |
| 136 weak_factory_.GetWeakPtr(), |
| 137 command)); |
| 138 return command->AsyncResponsePromise(); |
| 139 } |
| 140 |
| 141 void TracingHandler::OnRecordingEnabled( |
| 142 scoped_refptr<DevToolsProtocol::Command> command) { |
| 143 StartResponse response; |
| 144 client_->SendStartResponse(command, response); |
| 145 } |
| 146 |
| 147 void TracingHandler::OnBufferUsage(float usage) { |
| 148 BufferUsageParams params; |
| 149 params.set_value(usage); |
| 150 client_->BufferUsage(params); |
| 151 } |
| 152 |
| 153 void TracingHandler::OnCategoriesReceived( |
| 154 scoped_refptr<DevToolsProtocol::Command> command, |
| 155 const std::set<std::string>& category_set) { |
| 156 std::vector<std::string> categories(category_set.begin(), category_set.end()); |
| 157 GetCategoriesResponse response; |
| 158 response.set_categories(categories); |
| 159 client_->SendGetCategoriesResponse(command, response); |
| 160 } |
| 161 |
| 162 base::debug::TraceOptions TracingHandler::TraceOptionsFromString( |
| 163 const std::string* options) { |
| 164 base::debug::TraceOptions ret; |
| 165 if (!options) |
| 166 return ret; |
| 167 |
| 168 std::vector<std::string> split; |
| 169 std::vector<std::string>::iterator iter; |
| 170 |
| 171 base::SplitString(*options, ',', &split); |
| 172 for (iter = split.begin(); iter != split.end(); ++iter) { |
| 173 if (*iter == kRecordUntilFull) { |
| 174 ret.record_mode = base::debug::RECORD_UNTIL_FULL; |
| 175 } else if (*iter == kRecordContinuously) { |
| 176 ret.record_mode = base::debug::RECORD_CONTINUOUSLY; |
| 177 } else if (*iter == kRecordAsMuchAsPossible) { |
| 178 ret.record_mode = base::debug::RECORD_AS_MUCH_AS_POSSIBLE; |
| 179 } else if (*iter == kEnableSampling) { |
| 180 ret.enable_sampling = true; |
| 181 } |
| 182 } |
| 183 return ret; |
| 184 } |
| 185 |
| 186 void TracingHandler::SetupTimer(double usage_reporting_interval) { |
| 187 if (usage_reporting_interval == 0) return; |
| 188 |
| 189 if (usage_reporting_interval < kMinimumReportingInterval) |
| 190 usage_reporting_interval = kMinimumReportingInterval; |
| 191 |
| 192 base::TimeDelta interval = base::TimeDelta::FromMilliseconds( |
| 193 std::ceil(usage_reporting_interval)); |
| 194 buffer_usage_poll_timer_.reset(new base::Timer( |
| 195 FROM_HERE, |
| 196 interval, |
| 197 base::Bind( |
| 198 base::IgnoreResult(&TracingController::GetTraceBufferPercentFull), |
| 199 base::Unretained(TracingController::GetInstance()), |
| 200 base::Bind(&TracingHandler::OnBufferUsage, |
| 201 weak_factory_.GetWeakPtr())), |
| 202 true)); |
| 203 buffer_usage_poll_timer_->Reset(); |
| 204 } |
| 205 |
| 206 void TracingHandler::DisableRecording(bool abort) { |
| 207 is_recording_ = false; |
| 208 buffer_usage_poll_timer_.reset(); |
| 209 TracingController::GetInstance()->DisableRecording( |
| 210 abort ? nullptr : new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr())); |
47 } | 211 } |
48 | 212 |
49 } // namespace tracing | 213 } // namespace tracing |
50 } // namespace devtools | 214 } // namespace devtools |
51 } // namespace content | 215 } // namespace content |
OLD | NEW |