firebase-android-sdk
firebase-android-sdk copied to clipboard
[Crashlytics] cyclic dependency between gradle tasks becuase of injectCrashlyticsBuildIdsRelease depends on CMakeBuild
Environment
- Android Studio version: Iguana 2023.2.1
- Firebase Component: Crashlytics Gradle Plugin
- Component version: 2.9.9 (But started in 2.9.5)
The problem
Cyclic dependency between gradle tasks after trying to upgrade Crashlytics Gradle Plugin to 2.9.9.
In our setup we first build java/kotlin code, obfuscate it using R8, then use the R8 outputs to obfuscate JNI headers. This makes the buildCMake task depend on building java/kotlin code and R8.
After updating to 2.9.9 the injectCrashlyticsBuildIdsRelease task kicks in which seems to be necessary to mergeReleaseResources but at the same time depends on outputs from the native build which is the opposite order we have in our code. This causes cyclic dependency between gradle tasks. See output from the console:
:app:buildCMakeRelWithDebInfo[armeabi-v7a]
\--- :app:configureCMakeRelWithDebInfo[armeabi-v7a]
\--- :libom_generated:generateReleaseJniObfuscation
+--- :libom_generated:generateReleaseJniHeaders
| \--- :app:compileReleaseJavaWithJavac
| +--- :app:compileReleaseKotlin
| | +--- :app:dataBindingGenBaseClassesRelease
| | | +--- :app:mergeReleaseResources
| | | | \--- :app:injectCrashlyticsBuildIdsRelease
| | | | \--- :app:stripReleaseDebugSymbols
| | | | \--- :app:mergeReleaseNativeLibs
| | | | \--- :app:buildCMakeRelWithDebInfo[armeabi-v7a] (*)
| | | \--- :app:parseReleaseLocalResources
| | | \--- :app:packageReleaseResources
| | | \--- :app:injectCrashlyticsBuildIdsRelease (*)
| | +--- :app:kaptReleaseKotlin
| | | \--- :app:kaptGenerateStubsReleaseKotlin
| | | +--- :app:dataBindingGenBaseClassesRelease (*)
| | | +--- :app:kspReleaseKotlin
| | | | +--- :app:generateReleaseSources
| | | | | \--- :app:injectCrashlyticsBuildIdsRelease (*)
| | | | \--- :app:processReleaseResources
| | | | +--- :app:mapReleaseSourceSetPaths
| | | | | \--- :app:injectCrashlyticsBuildIdsRelease (*)
| | | | +--- :app:mergeReleaseResources (*)
| | | | \--- :app:parseReleaseLocalResources (*)
| | | \--- :app:processReleaseResources (*)
| | +--- :app:kspReleaseKotlin (*)
| | \--- :app:processReleaseResources (*)
| +--- :app:dataBindingGenBaseClassesRelease (*)
| +--- :app:generateReleaseSources (*)
| +--- :app:kaptReleaseKotlin (*)
| +--- :app:kspReleaseKotlin (*)
| \--- :app:processReleaseResources (*)
\--- :libom_generated:generateReleaseProguardMapping
\--- :app:compileReleaseJavaWithJavac (*)
Hi @mkubiczek, thanks for reaching out. In order for us to investigate this, could you provide a minimal reproducible example? Thanks!
Hi, I have prepared one here https://github.com/mar3kk/firebase-android-sdk-issue-5354 Please note this is very simplistic way that simulates the task dependency we have in our project. But in the end the culprit is that our cmake tasks depends on R8, which i simulated in the minimal reproducible example.
Just add a google-services.json file in the app/ directory and run ./gradlew app:assembleRelease to repro.
PS. I noticed that in this example the cyclic dependency starts to happen in plugin v2.9.3.
Hey @mkubiczek. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
I have provided more informations in this comment: https://github.com/firebase/firebase-android-sdk/issues/5354#issuecomment-1743521973
Thanks for the minimal repro, @mkubiczek. I was able to reproduce the same behavior. Let me notify our engineers and see what we can do here.
Any chance for fix anytime soon? It's blocking us from updating the crashlytics plugin.
Sorry about the delay! We are working on a major refactor to our Gradle plugin for next year, and was hoping to address issues like this then.
The inject build ids task needs the native binaries to extract their build ids and inject them into the app as a resource. Then Crashlytics can include that information in native ANR reports to support symbolication. If you don't care about that, you could disable the task in the meantime by something like:
project.afterEvaluate {
tasks.withType(InjectBuildIdsTask::class.java) {
// Effectively disable the InjectBuildIdsTask task, disabling symbolication of native ANRs
mergedNativeLibsDirs.set(null as File?)
}
}
Version 2.9.3 might be where we added the explicit dependency, when before it would have been an implicit dependency. So the native ANRs likely were not being symbolicated for you anyway. It would have been missing all the build ids, or doing something funny like including the build ids from your previous build.
Is using the R8 output to obfuscate JNI headers a standard build process? I just assumed R8 would handle that kind of detail for you, or maybe not obfuscate the referenced symbols. I am interested in the details of how developers build apps so I can better facilitate that with the Crashlytics build tools.
Thanks and sorry for not responding. I don't think obfuscating JNI headers is a common practice, but we have that. It's something R8 won't do as changing the JNI method signature requires you to change the call in native code as well. This is something R8 does not support. Not sure what you actually do with the buildId, but maybe it can be included in the apk/aab on a later stage before packaging.
Is the buildId only needed to symbolicate native ANRs or is it needed for native crashes as well? In our case native crashes are pretty poor in crashlytics, we usually only see one line and never full stacktrace like this:
Thread:
#00 pc 0x85c9c libc.so (BuildId: 26381bfa844b51288a6685202223a5f7)
#01 pc 0x8a4dc libc.so (BuildId: 26381bfa844b51288a6685202223a5f7)
#02 pc 0xea92c libc.so (BuildId: 26381bfa844b51288a6685202223a5f7)
#03 pc 0x621a4 libom.so (resolver(void*) [resolve.cpp:261]) (BuildId: 142b8a0d146db85a564187c456f850d7ec761da2)
#04 pc 0xeb6b0 libc.so (BuildId: 26381bfa844b51288a6685202223a5f7)
#05 pc 0x8af4c libc.so (BuildId: 26381bfa844b51288a6685202223a5f7)
While we do see way richer stacktraces in Google Play console.
@mar3kk @mkubiczek we have a prerelease of the next major version of the Crashlytics Gradle plugin, you can find it in #5733.
It is unlikely this will fix your issue alone, because we cannot inject Android resources after AAPT2 (resources linking), and this needs to happen before R8. Also, R class generation needs to see all resources, which happens before javac/kotlinc are invoked.
But if you combine this with applyMapping you could generate a mapping file once that includes all the mappings you need for your jni. Then keep reusing that same mapping as an input to both R8 and your native build.
It might make sense for the Crashlytics Gradle plugin to stop generating Android resources, and switch to Android assets as those are processed much later in the pipeline. That is a bigger change and would require updating the SDK too. Please let me know if nothing works for you, and we will add this to the backlog.
Hey @mkubiczek. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
Since there haven't been any recent updates here, I am going to close this issue.
@mkubiczek if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.