Skip to content

Commit

Permalink
[flutter_tools] Add support for vmServiceFileInfo when attaching (#12…
Browse files Browse the repository at this point in the history
…8503)

When building the new SDK DAPs, this functionality was missed from the Flutter adapter (but added to the Dart CLI adapter).

As well as passing a VM Service URI directly, we support passing a file that can be polled for it.

This uses the same mechanism we use to obtain the VM Service URI from a Dart debug session (we run `dart --write-service-info=foo.json my_file.dart` and then poll that file which the VM will write) and is useful for users that have their own mechanism for launching an app (for example using custom Flutter embedders - see Dart-Code/Dart-Code#3353) to provide a VM Service URI once the app is up and running.

Fixes Dart-Code/Dart-Code#4577.
  • Loading branch information
DanTup committed Jun 16, 2023
1 parent 7214cb2 commit dc4541f
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 4 deletions.
5 changes: 4 additions & 1 deletion packages/flutter_tools/lib/src/debug_adapters/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ Arguments specific to `launchRequest` are:

Arguments specific to `attachRequest` are:

- `String? vmServiceUri` - the VM Service URI to attach to (if not supplied, Flutter will try to discover it from the device)
- `String? vmServiceInfoFile` - the file to read the VM Service info from \*
- `String? vmServiceUri` - the VM Service URI to attach to \*

\* Only one of `vmServiceInfoFile` or `vmServiceUri` may be supplied. If neither are supplied, Flutter will try to discover it from the device.

## Custom Requests

Expand Down
19 changes: 17 additions & 2 deletions packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import 'package:vm_service/vm_service.dart' as vm;
import '../base/io.dart';
import '../cache.dart';
import '../convert.dart';
import '../globals.dart' as globals show fs;
import 'flutter_adapter_args.dart';
import 'flutter_base_adapter.dart';

/// A DAP Debug Adapter for running and debugging Flutter applications.
class FlutterDebugAdapter extends FlutterBaseDebugAdapter {
class FlutterDebugAdapter extends FlutterBaseDebugAdapter with VmServiceInfoFileUtils {
FlutterDebugAdapter(
super.channel, {
required super.fileSystem,
Expand Down Expand Up @@ -120,14 +121,28 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter {
@override
Future<void> attachImpl() async {
final FlutterAttachRequestArguments args = this.args as FlutterAttachRequestArguments;
String? vmServiceUri = args.vmServiceUri;
final String? vmServiceInfoFile = args.vmServiceInfoFile;

if (vmServiceUri != null && vmServiceInfoFile != null) {
sendConsoleOutput(
'To attach, provide only one (or neither) of vmServiceUri/vmServiceInfoFile',
);
handleSessionTerminate();
return;
}

launchProgress = startProgressNotification(
'launch',
'Flutter',
message: 'Attaching…',
);

final String? vmServiceUri = args.vmServiceUri;
if (vmServiceUri == null && vmServiceInfoFile != null) {
final Uri uriFromFile = await waitForVmServiceInfoFile(logger, globals.fs.file(vmServiceInfoFile));
vmServiceUri = uriFromFile.toString();
}

final List<String> toolArgs = <String>[
'attach',
'--machine',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class FlutterAttachRequestArguments
this.customTool,
this.customToolReplacesArgs,
this.vmServiceUri,
this.vmServiceInfoFile,
this.program,
super.restart,
super.name,
Expand All @@ -36,6 +37,7 @@ class FlutterAttachRequestArguments
customTool = obj['customTool'] as String?,
customToolReplacesArgs = obj['customToolReplacesArgs'] as int?,
vmServiceUri = obj['vmServiceUri'] as String?,
vmServiceInfoFile = obj['vmServiceInfoFile'] as String?,
program = obj['program'] as String?,
super.fromMap();

Expand Down Expand Up @@ -64,8 +66,15 @@ class FlutterAttachRequestArguments
final int? customToolReplacesArgs;

/// The VM Service URI of the running Flutter app to connect to.
///
/// Only one of this or [vmServiceInfoFile] (or neither) can be supplied.
final String? vmServiceUri;

/// The VM Service info file to extract the VM Service URI from to attach to.
///
/// Only one of this or [vmServiceUri] (or neither) can be supplied.
final String? vmServiceInfoFile;

/// The program/Flutter app to be run.
final String? program;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/debug_adapters/flutter_adapter.dart';
import 'package:flutter_tools/src/debug_adapters/flutter_adapter_args.dart';
import 'package:flutter_tools/src/globals.dart' as globals show platform;
import 'package:flutter_tools/src/globals.dart' as globals show fs, platform;
import 'package:test/fake.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
Expand Down Expand Up @@ -299,6 +299,107 @@ void main() {
]));
});

test('runs "flutter attach" with --debug-uri if vmServiceUri is passed', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle),
platform: platform,
);
final Completer<void> responseCompleter = Completer<void>();

final FlutterAttachRequestArguments args =
FlutterAttachRequestArguments(
cwd: '/project',
program: 'program/main.dart',
vmServiceUri: 'ws://1.2.3.4/ws'
);

await adapter.configurationDoneRequest(MockRequest(), null, () {});
await adapter.attachRequest(
MockRequest(), args, responseCompleter.complete);
await responseCompleter.future;

expect(
adapter.processArgs,
containsAllInOrder(<String>[
'attach',
'--machine',
'--debug-uri',
'ws://1.2.3.4/ws',
'--target',
'program/main.dart',
]));
});

test('runs "flutter attach" with --debug-uri if vmServiceInfoFile exists', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle),
platform: platform,
);
final Completer<void> responseCompleter = Completer<void>();
final File serviceInfoFile = globals.fs.systemTempDirectory.createTempSync('dap_flutter_attach_vmServiceInfoFile').childFile('vmServiceInfo.json');

final FlutterAttachRequestArguments args =
FlutterAttachRequestArguments(
cwd: '/project',
program: 'program/main.dart',
vmServiceInfoFile: serviceInfoFile.path,
);

// Write the service info file before trying to attach:
serviceInfoFile.writeAsStringSync('{ "uri": "ws://1.2.3.4/ws" }');

await adapter.configurationDoneRequest(MockRequest(), null, () {});
await adapter.attachRequest(MockRequest(), args, responseCompleter.complete);
await responseCompleter.future;

expect(
adapter.processArgs,
containsAllInOrder(<String>[
'attach',
'--machine',
'--debug-uri',
'ws://1.2.3.4/ws',
'--target',
'program/main.dart',
]));
});

test('runs "flutter attach" with --debug-uri if vmServiceInfoFile is created later', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle),
platform: platform,
);
final Completer<void> responseCompleter = Completer<void>();
final File serviceInfoFile = globals.fs.systemTempDirectory.createTempSync('dap_flutter_attach_vmServiceInfoFile').childFile('vmServiceInfo.json');

final FlutterAttachRequestArguments args =
FlutterAttachRequestArguments(
cwd: '/project',
program: 'program/main.dart',
vmServiceInfoFile: serviceInfoFile.path,
);


await adapter.configurationDoneRequest(MockRequest(), null, () {});
final Future<void> attachResponseFuture = adapter.attachRequest(MockRequest(), args, responseCompleter.complete);
// Write the service info file a little later to ensure we detect it:
await pumpEventQueue(times:5000);
serviceInfoFile.writeAsStringSync('{ "uri": "ws://1.2.3.4/ws" }');
await attachResponseFuture;
await responseCompleter.future;

expect(
adapter.processArgs,
containsAllInOrder(<String>[
'attach',
'--machine',
'--debug-uri',
'ws://1.2.3.4/ws',
'--target',
'program/main.dart',
]));
});

test('does not record the VMs PID for terminating', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle),
Expand Down

0 comments on commit dc4541f

Please sign in to comment.