@@ -10,6 +10,7 @@ import 'dart:isolate';
1010
1111import 'package:logging/logging.dart' ;
1212import 'package:path/path.dart' as path;
13+ import 'package:process/process.dart' ;
1314import 'package:stack_trace/stack_trace.dart' ;
1415
1516import 'devices.dart' ;
@@ -41,35 +42,43 @@ bool _isTaskRegistered = false;
4142///
4243/// It is OK for a [task] to perform many things. However, only one task can be
4344/// registered per Dart VM.
44- Future <TaskResult > task (TaskFunction task) async {
45+ ///
46+ /// If no `processManager` is provided, a default [LocalProcessManager] is created
47+ /// for the task.
48+ Future <TaskResult > task (TaskFunction task, { ProcessManager ? processManager }) async {
4549 if (_isTaskRegistered)
4650 throw StateError ('A task is already registered' );
47-
4851 _isTaskRegistered = true ;
4952
53+ processManager ?? = const LocalProcessManager ();
54+
5055 // TODO(ianh): allow overriding logging.
5156 Logger .root.level = Level .ALL ;
5257 Logger .root.onRecord.listen ((LogRecord rec) {
5358 print ('${rec .level .name }: ${rec .time }: ${rec .message }' );
5459 });
5560
56- final _TaskRunner runner = _TaskRunner (task);
61+ final _TaskRunner runner = _TaskRunner (task, processManager );
5762 runner.keepVmAliveUntilTaskRunRequested ();
5863 return runner.whenDone;
5964}
6065
6166class _TaskRunner {
62- _TaskRunner (this .task) {
67+ _TaskRunner (this .task, this .processManager ) {
6368 registerExtension ('ext.cocoonRunTask' ,
6469 (String method, Map <String , String > parameters) async {
6570 final Duration ? taskTimeout = parameters.containsKey ('timeoutInMinutes' )
6671 ? Duration (minutes: int .parse (parameters['timeoutInMinutes' ]! ))
6772 : null ;
68- // This is only expected to be passed in unit test runs so they do not
69- // kill the Dart process that is running them and waste time running config.
70- final bool runFlutterConfig = parameters['runFlutterConfig' ] != 'false' ;
73+ final bool runFlutterConfig = parameters['runFlutterConfig' ] != 'false' ; // used by tests to avoid changing the configuration
7174 final bool runProcessCleanup = parameters['runProcessCleanup' ] != 'false' ;
72- final TaskResult result = await run (taskTimeout, runProcessCleanup: runProcessCleanup, runFlutterConfig: runFlutterConfig);
75+ final String ? localEngine = parameters['localEngine' ];
76+ final TaskResult result = await run (
77+ taskTimeout,
78+ runProcessCleanup: runProcessCleanup,
79+ runFlutterConfig: runFlutterConfig,
80+ localEngine: localEngine,
81+ );
7382 return ServiceExtensionResponse .result (json.encode (result.toJson ()));
7483 });
7584 registerExtension ('ext.cocoonRunnerReady' ,
@@ -79,6 +88,7 @@ class _TaskRunner {
7988 }
8089
8190 final TaskFunction task;
91+ final ProcessManager processManager;
8292
8393 Future <Device ?> _getWorkingDeviceIfAvailable () async {
8494 try {
@@ -103,6 +113,7 @@ class _TaskRunner {
103113 Future <TaskResult > run (Duration ? taskTimeout, {
104114 bool runFlutterConfig = true ,
105115 bool runProcessCleanup = true ,
116+ required String ? localEngine,
106117 }) async {
107118 try {
108119 _taskStarted = true ;
@@ -113,34 +124,31 @@ class _TaskRunner {
113124 section ('Checking running Dart$exe processes' );
114125 beforeRunningDartInstances = await getRunningProcesses (
115126 processName: 'dart$exe ' ,
116- ).toSet ();
117- final Set <RunningProcessInfo > allProcesses = await getRunningProcesses ().toSet ();
127+ processManager: processManager,
128+ );
129+ final Set <RunningProcessInfo > allProcesses = await getRunningProcesses (processManager: processManager);
118130 beforeRunningDartInstances.forEach (print);
119131 for (final RunningProcessInfo info in allProcesses) {
120132 if (info.commandLine.contains ('iproxy' )) {
121133 print ('[LEAK]: ${info .commandLine } ${info .creationDate } ${info .pid } ' );
122134 }
123135 }
124- } else {
125- section ('Skipping check running Dart$exe processes' );
126136 }
127137
128138 if (runFlutterConfig) {
129- print ('enabling configs for macOS, Linux, Windows, and Web...' );
139+ print ('Enabling configs for macOS, Linux, Windows, and Web...' );
130140 final int configResult = await exec (path.join (flutterDirectory.path, 'bin' , 'flutter' ), < String > [
131141 'config' ,
132142 '-v' ,
133143 '--enable-macos-desktop' ,
134144 '--enable-windows-desktop' ,
135145 '--enable-linux-desktop' ,
136146 '--enable-web' ,
137- if (localEngine != null ) ...< String > ['--local-engine' , localEngine! ],
147+ if (localEngine != null ) ...< String > ['--local-engine' , localEngine],
138148 ], canFail: true );
139149 if (configResult != 0 ) {
140150 print ('Failed to enable configuration, tasks may not run.' );
141151 }
142- } else {
143- print ('Skipping enabling configs for macOS, Linux, Windows, and Web' );
144152 }
145153
146154 final Device ? device = await _getWorkingDeviceIfAvailable ();
@@ -169,26 +177,24 @@ class _TaskRunner {
169177 }
170178
171179 if (runProcessCleanup) {
172- section ('Checking running Dart$exe processes after task...' );
173- final List <RunningProcessInfo > afterRunningDartInstances = await getRunningProcesses (
180+ section ('Terminating lingering Dart$exe processes after task...' );
181+ final Set <RunningProcessInfo > afterRunningDartInstances = await getRunningProcesses (
174182 processName: 'dart$exe ' ,
175- ).toList ();
183+ processManager: processManager,
184+ );
176185 for (final RunningProcessInfo info in afterRunningDartInstances) {
177186 if (! beforeRunningDartInstances.contains (info)) {
178187 print ('$info was leaked by this test.' );
179188 if (result is TaskResultCheckProcesses ) {
180189 result = TaskResult .failure ('This test leaked dart processes' );
181190 }
182- final bool killed = await killProcess (info.pid);
183- if (! killed) {
184- print ('Failed to kill process ${info .pid }.' );
185- } else {
191+ if (await info.terminate (processManager: processManager)) {
186192 print ('Killed process id ${info .pid }.' );
193+ } else {
194+ print ('Failed to kill process ${info .pid }.' );
187195 }
188196 }
189197 }
190- } else {
191- print ('Skipping check running Dart$exe processes after task' );
192198 }
193199 _completer.complete (result);
194200 return result;
0 commit comments