Skip to content

Commit 3e94e18

Browse files
andrewkoloscaseycrogers
authored andcommitted
In flutter doctor -v, when JRE is too out-of-date to run sdkmanager, print a helpful error message (flutter#138762)
Closes flutter#138132. See this issue for more information.
1 parent a0556b2 commit 3e94e18

File tree

3 files changed

+76
-14
lines changed

3 files changed

+76
-14
lines changed

packages/flutter_tools/lib/src/android/android_workflow.dart

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -389,12 +389,16 @@ class AndroidLicenseValidator extends DoctorValidator {
389389
),
390390
);
391391

392+
final List<String> stderrLines = <String>[];
392393
// Wait for stdout and stderr to be fully processed, because process.exitCode
393394
// may complete first.
394395
try {
395396
await Future.wait<void>(<Future<void>>[
396397
_stdio.addStdoutStream(process.stdout),
397-
_stdio.addStderrStream(process.stderr),
398+
process.stderr.forEach((List<int> event) {
399+
_stdio.stderr.add(event);
400+
stderrLines.add(utf8.decode(event));
401+
}),
398402
]);
399403
} on Exception catch (err, stack) {
400404
_logger.printTrace('Echoing stdout or stderr from the license subprocess failed:');
@@ -403,11 +407,7 @@ class AndroidLicenseValidator extends DoctorValidator {
403407

404408
final int exitCode = await process.exitCode;
405409
if (exitCode != 0) {
406-
throwToolExit(_userMessages.androidCannotRunSdkManager(
407-
_androidSdk.sdkManagerPath ?? '',
408-
'exited code $exitCode',
409-
_platform,
410-
));
410+
throwToolExit(_messageForSdkManagerError(stderrLines, exitCode));
411411
}
412412
return true;
413413
} on ProcessException catch (e) {
@@ -426,4 +426,30 @@ class AndroidLicenseValidator extends DoctorValidator {
426426
}
427427
return _processManager.canRun(sdkManagerPath);
428428
}
429+
430+
String _messageForSdkManagerError(
431+
List<String> androidSdkStderr,
432+
int exitCode,
433+
) {
434+
final String sdkManagerPath = _androidSdk!.sdkManagerPath!;
435+
436+
final bool failedDueToJdkIncompatibility = androidSdkStderr.join().contains(
437+
RegExp(r'java\.lang\.UnsupportedClassVersionError.*SdkManagerCli '
438+
r'has been compiled by a more recent version of the Java Runtime'));
439+
440+
if (failedDueToJdkIncompatibility) {
441+
return 'Android sdkmanager tool was found, but failed to run ($sdkManagerPath): "exited code $exitCode".\n'
442+
'It appears the version of the Java binary used (${_java!.binaryPath}) is '
443+
'too out-of-date and is incompatible with the Android sdkmanager tool.\n'
444+
'If the Java binary came bundled with Android Studio, consider updating '
445+
'your installation of Android studio. Alternatively, you can uninstall '
446+
'the Android SDK command-line tools and install an earlier version. ';
447+
}
448+
449+
return _userMessages.androidCannotRunSdkManager(
450+
sdkManagerPath,
451+
'exited code $exitCode',
452+
_platform,
453+
);
454+
}
429455
}

packages/flutter_tools/lib/src/base/user_messages.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,15 @@ class UserMessages {
102102
'Unable to locate Android SDK.\n'
103103
'Install Android Studio from: https://developer.android.com/studio/index.html\n'
104104
'On first launch it will assist you in installing the Android SDK components.\n'
105-
'(or visit ${_androidSdkInstallUrl(platform)} for detailed instructions).\n'
105+
'(or visit ${androidSdkInstallUrl(platform)} for detailed instructions).\n'
106106
'If the Android SDK has been installed to a custom location, please use\n'
107107
'`flutter config --android-sdk` to update to that location.\n';
108108
String androidSdkLocation(String directory) => 'Android SDK at $directory';
109109
String androidSdkPlatformToolsVersion(String platform, String tools) =>
110110
'Platform $platform, build-tools $tools';
111111
String androidSdkInstallHelp(Platform platform) =>
112112
'Try re-installing or updating your Android SDK,\n'
113-
'visit ${_androidSdkInstallUrl(platform)} for detailed instructions.';
113+
'visit ${androidSdkInstallUrl(platform)} for detailed instructions.';
114114
// Also occurs in AndroidLicenseValidator
115115
String androidStatusInfo(String version) => 'Android SDK version $version';
116116

@@ -126,7 +126,7 @@ class UserMessages {
126126
String androidLicensesUnknown(Platform platform) =>
127127
'Android license status unknown.\n'
128128
'Run `flutter doctor --android-licenses` to accept the SDK licenses.\n'
129-
'See ${_androidSdkInstallUrl(platform)} for more details.';
129+
'See ${androidSdkInstallUrl(platform)} for more details.';
130130
String androidSdkManagerOutdated(String managerPath) =>
131131
'A newer version of the Android SDK is required. To update, run:\n'
132132
'$managerPath --update\n';
@@ -135,14 +135,14 @@ class UserMessages {
135135
String androidMissingSdkManager(String sdkManagerPath, Platform platform) =>
136136
'Android sdkmanager tool not found ($sdkManagerPath).\n'
137137
'Try re-installing or updating your Android SDK,\n'
138-
'visit ${_androidSdkInstallUrl(platform)} for detailed instructions.';
138+
'visit ${androidSdkInstallUrl(platform)} for detailed instructions.';
139139
String androidCannotRunSdkManager(String sdkManagerPath, String error, Platform platform) =>
140140
'Android sdkmanager tool was found, but failed to run ($sdkManagerPath): "$error".\n'
141141
'Try re-installing or updating your Android SDK,\n'
142-
'visit ${_androidSdkInstallUrl(platform)} for detailed instructions.';
142+
'visit ${androidSdkInstallUrl(platform)} for detailed instructions.';
143143
String androidSdkBuildToolsOutdated(int sdkMinVersion, String buildToolsMinVersion, Platform platform) =>
144144
'Flutter requires Android SDK $sdkMinVersion and the Android BuildTools $buildToolsMinVersion\n'
145-
'To update the Android SDK visit ${_androidSdkInstallUrl(platform)} for detailed instructions.';
145+
'To update the Android SDK visit ${androidSdkInstallUrl(platform)} for detailed instructions.';
146146
String get androidMissingCmdTools => 'cmdline-tools component is missing\n'
147147
'Run `path/to/sdkmanager --install "cmdline-tools;latest"`\n'
148148
'See https://developer.android.com/studio/command-line for more details.';
@@ -163,7 +163,7 @@ class UserMessages {
163163
'but Android Studio not found at this location.';
164164
String androidStudioInstallation(Platform platform) =>
165165
'Android Studio not found; download from https://developer.android.com/studio/index.html\n'
166-
'(or visit ${_androidSdkInstallUrl(platform)} for detailed instructions).';
166+
'(or visit ${androidSdkInstallUrl(platform)} for detailed instructions).';
167167

168168
// Messages used in XcodeValidator
169169
String xcodeLocation(String location) => 'Xcode at $location';
@@ -351,7 +351,7 @@ class UserMessages {
351351
'Read more about iOS versioning at\n'
352352
'https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html\n';
353353

354-
String _androidSdkInstallUrl(Platform platform) {
354+
String androidSdkInstallUrl(Platform platform) {
355355
const String baseUrl = 'https://flutter.dev/docs/get-started/install';
356356
const String fragment = '#android-setup';
357357
if (platform.isMacOS) {

packages/flutter_tools/test/general.shard/android/android_workflow_test.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,42 @@ Review licenses that have not been accepted (y/N)?
578578
true,
579579
);
580580
});
581+
582+
testWithoutContext('Asks user to upgrade Android Studio when it is too far behind the Android SDK', () async {
583+
const String sdkManagerPath = '/foo/bar/sdkmanager';
584+
sdk.sdkManagerPath = sdkManagerPath;
585+
final BufferLogger logger = BufferLogger.test();
586+
processManager.addCommand(
587+
const FakeCommand(
588+
command: <String>[sdkManagerPath, '--licenses'],
589+
exitCode: 1,
590+
stderr: '''
591+
Error: LinkageError occurred while loading main class com.android.sdklib.tool.sdkmanager.SdkManagerCli
592+
java.lang.UnsupportedClassVersionError: com/android/sdklib/tool/sdkmanager/SdkManagerCli has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0
593+
Android sdkmanager tool was found, but failed to run
594+
''',
595+
),
596+
);
597+
598+
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
599+
java: FakeJava(),
600+
androidSdk: sdk,
601+
processManager: processManager,
602+
platform: FakePlatform(environment: <String, String>{'HOME': '/home/me'}),
603+
stdio: stdio,
604+
logger: logger,
605+
userMessages: UserMessages(),
606+
);
607+
608+
await expectLater(
609+
licenseValidator.runLicenseManager(),
610+
throwsToolExit(
611+
message: RegExp('.*consider updating your installation of Android studio. Alternatively, you.*'),
612+
),
613+
);
614+
expect(processManager, hasNoRemainingExpectations);
615+
expect(stdio.stderr.getAndClear(), contains('UnsupportedClassVersionError'));
616+
});
581617
}
582618

583619
class FakeAndroidSdk extends Fake implements AndroidSdk {

0 commit comments

Comments
 (0)