diff --git a/agent/lib/src/runner.dart b/agent/lib/src/runner.dart index 6a64c7af41..533b7c7328 100644 --- a/agent/lib/src/runner.dart +++ b/agent/lib/src/runner.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:meta/meta.dart'; import 'package:vm_service_client/vm_service_client.dart'; import 'agent.dart'; @@ -128,12 +129,62 @@ Future runTask(Agent agent, CocoonTask task) async { await stdoutSub.cancel(); await stderrSub.cancel(); await sendLog('Task execution finished', flush: true); + // Force-quit the task runner process. if (!runnerFinished) runner.kill(ProcessSignal.SIGKILL); + // Force-quit processes launched by Flutter. + await _forceQuitFlutterProcesses(); + // Force-quit dangling local processes (such as adb commands). await forceQuitRunningProcesses(); } } +class ProcessListResult { + ProcessListResult({@required this.processId, @required this.currentWorkingDirectory}); + + /// The "PID" field reported by `ps`. + final int processId; + + /// The "cwd" field reported by `lsof`. + final String currentWorkingDirectory; +} + +Future _forceQuitFlutterProcesses() async { + List processes = await _listFlutterProcesses(); + for (ProcessListResult process in processes) { + Process.killPid(process.processId, ProcessSignal.SIGKILL); + } +} + +Future> _listFlutterProcesses() async { + List processes = await _listProcesses(); + return processes + .where((ProcessListResult result) => result.currentWorkingDirectory.contains(config.flutterDirectory.absolute.path)) + .toList(); +} + +final _emptySpace = new RegExp(r'\s+'); + +Future> _listProcesses() async { + var results = []; + String ps = await eval('ps', ['-ef', '-u', Platform.environment['USER']]); + for (String psLine in ps.split('\n').skip(1)) { + int processId = int.parse(psLine.trim().split(_emptySpace)[1].trim()); + String lsof = await eval('lsof', ['-p', '$processId'], canFail: true); + Iterable cwdGrep = grep('cwd', from: lsof); + if (cwdGrep.isEmpty) { + // Not all processes report cwd; skip those, unlikely to be interesting. + continue; + } + String cwd = cwdGrep.first.split(' ').last; + results.add(new ProcessListResult( + processId: processId, + currentWorkingDirectory: cwd, + )); + } + return results; +} + Future _connectToRunnerIsolate(int vmServicePort) async { String url = 'ws://localhost:$vmServicePort/ws'; DateTime started = new DateTime.now();