Commit 526339b6 authored by David Martos's avatar David Martos Committed by Christopher Fujino

Avoid killing Flutter tool process (#37471) (#37500)

parent 52fb11ec
...@@ -29,9 +29,15 @@ Future<bool> killProcess(String executable) async { ...@@ -29,9 +29,15 @@ Future<bool> killProcess(String executable) async {
if (values.length < 2) { if (values.length < 2) {
continue; continue;
} }
final String pid = values[1]; final String processPid = values[1];
final String currentRunningProcessPid = pid.toString();
// Don't kill the flutter tool process
if (processPid == currentRunningProcessPid) {
continue;
}
final ProcessResult killResult = await processManager.run(<String>[ final ProcessResult killResult = await processManager.run(<String>[
'kill', pid, 'kill', processPid,
]); ]);
succeeded &= killResult.exitCode == 0; succeeded &= killResult.exitCode == 0;
} }
......
...@@ -156,7 +156,7 @@ class WindowsDevices extends PollingDeviceDiscovery { ...@@ -156,7 +156,7 @@ class WindowsDevices extends PollingDeviceDiscovery {
Future<List<String>> getDiagnostics() async => const <String>[]; Future<List<String>> getDiagnostics() async => const <String>[];
} }
final RegExp _whitespace = RegExp(r'\w+'); final RegExp _whitespace = RegExp(r'\s+');
/// Returns the running process matching `process` name. /// Returns the running process matching `process` name.
/// ///
...@@ -174,8 +174,15 @@ List<String> runningProcess(String processName) { ...@@ -174,8 +174,15 @@ List<String> runningProcess(String processName) {
continue; continue;
} }
final List<String> parts = process.split(_whitespace); final List<String> parts = process.split(_whitespace);
final String processPid = parts[0];
final String currentRunningProcessPid = pid.toString();
// Don't kill the flutter tool process
if (processPid == currentRunningProcessPid) {
continue;
}
final List<String> data = <String>[ final List<String> data = <String>[
parts[0], // ID processPid, // ID
parts[1], // Name parts[1], // Name
]; ];
return data; return data;
......
...@@ -22,16 +22,21 @@ void main() { ...@@ -22,16 +22,21 @@ void main() {
final LinuxDevice device = LinuxDevice(); final LinuxDevice device = LinuxDevice();
final MockPlatform notLinux = MockPlatform(); final MockPlatform notLinux = MockPlatform();
final MockProcessManager mockProcessManager = MockProcessManager(); final MockProcessManager mockProcessManager = MockProcessManager();
const String flutterToolCommand = 'flutter --someoption somevalue';
when(notLinux.isLinux).thenReturn(false); when(notLinux.isLinux).thenReturn(false);
when(mockProcessManager.run(<String>[ when(mockProcessManager.run(<String>[
'ps', 'aux', 'ps', 'aux',
])).thenAnswer((Invocation invocation) async { ])).thenAnswer((Invocation invocation) async {
// The flutter tool process is returned as output to the ps aux command
final MockProcessResult result = MockProcessResult(); final MockProcessResult result = MockProcessResult();
when(result.exitCode).thenReturn(0); when(result.exitCode).thenReturn(0);
when<String>(result.stdout).thenReturn(''); when<String>(result.stdout).thenReturn('username $pid $flutterToolCommand');
return result; return result;
}); });
when(mockProcessManager.run(<String>[
'kill', '$pid',
])).thenThrow(Exception('Flutter tool process has been killed'));
testUsingContext('defaults', () async { testUsingContext('defaults', () async {
final PrebuiltLinuxApp linuxApp = PrebuiltLinuxApp(executable: 'foo'); final PrebuiltLinuxApp linuxApp = PrebuiltLinuxApp(executable: 'foo');
...@@ -55,6 +60,14 @@ void main() { ...@@ -55,6 +60,14 @@ void main() {
expect(portForwarder.forwardedPorts.isEmpty, true); expect(portForwarder.forwardedPorts.isEmpty, true);
}); });
testUsingContext('The current running process is not killed when stopping the app', () async {
// The name of the executable is the same as a command line argument to the flutter tool
final PrebuiltLinuxApp linuxApp = PrebuiltLinuxApp(executable: 'somevalue');
expect(await device.stopApp(linuxApp), true);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('No devices listed if platform unsupported', () async { testUsingContext('No devices listed if platform unsupported', () async {
expect(await LinuxDevices().devices, <Device>[]); expect(await LinuxDevices().devices, <Device>[]);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
......
...@@ -96,6 +96,25 @@ tester 17193 0.0 0.2 4791128 37820 ?? S 2:27PM 0:00.09 /Applica ...@@ -96,6 +96,25 @@ tester 17193 0.0 0.2 4791128 37820 ?? S 2:27PM 0:00.09 /Applica
FileSystem: () => mockFileSystem, FileSystem: () => mockFileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
}); });
testUsingContext('The current running process is not killed when stopping the app', () async {
final String psOut = '''
tester $pid 0.0 0.2 4791128 37820 ?? S 2:27PM 0:00.09 flutter run --use-application-binary /Applications/foo
''';
final MockMacOSApp mockMacOSApp = MockMacOSApp();
// The name of the executable is the same as a command line argument to the flutter tool
when(mockMacOSApp.executable(any)).thenReturn('/Applications/foo');
when(mockProcessManager.run(<String>['ps', 'aux'])).thenAnswer((Invocation invocation) async {
return ProcessResult(1, 0, psOut, '');
});
when(mockProcessManager.run(<String>[
'kill', '$pid',
])).thenThrow(Exception('Flutter tool process has been killed'));
expect(await device.stopApp(mockMacOSApp), true);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
}); });
test('noop port forwarding', () async { test('noop port forwarding', () async {
......
...@@ -22,17 +22,22 @@ void main() { ...@@ -22,17 +22,22 @@ void main() {
final WindowsDevice device = WindowsDevice(); final WindowsDevice device = WindowsDevice();
final MockPlatform notWindows = MockPlatform(); final MockPlatform notWindows = MockPlatform();
final MockProcessManager mockProcessManager = MockProcessManager(); final MockProcessManager mockProcessManager = MockProcessManager();
const String flutterToolBinary = 'flutter.exe';
when(notWindows.isWindows).thenReturn(false); when(notWindows.isWindows).thenReturn(false);
when(notWindows.environment).thenReturn(const <String, String>{}); when(notWindows.environment).thenReturn(const <String, String>{});
when(mockProcessManager.runSync(<String>[ when(mockProcessManager.runSync(<String>[
'powershell', '-script="Get-CimInstance Win32_Process"' 'powershell', '-script="Get-CimInstance Win32_Process"'
])).thenAnswer((Invocation invocation) { ])).thenAnswer((Invocation invocation) {
// The flutter tool process is returned as output to the powershell script
final MockProcessResult result = MockProcessResult(); final MockProcessResult result = MockProcessResult();
when(result.exitCode).thenReturn(0); when(result.exitCode).thenReturn(0);
when<String>(result.stdout).thenReturn(''); when<String>(result.stdout).thenReturn('$pid $flutterToolBinary');
return result; return result;
}); });
when(mockProcessManager.run(<String>[
'Taskkill', '/PID', '$pid', '/F'
])).thenThrow(Exception('Flutter tool process has been killed'));
testUsingContext('defaults', () async { testUsingContext('defaults', () async {
final PrebuiltWindowsApp windowsApp = PrebuiltWindowsApp(executable: 'foo'); final PrebuiltWindowsApp windowsApp = PrebuiltWindowsApp(executable: 'foo');
...@@ -82,6 +87,14 @@ void main() { ...@@ -82,6 +87,14 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => MemoryFileSystem(),
}); });
testUsingContext('The current running process is not killed when stopping the app', () async {
// The name of the executable is the same as the flutter tool one
final PrebuiltWindowsApp windowsApp = PrebuiltWindowsApp(executable: flutterToolBinary);
expect(await device.stopApp(windowsApp), false);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment