Index: runtime/vm/service/vmservice.dart |
diff --git a/runtime/vm/service/vmservice.dart b/runtime/vm/service/vmservice.dart |
deleted file mode 100644 |
index 3c66673731d15fd3ff931823071355d469643396..0000000000000000000000000000000000000000 |
--- a/runtime/vm/service/vmservice.dart |
+++ /dev/null |
@@ -1,331 +0,0 @@ |
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library vmservice; |
- |
-import 'dart:async'; |
-import 'dart:convert'; |
-import 'dart:isolate'; |
-import 'dart:typed_data'; |
- |
-part 'client.dart'; |
-part 'constants.dart'; |
-part 'running_isolate.dart'; |
-part 'running_isolates.dart'; |
-part 'message.dart'; |
-part 'message_router.dart'; |
- |
-final RawReceivePort isolateLifecyclePort = new RawReceivePort(); |
-final RawReceivePort scriptLoadPort = new RawReceivePort(); |
- |
-typedef ShutdownCallback(); |
- |
-// These must be kept in sync with the declarations in vm/json_stream.h. |
-const kInvalidParams = -32602; |
-const kInternalError = -32603; |
-const kStreamAlreadySubscribed = 103; |
-const kStreamNotSubscribed = 104; |
- |
-var _errorMessages = { |
- kInvalidParams: 'Invalid params', |
- kInternalError: 'Internal error', |
- kStreamAlreadySubscribed: 'Stream already subscribed', |
- kStreamNotSubscribed: 'Stream not subscribed', |
-}; |
- |
-String encodeRpcError(Message message, int code, {String details}) { |
- var response = { |
- 'jsonrpc': '2.0', |
- 'id' : message.serial, |
- 'error' : { |
- 'code': code, |
- 'message': _errorMessages[code], |
- }, |
- }; |
- if (details != null) { |
- response['error']['data'] = { |
- 'details': details, |
- }; |
- } |
- return JSON.encode(response); |
-} |
- |
-String encodeResult(Message message, Map result) { |
- var response = { |
- 'jsonrpc': '2.0', |
- 'id' : message.serial, |
- 'result' : result, |
- }; |
- return JSON.encode(response); |
-} |
- |
- |
-class VMService extends MessageRouter { |
- static VMService _instance; |
- |
- /// Collection of currently connected clients. |
- final Set<Client> clients = new Set<Client>(); |
- |
- /// Collection of currently running isolates. |
- RunningIsolates runningIsolates = new RunningIsolates(); |
- |
- /// A port used to receive events from the VM. |
- final RawReceivePort eventPort; |
- |
- ShutdownCallback onShutdown; |
- |
- void _addClient(Client client) { |
- assert(client.streams.isEmpty); |
- clients.add(client); |
- } |
- |
- void _removeClient(Client client) { |
- clients.remove(client); |
- for (var streamId in client.streams) { |
- if (!_isAnyClientSubscribed(streamId)) { |
- _vmCancelStream(streamId); |
- } |
- } |
- } |
- |
- void _eventMessageHandler(List eventMessage) { |
- var streamId = eventMessage[0]; |
- var event = eventMessage[1]; |
- for (var client in clients) { |
- if (client.sendEvents && client.streams.contains(streamId)) { |
- client.post(event); |
- } |
- } |
- } |
- |
- void _controlMessageHandler(int code, |
- int portId, |
- SendPort sp, |
- String name) { |
- switch (code) { |
- case Constants.ISOLATE_STARTUP_MESSAGE_ID: |
- runningIsolates.isolateStartup(portId, sp, name); |
- break; |
- case Constants.ISOLATE_SHUTDOWN_MESSAGE_ID: |
- runningIsolates.isolateShutdown(portId, sp); |
- break; |
- } |
- } |
- |
- void _exit() { |
- isolateLifecyclePort.close(); |
- scriptLoadPort.close(); |
- // Create a copy of the set as a list because client.disconnect() will |
- // alter the connected clients set. |
- var clientsList = clients.toList(); |
- for (var client in clientsList) { |
- client.disconnect(); |
- } |
- // Call embedder shutdown hook after the internal shutdown. |
- if (onShutdown != null) { |
- onShutdown(); |
- } |
- _onExit(); |
- } |
- |
- void messageHandler(message) { |
- if (message is List) { |
- if (message.length == 2) { |
- // This is an event. |
- assert(message[0] is String); |
- assert(message[1] is String || message[1] is Uint8List); |
- _eventMessageHandler(message); |
- return; |
- } |
- if (message.length == 1) { |
- // This is a control message directing the vm service to exit. |
- assert(message[0] == Constants.SERVICE_EXIT_MESSAGE_ID); |
- _exit(); |
- return; |
- } |
- if (message.length == 4) { |
- // This is a message informing us of the birth or death of an |
- // isolate. |
- _controlMessageHandler(message[0], message[1], message[2], message[3]); |
- return; |
- } |
- } |
- Logger.root.severe( |
- 'Internal vm-service error: ignoring illegal message: $message'); |
- } |
- |
- void _notSupported(_) { |
- throw new UnimplementedError('Service script loading not supported.'); |
- } |
- |
- VMService._internal() |
- : eventPort = isolateLifecyclePort { |
- scriptLoadPort.handler = _notSupported; |
- eventPort.handler = messageHandler; |
- } |
- |
- factory VMService() { |
- if (VMService._instance == null) { |
- VMService._instance = new VMService._internal(); |
- _onStart(); |
- } |
- return _instance; |
- } |
- |
- void _clientCollection(Message message) { |
- var members = []; |
- var result = {}; |
- clients.forEach((client) { |
- members.add(client.toJson()); |
- }); |
- result['type'] = 'ClientList'; |
- result['members'] = members; |
- message.setResponse(JSON.encode(result)); |
- } |
- |
- bool _isAnyClientSubscribed(String streamId) { |
- for (var client in clients) { |
- if (client.streams.contains(streamId)) { |
- return true; |
- } |
- } |
- return false; |
- } |
- |
- Future<String> _streamListen(Message message) async { |
- var client = message.client; |
- var streamId = message.params['streamId']; |
- |
- if (client.streams.contains(streamId)) { |
- return encodeRpcError(message, kStreamAlreadySubscribed); |
- } |
- if (!_isAnyClientSubscribed(streamId)) { |
- if (!_vmListenStream(streamId)) { |
- return encodeRpcError( |
- message, kInvalidParams, |
- details:"streamListen: invalid 'streamId' parameter: ${streamId}"); |
- } |
- } |
- client.streams.add(streamId); |
- |
- var result = { 'type' : 'Success' }; |
- return encodeResult(message, result); |
- } |
- |
- Future<String> _streamCancel(Message message) async { |
- var client = message.client; |
- var streamId = message.params['streamId']; |
- |
- if (!client.streams.contains(streamId)) { |
- return encodeRpcError(message, kStreamNotSubscribed); |
- } |
- client.streams.remove(streamId); |
- if (!_isAnyClientSubscribed(streamId)) { |
- _vmCancelStream(streamId); |
- } |
- |
- var result = { 'type' : 'Success' }; |
- return encodeResult(message, result); |
- } |
- |
- // TODO(johnmccutchan): Turn this into a command line tool that uses the |
- // service library. |
- Future<String> _getCrashDump(Message message) async { |
- var client = message.client; |
- final perIsolateRequests = [ |
- // ?isolateId=<isolate id> will be appended to each of these requests. |
- // Isolate information. |
- Uri.parse('getIsolate'), |
- // State of heap. |
- Uri.parse('_getAllocationProfile'), |
- // Call stack + local variables. |
- Uri.parse('getStack?_full=true'), |
- ]; |
- |
- // Snapshot of running isolates. |
- var isolates = runningIsolates.isolates.values.toList(); |
- |
- // Collect the mapping from request uris to responses. |
- var responses = { |
- }; |
- |
- // Request VM. |
- var getVM = Uri.parse('getVM'); |
- var getVmResponse = JSON.decode( |
- await new Message.fromUri(client, getVM).sendToVM()); |
- responses[getVM.toString()] = getVmResponse['result']; |
- |
- // Request command line flags. |
- var getFlagList = Uri.parse('getFlagList'); |
- var getFlagListResponse = JSON.decode( |
- await new Message.fromUri(client, getFlagList).sendToVM()); |
- responses[getFlagList.toString()] = getFlagListResponse['result']; |
- |
- // Make requests to each isolate. |
- for (var isolate in isolates) { |
- for (var request in perIsolateRequests) { |
- var message = new Message.forIsolate(client, request, isolate); |
- // Decode the JSON and and insert it into the map. The map key |
- // is the request Uri. |
- var response = JSON.decode(await isolate.route(message)); |
- responses[message.toUri().toString()] = response['result']; |
- } |
- // Dump the object id ring requests. |
- var message = |
- new Message.forIsolate(client, Uri.parse('_dumpIdZone'), isolate); |
- var response = JSON.decode(await isolate.route(message)); |
- // Insert getObject requests into responses map. |
- for (var object in response['result']['objects']) { |
- final requestUri = |
- 'getObject&isolateId=${isolate.serviceId}?objectId=${object["id"]}'; |
- responses[requestUri] = object; |
- } |
- } |
- |
- // Encode the entire crash dump. |
- return encodeResult(message, responses); |
- } |
- |
- Future<String> route(Message message) { |
- if (message.completed) { |
- return message.response; |
- } |
- // TODO(turnidge): Update to json rpc. BEFORE SUBMIT. |
- if ((message.path.length == 1) && (message.path[0] == 'clients')) { |
- _clientCollection(message); |
- return message.response; |
- } |
- if (message.method == '_getCrashDump') { |
- return _getCrashDump(message); |
- } |
- if (message.method == 'streamListen') { |
- return _streamListen(message); |
- } |
- if (message.method == 'streamCancel') { |
- return _streamCancel(message); |
- } |
- if (message.params['isolateId'] != null) { |
- return runningIsolates.route(message); |
- } |
- return message.sendToVM(); |
- } |
-} |
- |
-RawReceivePort boot() { |
- // Return the port we expect isolate startup and shutdown messages on. |
- return isolateLifecyclePort; |
-} |
- |
-void _registerIsolate(int port_id, SendPort sp, String name) { |
- var service = new VMService(); |
- service.runningIsolates.isolateStartup(port_id, sp, name); |
-} |
- |
-void _onStart() native "VMService_OnStart"; |
- |
-void _onExit() native "VMService_OnExit"; |
- |
-bool _vmListenStream(String streamId) native "VMService_ListenStream"; |
- |
-void _vmCancelStream(String streamId) native "VMService_CancelStream"; |