From 1a6a20cdc67d903bcc0f9626c82987d5766cd49e Mon Sep 17 00:00:00 2001 From: Danny Tuppeny Date: Wed, 5 Apr 2023 06:39:09 +0100 Subject: [PATCH] [flutter_tools] Include mode in app.start event, and forward app.start to DAP clients (#121239) [flutter_tools] Include mode in app.start event, and forward app.start to DAP clients --- packages/flutter_tools/doc/daemon.md | 2 +- .../lib/src/commands/daemon.dart | 1 + .../src/debug_adapters/flutter_adapter.dart | 10 ++++++++ .../test/general.shard/dap/mocks.dart | 8 ++++--- .../debug_adapter/flutter_adapter_test.dart | 24 +++++++++++++++++++ .../integration.shard/flutter_run_test.dart | 6 +++++ .../test/integration.shard/test_driver.dart | 14 +++++++++-- 7 files changed, 59 insertions(+), 6 deletions(-) diff --git a/packages/flutter_tools/doc/daemon.md b/packages/flutter_tools/doc/daemon.md index b1e2f5f2ce4..73a85c29a97 100644 --- a/packages/flutter_tools/doc/daemon.md +++ b/packages/flutter_tools/doc/daemon.md @@ -136,7 +136,7 @@ The `stop()` command takes one parameter, `appId`. It returns a `bool` to indica #### app.start -This is sent when an app is starting. The `params` field will be a map with the fields `appId`, `directory`, `deviceId`, and `launchMode`. +This is sent when an app is starting. The `params` field will be a map with the fields `appId`, `directory`, `deviceId`, `launchMode` (`run`/`attach`) and `mode` (`debug`, `profile`, `release`, `jit_release`). #### app.debugPort diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart index 4caaa828448..4c82d7faf42 100644 --- a/packages/flutter_tools/lib/src/commands/daemon.dart +++ b/packages/flutter_tools/lib/src/commands/daemon.dart @@ -613,6 +613,7 @@ class AppDomain extends Domain { 'directory': projectDirectory, 'supportsRestart': isRestartSupported(enableHotReload, device), 'launchMode': launchMode.toString(), + 'mode': runner.debuggingOptions.buildInfo.modeName, }); Completer? connectionInfoCompleter; diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart index f02b2f511cb..231c3f563bc 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart @@ -393,6 +393,16 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter { // session (which is much slower, but required for profile/release mode). final bool supportsRestart = (params['supportsRestart'] as bool?) ?? false; sendEvent(CapabilitiesEventBody(capabilities: Capabilities(supportsRestartRequest: supportsRestart))); + + // Send a custom event so the editor has info about the app starting. + // + // This message contains things like the `deviceId` and `mode` that the + // client might not know about if they were inferred or set by users custom + // args. + sendEvent( + RawEventBody(params), + eventType: 'flutter.appStart', + ); } /// Handles the app.started event from Flutter. diff --git a/packages/flutter_tools/test/general.shard/dap/mocks.dart b/packages/flutter_tools/test/general.shard/dap/mocks.dart index 498949235f1..515d1513896 100644 --- a/packages/flutter_tools/test/general.shard/dap/mocks.dart +++ b/packages/flutter_tools/test/general.shard/dap/mocks.dart @@ -107,16 +107,18 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter { // Simulate the app starting by triggering handling of events that Flutter // would usually write to stdout. if (simulateAppStarted) { - simulateStdoutMessage({ - 'event': 'app.started', - }); simulateStdoutMessage({ 'event': 'app.start', 'params': { 'appId': 'TEST', 'supportsRestart': supportsRestart, + 'deviceId': 'flutter-tester', + 'mode': 'debug', } }); + simulateStdoutMessage({ + 'event': 'app.started', + }); } } diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart index a09af553153..c27b7c295a9 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart @@ -452,6 +452,30 @@ void main() { await dap.client.terminate(); }); + testWithoutContext('provides appStarted events to the client', () async { + final BasicProject project = BasicProject(); + await project.setUpIn(tempDir); + + // Launch the app and wait for it to send a 'flutter.appStart' event. + final Future appStartFuture = dap.client.event('flutter.appStart'); + await Future.wait(>[ + appStartFuture, + dap.client.start( + launch: () => dap.client.launch( + cwd: project.dir.path, + toolArgs: ['-d', 'flutter-tester'], + ), + ), + ], eagerError: true); + + await dap.client.terminate(); + + final Event appStart = await appStartFuture; + final Map params = appStart.body! as Map; + expect(params['deviceId'], 'flutter-tester'); + expect(params['mode'], 'debug'); + }); + testWithoutContext('provides appStarted events to the client', () async { final BasicProject project = BasicProject(); await project.setUpIn(tempDir); diff --git a/packages/flutter_tools/test/integration.shard/flutter_run_test.dart b/packages/flutter_tools/test/integration.shard/flutter_run_test.dart index 8a58f038495..e3b94ed4c4f 100644 --- a/packages/flutter_tools/test/integration.shard/flutter_run_test.dart +++ b/packages/flutter_tools/test/integration.shard/flutter_run_test.dart @@ -68,4 +68,10 @@ void main() { matches: isNotEmpty, ); }); + + testWithoutContext('reports deviceId and mode in app.start event', () async { + await flutter.run(); + expect(flutter.currentRunningDeviceId, 'flutter-tester'); + expect(flutter.currentRunningMode, 'debug'); + }); } diff --git a/packages/flutter_tools/test/integration.shard/test_driver.dart b/packages/flutter_tools/test/integration.shard/test_driver.dart index db034d4a294..31bf7f53c3d 100644 --- a/packages/flutter_tools/test/integration.shard/test_driver.dart +++ b/packages/flutter_tools/test/integration.shard/test_driver.dart @@ -496,6 +496,11 @@ class FlutterRunTestDriver extends FlutterTestDriver { }); String? _currentRunningAppId; + String? _currentRunningDeviceId; + String? _currentRunningMode; + + String? get currentRunningDeviceId => _currentRunningDeviceId; + String? get currentRunningMode => _currentRunningMode; Future run({ bool withDebugger = false, @@ -611,6 +616,7 @@ class FlutterRunTestDriver extends FlutterTestDriver { // Set this up now, but we don't wait it yet. We want to make sure we don't // miss it while waiting for debugPort below. + final Future> start = _waitFor(event: 'app.start', timeout: appStartTimeout); final Future> started = _waitFor(event: 'app.started', timeout: appStartTimeout); if (withDebugger) { @@ -630,9 +636,13 @@ class FlutterRunTestDriver extends FlutterTestDriver { _attachPort = attachPort; } - // Now await the started event; if it had already happened the future will + // Now await the start/started events; if it had already happened the future will // have already completed. - _currentRunningAppId = ((await started)['params'] as Map?)?['appId'] as String?; + final Map? startParams = (await start)['params'] as Map?; + final Map? startedParams = (await started)['params'] as Map?; + _currentRunningAppId = startedParams?['appId'] as String?; + _currentRunningDeviceId = startParams?['deviceId'] as String?; + _currentRunningMode = startParams?['mode'] as String?; prematureExitGuard.complete(); } on Exception catch (error, stackTrace) { prematureExitGuard.completeError(Exception(error.toString()), stackTrace);