realm / realm-java

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

Realm stops working in debug mode when externalNativeBuild is modified. #7288

Closed dsemelianov closed 2 years ago

dsemelianov commented 3 years ago

Goal

Add a different native library (not Realm) to my Android project, without breaking Realm when in debug mode.

Actual Results

I have an Android app which uses Realm, and works fine. But when I add a native library to the app (not Realm), then things stop working. It seems that changing my build.gradle to specify an externalNativeBuild which references CMake causes Realm to break BUT ONLY IN DEBUG MODE.

Steps & Code to Reproduce

Steps to reproduce:

1) Integrate Realm to your Android app via maven.

2) Update my build.grade with this (needed for the new library I'm adding):

externalNativeBuild {
            cmake {
                arguments '-DANDROID_PLATFORM=android-19', '-DANDROID_TOOLCHAIN=clang', '-DANDROID_ARM_NEON=TRUE', '-DANDROID_STL=c++_static', "-DPATH_TO_SUPERPOWERED:STRING=${superpowered_sdk_path}"
                cFlags '-O3', '-fsigned-char' // full optimization, char data type is signed
                cppFlags '-fsigned-char', "-I${superpowered_sdk_path}"
            }
        }

3) Run the app in debug mode

4) LLDB debugger hits 3 breakpoints, although code is not visible. The error for each of these breakpoints is as follows:

SIGSEGV (signal SIGSEGV: invalid address (fault address: 0x0)) SIGSEGV (signal SIGSEGV: address access protected (fault address: 0xab39bf40)) SIGSEGV (unknown crash reason)

5) Even though I have breakpoints in my Java code, none of them are triggered.

6) The app crashes, and logcat show an exception from those Java lines on which I had breakpoints set in step 5. The failure occurs because I am expecting to find a Realm object which does not exist. It appears that the crash from the LLDB debugger is preventing Realm from working properly, so my Java logic is breaking too.

6) After the crash, looking at the logcat, I also see some failures around the SIGSEGV:

2021-02-01 11:42:48.739 32229-32229/? E/adbd: failed to connect to socket 'localabstract:/com.emelianov.audio-0/platform-1612197760986.sock': Connection refused
2021-02-01 11:42:59.181 18982-18982/com.emelianov.audio E/RecyclerView: No adapter attached; skipping layout
2021-02-01 11:44:31.678 18982-18982/com.emelianov.audio A/libc: Fatal signal 11 (SIGSEGV), code 0, fault addr 0x4aaf in tid 18982 (emelianov.audio), pid 18982 (emelianov.audio)
2021-02-01 11:44:39.922 18982-18982/com.emelianov.audio A/libc: crash_dump helper failed to exec
2021-02-01 11:44:39.924 18982-18982/com.emelianov.audio A/libc: failed to wait for crash_dump helper: No child processes
2021-02-01 11:44:47.004 1271-1681/? E/InputDispatcher: channel '21319d4 com.emelianov.audio/com.emelianov.audio.activities.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!

The weird thing is that whenever I run the app in non-debug mode, everything works fine. Both Realm and the new native library that I am adding work just fine. I'm new to using native libraries in Android, so is it possible that I'm initializing the CMake incorrectly?

Anyway, here's my build.grade and CMakeLists.txt:

build.grade:

buildscript {
    repositories {
        mavenCentral()
        maven {
            url "https://jitpack.io"
        }
        maven {
            url "https://maven.google.com"
        }
        jcenter()
        google()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.2'
        classpath 'com.google.gms:google-services:4.3.4'
        classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1'
        classpath "io.realm:realm-gradle-plugin:10.3.1"
    }
}

apply plugin: 'com.android.application'
apply plugin: 'realm-android'

def superpowered_sdk_path = new File(projectDir, '../SuperpoweredSDK/Superpowered')

repositories {
    mavenCentral()
    maven {
        url "https://jitpack.io"
    }
    maven {
        url "https://maven.google.com"
    }
    jcenter()
    google()
}

android {
    compileSdkVersion 29
    buildToolsVersion '29.0.3'

    defaultConfig {
        applicationId "{myapplicationid}"
        minSdkVersion 24
        targetSdkVersion 29
        versionCode 320
        versionName "21.151.2"

        ndk { // these platforms cover 99.9% percent of all Android devices
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }

        compileOptions {
            incremental false
        }

        externalNativeBuild {
            cmake {
                arguments '-DANDROID_PLATFORM=android-19', '-DANDROID_TOOLCHAIN=clang', '-DANDROID_ARM_NEON=TRUE', '-DANDROID_STL=c++_static', "-DPATH_TO_SUPERPOWERED:STRING=${superpowered_sdk_path}"
                cFlags '-O3', '-fsigned-char' // full optimization, char data type is signed
                cppFlags '-fsigned-char', "-I${superpowered_sdk_path}"
            }
        }
    }

    buildTypes {
        release {
            shrinkResources false
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            jniLibs.srcDir 'libs'
            jni.srcDirs = []
        }

        // Move the tests to tests/java, tests/res, etc...
        androidTest.setRoot('tests')

        // Move the build types to build-types/<type>
        // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
        // This moves them out of them default location under src/<type>/... which would
        // conflict with src/ being used by the main source set.
        // Adding new build types or product flavors should be accompanied
        // by a similar customization.
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }

    compileOptions {
        sourceCompatibility = '1.8'
        targetCompatibility = '1.8'
    }

    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }

    ndkVersion '21.3.6528147'

}

dependencies {

    ... a bunch of dependencies

    implementation fileTree(include: '*.jar', dir: 'libs')

    ... more dependencies

}

apply plugin: 'com.google.gms.google-services'

apply plugin: 'com.google.firebase.crashlytics'

allprojects {
    repositories {
        jcenter()
        google()
    }
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.4.1)

# convert SDK path to forward slashes on Windows
file(TO_CMAKE_PATH ${PATH_TO_SUPERPOWERED} PATH_TO_SUPERPOWERED)

#include_directories(src/main/cpp)
include_directories(${PATH_TO_SUPERPOWERED})

# compile player example to a native library
add_library (
        PlayerExample
        SHARED
        jni/PlayerExample.cpp
        ${PATH_TO_SUPERPOWERED}/OpenSource/SuperpoweredAndroidAudioIO.cpp
)

# link the native library against the following libraries
target_link_libraries (
        PlayerExample
        log
        android
        OpenSLES
        ${PATH_TO_SUPERPOWERED}/libSuperpoweredAndroid${ANDROID_ABI}.a
)

Version of Realm and tooling

Realm version(s): io.realm:realm-gradle-plugin:10.3.1

Realm Sync feature enabled: No

Android Studio version: 4.1.2

Android Build Tools version: 29.0.3

Gradle version: 6.5

Which Android version and device(s): Android version 8.1.0 on an LG Phoenix 4

clementetb commented 3 years ago

Have you tried debugging the app without the realm library?

bmunkholm commented 2 years ago

@dsemelianov I'm closing this since you haven't responded and I assume you have resolved the issue.