Add ability to plumb an appName through DDS to DTD.

- Adds a parameter to DartDevelopmentServiceLauncher.start, as well as DartDevelopmentService.startDevelopmentService
- Adds an `--app-name` command line argument to the DDS cli.
- Passes this app name through when registering VmService URIs on DTD.

Bug: https://github.com/flutter/flutter/issues/184251
Change-Id: Ica4487214a69a165fe891d4b8de12d72b052783c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/491360
Auto-Submit: Jake Macdonald <jakemac@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
Reviewed-by: Ben Konyi <bkonyi@google.com>
This commit is contained in:
Jake Macdonald
2026-03-31 13:38:49 -07:00
committed by Commit Queue
parent 1cea4f514e
commit db42b359c3
11 changed files with 79 additions and 21 deletions
+5
View File
@@ -1,3 +1,8 @@
# 5.3.0
- Add `--app-name` option to `dart development-service`. This is a short, user
focused name to describe the application being debugged.
# 5.2.0
- [DAP] `Stopped(reason: 'entry')` events will no longer be lost if an isolate has not yet reached the `PauseStart` state when connecting to the VM.
+10
View File
@@ -44,8 +44,13 @@ abstract class DartDevelopmentService {
///
/// If [enablesServicePortFallback] is enabled, DDS will attempt to bind to any
/// available port if the specified port is unavailable.
///
/// [appName] is a short description of the application that is being served
/// by the vm service, and will be sent as the `name` when registering the vm
/// service with the Dart Tooling Daemon.
static Future<DartDevelopmentService> startDartDevelopmentService(
Uri remoteVmServiceUri, {
String? appName,
Uri? serviceUri,
bool enableAuthCodes = true,
bool ipv6 = false,
@@ -98,6 +103,7 @@ abstract class DartDevelopmentService {
logRequests,
enableServicePortFallback,
uriConverter,
appName,
);
await service.startService();
return service;
@@ -115,6 +121,10 @@ abstract class DartDevelopmentService {
/// Throws a [StateError] if DevTools is already being served by DDS.
void setExternalDevToolsUri(Uri uri);
/// The name of the application that is being served by the vm service if
/// provided.
String? get appName;
/// Set to `true` if this instance of [DartDevelopmentService] requires an
/// authentication code to connect.
bool get authCodesEnabled;
+18 -5
View File
@@ -45,9 +45,13 @@ import 'src/dds_impl.dart';
/// If provided, [dartExecutable] is the path to the 'dart' executable that
/// should be used to spawn the DDS instance. By default, `Platform.executable`
/// is used.
///
/// If provided, [appName] is a short user focused description of the
/// application, used to help identify it.
class DartDevelopmentServiceLauncher {
static Future<DartDevelopmentServiceLauncher> start({
required Uri remoteVmServiceUri,
String? appName,
Uri? serviceUri,
bool enableAuthCodes = true,
bool serveDevTools = false,
@@ -72,6 +76,8 @@ class DartDevelopmentServiceLauncher {
'--${DartDevelopmentServiceOptions.enableServicePortFallbackFlag}',
if (google3WorkspaceRoot != null)
'--${DartDevelopmentServiceOptions.google3WorkspaceRootOption}=$google3WorkspaceRoot',
if (appName != null)
'--${DartDevelopmentServiceOptions.appNameOption}=$appName',
];
late String executable;
if (dartExecutable == null) {
@@ -80,7 +86,8 @@ class DartDevelopmentServiceLauncher {
// then invoke it directly as it would avoid the additional hop
// of going through the dart CLI process to invoke dds.
executable = Platform.executable;
var sdkPath = path.absolute(path.dirname(path.dirname(executable)), 'bin');
var sdkPath =
path.absolute(path.dirname(path.dirname(executable)), 'bin');
var snapshotsDir = path.join(sdkPath, 'snapshots');
final type = FileSystemEntity.typeSync(snapshotsDir);
if (type != FileSystemEntityType.directory &&
@@ -91,12 +98,12 @@ class DartDevelopmentServiceLauncher {
sdkPath = path.absolute(path.dirname(executable));
snapshotsDir = sdkPath;
}
final dartAotRuntime = path.absolute(
sdkPath, Platform.isWindows ? 'dartaotruntime.exe' : 'dartaotruntime');
final dartAotRuntime = path.absolute(sdkPath,
Platform.isWindows ? 'dartaotruntime.exe' : 'dartaotruntime');
final ddsAotSnapshot =
path.absolute(snapshotsDir, 'dds_aot.dart.snapshot');
if (File(dartAotRuntime).existsSync()
&& File(ddsAotSnapshot).existsSync()) {
if (File(dartAotRuntime).existsSync() &&
File(ddsAotSnapshot).existsSync()) {
executable = dartAotRuntime;
args = [ddsAotSnapshot, ...args];
} else {
@@ -132,6 +139,7 @@ class DartDevelopmentServiceLauncher {
uri: ddsUri,
devToolsUri: devToolsUri,
dtdUri: dtdUri,
appName: appName,
),
);
} else if (result
@@ -159,10 +167,15 @@ class DartDevelopmentServiceLauncher {
required this.uri,
required this.devToolsUri,
required this.dtdUri,
required this.appName,
}) : _ddsInstance = process;
final Process _ddsInstance;
/// A short, user focused description of the application that DDS will
/// connect to.
final String? appName;
/// The [Uri] VM service clients can use to communicate with this
/// DDS instance via HTTP.
final Uri uri;
+6
View File
@@ -17,6 +17,7 @@ abstract class DartDevelopmentServiceOptions {
static const cachedUserTagsOption = 'cached-user-tags';
static const devToolsServerAddressOption = 'devtools-server-address';
static const google3WorkspaceRootOption = 'google3-workspace-root';
static const appNameOption = 'app-name';
static ArgParser createArgParser({
int? usageLineLength,
@@ -84,6 +85,11 @@ abstract class DartDevelopmentServiceOptions {
help: 'Sets the Google3 workspace root used for google3:// URI '
'resolution.',
hide: !verbose,
)
..addOption(
appNameOption,
help: 'A short, user focused description of the application that DDS '
'will connect to.',
);
if (includeHelp) {
argParser.addFlag('help', negatable: false);
+2
View File
@@ -141,6 +141,7 @@ ${argParser.usage}
: null,
enableServicePortFallback: enableServicePortFallback,
uriConverter: uriConverter,
appName: argResults[DartDevelopmentServiceOptions.appNameOption],
);
final dtdInfo = dds.hostedDartToolingDaemon;
stderr.write(json.encode({
@@ -153,6 +154,7 @@ ${argParser.usage}
// is no mechanism for exposing URIs.
'uri': dtdInfo.localUri.toString(),
},
'name': dds.appName,
}));
} catch (e, st) {
writeErrorResponse(e, st);
+5
View File
@@ -65,6 +65,7 @@ class DartDevelopmentServiceImpl implements DartDevelopmentService {
this.shouldLogRequests,
this._enableServicePortFallback,
this.uriConverter,
this.appName,
) {
_clientManager = ClientManager(this);
_expressionEvaluator = ExpressionEvaluator(this);
@@ -281,6 +282,7 @@ class DartDevelopmentServiceImpl implements DartDevelopmentService {
await dtdClient.registerVmService(
uri: wsUri!.toString(),
secret: hostedDtd.secret!,
name: appName,
);
// Immediately close this client after registering the VM service. The
// VM service will be automatically unregistered from DTD when the VM
@@ -562,6 +564,9 @@ class DartDevelopmentServiceImpl implements DartDevelopmentService {
bool _initializationComplete = false;
bool _shuttingDown = false;
@override
final String? appName;
UriConverter? uriConverter;
PackageUriConverter get packageUriConverter => _packageUriConverter;
late PackageUriConverter _packageUriConverter;
+7 -13
View File
@@ -69,21 +69,15 @@ Future<DtdInfo?> startDtd({
required bool printDtdUri,
}) async {
final snapshotDir = getDTDSnapshotDir();
final dtdAotSnapshot = path.absolute(
final dtdAotSnapshot = path.absolute(
snapshotDir,
'dart_tooling_daemon_aot.dart.snapshot',
);
final completer = Completer<DtdInfo?>();
void completeForError() => completer.complete(null);
void completeForError([_]) => completer.complete(null);
final exitPort = ReceivePort()
..listen((_) {
completeForError();
});
final errorPort = ReceivePort()
..listen((_) {
completeForError();
});
final exitPort = ReceivePort()..listen(completeForError);
final errorPort = ReceivePort()..listen(completeForError);
final receivePort = ReceivePort()
..listen((message) {
try {
@@ -122,10 +116,10 @@ Future<DtdInfo?> startDtd({
onExit: exitPort.sendPort,
onError: errorPort.sendPort,
);
} catch (_, __) {
} catch (_) {
// Spawning an isolate using the AOT snapshot of the tooling daemon failed,
// try again using the JIT snapshot of the tooling daemon.
final dtdSnapshot = path.absolute(
final dtdSnapshot = path.absolute(
snapshotDir,
'dart_tooling_daemon.dart.snapshot',
);
@@ -137,7 +131,7 @@ Future<DtdInfo?> startDtd({
onExit: exitPort.sendPort,
onError: errorPort.sendPort,
);
} catch (_, __) {
} catch (_) {
completeForError();
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
name: dds
version: 5.2.0
version: 5.3.0
description: >-
A library used to spawn the Dart Developer Service, used to communicate with
a Dart VM Service instance.
+3
View File
@@ -270,6 +270,9 @@ class MockDartDevelopmentServiceLauncher
implements DartDevelopmentServiceLauncher {
MockDartDevelopmentServiceLauncher();
@override
String? get appName => throw UnimplementedError();
@override
Uri? get devToolsUri => throw UnimplementedError();
+17 -1
View File
@@ -6,6 +6,7 @@ import 'dart:convert';
import 'dart:io';
import 'package:dds/dds_launcher.dart';
import 'package:dtd/dtd.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service_io.dart';
@@ -67,7 +68,7 @@ void main() {
}
test(
'External DevTools address is reported correctly',
'External DevTools address and appName are reported correctly',
() async {
final fakeDevToolsUri =
Uri.parse('http://localhost:12345/my_devtools/');
@@ -75,10 +76,25 @@ void main() {
remoteVmServiceUri: remoteVmServiceUri,
serveDevTools: true,
devToolsServerAddress: fakeDevToolsUri,
appName: 'my-app',
);
expect(dds.devToolsUri,
fakeDevToolsUri.replace(query: 'uri=${dds.wsUri.toString()}'));
expect(dds.appName, 'my-app');
final dtdUri = dds.dtdUri;
expect(dtdUri, isNotNull);
final dtdClient = await DartToolingDaemon.connect(dtdUri!);
try {
final response = await dtdClient.getVmServices();
final vmServiceInfo = response.vmServicesInfos
.firstWhere((info) => info.name == 'my-app');
expect(vmServiceInfo.uri, dds.wsUri.toString());
} finally {
await dtdClient.close();
}
},
);
+5 -1
View File
@@ -10,6 +10,7 @@ group("dds_aot") {
public_deps = [
":dds_aot_product_snapshot",
":dds_aot_snapshot",
"../dtd:dtd_aot_snapshot",
]
}
@@ -32,7 +33,10 @@ aot_snapshot("dds_aot_product_snapshot") {
}
group("dds") {
public_deps = [ ":copy_dds_snapshot" ]
public_deps = [
":copy_dds_snapshot",
"../dtd",
]
}
copy("copy_dds_snapshot") {