1// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/service_event.h"
6
7#include "vm/debugger.h"
8#include "vm/message_handler.h"
9#include "vm/service_isolate.h"
10#include "vm/timeline.h"
11
12namespace dart {
13
14#ifndef PRODUCT
15
16ServiceEvent::ServiceEvent(Isolate* isolate, EventKind event_kind)
17 : isolate_(isolate),
18 kind_(event_kind),
19 flag_name_(NULL),
20 flag_new_value_(NULL),
21 embedder_kind_(NULL),
22 embedder_stream_id_(NULL),
23 breakpoint_(NULL),
24 top_frame_(NULL),
25 timeline_event_block_(NULL),
26 extension_rpc_(NULL),
27 exception_(NULL),
28 reload_error_(NULL),
29 spawn_token_(NULL),
30 spawn_error_(NULL),
31 at_async_jump_(false),
32 inspectee_(NULL),
33 gc_stats_(NULL),
34 bytes_(NULL),
35 bytes_length_(0),
36 timestamp_(OS::GetCurrentTimeMillis()) {
37 // We should never generate events for the vm or service isolates.
38 ASSERT(isolate_ != Dart::vm_isolate());
39 ASSERT(isolate == NULL || FLAG_show_invisible_isolates ||
40 !Isolate::IsVMInternalIsolate(isolate));
41
42 if ((event_kind == ServiceEvent::kPauseStart) ||
43 (event_kind == ServiceEvent::kPauseExit)) {
44 timestamp_ = isolate->message_handler()->paused_timestamp();
45 } else if (event_kind == ServiceEvent::kResume) {
46 timestamp_ = isolate->last_resume_timestamp();
47 }
48 ASSERT(timestamp_ > -1);
49}
50
51void ServiceEvent::UpdateTimestamp() {
52 timestamp_ = OS::GetCurrentTimeMillis();
53}
54
55const char* ServiceEvent::KindAsCString() const {
56 switch (kind()) {
57 case kVMUpdate:
58 return "VMUpdate";
59 case kVMFlagUpdate:
60 return "VMFlagUpdate";
61 case kIsolateStart:
62 return "IsolateStart";
63 case kIsolateRunnable:
64 return "IsolateRunnable";
65 case kIsolateExit:
66 return "IsolateExit";
67 case kIsolateUpdate:
68 return "IsolateUpdate";
69 case kServiceExtensionAdded:
70 return "ServiceExtensionAdded";
71 case kIsolateReload:
72 return "IsolateReload";
73 case kPauseStart:
74 return "PauseStart";
75 case kPauseExit:
76 return "PauseExit";
77 case kPauseBreakpoint:
78 return "PauseBreakpoint";
79 case kPauseInterrupted:
80 return "PauseInterrupted";
81 case kPauseException:
82 return "PauseException";
83 case kPausePostRequest:
84 return "PausePostRequest";
85 case kNone:
86 return "None";
87 case kResume:
88 return "Resume";
89 case kBreakpointAdded:
90 return "BreakpointAdded";
91 case kBreakpointResolved:
92 return "BreakpointResolved";
93 case kBreakpointRemoved:
94 return "BreakpointRemoved";
95 case kGC:
96 return "GC"; // TODO(koda): Change to GarbageCollected.
97 case kInspect:
98 return "Inspect";
99 case kEmbedder:
100 return embedder_kind();
101 case kLogging:
102 return "Logging";
103 case kDebuggerSettingsUpdate:
104 return "_DebuggerSettingsUpdate";
105 case kIllegal:
106 return "Illegal";
107 case kExtension:
108 return "Extension";
109 case kTimelineEvents:
110 return "TimelineEvents";
111 case kTimelineStreamSubscriptionsUpdate:
112 return "TimelineStreamSubscriptionsUpdate";
113 default:
114 UNREACHABLE();
115 return "Unknown";
116 }
117}
118
119const StreamInfo* ServiceEvent::stream_info() const {
120 switch (kind()) {
121 case kVMUpdate:
122 case kVMFlagUpdate:
123 return &Service::vm_stream;
124
125 case kIsolateStart:
126 case kIsolateRunnable:
127 case kIsolateExit:
128 case kIsolateUpdate:
129 case kIsolateReload:
130 case kServiceExtensionAdded:
131 return &Service::isolate_stream;
132
133 case kPauseStart:
134 case kPauseExit:
135 case kPauseBreakpoint:
136 case kPauseInterrupted:
137 case kPauseException:
138 case kPausePostRequest:
139 case kNone:
140 case kResume:
141 case kBreakpointAdded:
142 case kBreakpointResolved:
143 case kBreakpointRemoved:
144 case kInspect:
145 case kDebuggerSettingsUpdate:
146 return &Service::debug_stream;
147
148 case kGC:
149 return &Service::gc_stream;
150
151 case kLogging:
152 return &Service::logging_stream;
153
154 case kExtension:
155 return &Service::extension_stream;
156
157 case kTimelineEvents:
158 case kTimelineStreamSubscriptionsUpdate:
159 return &Service::timeline_stream;
160
161 case kEmbedder:
162 return NULL;
163
164 default:
165 UNREACHABLE();
166 return NULL;
167 }
168}
169
170const char* ServiceEvent::stream_id() const {
171 const StreamInfo* stream = stream_info();
172 if (stream == NULL) {
173 ASSERT(kind() == kEmbedder);
174 return embedder_stream_id_;
175 } else {
176 return stream->id();
177 }
178}
179
180void ServiceEvent::PrintJSON(JSONStream* js) const {
181 JSONObject jsobj(js);
182 PrintJSONHeader(&jsobj);
183 if (kind() == kVMFlagUpdate) {
184 jsobj.AddProperty("flag", flag_name());
185 // For backwards compatibility, "new_value" is also provided.
186 // TODO(bkonyi): remove when service protocol major version is incremented.
187 ASSERT(SERVICE_PROTOCOL_MAJOR_VERSION == 3);
188 jsobj.AddProperty("new_value", flag_new_value());
189 jsobj.AddProperty("newValue", flag_new_value());
190 }
191 if (kind() == kIsolateReload) {
192 if (reload_error_ == NULL) {
193 jsobj.AddProperty("status", "success");
194 } else {
195 jsobj.AddProperty("status", "failure");
196 jsobj.AddProperty("reloadError", *(reload_error()));
197 }
198 }
199 if (kind() == kServiceExtensionAdded) {
200 ASSERT(extension_rpc_ != NULL);
201 jsobj.AddProperty("extensionRPC", extension_rpc_->ToCString());
202 }
203 if (kind() == kPauseBreakpoint) {
204 JSONArray jsarr(&jsobj, "pauseBreakpoints");
205 // TODO(rmacnak): If we are paused at more than one breakpoint,
206 // provide it here.
207 if (breakpoint() != NULL) {
208 jsarr.AddValue(breakpoint());
209 }
210 } else {
211 if (breakpoint() != NULL) {
212 jsobj.AddProperty("breakpoint", breakpoint());
213 }
214 }
215 if (kind() == kTimelineEvents) {
216 jsobj.AddProperty("timelineEvents", timeline_event_block_);
217 }
218 if (kind() == kTimelineStreamSubscriptionsUpdate) {
219 JSONArray arr(&jsobj, "updatedStreams");
220 Timeline::PrintFlagsToJSONArray(&arr);
221 }
222 if (kind() == kDebuggerSettingsUpdate) {
223 JSONObject jssettings(&jsobj, "_debuggerSettings");
224 isolate()->debugger()->PrintSettingsToJSONObject(&jssettings);
225 }
226#if !defined(DART_PRECOMPILED_RUNTIME)
227 if (top_frame() != nullptr) {
228 JSONObject jsFrame(&jsobj, "topFrame");
229 top_frame()->PrintToJSONObject(&jsFrame);
230 intptr_t index = 0; // Avoid ambiguity in call to AddProperty.
231 jsFrame.AddProperty("index", index);
232 }
233#endif
234 if (exception() != NULL) {
235 jsobj.AddProperty("exception", *(exception()));
236 }
237 if (at_async_jump()) {
238 jsobj.AddProperty("atAsyncSuspension", true);
239 }
240 if (inspectee() != NULL) {
241 jsobj.AddProperty("inspectee", *(inspectee()));
242 }
243 if (gc_stats() != NULL) {
244 jsobj.AddProperty("reason", Heap::GCReasonToString(gc_stats()->reason_));
245 isolate()->heap()->PrintToJSONObject(Heap::kNew, &jsobj);
246 isolate()->heap()->PrintToJSONObject(Heap::kOld, &jsobj);
247 }
248 if (bytes() != NULL) {
249 jsobj.AddPropertyBase64("bytes", bytes(), bytes_length());
250 }
251 if (kind() == kLogging) {
252 JSONObject logRecord(&jsobj, "logRecord");
253 logRecord.AddProperty("type", "LogRecord");
254 logRecord.AddProperty64("sequenceNumber", log_record_.sequence_number);
255 logRecord.AddPropertyTimeMillis("time", log_record_.timestamp);
256 logRecord.AddProperty64("level", log_record_.level);
257 logRecord.AddProperty("loggerName", *(log_record_.name));
258 logRecord.AddProperty("message", *(log_record_.message));
259 logRecord.AddProperty("zone", *(log_record_.zone));
260 logRecord.AddProperty("error", *(log_record_.error));
261 logRecord.AddProperty("stackTrace", *(log_record_.stack_trace));
262 }
263 if (kind() == kExtension) {
264 js->AppendSerializedObject("extensionData",
265 extension_event_.event_data->ToCString());
266 }
267}
268
269void ServiceEvent::PrintJSONHeader(JSONObject* jsobj) const {
270 ASSERT(jsobj != NULL);
271 jsobj->AddProperty("type", "Event");
272 jsobj->AddProperty("kind", KindAsCString());
273 if (kind() == kExtension) {
274 ASSERT(extension_event_.event_kind != NULL);
275 jsobj->AddProperty("extensionKind",
276 extension_event_.event_kind->ToCString());
277 }
278 if (isolate() == NULL) {
279 jsobj->AddPropertyVM("vm");
280 } else {
281 jsobj->AddProperty("isolate", isolate());
282 }
283 ASSERT(timestamp_ != -1);
284 jsobj->AddPropertyTimeMillis("timestamp", timestamp_);
285}
286
287#endif // !PRODUCT
288
289} // namespace dart
290