[VM/Service] - Launch dds from vmservice code instead of dartdev code

Currently the dds process is being launched from dartdev and
this causes problems when the dartdev commands 'run' and 'test'
are implemented by spawning child processes (this is needed
to make dartdev an AOT snapshot).
This CL attempts to lauch dds from the service isolate code.

TEST=ci

Change-Id: Iad00a17473a630659f15a5c73be0f5385ea35bdd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/350688
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Siva Annamalai <asiva@google.com>
This commit is contained in:
asiva 2024-02-22 06:22:12 +00:00 committed by Commit Queue
parent af17bedd44
commit 58098d3414
12 changed files with 93 additions and 122 deletions

View file

@ -12,7 +12,6 @@ import 'package:path/path.dart';
import 'package:pub/pub.dart';
import '../core.dart';
import '../dds_runner.dart';
import '../experiments.dart';
import '../generate_kernel.dart';
import '../native_assets.dart';
@ -278,47 +277,6 @@ class RunCommand extends DartdevCommand {
// The command line arguments after the command name.
runArgs = args.rest.skip(1).toList();
}
if (!isProductMode) {
// --launch-dds is provided by the VM if the VM service is to be enabled. In
// that case, we need to launch DDS as well.
String? launchDdsArg = args['launch-dds'];
String ddsHost = '';
String ddsPort = '';
bool launchDevTools = args['serve-devtools'] ?? false;
bool launchDds = false;
if (launchDdsArg != null) {
launchDds = true;
final ddsUrl = launchDdsArg.split('\\:');
ddsHost = ddsUrl[0];
ddsPort = ddsUrl[1];
}
final bool debugDds = args['debug-dds'];
bool disableServiceAuthCodes = args['disable-service-auth-codes'];
final bool enableServicePortFallback =
args['enable-service-port-fallback'];
// If the user wants to start a debugging session we need to do some extra
// work and spawn a Dart Development Service (DDS) instance. DDS is a VM
// service intermediary which implements the VM service protocol and
// provides non-VM specific extensions (e.g., log caching, client
// synchronization).
DDSRunner debugSession;
if (launchDds) {
debugSession = DDSRunner();
if (!await debugSession.startForCurrentProcess(
ddsHost: ddsHost,
ddsPort: ddsPort,
disableServiceAuthCodes: disableServiceAuthCodes,
enableDevTools: launchDevTools,
debugDds: debugDds,
enableServicePortFallback: enableServicePortFallback,
)) {
return errorExitCode;
}
}
}
String? nativeAssets;
if (!nativeAssetsExperimentEnabled) {

View file

@ -106,13 +106,12 @@ void main() {
observeScript,
],
);
int port = server.port;
final completer = Completer<void>();
late StreamSubscription sub;
bool sawServiceMsg = false;
void onData(event) {
if (event.contains(
'Could not start the VM service: localhost:$port is already in use')) {
print(event);
if (event.contains('Could not start the VM service:')) {
sawServiceMsg = true;
process.kill();
}

View file

@ -14,6 +14,7 @@ import 'common/service_test_common.dart';
import 'common/test_helper.dart';
void test() {
debugger();
print('start');
debugger();
print('stdout');
@ -26,6 +27,14 @@ void test() {
}
var tests = <IsolateTest>[
// The testeee will print the VM service is listening message
// which could race with the regular stdio prints from the testee
// The first debugger stop ensures we have these VM service
// messages outputed before the testee writes anything to stdout.
hasStoppedAtBreakpoint,
(VmService service, IsolateRef isolateRef) async {
await service.resume(isolateRef.id!);
},
hasStoppedAtBreakpoint,
(VmService service, IsolateRef isolateRef) async {
final completer = Completer<void>();

View file

@ -13,12 +13,21 @@ import 'common/service_test_common.dart';
import 'common/test_helper.dart';
void test() {
debugger();
print('started');
debugger();
print('lf1\ntrail');
}
var tests = <IsolateTest>[
// The testeee will print the VM service is listening message
// which could race with the regular stdio prints from the testee
// The first debugger stop ensures we have these VM service
// messages outputed before the testee writes anything to stdout.
hasStoppedAtBreakpoint,
(VmService service, IsolateRef isolateRef) async {
await service.resume(isolateRef.id!);
},
hasStoppedAtBreakpoint,
(VmService service, IsolateRef isolateRef) async {
print('At breakpoint');

View file

@ -109,6 +109,7 @@ Dart_Isolate CreateVmServiceIsolate(const IsolateCreationData& data,
/*trace_loading=*/false, config.deterministic,
/*enable_service_port_fallback=*/false,
/*wait_for_dds_to_advertise_service=*/false,
/*serve_devtools=*/false,
/*serve_observatory=*/true)) {
*error = Utils::StrDup(bin::VmService::GetErrorMessage());
return nullptr;
@ -146,6 +147,7 @@ Dart_Isolate CreateVmServiceIsolateFromKernel(
/*trace_loading=*/false, config.deterministic,
/*enable_service_port_fallback=*/false,
/*wait_for_dds_to_advertise_service=*/false,
/*serve_devtools=*/false,
/*serve_observatory*/ true)) {
*error = Utils::StrDup(bin::VmService::GetErrorMessage());
return nullptr;

View file

@ -543,31 +543,21 @@ static Dart_Isolate CreateAndSetupServiceIsolate(const char* script_uri,
result = Dart_SetDeferredLoadHandler(Loader::DeferredLoadHandler);
CHECK_RESULT(result);
int vm_service_server_port = INVALID_VM_SERVICE_SERVER_PORT;
if (Options::disable_dart_dev() || Options::disable_dds()) {
vm_service_server_port = Options::vm_service_server_port();
} else if (Options::vm_service_server_port() !=
INVALID_VM_SERVICE_SERVER_PORT) {
vm_service_server_port = 0;
}
// We do not want to wait for DDS to advertise availability of VM service in
// the following scenarios:
// - The DartDev CLI is disabled (CLI isolate starts DDS) and VM service is
// enabled.
// We do not spawn the external dds process in the following scenarios:
// - The DartDev CLI is disabled and VM service is enabled.
// - DDS is disabled.
// TODO(bkonyi): do we want to tie DevTools / DDS to the CLI in the long run?
bool wait_for_dds_to_advertise_service =
!(Options::disable_dart_dev() || Options::disable_dds());
bool serve_devtools =
Options::enable_devtools() || !Options::disable_devtools();
// Load embedder specific bits and return.
if (!VmService::Setup(
!wait_for_dds_to_advertise_service ? Options::vm_service_server_ip()
: DEFAULT_VM_SERVICE_SERVER_IP,
vm_service_server_port, Options::vm_service_dev_mode(),
Options::vm_service_auth_disabled(),
Options::vm_service_server_ip(), Options::vm_service_server_port(),
Options::vm_service_dev_mode(), Options::vm_service_auth_disabled(),
Options::vm_write_service_info_filename(), Options::trace_loading(),
Options::deterministic(), Options::enable_service_port_fallback(),
wait_for_dds_to_advertise_service, Options::enable_observatory())) {
wait_for_dds_to_advertise_service, serve_devtools,
Options::enable_observatory())) {
*error = Utils::StrDup(VmService::GetErrorMessage());
return nullptr;
}

View file

@ -445,7 +445,6 @@ bool Options::ParseArguments(int argc,
bool enable_dartdev_analytics = false;
bool disable_dartdev_analytics = false;
bool serve_devtools = true;
char* packages_argument = nullptr;
// Parse out the vm options.
@ -476,12 +475,6 @@ bool Options::ParseArguments(int argc,
// It is irrelevant for the vm.
dart_options->AddArgument("--no-analytics");
skipVmOption = true;
} else if (IsOption(argv[i], "serve-devtools")) {
serve_devtools = true;
skipVmOption = true;
} else if (IsOption(argv[i], "no-serve-devtools")) {
serve_devtools = false;
skipVmOption = true;
} else if (IsOption(argv[i], "dds")) {
// This flag is set by default in dartdev, so we ignore it. --no-dds is
// a VM flag as disabling DDS changes how we configure the VM service,
@ -642,16 +635,6 @@ bool Options::ParseArguments(int argc,
// run command. If 'run' is provided, it will be the first argument
// processed in this loop.
dart_options->AddArgument("run");
// Ensure we can enable / disable DevTools when invoking 'dart run'
// implicitly.
if (enable_vm_service_) {
if (serve_devtools) {
dart_options->AddArgument("--serve-devtools");
} else {
dart_options->AddArgument("--no-serve-devtools");
}
}
} else {
dart_options->AddArgument(argv[i]);
i++;
@ -665,29 +648,6 @@ bool Options::ParseArguments(int argc,
if (!run_command && strcmp(argv[i - 1], "run") == 0) {
run_command = true;
}
if (!Options::disable_dart_dev() && !Options::disable_dds() &&
enable_vm_service_ && run_command) {
const char* dds_format_str = "--launch-dds=%s\\:%d";
size_t size =
snprintf(nullptr, 0, dds_format_str, vm_service_server_ip(),
vm_service_server_port());
// Make room for '\0'.
++size;
char* dds_uri = new char[size];
snprintf(dds_uri, size, dds_format_str, vm_service_server_ip(),
vm_service_server_port());
dart_options->AddArgument(dds_uri);
// Only add --disable-service-auth-codes if dartdev is being run
// implicitly. Otherwise it will already be forwarded.
if (implicitly_use_dart_dev && Options::vm_service_auth_disabled()) {
dart_options->AddArgument("--disable-service-auth-codes");
}
if (implicitly_use_dart_dev &&
Options::enable_service_port_fallback()) {
dart_options->AddArgument("--enable-service-port-fallback");
}
}
#if !defined(DART_PRECOMPILED_RUNTIME)
// Bring any --packages option into the dartdev command
if (DartDevIsolate::should_run_dart_dev() &&

View file

@ -49,6 +49,8 @@ namespace bin {
V(bypass_trusting_system_roots, bypass_trusting_system_roots) \
V(delayed_filewatch_callback, delayed_filewatch_callback) \
V(mark_main_isolate_as_system_isolate, mark_main_isolate_as_system_isolate) \
V(no_serve_devtools, disable_devtools) \
V(serve_devtools, enable_devtools) \
V(no_serve_observatory, disable_observatory) \
V(serve_observatory, enable_observatory)

View file

@ -150,11 +150,12 @@ static Dart_Isolate CreateAndSetupServiceIsolate(const char* script_uri,
// Load embedder specific bits and return.
if (!bin::VmService::Setup("127.0.0.1", 0,
/*dev_mode=*/false, /*auth_disabled=*/true,
/*write_service_info_filename*/ "",
/*write_service_info_filename=*/"",
/*trace_loading=*/false, /*deterministic=*/true,
/*enable_service_port_fallback=*/false,
/*wait_for_dds_to_advertise_service*/ false,
/*serve_observatory*/ true)) {
/*wait_for_dds_to_advertise_service=*/false,
/*serve_devtools=*/false,
/*serve_observatory-*/ true)) {
*error = Utils::StrDup(bin::VmService::GetErrorMessage());
return nullptr;
}

View file

@ -9,6 +9,7 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
#include "bin/isolate_data.h"
#include "bin/main_options.h"
#include "bin/platform.h"
#include "bin/thread.h"
#include "bin/utils.h"
@ -122,6 +123,7 @@ bool VmService::Setup(const char* server_ip,
bool deterministic,
bool enable_service_port_fallback,
bool wait_for_dds_to_advertise_service,
bool serve_devtools,
bool serve_observatory) {
Dart_Isolate isolate = Dart_CurrentIsolate();
ASSERT(isolate != nullptr);
@ -161,8 +163,6 @@ bool VmService::Setup(const char* server_ip,
SHUTDOWN_ON_ERROR(library);
// Set HTTP server state.
result = DartUtils::SetStringField(library, "_ip", server_ip);
SHUTDOWN_ON_ERROR(result);
// If we have a port specified, start the server immediately.
bool auto_start = server_port >= 0;
if (server_port < 0) {
@ -170,8 +170,22 @@ bool VmService::Setup(const char* server_ip,
// port when the HTTP server is started.
server_port = 0;
}
result = DartUtils::SetIntegerField(library, "_port", server_port);
SHUTDOWN_ON_ERROR(result);
if (wait_for_dds_to_advertise_service) {
result = DartUtils::SetStringField(library, "_ddsIP", server_ip);
SHUTDOWN_ON_ERROR(result);
result = DartUtils::SetIntegerField(library, "_ddsPort", server_port);
SHUTDOWN_ON_ERROR(result);
result =
DartUtils::SetStringField(library, "_ip", DEFAULT_VM_SERVICE_SERVER_IP);
SHUTDOWN_ON_ERROR(result);
result = DartUtils::SetIntegerField(library, "_port", 0);
SHUTDOWN_ON_ERROR(result);
} else {
result = DartUtils::SetStringField(library, "_ip", server_ip);
SHUTDOWN_ON_ERROR(result);
result = DartUtils::SetIntegerField(library, "_port", server_port);
SHUTDOWN_ON_ERROR(result);
}
result = Dart_SetField(library, DartUtils::NewString("_autoStart"),
Dart_NewBoolean(auto_start));
SHUTDOWN_ON_ERROR(result);
@ -199,6 +213,10 @@ bool VmService::Setup(const char* server_ip,
Dart_NewBoolean(wait_for_dds_to_advertise_service));
SHUTDOWN_ON_ERROR(result);
result = Dart_SetField(library, DartUtils::NewString("_serveDevtools"),
serve_devtools ? Dart_True() : Dart_False());
SHUTDOWN_ON_ERROR(result);
result = Dart_SetField(library, DartUtils::NewString("_serveObservatory"),
serve_observatory ? Dart_True() : Dart_False());
SHUTDOWN_ON_ERROR(result);

View file

@ -24,6 +24,7 @@ class VmService {
bool deterministic,
bool enable_service_port_fallback,
bool wait_for_dds_to_advertise_service,
bool serve_devtools,
bool serve_observatory) {
return false;
}
@ -49,6 +50,7 @@ class VmService {
bool deterministic,
bool enable_service_port_fallback,
bool wait_for_dds_to_advertise_service,
bool serve_devtools,
bool serve_observatory);
static void SetNativeResolver();

View file

@ -11,6 +11,13 @@ import 'dart:_vmservice';
part 'vmservice_server.dart';
// The TCP ip/port that dds listens on.
@pragma('vm:entry-point', !const bool.fromEnvironment('dart.vm.product'))
int _ddsPort = 0;
@pragma('vm:entry-point', !const bool.fromEnvironment('dart.vm.product'))
String _ddsIP = '';
// The TCP ip/port that the HTTP server listens on.
@pragma('vm:entry-point', !const bool.fromEnvironment('dart.vm.product'))
int _port = 0;
@ -46,6 +53,9 @@ Stream<ProcessSignal> Function(ProcessSignal signal)? _signalWatch;
@pragma('vm:entry-point', !const bool.fromEnvironment('dart.vm.product'))
StreamSubscription<ProcessSignal>? _signalSubscription;
@pragma('vm:entry-point', !const bool.fromEnvironment('dart.vm.product'))
bool _serveDevtools = true;
@pragma('vm:entry-point', !const bool.fromEnvironment('dart.vm.product'))
bool _enableServicePortFallback = false;
@ -155,10 +165,8 @@ class _DebuggingSession {
completer.complete();
} else {
final error = result['error'] ?? event;
final stacktrace = result['stacktrace'] ?? '';
stderrSub.cancel();
completer.completeError(
'Could not start Observatory HTTP server:\n$error\n$stacktrace\n');
completer.completeError('Could not start the VM service:\n$error\n');
}
});
try {
@ -330,6 +338,7 @@ Future<Uri?> webServerControlCallback(bool enable, bool? silenceOutput) async {
if (_server.running != enable) {
if (enable) {
await _server.startup();
// TODO: if dds is enabled a dds instance needs to be started.
} else {
await _server.shutdown(true);
}
@ -342,7 +351,7 @@ void webServerAcceptNewWebSocketConnections(bool enable) {
_server.acceptNewWebSocketConnections = enable;
}
_onSignal(ProcessSignal signal) {
_onSignal(ProcessSignal signal) async {
if (serverFuture != null) {
// Still waiting.
return;
@ -357,13 +366,15 @@ _onSignal(ProcessSignal signal) {
});
} else {
_server.startup().then((_) {
ddsInstance = _DebuggingSession()
..start(
_server._ip,
_server._port.toString(),
false,
true,
);
if (_waitForDdsToAdvertiseService) {
ddsInstance = _DebuggingSession()
..start(
_ddsIP,
_ddsPort.toString(),
_authCodesDisabled,
_serveDevtools,
);
}
});
}
}
@ -412,7 +423,17 @@ main() {
VMService();
if (_autoStart) {
final _server = _lazyServerBoot();
_server.startup();
_server.startup().then((_) {
if (_waitForDdsToAdvertiseService) {
ddsInstance = _DebuggingSession()
..start(
_ddsIP,
_ddsPort.toString(),
_authCodesDisabled,
_serveDevtools,
);
}
});
// It's just here to push an event on the event loop so that we invoke the
// scheduled microtasks.
Timer.run(() {});