From 831ae93c478df51da4b4d162db8a56131e63f136 Mon Sep 17 00:00:00 2001 From: flutteractionsbot <154381524+flutteractionsbot@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:42:51 -0800 Subject: [PATCH] [CP-beta]Add handler for jlink error when using Java 21 (#157946) This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/156304 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Provides guidance on how to fix a common error encountered when using Java 21 and Android Gradle Plugin versions less than 8.2.1, a combination that many users are encountering due to a recent Android Studio upgrade. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Flutter apps fail to build on Android when using the previously mentioned combination (Java 21/AGP < 8.2.1). This error handler guides users on fixing the problem. ### Workaround: Is there a workaround for this issue? Users can upgrade their AGP version, or specify a lower Java version. But they would be unlikely to know this, because the (unhandled) error message is not helpful for Flutter developers. ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? Try building an app with the mentioned combination, verify that the handler triggers (i.e., the message includes `flutter fix...` --- .../lib/src/android/gradle_errors.dart | 35 ++++++++++- .../android/gradle_errors_test.dart | 59 +++++++++++++++++-- 2 files changed, 87 insertions(+), 7 deletions(-) diff --git a/packages/flutter_tools/lib/src/android/gradle_errors.dart b/packages/flutter_tools/lib/src/android/gradle_errors.dart index d70335d105e..09540a05ba4 100644 --- a/packages/flutter_tools/lib/src/android/gradle_errors.dart +++ b/packages/flutter_tools/lib/src/android/gradle_errors.dart @@ -80,6 +80,7 @@ final List gradleErrors = [ remoteTerminatedHandshakeHandler, couldNotOpenCacheDirectoryHandler, incompatibleCompileSdk35AndAgpVersionHandler, + jlinkErrorWithJava21AndSourceCompatibility, incompatibleKotlinVersionHandler, // This handler should always be last, as its key log output is sometimes in error messages with other root causes. ]; @@ -634,15 +635,15 @@ final GradleHandledError couldNotOpenCacheDirectoryHandler = GradleHandledError( eventLabel: 'could-not-open-cache-directory', ); - String _getAgpLocation(FlutterProject project) { return ''' The version of AGP that your project uses is likely defined in: ${project.android.settingsGradleFile.path}, -in the 'plugins' closure. +in the 'plugins' closure (by the number following "com.android.application"). Alternatively, if your project was created with an older version of the templates, it is likely in the buildscript.dependencies closure of the top-level build.gradle: -${project.android.hostAppGradleFile.path}.'''; +${project.android.hostAppGradleFile.path}, +as the number following "com.android.tools.build:gradle:".'''; } @visibleForTesting @@ -685,3 +686,31 @@ ${_getAgpLocation(project)}''', }, eventLabel: 'r8-dexing-bug-in-AGP-7.3' ); + +@visibleForTesting +const String jlinkErrorMessage = '> Error while executing process'; + +@visibleForTesting +final GradleHandledError jlinkErrorWithJava21AndSourceCompatibility = GradleHandledError( + test: (String line) => line.contains('> Error while executing process')&& line.contains('jlink'), + handler: ({ + required String line, + required FlutterProject project, + required bool usesAndroidX, + }) async { + globals.printBox(''' +${globals.logger.terminal.warningMark} This is likely due to a known bug in Android Gradle Plugin (AGP) versions less than 8.2.1, when + 1. setting a value for SourceCompatibility and + 2. using Java 21 or above. +To fix this error, please upgrade your AGP version to at least 8.2.1.${_getAgpLocation(project)} + +For more information, see: +https://issuetracker.google.com/issues/294137077 +https://github.com/flutter/flutter/issues/156304''', + title: _boxTitle, + ); + + return GradleBuildStatus.exit; + }, + eventLabel: 'java21-and-source-compatibility' +); diff --git a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart index 3f2fd977a7f..6ba98745bee 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart @@ -51,6 +51,7 @@ void main() { remoteTerminatedHandshakeHandler, couldNotOpenCacheDirectoryHandler, incompatibleCompileSdk35AndAgpVersionHandler, + jlinkErrorWithJava21AndSourceCompatibility, incompatibleKotlinVersionHandler, ]) ); @@ -1314,10 +1315,11 @@ Execution failed for task ':app:bundleReleaseResources'. '│ Please upgrade to a newer AGP version. The version of AGP that your project uses is likely │\n' '│ defined in: │\n' '│ /android/settings.gradle, │\n' - "│ in the 'plugins' closure. │\n" + '│ in the \'plugins\' closure (by the number following "com.android.application"). │\n' '│ Alternatively, if your project was created with an older version of the templates, it is likely │\n' '│ in the buildscript.dependencies closure of the top-level build.gradle: │\n' - '│ /android/build.gradle. │\n' + '│ /android/build.gradle, │\n' + '│ as the number following "com.android.tools.build:gradle:". │\n' '│ │\n' '│ Finally, if you have a strong reason to avoid upgrading AGP, you can temporarily lower the │\n' '│ compileSdk version in the following file: │\n' @@ -1355,10 +1357,11 @@ ERROR:/Users/mackall/.gradle/caches/transforms-3/bd2c84591857c6d4c308221ffece862 '│ │\n' '│ The version of AGP that your project uses is likely defined in: │\n' '│ /android/settings.gradle, │\n' - "│ in the 'plugins' closure. │\n" + '│ in the \'plugins\' closure (by the number following "com.android.application"). │\n' '│ Alternatively, if your project was created with an older version of the templates, it is likely │\n' '│ in the buildscript.dependencies closure of the top-level build.gradle: │\n' - '│ /android/build.gradle. │\n' + '│ /android/build.gradle, │\n' + '│ as the number following "com.android.tools.build:gradle:". │\n' '└──────────────────────────────────────────────────────────────────────────────────────────────────┘\n' '' ) @@ -1369,6 +1372,54 @@ ERROR:/Users/mackall/.gradle/caches/transforms-3/bd2c84591857c6d4c308221ffece862 FileSystem: () => fileSystem, ProcessManager: () => processManager, }); + + testUsingContext('Java 21 and jlink bug', () async { + const String errorExample = r''' +* What went wrong: +Execution failed for task ':shared_preferences_android:compileReleaseJavaWithJavac'. +> Could not resolve all files for configuration ':shared_preferences_android:androidJdkImage'. + > Failed to transform core-for-system-modules.jar to match attributes {artifactType=_internal_android_jdk_image, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime}. + > Execution failed for JdkImageTransform: /Users/mackall/Library/Android/sdk/platforms/android-34/core-for-system-modules.jar. + > Error while executing process /Users/mackall/Desktop/JDKs/21/jdk-21.0.2.jdk/Contents/Home/bin/jlink with arguments {--module-path /Users/mackall/.gradle/caches/8.9/transforms/2890fec03da42154757073d3208548e5-79660961-f91d-4df2-90bc-b9a3f2a270bd/transformed/output/temp/jmod --add-modules java.base --output /Users/mackall/.gradle/caches/8.9/transforms/2890fec03da42154757073d3208548e5-79660961-f91d-4df2-90bc-b9a3f2a270bd/transformed/output/jdkImage --disable-plugin system-modules} + '''; + + final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); + await jlinkErrorWithJava21AndSourceCompatibility.handler( + line: errorExample, + project: project, + usesAndroidX: true, + ); + + // Main fix text. + expect( + testLogger.statusText, + contains('To fix this error, please upgrade your AGP version to at least 8.2.1.') + ); + // Paths to AGP location. + expect( + testLogger.statusText, + contains('/android/settings.gradle') + ); + expect( + testLogger.statusText, + contains('/android/build.gradle') + ); + // Links to info. + expect( + testLogger.statusText, + contains('https://issuetracker.google.com/issues/294137077') + ); + expect( + testLogger.statusText, + contains('https://github.com/flutter/flutter/issues/156304') + ); + + }, overrides: { + GradleUtils: () => FakeGradleUtils(), + Platform: () => fakePlatform('android'), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + }); } bool formatTestErrorMessage(String errorMessage, GradleHandledError error) {