From 1c2d3f324d29d9e89b8579db67101218047b8112 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 28 Aug 2018 11:28:25 -0700 Subject: [PATCH] Shut down gradle at the end of each task (#20968) Apparently Gradle leaks memory and it's causing failures. --- dev/devicelab/README.md | 6 ++++ dev/devicelab/lib/framework/runner.dart | 39 +++++++++++++++++++++++++ dev/devicelab/lib/framework/utils.dart | 12 ++++---- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/dev/devicelab/README.md b/dev/devicelab/README.md index 2a0eba6281..e584e5a146 100644 --- a/dev/devicelab/README.md +++ b/dev/devicelab/README.md @@ -108,6 +108,12 @@ Android SDK at `.../engine/src/third_party/android_tools/sdk`. You can find where your Android SDK is using `flutter doctor`. +## Warnings + +Running devicelab will do things to your environment. + +Notably, it will start and stop gradle, for instance. + ## Running all tests To run all tests defined in `manifest.yaml`, use option `-a` (`--all`): diff --git a/dev/devicelab/lib/framework/runner.dart b/dev/devicelab/lib/framework/runner.dart index 1332c9b852..7985e86a77 100644 --- a/dev/devicelab/lib/framework/runner.dart +++ b/dev/devicelab/lib/framework/runner.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:path/path.dart' as path; import 'package:vm_service_client/vm_service_client.dart'; import 'package:flutter_devicelab/framework/utils.dart'; @@ -81,6 +82,7 @@ Future> runTask(String taskName, { bool silent = false }) a } finally { if (!runnerFinished) runner.kill(ProcessSignal.sigkill); + await cleanupSystem(); await stdoutSub.cancel(); await stderrSub.cancel(); } @@ -125,3 +127,40 @@ Future _connectToRunnerIsolate(int vmServicePort) async { } } } + +Future cleanupSystem() async { + print('\n\nCleaning up system after task...'); + final String javaHome = await findJavaHome(); + if (javaHome != null) { + // To shut gradle down, we have to call "gradlew --stop". + // To call gradlew, we need to have a gradle-wrapper.properties file along + // with a shell script, a .jar file, etc. We get these from various places + // as you see in the code below, and we save them all into a temporary dir + // which we can then delete after. + // All the steps below are somewhat tolerant of errors, because it doesn't + // really matter if this succeeds every time or not. + print('\nTelling Gradle to shut down (JAVA_HOME=$javaHome)'); + final String gradlewBinaryName = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; + final Directory tempDir = Directory.systemTemp.createTempSync('flutter_devicelab_shutdown_gradle.'); + recursiveCopy(new Directory(path.join(flutterDirectory.path, 'bin', 'cache', 'artifacts', 'gradle_wrapper')), tempDir); + copy(new File(path.join(path.join(flutterDirectory.path, 'packages', 'flutter_tools'), 'templates', 'create', 'android.tmpl', 'gradle', 'wrapper', 'gradle-wrapper.properties')), new Directory(path.join(tempDir.path, 'gradle', 'wrapper'))); + if (!Platform.isWindows) { + await exec( + 'chmod', + ['a+x', path.join(tempDir.path, gradlewBinaryName)], + canFail: true, + ); + } + await exec( + path.join(tempDir.path, gradlewBinaryName), + ['--stop'], + environment: { 'JAVA_HOME': javaHome }, + workingDirectory: tempDir.path, + canFail: true, + ); + rmTree(tempDir); + print('\n'); + } else { + print('Could not determine JAVA_HOME; not shutting down Gradle.'); + } +} \ No newline at end of file diff --git a/dev/devicelab/lib/framework/utils.dart b/dev/devicelab/lib/framework/utils.dart index fd85a9b99f..f4fffdbaa5 100644 --- a/dev/devicelab/lib/framework/utils.dart +++ b/dev/devicelab/lib/framework/utils.dart @@ -236,7 +236,7 @@ Future startProcess( _runningProcesses.add(processInfo); process.exitCode.then((int exitCode) { - print('exitcode: $exitCode'); + print('"$executable" exit code: $exitCode'); _runningProcesses.remove(processInfo); }); @@ -266,8 +266,9 @@ Future exec( List arguments, { Map environment, bool canFail = false, // as in, whether failures are ok. False means that they are fatal. + String workingDirectory, }) async { - final Process process = await startProcess(executable, arguments, environment: environment); + final Process process = await startProcess(executable, arguments, environment: environment, workingDirectory: workingDirectory); final Completer stdoutDone = new Completer(); final Completer stderrDone = new Completer(); @@ -288,7 +289,7 @@ Future exec( final int exitCode = await process.exitCode; if (exitCode != 0 && !canFail) - fail('Executable failed with exit code $exitCode.'); + fail('Executable "$executable" failed with exit code $exitCode.'); return exitCode; } @@ -301,8 +302,9 @@ Future eval( List arguments, { Map environment, bool canFail = false, // as in, whether failures are ok. False means that they are fatal. + String workingDirectory, }) async { - final Process process = await startProcess(executable, arguments, environment: environment); + final Process process = await startProcess(executable, arguments, environment: environment, workingDirectory: workingDirectory); final StringBuffer output = new StringBuffer(); final Completer stdoutDone = new Completer(); @@ -325,7 +327,7 @@ Future eval( final int exitCode = await process.exitCode; if (exitCode != 0 && !canFail) - fail('Executable failed with exit code $exitCode.'); + fail('Executable "$executable" failed with exit code $exitCode.'); return output.toString().trimRight(); }