Error trying to load SQL Cipher JNI libs using cordova on Android 4.4.2

Hi,

I managed to build sqlicipher 3.2.0. Now, I’m trying to use it in a cordova android project. However I get a runtime error trying to load the sqlite database. failed: dlopen failed: cannot locate symbol "__exidx_end" referenced by "libsqlcipher_android.so"... As of so far I can say this error seems to only happen with devices running Android 4.4.2 (tested with Galaxy S4 and S5), but with Samsung Galxy Note II GT-N7100 with Android 4.1.1 there’s no error. Any idea what could be the cause of this?

What I did was
make init
make
and copied the sqlicphers lib folders content to projects platform/android/lib
and the assets to assets
The import succeeds alright: import net.sqlcipher.database.SQLiteDatabase;
But then the app crashes when I call: SQLiteDatabase.loadLibs(this);

Full error log:

E/dalvikvm(26116): >>>>> Normal User
E/dalvikvm(26116): >>>>> io.cordova.hellocordova [ userId:0 | appId:10241 ]
E/ActivityThread( 1492): Performing stop of activity that is not resumed: {com.sec.android.app.launcher/com.android.launcher2.Launcher}
E/ActivityThread( 1492): java.lang.RuntimeException: Performing stop of activity that is not resumed: {com.sec.android.app.launcher/com.android.launcher2.Launcher}
E/ActivityThread( 1492): 	at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:3333)
E/ActivityThread( 1492): 	at android.app.ActivityThread.handleStopActivity(ActivityThread.java:3420)
E/ActivityThread( 1492): 	at android.app.ActivityThread.access$1200(ActivityThread.java:161)
E/ActivityThread( 1492): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1292)
E/ActivityThread( 1492): 	at android.os.Handler.dispatchMessage(Handler.java:102)
E/ActivityThread( 1492): 	at android.os.Looper.loop(Looper.java:157)
E/ActivityThread( 1492): 	at android.app.ActivityThread.main(ActivityThread.java:5356)
E/ActivityThread( 1492): 	at java.lang.reflect.Method.invokeNative(Native Method)
E/ActivityThread( 1492): 	at java.lang.reflect.Method.invoke(Method.java:515)
E/ActivityThread( 1492): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
E/ActivityThread( 1492): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
E/ActivityThread( 1492): 	at dalvik.system.NativeStart.main(Native Method)
E/dalvikvm(26130): >>>>> Normal User
E/dalvikvm(26130): >>>>> com.sec.kidsplat.installer [ userId:0 | appId:10149 ]
E/dalvikvm(26143): >>>>> Normal User
E/dalvikvm(26143): >>>>> com.samsung.android.app.watchmanagerstub [ userId:0 | appId:10282 ]
E/dalvikvm(26116): dlopen("/data/app-lib/io.cordova.hellocordova-24/libsqlcipher_android.so") failed: dlopen failed: cannot locate symbol "__exidx_end" referenced by "libsqlcipher_android.so"...
E/AndroidRuntime(26116): FATAL EXCEPTION: main
E/AndroidRuntime(26116): Process: io.cordova.hellocordova, PID: 26116
E/AndroidRuntime(26116): java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__exidx_end" referenced by "libsqlcipher_android.so"...
E/AndroidRuntime(26116): 	at java.lang.Runtime.loadLibrary(Runtime.java:365)
E/AndroidRuntime(26116): 	at java.lang.System.loadLibrary(System.java:526)
E/AndroidRuntime(26116): 	at net.sqlcipher.database.SQLiteDatabase.loadLibs(SQLiteDatabase.java:119)
E/AndroidRuntime(26116): 	at net.sqlcipher.database.SQLiteDatabase.loadLibs(SQLiteDatabase.java:113)
E/AndroidRuntime(26116): 	at io.cordova.hellocordova.CordovaApp.InitializeSQLCipher(CordovaApp.java:124)
E/AndroidRuntime(26116): 	at io.cordova.hellocordova.CordovaApp.onCreate(CordovaApp.java:52)
E/AndroidRuntime(26116): 	at android.app.Activity.performCreate(Activity.java:5426)
E/AndroidRuntime(26116): 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
E/AndroidRuntime(26116): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2269)
E/AndroidRuntime(26116): 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
E/AndroidRuntime(26116): 	at android.app.ActivityThread.access$900(ActivityThread.java:161)
E/AndroidRuntime(26116): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
E/AndroidRuntime(26116): 	at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(26116): 	at android.os.Looper.loop(Looper.java:157)
E/AndroidRuntime(26116): 	at android.app.ActivityThread.main(ActivityThread.java:5356)
E/AndroidRuntime(26116): 	at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(26116): 	at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime(26116): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
E/AndroidRuntime(26116): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
E/AndroidRuntime(26116): 	at dalvik.system.NativeStart.main(Native Method)

Hi @timolehto

To rule out a build issue, could you try the community binaries available here?

The prebuilt binaries do seem to work better, thank you. However, should I want to compile it myself, do you have any idea why my build process might have produced partially invalid binaries? I had a weird issue with the android sdk, i had to install android target 7 (2.1) or else it would fail. I found that a bit strange. Is it really even suppose to work with that ancient platforms?

Another problem that I now have is that the standard cordova/phonegap SQLitePlugin expects SQLiteDtabase to have a static method like this, but it seems it doesn’t konw that method? I was digging though the sources and all I could find was some context related methods that took a String as an argument. Was this static version removed or what’s going on? SQLiteDatabase.deleteDatabase(dbfile);

Should I just replace the calls to the static method with ones that use the Context.deleteDatabase(fileString); e.g. something like this:
this.cordova.getActivity().deleteDatabase(dbfile.toString())

Hi @timolehto

I’m glad to hear the community binaries worked. I do not know why your build processed generated that error. SQLCipher for Android supports down to Android 2.1 currently. The Java API for SQLCipher for Android was based on an AOSP snapshot from quite awhile ago, that is possibly why you are seeing different method calls used in the plugin, nothing was specifically removed. You could certainly implement your own version of a delete function for the plugin.

Hi @developernotes
The prebuilt community binaries don’t seem to have FTS4 support? I would have liked to mess around with that too. Is there anything you could possible suggest, any ideas what could have been the source of trouble so that I could compile my own mashup of the features I need?

Hello @timolehto

The community binaries do support FTS, having supported FTS 3 for awhile, we added FTS 4 support with the 3.2.0 release. You can see an example of FTS usage within SQLCipher for Android test suite here.

Oh they do? Hmm… how come it didn’t seem to work for me… I guess it must have been a bug in my code then. I have to do some debugging then…

Or could it be because the database was built with SQLCipher version that did not support it? What I did was created a database locally on my mac and then transferred that on to the phone where I tried to create FTS4 virtual table, but it just refused to do it.

Hi @timolehto

Could you try running the SQLCipher for Android test suite, it is difficult to say why you received that error.

@timolehto Are you still having trouble with this?

I ended up using the prebuilt binaries. They have at least so far sufficed for our use case, so debugging the compilation has not been a high priority. So, in other words I’m not really having trouble with this anymore, since we’ve been able to avoid the need to compile our own binary, but the problems regarding the compilation have not resolved, but would require further investigation from my part.

Hello, I have exacly the same issue.
Trying to load lib /data/app-lib/com.example.pegahybridcontainer-1/libsqlcipher_android.so
E/dalvikvm﹕ dlopen("/libsqlcipher_android.so") failed: dlopen failed: cannot locate symbol “_exidxend” referenced by “libsqlcipher_android.so”…

I downloaded https://github.com/sqlcipher/android-database-sqlcipher, newest ndk, sdk and use android 4.4.4 phone.

make output (dont know why not all went to file):
http://pastebin.com/kAitXGXT

Any ideas?

PS

I also tried to run tests but got same exception

 836-897/net.zetetic E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #1
Process: net.zetetic, PID: 836
java.lang.RuntimeException: An error occured while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:300)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
        at java.util.concurrent.FutureTask.run(FutureTask.java:242)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:841)
 Caused by: java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__exidx_end" referenced by "libsqlcipher_android.so"...
        at java.lang.Runtime.loadLibrary(Runtime.java:364)
        at java.lang.System.loadLibrary(System.java:526)
        at net.sqlcipher.database.SQLiteDatabase.loadLibs(SQLiteDatabase.java:119)
        at net.sqlcipher.database.SQLiteDatabase.loadLibs(SQLiteDatabase.java:113)
        at net.zetetic.tests.TestSuiteRunner.runSuite(TestSuiteRunner.java:34)
        at net.zetetic.tests.TestSuiteRunner.doInBackground(TestSuiteRunner.java:18)
        at net.zetetic.tests.TestSuiteRunner.doInBackground(TestSuiteRunner.java:11)
        at android.os.AsyncTask$2.call(AsyncTask.java:288)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:841)

Hello @ozaru

Did you first perform a make init? Your pastebin output does not show that. If not, please execute make init first, then make.

yes I did and it ended without any errors or warnings.

Hello @ozaru

I wonder if it is an NDK issue (e.g., this references an issue that may be related). Could you try building with the r9d version of the NDK? I’m not aware of your platform, but you can usually adjust the URL to match for your particular version. Here is a link to the r9d x64 NDK as an example:

http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86_64.tar.bz2

Using r9d ndk instead of r10d fixed this problem, thank you very much for quick reply

Hello @ozaru

Thanks for getting back to us, glad to hear that addressed the issue. We will keep an eye out for this.

Hi, if anyone is interested there are at least 2 workarounds reported:

https://code.google.com/p/android/issues/detail?id=109071
Built on NDK r10e - OK
Doesn’t work on API 23


Built on NDK r10e - OK
Works on API 23!

Please, share your results on various other API/NDK versions.