Native runtime crash from SQLCipher for Android

Hi, I’m trying to use SQLCipher in Android Studio following your instruction but once the program reaches SQLiteDatabase.loadLibs(this); it fails both on x86 emulator and on my physical device (Xiaomi Mi4).

Device error output:

01-26 20:56:42.850 12905-12905/com.btcontract.wallet E/dalvikvm: ERROR: couldn't find native method
01-26 20:56:42.850 12905-12905/com.btcontract.wallet E/dalvikvm: Requested: Lnet/sqlcipher/database/SQLiteDatabase;.dbopen:(Ljava/lang/String;I)V
01-26 20:56:42.860 12905-12905/com.btcontract.wallet E/dalvikvm: VM aborting
01-26 20:56:42.860 12905-12905/com.btcontract.wallet A/libc: Fatal signal 6 (SIGABRT) at 0x00003269 (code=-6), thread 12905 (contract.wallet)

Emulator error output:

01-26 20:59:23.040 24802-24802/com.btcontract.wallet E/art: Failed to register native method net.sqlcipher.database.SQLiteDatabase.dbopen(Ljava/lang/String;I)V in /data/app/com.btcontract.wallet-2/base.apk
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art: ----- class 'Lnet/sqlcipher/database/SQLiteDatabase;' cl=0x12d2a2e0 -----
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:   objectSize=476 (136 from super)
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:   access=0x8008.0001
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:   super='java.lang.Class<net.sqlcipher.database.SQLiteClosable>' (cl=0x12d2a2e0)
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:   vtable (5 entries, 2 in super):
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      0: void net.sqlcipher.database.SQLiteDatabase.finalize()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      1: boolean net.sqlcipher.database.SQLiteDatabase.isOpen()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      2: void net.sqlcipher.database.SQLiteDatabase.lock()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      3: void net.sqlcipher.database.SQLiteDatabase.onAllReferencesReleased()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      4: void net.sqlcipher.database.SQLiteDatabase.unlock()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:   direct methods (10 entries):
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      0: void net.sqlcipher.database.SQLiteDatabase.<clinit>()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      1: void net.sqlcipher.database.SQLiteDatabase.checkLockHoldTime()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      2: void net.sqlcipher.database.SQLiteDatabase.closeClosable()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      3: void net.sqlcipher.database.SQLiteDatabase.dbclose()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      4: void net.sqlcipher.database.SQLiteDatabase.deallocCachedSqlStatements()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      5: java.lang.String net.sqlcipher.database.SQLiteDatabase.getTime()
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      6: void net.sqlcipher.database.SQLiteDatabase.loadICUData(android.content.Context, java.io.File)
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      7: void net.sqlcipher.database.SQLiteDatabase.loadLibs(android.content.Context)
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      8: void net.sqlcipher.database.SQLiteDatabase.loadLibs(android.content.Context, java.io.File)
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      9: void net.sqlcipher.database.SQLiteDatabase.setICURoot(java.lang.String)
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:   static fields (4 entries):
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      0: java.lang.String[] net.sqlcipher.database.SQLiteDatabase.CONFLICT_VALUES
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      1: java.util.regex.Pattern net.sqlcipher.database.SQLiteDatabase.EMAIL_IN_DB_PATTERN
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      2: java.util.WeakHashMap net.sqlcipher.database.SQLiteDatabase.sActiveDatabases
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      3: int net.sqlcipher.database.SQLiteDatabase.sQueryLogTimeInMillis
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:   instance fields (11 entries):
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      0: java.util.Map net.sqlcipher.database.SQLiteDatabase.mCompiledQueries
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      1: long net.sqlcipher.database.SQLiteDatabase.mLastLockMessageTime
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      2: java.util.concurrent.locks.ReentrantLock net.sqlcipher.database.SQLiteDatabase.mLock
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      3: long net.sqlcipher.database.SQLiteDatabase.mLockAcquiredThreadTime
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      4: long net.sqlcipher.database.SQLiteDatabase.mLockAcquiredWallTime
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      5: boolean net.sqlcipher.database.SQLiteDatabase.mLockingEnabled
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      6: int net.sqlcipher.database.SQLiteDatabase.mNativeHandle
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      7: java.lang.String net.sqlcipher.database.SQLiteDatabase.mPath
01-26 20:59:23.041 24802-24802/com.btcontract.wallet E/art:      8: java.util.WeakHashMap net.sqlcipher.database.SQLiteDatabase.mPrograms
01-26 20:59:23.042 24802-24802/com.btcontract.wallet E/art:      9: java.lang.Throwable net.sqlcipher.database.SQLiteDatabase.mStackTrace
01-26 20:59:23.042 24802-24802/com.btcontract.wallet E/art:     10: java.lang.String net.sqlcipher.database.SQLiteDatabase.mTimeClosed
01-26 20:59:23.042 24802-24802/com.btcontract.wallet A/art: art/runtime/jni_internal.cc:497] JNI FatalError called: RegisterNatives failed for 'net/sqlcipher/database/SQLiteDatabase'; aborting...
01-26 20:59:23.254 24802-24802/com.btcontract.wallet A/art: art/runtime/barrier.cc:90] Check failed: count_ == 0 (count_=-1, 0=0) Attempted to destroy barrier with non zero count
01-26 20:59:23.254 24802-24802/com.btcontract.wallet A/art: art/runtime/runtime.cc:366] Runtime aborting --- recursively, so no thread-specific detail!
01-26 20:59:23.254 24802-24802/com.btcontract.wallet A/art: art/runtime/runtime.cc:366] 
01-26 20:59:23.254 24802-24802/com.btcontract.wallet A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 24802 (contract.wallet)

Can you please verify your apk is properly including the SQLCipher for Android native libraries? You can dump the packaged content of the apk with apktool.

Sure, here’s how it looks:

anton@anton-VPCCW2S1R:~$ tree '/home/anton/app-debug/lib' 
/home/anton/app-debug/lib
├── armeabi
│   ├── libdatabase_sqlcipher.so
│   ├── libscrypt.so
│   ├── libsqlcipher_android.so
│   └── libstlport_shared.so
├── armeabi-v7a
│   ├── libdatabase_sqlcipher.so
│   ├── libscrypt.so
│   ├── libsqlcipher_android.so
│   └── libstlport_shared.so
├── x86
│   ├── libdatabase_sqlcipher.so
│   ├── libscrypt.so
│   ├── libsqlcipher_android.so
│   └── libstlport_shared.so
└── x86_64
    ├── darwin
    │   └── libscrypt.dylib
    ├── freebsd
    │   └── libscrypt.so
    └── linux
        └── libscrypt.so

7 directories, 15 files

Hi @anton.kumaigorodskiy

The reason you are likely receiving this issue is that SQLCipher for Android is only built for armeabi, armeabi-v7a, and x86 platforms. You are likely deploying to a x86_64 device so Android uses the corresponding folder for resolving all native libraries (i.e., x86_64), as such the SQLCipher for Android binaries are not present in your x86_64 folder. A work around is to remove the x86_64 native libraries entirely, it should fall back to x86 folder for x86_64 devices.

Thanks for suggestions! The issue was not there, however, it was that I have minifyEnabled true in Gradle settings and it looks like ProGuard was cutting some net.sqlcipher.* classes off.

Adding the following to ProGuard settings solved the problem:

-keep class net.sqlcipher.** { *; }
-dontwarn net.sqlcipher.**

Hello @anton.kumaigorodskiy

Great, I’m glad to hear you were able to solve the issue! Please note, you will see the issue I describe above on an x86_64 device so you may consider adjusting for that as well.

Can You share whole code of gradle to resolve above issues?

yes,


Hi, I am new to SQLCipher, I just started integrating it to some messed up SQLite project and I could not understand even a thing.

Zygote’s thread crashed with really large log and I freaked out. I really appreciate you sharing that, you saved my day or even a week figuring that out.

So this worked for me but I guess proguard rules also working. Now it works out of the box as expected with just small hacks in the code.

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

I suppose you should add that gradle stuff to main howto on github page cause that’s really confusing issue.

Hi @POMATu

Thank you for the feedback, we will consider integrating ProGuard into the library build itself.