3

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:

  1. https://firebase.google.com/docs/android/setup
  2. https://firebase.google.com/docs/crashlytics/get-started?platform=android
  3. 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.

3 Answers3

2

You may want to consider upgrading to the new (non fabric) Crashlytics SDK. It is, assumedly, the roadmap replacement for fabric.

https://firebase.google.com/docs/crashlytics/upgrade-sdk?platform=android

and

https://firebase.google.com/docs/crashlytics/ndk-reports-new-sdk

While it is in Beta as of this writing, I recently converted to it fairly easily. In the process I was also able to stop using the fabric native library (libCrashlytics) and its header in my native code.

Additionally, ensure you are properly uploading the symbols to Firebase / Fabric as part of your build process. You may need to do this explicitly as part of an afterEvaluate block like so:

afterEvaluate {
    if (gradle.startParameter.taskNames.contains(":app:assemble<Flavor><BuildType>")) {
        assemble<Flavor><BuildType>.finalizedBy(uploadCrashlyticsSymbolFile<Flavor><BuildType>)
    }
}

Be sure to replace <Flavor> and <BuildType> with the flavor and build type(s) you defined in your productFlavors and buildTypes blocks.

For example, the below flavor / build types:

buildTypes {
    release {
        signingConfig signingConfigs.release
        buildConfigField "boolean", "RELEASE", "true"
        shrinkResources true
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
    debug {
        buildConfigField "boolean", "RELEASE", "false"
        applicationIdSuffix '.debug'
        versionNameSuffix '-DEBUG'
        ext.alwaysUpdateBuildId = false
        crunchPngs false
    }
}

flavorDimensions "all"

productFlavors {
    fat {
        ndk {
            abiFilters "x86_64", "x86", "arm64-v8a", "armeabi-v7a"
        }
        dimension "all"
    }
}

would result in assembleFatDebug and assembleFatRelease tasks that you'd need to finalize with uploadCrashlyticsSymbolFileFatDebug and uploadCrashlyticsSymbolFileFatRelease tasks accordingly.

NOTE: If you are still using Fabric, the task you want to finalize your assemble* task with is crashlyticsUploadSymbols<Flavor><BuildType>.

ShellDude
  • 579
  • 6
  • 12
  • Thanks for your response. I've upgraded my project as the 2 URLs suggest but the problem still happen. It is uploading the crash, however, the crash is empty, all frames are missing. I don't know what can I do for getting a proper NDK crash logs... Can you help me? are There any steps I'm forgetting? It seems like the symbols are not properly uploaded in spite of I'm uploading them... – Javier Rodriguez Jan 21 '20 at 17:31
  • you need to make sure they are being uploaded... check your Gradle/build log to ensure the uploadCrashlyticsSymbolFile task is running. – ShellDude Jan 22 '20 at 01:27
  • I'm going to update my answer with some Gradle stuff to cover the symbol file upload. – ShellDude Jan 22 '20 at 01:48
  • Seems to be uploaded properly: "Crashlytics symbol file uploaded successfully; deleting local csym:" Should I configure Cmake in a way? – Javier Rodriguez Jan 22 '20 at 09:33
  • Could be the compiler I'm using? Which compiler are you using? gcc or clang? – Javier Rodriguez Jan 22 '20 at 10:42
  • both actually. I moved from gcc to clang a couple versions of Gradle back – ShellDude Jan 23 '20 at 03:26
  • Hi! I guess I've found the solution. In my case, and due to requirements, our native libraries need to be packed within the APK, this mean that the libraries will not extracted when the APK is insatalled. (Adding android:extractNativeLibs="false" in Manifest). If I extract the libraries, the native crash is properly reported – Javier Rodriguez Jan 23 '20 at 16:33
  • Hello @ShellDude this is not working for me, I have done all steps from given links of firebase, I'm still getting missing everything into the log, please help me – Priyanka Feb 06 '20 at 12:36
0

In my case adding of -Wl,--build-id to compiler flags solved such issue. Looks like Crashlytics could not match received crash reports with uploaded symbols.

  • Finally I just talked with Firebase support and they found the issue and now it is fixed. The issue was related with place where my libraries was installed in, because due to design restrictions, my libraries must be packed within the apk instead of being installed outside. – Javier Rodriguez Feb 15 '21 at 15:20
0

I solved the problem by replacing the NDK version from 10d to 13d.

Chao
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 12 '21 at 06:20