diff --git a/pkg/dart_runtime_service/lib/src/isolate_manager.dart b/pkg/dart_runtime_service/lib/src/isolate_manager.dart index 5208dd63b6a..b527ff8171d 100644 --- a/pkg/dart_runtime_service/lib/src/isolate_manager.dart +++ b/pkg/dart_runtime_service/lib/src/isolate_manager.dart @@ -87,6 +87,12 @@ abstract base class IsolateManager { /// Used to support the `isolates/root` isolate ID. int? _rootIsolateId; + @protected + int? get rootIsolateId => _rootIsolateId; + + @protected + set rootIsolateId(int? value) => _rootIsolateId = value; + @mustCallSuper Future shutdown() async { _logger.info('Shutting down.'); @@ -103,10 +109,12 @@ abstract base class IsolateManager { }); /// Initializes state for a newly started isolate. - void isolateStarted({required RunningIsolate isolate}) { + void isolateStarted({ + required RunningIsolate isolate, + bool isSystemIsolate = false, + }) { _logger.info('Starting isolate: $isolate'); - if (_rootIsolateId == null) { - // TODO(bkonyi): ensure this is a non-system isolate + if (_rootIsolateId == null && !isSystemIsolate) { _logger.info('$isolate is the root isolate.'); _rootIsolateId = isolate.id; } diff --git a/pkg/dart_runtime_service/test/isolate_manager_test.dart b/pkg/dart_runtime_service/test/isolate_manager_test.dart new file mode 100644 index 00000000000..62e482ecc98 --- /dev/null +++ b/pkg/dart_runtime_service/test/isolate_manager_test.dart @@ -0,0 +1,52 @@ +import 'dart:async'; +import 'package:dart_runtime_service/dart_runtime_service.dart'; +import 'package:test/test.dart'; + +base class TestRunningIsolate extends RunningIsolate { + TestRunningIsolate({required super.id, required super.name}); +} + +base class TestIsolateManager extends IsolateManager { + @override + Future sendToIsolate({ + required String method, + required Map params, + }) { + throw UnimplementedError(); + } +} + +void main() { + group('IsolateManager', () { + test('ignores system isolates when assigning the root isolate', () async { + final manager = TestIsolateManager(); + + // A system isolate starts first. + final systemIsolate = TestRunningIsolate(id: 1, name: 'vm-service'); + manager.isolateStarted(isolate: systemIsolate, isSystemIsolate: true); + + // The root isolate id should not be set yet. + expect( + () => manager.lookupIsolateFromParams( + method: 'foo', + params: {'isolateId': 'isolates/root'}, + ), + throwsA(isA()), + ); + + // A non-system isolate starts next. + final normalIsolate = TestRunningIsolate(id: 2, name: 'main'); + manager.isolateStarted(isolate: normalIsolate); + + await Future.delayed(const Duration(milliseconds: 10)); + + // Now the root isolate ID should point to the normal isolate. + final rootIsolate = manager.lookupIsolateFromParams( + method: 'foo', + params: {'isolateId': 'isolates/root'}, + ); + expect(rootIsolate, isNotNull); + expect(rootIsolate!.id, equals(2)); + }); + }); +} diff --git a/pkg/dart_runtime_service_vm/bin/vm_service_entrypoint.dart b/pkg/dart_runtime_service_vm/bin/vm_service_entrypoint.dart index c7663d791d7..5e4ec54c96a 100644 --- a/pkg/dart_runtime_service_vm/bin/vm_service_entrypoint.dart +++ b/pkg/dart_runtime_service_vm/bin/vm_service_entrypoint.dart @@ -71,10 +71,19 @@ final _isolateRegistrationStreamController = StreamController( @entrypoint // ignore: unused_element -void _registerIsolate(int portId, SendPort sendPort, String name) => - _isolateRegistrationStreamController.sink.add( - VmRunningIsolate(id: portId, name: name, sendPort: sendPort), - ); +void _registerIsolate( + int portId, + SendPort sendPort, + String name, + bool isSystemIsolate, +) => _isolateRegistrationStreamController.sink.add( + VmRunningIsolate( + id: portId, + name: name, + sendPort: sendPort, + isSystemIsolate: isSystemIsolate, + ), +); // ignore: unused_element StreamSubscription? _signalSubscription; diff --git a/pkg/dart_runtime_service_vm/lib/dart_runtime_service_vm.dart b/pkg/dart_runtime_service_vm/lib/dart_runtime_service_vm.dart index 124090ebdb2..db647979acb 100644 --- a/pkg/dart_runtime_service_vm/lib/dart_runtime_service_vm.dart +++ b/pkg/dart_runtime_service_vm/lib/dart_runtime_service_vm.dart @@ -271,11 +271,23 @@ class DartRuntimeServiceVMBackend final SendPort sendPort, final String name, ] - when opcode == _kIsolateStartupMessageId || - opcode == _kIsolateShutdownMessageId: - // This is a message informing us of the birth or death of an - // isolate. + when opcode == _kIsolateShutdownMessageId: _isolateControlMessageHandler(opcode, portId, sendPort, name); + case [ + final int opcode, + final int portId, + final SendPort sendPort, + final String name, + final bool isSystemIsolate, + ] + when opcode == _kIsolateStartupMessageId: + _isolateControlMessageHandler( + opcode, + portId, + sendPort, + name, + isSystemIsolate: isSystemIsolate, + ); default: _logger.warning( 'Internal vm-service error: ignoring illegal message: $message', @@ -311,14 +323,16 @@ class DartRuntimeServiceVMBackend int code, int portId, SendPort sp, - String name, - ) { + String name, { + bool isSystemIsolate = false, + }) { switch (code) { case _kIsolateStartupMessageId: isolateManager.onIsolateStartupMessage( id: portId, sendPort: sp, name: name, + isSystemIsolate: isSystemIsolate, ); case _kIsolateShutdownMessageId: isolateManager.onIsolateShutdownMessage(id: portId); diff --git a/pkg/dart_runtime_service_vm/lib/src/vm_isolate_manager.dart b/pkg/dart_runtime_service_vm/lib/src/vm_isolate_manager.dart index 264adc4afb7..72027efd8a3 100644 --- a/pkg/dart_runtime_service_vm/lib/src/vm_isolate_manager.dart +++ b/pkg/dart_runtime_service_vm/lib/src/vm_isolate_manager.dart @@ -17,11 +17,15 @@ final class VmRunningIsolate extends RunningIsolate { required super.id, required super.name, required this.sendPort, + required this.isSystemIsolate, }); /// The port used to send service requests to the isolate within the VM. final SendPort sendPort; + /// Whether this is a system isolate. + final bool isSystemIsolate; + /// The set of ports for outstanding requests that are used by the VM to send /// responses. final outstandingRequestPorts = {}; @@ -64,10 +68,16 @@ final class VmIsolateManager extends IsolateManager { required int id, required SendPort sendPort, required String name, + required bool isSystemIsolate, }) { - final isolate = VmRunningIsolate(id: id, name: name, sendPort: sendPort); + final isolate = VmRunningIsolate( + id: id, + name: name, + sendPort: sendPort, + isSystemIsolate: isSystemIsolate, + ); _logger.info('Isolate startup message received for $isolate'); - isolateStarted(isolate: isolate); + isolateStarted(isolate: isolate, isSystemIsolate: isSystemIsolate); } /// Reports that an isolate is shutting down based on a message over the diff --git a/runtime/lib/vmservice.cc b/runtime/lib/vmservice.cc index c6381516010..bb6a0892b76 100644 --- a/runtime/lib/vmservice.cc +++ b/runtime/lib/vmservice.cc @@ -35,17 +35,20 @@ class RegisterRunningIsolatesVisitor : public IsolateVisitor { virtual void VisitIsolate(Isolate* isolate) { isolate_ports_.Add(isolate->main_port()); isolate_names_.Add(&String::Handle(zone_, String::New(isolate->name()))); + isolate_is_system_.Add(Isolate::IsSystemIsolate(isolate)); isolate->set_is_service_registered(true); } void RegisterIsolates() { - ServiceIsolate::RegisterRunningIsolates(isolate_ports_, isolate_names_); + ServiceIsolate::RegisterRunningIsolates(isolate_ports_, isolate_names_, + isolate_is_system_); } private: Zone* zone_; GrowableArray isolate_ports_; GrowableArray isolate_names_; + GrowableArray isolate_is_system_; Function& register_function_; Isolate* service_isolate_; }; diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc index 4a9181e1452..60812204379 100644 --- a/runtime/vm/service_isolate.cc +++ b/runtime/vm/service_isolate.cc @@ -70,15 +70,25 @@ bool ServiceIsolate::SendServiceControlMessage(Thread* thread, cname.type = Dart_CObject_kString; cname.value.as_string = const_cast(name); - Dart_CObject* values[4]; + Dart_CObject cis_system; + bool is_startup = (code == VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID); + if (is_startup) { + cis_system.type = Dart_CObject_kBool; + cis_system.value.as_bool = Isolate::IsSystemIsolate(thread->isolate()); + } + + Dart_CObject* values[5]; values[0] = &ccode; values[1] = &port_int; values[2] = &send_port; values[3] = &cname; + if (is_startup) { + values[4] = &cis_system; + } Dart_CObject message; message.type = Dart_CObject_kArray; - message.value.as_array.length = 4; + message.value.as_array.length = is_startup ? 5 : 4; message.value.as_array.values = values; return PortMap::PostMessage(WriteApiMessage(thread->zone(), &message, port_, @@ -630,7 +640,8 @@ void ServiceIsolate::BootVmServiceLibrary() { void ServiceIsolate::RegisterRunningIsolates( const GrowableArray& isolate_ports, - const GrowableArray& isolate_names) { + const GrowableArray& isolate_names, + const GrowableArray& isolate_is_system) { auto thread = Thread::Current(); auto zone = thread->zone(); @@ -653,10 +664,11 @@ void ServiceIsolate::RegisterRunningIsolates( Integer& port_int = Integer::Handle(zone); SendPort& send_port = SendPort::Handle(zone); - Array& args = Array::Handle(zone, Array::New(3)); + Array& args = Array::Handle(zone, Array::New(4)); Object& result = Object::Handle(zone); ASSERT(isolate_ports.length() == isolate_names.length()); + ASSERT(isolate_ports.length() == isolate_is_system.length()); for (intptr_t i = 0; i < isolate_ports.length(); ++i) { const Dart_Port port_id = isolate_ports[i]; const String& name = *isolate_names[i]; @@ -666,6 +678,7 @@ void ServiceIsolate::RegisterRunningIsolates( args.SetAt(0, port_int); args.SetAt(1, send_port); args.SetAt(2, name); + args.SetAt(3, Bool::Get(isolate_is_system[i])); result = DartEntry::InvokeFunction(register_function_, args); if (FLAG_trace_service) { OS::PrintErr("vm-service: Isolate %s %" Pd64 " registered.\n", diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h index d4236e1fcf2..68dee8b40f6 100644 --- a/runtime/vm/service_isolate.h +++ b/runtime/vm/service_isolate.h @@ -55,7 +55,8 @@ class ServiceIsolate : public AllStatic { static void RegisterRunningIsolates( const GrowableArray& isolate_ports, - const GrowableArray& isolate_names); + const GrowableArray& isolate_names, + const GrowableArray& isolate_is_system); static void RequestServerInfo(const SendPort& sp); static void ControlWebServer(const SendPort& sp, diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart index 2aa66d8f9b6..42be23e10fe 100644 --- a/sdk/lib/vmservice/vmservice.dart +++ b/sdk/lib/vmservice/vmservice.dart @@ -476,7 +476,8 @@ class VMService extends MessageRouter { _serverMessageHandler(opcode, sendPort, enable, silenceOutput); return; } - if (message case [int opcode, int portId, SendPort sendPort, String name] + if (message + case [int opcode, int portId, SendPort sendPort, String name, ...] when opcode == Constants.ISOLATE_STARTUP_MESSAGE_ID || opcode == Constants.ISOLATE_SHUTDOWN_MESSAGE_ID) { // This is a message informing us of the birth or death of an @@ -802,8 +803,12 @@ RawReceivePort boot() { @pragma('vm:entry-point', !bool.fromEnvironment('dart.vm.product')) // ignore: unused_element -void _registerIsolate(int port_id, SendPort sp, String name) => - VMService().runningIsolates.isolateStartup(port_id, sp, name); +void _registerIsolate( + int port_id, + SendPort sp, + String name, + bool isSystemIsolate, +) => VMService().runningIsolates.isolateStartup(port_id, sp, name); /// Notify the VM that the service is running. @pragma("vm:external-name", "VMService_OnStart")