Unverified Commit c22c19b6 authored by Andrew Kolos's avatar Andrew Kolos Committed by GitHub

have Java.version return null if `java --version` fails or cannot be run (#139614)

## Summary
Fixes https://github.com/flutter/flutter/issues/139180, where `flutter create` could crash if the `java` binary the tool found cannot be run.

## Context

At startup, the tool searches for a Java installation[^1]. Unless the located installation is from [an Android Studio installation](https://github.com/flutter/flutter/blob/e1967ecabf014bf93d1731fde6a6547b06ca9c33/packages/flutter_tools/lib/src/android/android_studio.dart#L163), the tool does not verify that the binary is runnable. For more, see https://github.com/flutter/flutter/issues/139613, which tracks this inconsistency in behavior. 

This means that in the scenario where

1) the user does not have Android Studio installed or the java binary found within cannot be run **and**
2) the user has a) `flutter config --jdk-dir` set, b) `JAVA_HOME` set in their environment, **or** c) `java` on their system path **and**
3) the java binary we think we found during cannot be run (or `java --version` fails), **then**

the user running `flutter create` with Android enabled will hit a tool crash.

## Change

`Java.version` should return null if version checking fails for any reason. [This is documented behavior](https://github.com/flutter/flutter/blob/48f57621ade657b0c20ba53d513de4c3cd563abd/packages/flutter_tools/lib/src/android/java.dart#L136). Therefore, we'll update the implementation to first verify that the binary is runnable. If it isn't, it will return `null`.

[^1]: We find java by calling the static `Java.find`, see: https://github.com/flutter/flutter/blob/48187028c11ca8ca10e0179705d25553e1fe2c14/packages/flutter_tools/lib/src/context_runner.dart#L271
[^2]: This PR doesn't change this, as this would be too dangerous to cherry-pick into stable.
parent 2230c091
......@@ -135,6 +135,10 @@ class Java {
/// Returns the version of java in the format \d(.\d)+(.\d)+
/// Returns null if version could not be determined.
late final Version? version = (() {
if (!canRun()) {
return null;
}
final RunResult result = _processUtils.runSync(
<String>[binaryPath, '--version'],
environment: environment,
......@@ -142,6 +146,7 @@ class Java {
if (result.exitCode != 0) {
_logger.printTrace('java --version failed: exitCode: ${result.exitCode}'
' stdout: ${result.stdout} stderr: ${result.stderr}');
return null;
}
final String rawVersionOutput = result.stdout;
final List<String> versionLines = rawVersionOutput.split('\n');
......
......@@ -183,7 +183,7 @@ OpenJDK 64-Bit Server VM Zulu19.32+15-CA (build 19.0.2+7, mixed mode, sharing)
});
});
group('getVersionString', () {
group('version', () {
late Java java;
setUp(() {
......@@ -208,6 +208,23 @@ OpenJDK 64-Bit Server VM Zulu19.32+15-CA (build 19.0.2+7, mixed mode, sharing)
);
}
testWithoutContext('is null when java binary cannot be run', () async {
addJavaVersionCommand('');
processManager.excludedExecutables.add('java');
expect(java.version, null);
});
testWithoutContext('is null when java --version returns a non-zero exit code', () async {
processManager.addCommand(
FakeCommand(
command: <String>[java.binaryPath, '--version'],
exitCode: 1,
),
);
expect(java.version, null);
});
testWithoutContext('parses jdk 8', () {
addJavaVersionCommand('''
java version "1.8.0_202"
......
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