I have a project in Android Studio that consist on Android Java Services that uses some native libraries through JNI calls.
Basically, I have 2 libraries I compile and another library that is precompiled, so I don't have access to the source code. As the precompiled library is only built for armeabi-v7a, I have an abiFilter.
Here, my /build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
classpath 'io.fabric.tools:gradle:1.31.2'
classpath 'com.google.gms:google-services:4.3.3' // Google Services plugin
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
and my /app/build.gradle (omitted the sensible code)
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
def enableCrashlyticsNdk = true
repositories {
jcenter()
maven { url 'https://maven.fabric.io/public' }
}
android {
signingConfigs {
platformSignature {
keyAlias "${platform_keystore_alias}"
keyPassword "${platform_keystore_password}"
storeFile file("${platform_keystore_path}")
storePassword "${platform_keystore_password}"
}
}
compileSdkVersion 29
buildToolsVersion "29.0.2"
lintOptions {
abortOnError false
}
defaultConfig {
applicationId com.example.stackoverflowapp
minSdkVersion 26
targetSdkVersion 28
versionCode 1
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -Werror"
}
}
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
abiFilters 'armeabi-v7a'
}
}
buildTypes {
release {
minifyEnabled true
jniDebuggable false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.platformSignature
}
debug {
debuggable true
jniDebuggable true
versionNameSuffix = " (debug)"
signingConfig signingConfigs.platformSignature
}
}
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = buildOutputName(variant)
}
}
packagingOptions {
exclude 'jsr305_annotations/Jsr305_annotations.gwt.xml'
exclude 'error_prone/Annotations.gwt.xml'
exclude 'third_party/java_src/error_prone/project/annotations/Annotations.gwt.xml'
exclude 'third_party/java_src/error_prone/project/annotations/Google_internal.gwt.xml'
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
ext {
appCompatVersion = '28.0.0'
}
crashlytics {
enableNdk enableCrashlyticsNdk
}
tasks.whenTaskAdded { task ->
if (enableCrashlyticsNdk && task.name.startsWith('assemble')) {
task.finalizedBy "crashlyticsUploadSymbols" + task.name.substring('assemble'.length())
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'androidx.leanback:leanback:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'com.google.android.exoplayer:exoplayer:r1.5.14'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.google.firebase:firebase-analytics:17.2.1'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
implementation 'com.crashlytics.sdk.android:crashlytics-ndk:2.1.1'
}
apply plugin: 'com.google.gms.google-services' // Google Play services Gradle plugin
As my app is part of the Android system, it is signed with a platform signature.
I compile my 2 libraries with CMake.
I have followed all steps from the firebase web:
- https://firebase.google.com/docs/android/setup
- https://firebase.google.com/docs/crashlytics/get-started?platform=android
- https://firebase.google.com/docs/crashlytics/ndk-reports
I've added a crash intentionally within one of my libraries and when the app reaches crash, The Crashlytics gathered the crash and upload the crash report successfully.
CrashlyticsCore: Crashlytics report upload complete: 5DE66A450116-0001-1A8B-A3EE77BA9366
Then, when I go to the firebase console, I see that all stack frames are (missing)
Crashed: Thread #1
SIGSEGV 0x0000000000000028
-------------------------------------------
0 MyApp.apk (Missing)
1 libart.so (Missing)
2 (Missing)
3 (Missing)
4 (Missing)
5 (Missing)
6 (Missing)
7 libart.so (Missing)
8 libart.so (Missing)
9 libart.so (Missing)
10 (Missing)
11 libart.so (Missing)
12 (Missing)
Reviewing the Crashlytics build logs, it seems like the cSym files are uploaded properly.
[DEBUG] (Execution worker for ':' Thread 6) com.crashlytics - cSYM file(s) uploaded.
I'm not really sure if the symbols are properly created and uploaded or if there is an issue with the crash reports created by the device. I'm afraid of the problem would be related with android permissions as my app is a system app.
I guess I've read all the stackoverflow posts related with Crashlytics and NDK. Also, I've also googled any kind of combination related with "crashlytics, ndk and symbols".
Finally, the tool versions I'm using:
- Android Studio: 3.5.1
- Gradle: 5.4.1
- Gradle plugin: 3.5.2
- Fabric gradle plugin: 1.31.2
Thank you so much.