diff --git a/packages/flutter_tools/lib/src/android/android_workflow.dart b/packages/flutter_tools/lib/src/android/android_workflow.dart index ca81c128829..c3c0a67b53c 100644 --- a/packages/flutter_tools/lib/src/android/android_workflow.dart +++ b/packages/flutter_tools/lib/src/android/android_workflow.dart @@ -439,8 +439,8 @@ class AndroidLicenseValidator extends DoctorValidator { .then( (Object? socket) => socket, onError: (dynamic err, StackTrace stack) { - _logger.printError('Echoing stdin to the licenses subprocess failed:'); - _logger.printError('$err\n$stack'); + _logger.printTrace('Echoing stdin to the licenses subprocess failed:'); + _logger.printTrace('$err\n$stack'); }, ), ); @@ -453,12 +453,19 @@ class AndroidLicenseValidator extends DoctorValidator { _stdio.addStderrStream(process.stderr), ]); } on Exception catch (err, stack) { - _logger.printError('Echoing stdout or stderr from the license subprocess failed:'); - _logger.printError('$err\n$stack'); + _logger.printTrace('Echoing stdout or stderr from the license subprocess failed:'); + _logger.printTrace('$err\n$stack'); } final int exitCode = await process.exitCode; - return exitCode == 0; + if (exitCode != 0) { + throwToolExit(_userMessages.androidCannotRunSdkManager( + _androidSdk?.sdkManagerPath ?? '', + 'exited code $exitCode', + _platform, + )); + } + return true; } on ProcessException catch (e) { throwToolExit(_userMessages.androidCannotRunSdkManager( _androidSdk?.sdkManagerPath ?? '', diff --git a/packages/flutter_tools/test/general.shard/android/android_workflow_test.dart b/packages/flutter_tools/test/general.shard/android/android_workflow_test.dart index 7c705690e53..e86165c023a 100644 --- a/packages/flutter_tools/test/general.shard/android/android_workflow_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_workflow_test.dart @@ -339,7 +339,7 @@ Review licenses that have not been accepted (y/N)? ); await licenseValidator.runLicenseManager(); - expect(logger.errorText, contains(exceptionMessage)); + expect(logger.traceText, contains(exceptionMessage)); expect(processManager, hasNoRemainingExpectations); }); @@ -362,6 +362,42 @@ Review licenses that have not been accepted (y/N)? expect(licenseValidator.runLicenseManager(), throwsToolExit()); }); + testWithoutContext('runLicenseManager errors when sdkmanager exits non-zero', () async { + const String sdkManagerPath = '/foo/bar/sdkmanager'; + sdk.sdkManagerPath = sdkManagerPath; + final BufferLogger logger = BufferLogger.test(); + processManager.addCommand( + const FakeCommand( + command: [sdkManagerPath, '--licenses'], + exitCode: 1, + stderr: 'sdkmanager crash', + ), + ); + + final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( + androidSdk: sdk, + fileSystem: fileSystem, + processManager: processManager, + platform: FakePlatform(environment: {'HOME': '/home/me'}), + stdio: stdio, + logger: logger, + userMessages: UserMessages(), + androidStudio: FakeAndroidStudio(), + operatingSystemUtils: FakeOperatingSystemUtils(), + ); + + await expectLater( + licenseValidator.runLicenseManager(), + throwsToolExit( + message: 'Android sdkmanager tool was found, but failed to run ($sdkManagerPath): "exited code 1"', + ), + ); + expect(processManager, hasNoRemainingExpectations); + expect(logger.traceText, isEmpty); + expect(stdio.writtenToStdout, isEmpty); + expect(stdio.writtenToStderr, contains('sdkmanager crash')); + }); + testWithoutContext('detects license-only SDK installation with cmdline-tools', () async { sdk ..licensesAvailable = true