realm / realm-java

Realm is a mobile database: a replacement for SQLite & ORMs
http://realm.io
Apache License 2.0
11.45k stars 1.74k forks source link

Make debug symbols available in Google Play or Crashlytics (or improve documentation on how) #6773

Open dsuresh-ap opened 4 years ago

dsuresh-ap commented 4 years ago

Goal

Figure out why Crashlytics cannot find symbols to upload for crashlytics.

Filed a similar issue for Crashlytics here: https://github.com/firebase/firebase-android-sdk/issues/1316

Actual Results

The logs for Crashlytics show that symbol files were not found for the .so file.

2020-03-05 11:11:23.406 [DEBUG] (Execution worker for ':' Thread 4) com.crashlytics  - Crashlytics found no symbols for /productionDebug/out/lib/armeabi-v7a/libcrashlytics.so, skipping.
2020-03-05 11:11:23.406 [DEBUG] (Execution worker for ':' Thread 4) com.crashlytics  - Generating cSYM for /productionDebug/out/lib/armeabi-v7a/librealm-jni.so
2020-03-05 11:11:23.418 [DEBUG] (Execution worker for ':' Thread 4) com.crashlytics  - Using ELF data for cSYM generation.
2020-03-05 11:11:23.418 [DEBUG] (Execution worker for ':' Thread 4) com.crashlytics  - Crashlytics found no symbols for /productionDebug/out/lib/armeabi-v7a/librealm-jni.so, skipping.

Steps & Code to Reproduce

Followed steps with https://realm.io/docs/java/latest/#ndk-debugging and the Fabric docs to setup Crashlytics. Had to adjust the NDK out dirs to:

crashlytics {
    enableNdk = true
    androidNdkOut = "build/intermediates/merged_native_libs"
    androidNdkLibsOut = "build/intermediates/stripped_native_libs"
}

Version of Realm and tooling

Realm version(s): 6.0.1

Realm Sync feature enabled: No

Android Studio version: 3.6.1

Android Build Tools version: 29.0.0

Gradle version: 5.4.1 wrapper - 3.5.0 plugin

Which Android version and device(s): Samsung S9, Android 10

cmelchior commented 4 years ago

The Realm .so files are not provided with debug symbols due to size. We do have the unstripped .so files available if you need them though, but you need to download them manually from S3. You can see how we do it here: https://github.com/realm/realm-java/blob/master/tools/unroll_stacktrace.sh#L66

dsuresh-ap commented 4 years ago

@cmelchior Thanks this is helpful and we will try to integrate that.

Is it possible to update the Realm Java docs to include some reference to this. Reading the docs it sounded like support for Crashlytics will be enabled for Realm just by following the steps.

NDK debugging
Realm is a library that contains native code. We recommend that you use a crash reporting tool, such as Crashlytics, to track native errors so we are in a better position to help you if something goes wrong.

Debugging NDK crashes is usually cumbersome as the default stack trace provides minimal information that can be of use. Crashlytics will allow you to capture valuable NDK crash information. To enable NDK crash reporting in Crashlytics, please follow the steps outlined in this guide.

To enable NDK crash reporting for your project, add this to the root of your build.gradle file. Please note, the values androidNdkOut and androidNdkLibsOut are not needed.

crashlytics {
  enableNdk true
}
hardysim commented 4 years ago

Is it possible to create some sort of plugin for Android Studio for this? One which gets the debug symbols and packs them into the Android App Bundle to be used in Android Vitals and Crashlytics etc. but which will not be added to the final APK installed on the device?

The new Google Play Console warns about missing debug symbols of the native code. I think, everyone will get this warning in the console when using realm from now on?!

iwo commented 3 years ago

@cmelchior which symbols should I upload to Play Store base or objectSaver? I'm using Realm Gradle plugin: 'io.realm:realm-gradle-plugin:7.0.8'.

cmelchior commented 3 years ago

@iwo objectServer is if you are using sync enabled through the realm closure in Gradle:

realm {
  syncEnabled = true
}

If you don't have that you just need the base variant.

hardysim commented 3 years ago

Is it possible to create some sort of plugin for Android Studio for this? One which gets the debug symbols and packs them into the Android App Bundle to be used in Android Vitals and Crashlytics etc. but which will not be added to the final APK installed on the device?

The new Google Play Console warns about missing debug symbols of the native code. I think, everyone will get this warning in the console when using realm from now on?!

I just found a hint in the release notes for Android Studio 4.1 about "Symbolication for native crash reports". Just add the following line to the app's build.gradle (having the NDK installed) and it will generate debug symbols into the app bundle. When using this, the PlayStore not longer shows the warning.

android.buildTypes.release.ndk.debugSymbolLevel = 'SYMBOL_TABLE'

References:

hardysim commented 3 years ago

So my adding the symbol level (see https://github.com/realm/realm-java/issues/6773#issuecomment-708202945) just helps with the PlayStore but not with crashlytics.

Crashlytics seem to need a manual upload of native symbols. But the documentation at realm is outdated. The current crashlytics documentation uses different parameters to set the directories.

I'm stuck now so it seems this issue still exists using the current crashlytics version. Any updates on this?

afaucogney commented 3 years ago

Is there any related issue with this : https://stackoverflow.com/a/55969995/2733216 ? They post upload of symbol will come back with NDK 22 when publishing an app in bundle format. I saw that realm java is built with NDK 21.

afaucogney commented 3 years ago

I tried to achieve uploading symbol anyhow based on the @cmelchior script link. Here is the gradle code:

android {
    buildTypes {
        release {
            minifyEnabled true
            firebaseCrashlytics {
                nativeSymbolUploadEnabled true
                unstrippedNativeLibsDir "build/realm/base"
            }
        }
    }
}

afterEvaluate {
    // upload symbol files for Crashlytics NDK reports after generating a release build variant
    assembleProdRelease.finalizedBy(downloadAndUnZipUnstrippedRealmLibrary)
    downloadAndUnZipUnstrippedRealmLibrary.finalizedBy(uploadCrashlyticsSymbolFileProdRelease)
}

task downloadAndUnZipUnstrippedRealmLibrary {
    def src = "https://static.realm.io/downloads/java/realm-java-jni-libs-unstripped-$rootProject.depRealm" +".zip"
    def destdir = "build/realm"
    def destfile = "$destdir/realm-java-jni-libs-unstripped-$rootProject.depRealm" +".zip"
    doLast {
        def url = new URL(src)
        def f = new File(destfile)
        if (f.exists()) {
            println "file $destfile already exists, skipping download"
        } else {
            mkdir "$destdir"
            println "Downloading $destfile from $url..."
            url.withInputStream { i -> f.withOutputStream { it << i } }
        }
        def zipFile = new java.util.zip.ZipFile(new File(destfile))
        zipFile.entries().each {
            def path = java.nio.file.Paths.get("$destdir/$it.name")
            if(it.directory){
                 java.nio.file.Files.createDirectories(path)
            }
            else {
                def parentDir = path.getParent()
                if (! java.nio.file.Files.exists(parentDir)) {
                     java.nio.file.Files.createDirectories(parentDir)
                }
                java.nio.file.Files.copy(zipFile.getInputStream(it), path)
            }
        }
    }
}

Would that be right, enough ?