@@ -25,9 +25,6 @@ class AppDomain extends Domain {
25
25
26
26
final _appStates = < String , _AppState > {};
27
27
28
- // Prevents duplicate stdout listeners for the same appId
29
- final _activeListeners = < String > {};
30
-
31
28
// Mapping from service name to service method.
32
29
final Map <String , String > _registeredMethodsForService = < String , String > {};
33
30
@@ -66,30 +63,30 @@ class AppDomain extends Domain {
66
63
67
64
Future <void > _handleAppConnections (WebDevServer server) async {
68
65
final dwds = server.dwds! ;
66
+
69
67
// The connection is established right before `main()` is called.
70
68
await for (final appConnection in dwds.connectedApps) {
69
+ final appId = appConnection.request.appId;
70
+
71
+ // Check if we already have an active app state for this appId
72
+ if (_appStates.containsKey (appId)) {
73
+ // Reuse existing connection, just run main again
74
+ appConnection.runMain ();
75
+ continue ;
76
+ }
77
+
71
78
final debugConnection = await dwds.debugConnection (appConnection);
72
79
final debugUri = debugConnection.ddsUri ?? debugConnection.uri;
73
80
final vmService = await vmServiceConnectUri (debugUri);
74
- final appId = appConnection.request.appId;
75
- unawaited (debugConnection.onDone.then ((_) {
76
- sendEvent ('app.log' , {
77
- 'appId' : appId,
78
- 'log' : 'Lost connection to device.' ,
79
- });
80
- sendEvent ('app.stop' , {
81
- 'appId' : appId,
82
- });
83
- daemon.shutdown ();
84
- }));
81
+
85
82
sendEvent ('app.start' , {
86
83
'appId' : appId,
87
84
'directory' : Directory .current.path,
88
85
'deviceId' : 'chrome' ,
89
86
'launchMode' : 'run'
90
87
});
91
88
92
- // Set up VM service listeners (only once per appId to prevent duplicates)
89
+ // Set up VM service listeners for this appId
93
90
// ignore: cancel_subscriptions
94
91
final stdOutSub = await _setupVmServiceListeners (appId, vmService);
95
92
@@ -110,7 +107,18 @@ class AppDomain extends Domain {
110
107
111
108
appConnection.runMain ();
112
109
113
- unawaited (debugConnection.onDone.whenComplete (() {
110
+ // Handle connection termination - send events first, then cleanup
111
+ unawaited (debugConnection.onDone.then ((_) {
112
+ sendEvent ('app.log' , {
113
+ 'appId' : appId,
114
+ 'log' : 'Lost connection to device.' ,
115
+ });
116
+ sendEvent ('app.stop' , {
117
+ 'appId' : appId,
118
+ });
119
+ daemon.shutdown ();
120
+
121
+ // Clean up app resources
114
122
_cleanupAppConnection (appId, appState);
115
123
}));
116
124
}
@@ -212,27 +220,19 @@ class AppDomain extends Domain {
212
220
return true ;
213
221
}
214
222
215
- /// Sets up VM service listeners for the given appId if not already active .
216
- /// Returns the stdout subscription if created, null otherwise .
217
- Future <StreamSubscription <Event >? > _setupVmServiceListeners (
223
+ /// Sets up VM service listeners for the given appId.
224
+ /// Returns the stdout subscription.
225
+ Future <StreamSubscription <Event >> _setupVmServiceListeners (
218
226
String appId, VmService vmService) async {
219
- if (_activeListeners.contains (appId)) {
220
- return null ; // Already listening for this appId
221
- }
222
-
223
- _activeListeners.add (appId);
224
-
225
- // TODO(grouma) - limit the catch to the appropriate error.
226
227
try {
227
- await vmService.streamCancel ('Stdout' );
228
+ vmService.onServiceEvent.listen (_onServiceEvent);
229
+ await vmService.streamListen ('Service' );
228
230
} catch (_) {}
231
+
232
+ // Set up stdout listener
229
233
try {
230
234
await vmService.streamListen ('Stdout' );
231
235
} catch (_) {}
232
- try {
233
- vmService.onServiceEvent.listen (_onServiceEvent);
234
- await vmService.streamListen ('Service' );
235
- } catch (_) {}
236
236
237
237
// ignore: cancel_subscriptions
238
238
return vmService.onStdoutEvent.listen ((log) {
@@ -247,7 +247,6 @@ class AppDomain extends Domain {
247
247
void _cleanupAppConnection (String appId, _AppState appState) {
248
248
appState.dispose ();
249
249
_appStates.remove (appId);
250
- _activeListeners.remove (appId);
251
250
}
252
251
253
252
@override
@@ -257,14 +256,13 @@ class AppDomain extends Domain {
257
256
state.dispose ();
258
257
}
259
258
_appStates.clear ();
260
- _activeListeners.clear ();
261
259
}
262
260
}
263
261
264
262
class _AppState {
265
263
final DebugConnection _debugConnection;
266
264
final StreamSubscription <BuildResult > _resultSub;
267
- final StreamSubscription <Event >? _stdOutSub;
265
+ final StreamSubscription <Event > _stdOutSub;
268
266
269
267
bool _isDisposed = false ;
270
268
@@ -275,7 +273,7 @@ class _AppState {
275
273
void dispose () {
276
274
if (_isDisposed) return ;
277
275
_isDisposed = true ;
278
- _stdOutSub? .cancel ();
276
+ _stdOutSub.cancel ();
279
277
_resultSub.cancel ();
280
278
_debugConnection.close ();
281
279
}
0 commit comments