Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: runtime/vm/service/vmservice.dart

Issue 1387043002: Make dart:_vmservice a proper builtin library (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/service/running_isolates.dart ('k') | runtime/vm/service_isolate.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 library vmservice;
6
7 import 'dart:async';
8 import 'dart:convert';
9 import 'dart:isolate';
10 import 'dart:typed_data';
11
12 part 'client.dart';
13 part 'constants.dart';
14 part 'running_isolate.dart';
15 part 'running_isolates.dart';
16 part 'message.dart';
17 part 'message_router.dart';
18
19 final RawReceivePort isolateLifecyclePort = new RawReceivePort();
20 final RawReceivePort scriptLoadPort = new RawReceivePort();
21
22 typedef ShutdownCallback();
23
24 // These must be kept in sync with the declarations in vm/json_stream.h.
25 const kInvalidParams = -32602;
26 const kInternalError = -32603;
27 const kStreamAlreadySubscribed = 103;
28 const kStreamNotSubscribed = 104;
29
30 var _errorMessages = {
31 kInvalidParams: 'Invalid params',
32 kInternalError: 'Internal error',
33 kStreamAlreadySubscribed: 'Stream already subscribed',
34 kStreamNotSubscribed: 'Stream not subscribed',
35 };
36
37 String encodeRpcError(Message message, int code, {String details}) {
38 var response = {
39 'jsonrpc': '2.0',
40 'id' : message.serial,
41 'error' : {
42 'code': code,
43 'message': _errorMessages[code],
44 },
45 };
46 if (details != null) {
47 response['error']['data'] = {
48 'details': details,
49 };
50 }
51 return JSON.encode(response);
52 }
53
54 String encodeResult(Message message, Map result) {
55 var response = {
56 'jsonrpc': '2.0',
57 'id' : message.serial,
58 'result' : result,
59 };
60 return JSON.encode(response);
61 }
62
63
64 class VMService extends MessageRouter {
65 static VMService _instance;
66
67 /// Collection of currently connected clients.
68 final Set<Client> clients = new Set<Client>();
69
70 /// Collection of currently running isolates.
71 RunningIsolates runningIsolates = new RunningIsolates();
72
73 /// A port used to receive events from the VM.
74 final RawReceivePort eventPort;
75
76 ShutdownCallback onShutdown;
77
78 void _addClient(Client client) {
79 assert(client.streams.isEmpty);
80 clients.add(client);
81 }
82
83 void _removeClient(Client client) {
84 clients.remove(client);
85 for (var streamId in client.streams) {
86 if (!_isAnyClientSubscribed(streamId)) {
87 _vmCancelStream(streamId);
88 }
89 }
90 }
91
92 void _eventMessageHandler(List eventMessage) {
93 var streamId = eventMessage[0];
94 var event = eventMessage[1];
95 for (var client in clients) {
96 if (client.sendEvents && client.streams.contains(streamId)) {
97 client.post(event);
98 }
99 }
100 }
101
102 void _controlMessageHandler(int code,
103 int portId,
104 SendPort sp,
105 String name) {
106 switch (code) {
107 case Constants.ISOLATE_STARTUP_MESSAGE_ID:
108 runningIsolates.isolateStartup(portId, sp, name);
109 break;
110 case Constants.ISOLATE_SHUTDOWN_MESSAGE_ID:
111 runningIsolates.isolateShutdown(portId, sp);
112 break;
113 }
114 }
115
116 void _exit() {
117 isolateLifecyclePort.close();
118 scriptLoadPort.close();
119 // Create a copy of the set as a list because client.disconnect() will
120 // alter the connected clients set.
121 var clientsList = clients.toList();
122 for (var client in clientsList) {
123 client.disconnect();
124 }
125 // Call embedder shutdown hook after the internal shutdown.
126 if (onShutdown != null) {
127 onShutdown();
128 }
129 _onExit();
130 }
131
132 void messageHandler(message) {
133 if (message is List) {
134 if (message.length == 2) {
135 // This is an event.
136 assert(message[0] is String);
137 assert(message[1] is String || message[1] is Uint8List);
138 _eventMessageHandler(message);
139 return;
140 }
141 if (message.length == 1) {
142 // This is a control message directing the vm service to exit.
143 assert(message[0] == Constants.SERVICE_EXIT_MESSAGE_ID);
144 _exit();
145 return;
146 }
147 if (message.length == 4) {
148 // This is a message informing us of the birth or death of an
149 // isolate.
150 _controlMessageHandler(message[0], message[1], message[2], message[3]);
151 return;
152 }
153 }
154 Logger.root.severe(
155 'Internal vm-service error: ignoring illegal message: $message');
156 }
157
158 void _notSupported(_) {
159 throw new UnimplementedError('Service script loading not supported.');
160 }
161
162 VMService._internal()
163 : eventPort = isolateLifecyclePort {
164 scriptLoadPort.handler = _notSupported;
165 eventPort.handler = messageHandler;
166 }
167
168 factory VMService() {
169 if (VMService._instance == null) {
170 VMService._instance = new VMService._internal();
171 _onStart();
172 }
173 return _instance;
174 }
175
176 void _clientCollection(Message message) {
177 var members = [];
178 var result = {};
179 clients.forEach((client) {
180 members.add(client.toJson());
181 });
182 result['type'] = 'ClientList';
183 result['members'] = members;
184 message.setResponse(JSON.encode(result));
185 }
186
187 bool _isAnyClientSubscribed(String streamId) {
188 for (var client in clients) {
189 if (client.streams.contains(streamId)) {
190 return true;
191 }
192 }
193 return false;
194 }
195
196 Future<String> _streamListen(Message message) async {
197 var client = message.client;
198 var streamId = message.params['streamId'];
199
200 if (client.streams.contains(streamId)) {
201 return encodeRpcError(message, kStreamAlreadySubscribed);
202 }
203 if (!_isAnyClientSubscribed(streamId)) {
204 if (!_vmListenStream(streamId)) {
205 return encodeRpcError(
206 message, kInvalidParams,
207 details:"streamListen: invalid 'streamId' parameter: ${streamId}");
208 }
209 }
210 client.streams.add(streamId);
211
212 var result = { 'type' : 'Success' };
213 return encodeResult(message, result);
214 }
215
216 Future<String> _streamCancel(Message message) async {
217 var client = message.client;
218 var streamId = message.params['streamId'];
219
220 if (!client.streams.contains(streamId)) {
221 return encodeRpcError(message, kStreamNotSubscribed);
222 }
223 client.streams.remove(streamId);
224 if (!_isAnyClientSubscribed(streamId)) {
225 _vmCancelStream(streamId);
226 }
227
228 var result = { 'type' : 'Success' };
229 return encodeResult(message, result);
230 }
231
232 // TODO(johnmccutchan): Turn this into a command line tool that uses the
233 // service library.
234 Future<String> _getCrashDump(Message message) async {
235 var client = message.client;
236 final perIsolateRequests = [
237 // ?isolateId=<isolate id> will be appended to each of these requests.
238 // Isolate information.
239 Uri.parse('getIsolate'),
240 // State of heap.
241 Uri.parse('_getAllocationProfile'),
242 // Call stack + local variables.
243 Uri.parse('getStack?_full=true'),
244 ];
245
246 // Snapshot of running isolates.
247 var isolates = runningIsolates.isolates.values.toList();
248
249 // Collect the mapping from request uris to responses.
250 var responses = {
251 };
252
253 // Request VM.
254 var getVM = Uri.parse('getVM');
255 var getVmResponse = JSON.decode(
256 await new Message.fromUri(client, getVM).sendToVM());
257 responses[getVM.toString()] = getVmResponse['result'];
258
259 // Request command line flags.
260 var getFlagList = Uri.parse('getFlagList');
261 var getFlagListResponse = JSON.decode(
262 await new Message.fromUri(client, getFlagList).sendToVM());
263 responses[getFlagList.toString()] = getFlagListResponse['result'];
264
265 // Make requests to each isolate.
266 for (var isolate in isolates) {
267 for (var request in perIsolateRequests) {
268 var message = new Message.forIsolate(client, request, isolate);
269 // Decode the JSON and and insert it into the map. The map key
270 // is the request Uri.
271 var response = JSON.decode(await isolate.route(message));
272 responses[message.toUri().toString()] = response['result'];
273 }
274 // Dump the object id ring requests.
275 var message =
276 new Message.forIsolate(client, Uri.parse('_dumpIdZone'), isolate);
277 var response = JSON.decode(await isolate.route(message));
278 // Insert getObject requests into responses map.
279 for (var object in response['result']['objects']) {
280 final requestUri =
281 'getObject&isolateId=${isolate.serviceId}?objectId=${object["id"]}';
282 responses[requestUri] = object;
283 }
284 }
285
286 // Encode the entire crash dump.
287 return encodeResult(message, responses);
288 }
289
290 Future<String> route(Message message) {
291 if (message.completed) {
292 return message.response;
293 }
294 // TODO(turnidge): Update to json rpc. BEFORE SUBMIT.
295 if ((message.path.length == 1) && (message.path[0] == 'clients')) {
296 _clientCollection(message);
297 return message.response;
298 }
299 if (message.method == '_getCrashDump') {
300 return _getCrashDump(message);
301 }
302 if (message.method == 'streamListen') {
303 return _streamListen(message);
304 }
305 if (message.method == 'streamCancel') {
306 return _streamCancel(message);
307 }
308 if (message.params['isolateId'] != null) {
309 return runningIsolates.route(message);
310 }
311 return message.sendToVM();
312 }
313 }
314
315 RawReceivePort boot() {
316 // Return the port we expect isolate startup and shutdown messages on.
317 return isolateLifecyclePort;
318 }
319
320 void _registerIsolate(int port_id, SendPort sp, String name) {
321 var service = new VMService();
322 service.runningIsolates.isolateStartup(port_id, sp, name);
323 }
324
325 void _onStart() native "VMService_OnStart";
326
327 void _onExit() native "VMService_OnExit";
328
329 bool _vmListenStream(String streamId) native "VMService_ListenStream";
330
331 void _vmCancelStream(String streamId) native "VMService_CancelStream";
OLDNEW
« no previous file with comments | « runtime/vm/service/running_isolates.dart ('k') | runtime/vm/service_isolate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698