Sqlcipher crash on android over time

Hi Sqlcipher team:

We recently got a crash issue on Android 7 with sqlcipher v5.3.6. The exception is throw when the app first call getWritableDatabase. The strange part is that: it happens after the app is installed and being played for one day or two days later. Once it happened, user cannot successfully launch app anymore. If user reinstalls the app, it works again (or use adb reinstall directly, no need to delete, which means database file is not corrupted), however the crash will happen one or two days later.

We initialize the SQLiteOpenHelper with null factory, so it suppose to return a new SQLiteCursor (SQLiteDirectCursorDriver.java) to CursorWrapper. How come mCursor inside CursorWrapper became null…?

Our application is built with multidex android platform 23 by Unity. We need your help with this critical issue. Thank you.

java.lang.RuntimeException: Unable to start activity ComponentInfo{MY_ACTIVITY}: java.lang.NullPointerException: Attempt to invoke interface method ‘boolean android.database.Cursor.moveToFirst()’ on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2711)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2772)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1515)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:241)
at android.app.ActivityThread.main(ActivityThread.java:6223)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method ‘boolean android.database.Cursor.moveToFirst()’ on a null object reference
at android.database.CursorWrapper.moveToFirst(CursorWrapper.java:71)
at net.sqlcipher.database.SQLiteDatabase.keyDatabase(SQLiteDatabase.java:2488)
at net.sqlcipher.database.SQLiteDatabase.openDatabaseInternal(SQLiteDatabase.java:2415)
at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1149)
at net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1212)
at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:162)
at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:129)
at MY_PACKAGE.StepEnctyptDatabase.getDatabase(StepEnctyptDatabase.java:123)
at MY_PACKAGE.StepEnctyptDatabase.getDbStatusItem(StepEnctyptDatabase.java:209)
at MY_PACKAGE.StepEnctyptDatabase.checkNeedMigration(StepEnctyptDatabase.java:183)
at MY_PACKAGE.StepEnctyptDatabase.getSharedDatabase(StepEnctyptDatabase.java:90)
at MY_PACKAGE.SWUnityExternalJavaPlugin.onCreate(SWUnityExternalJavaPlugin.java:134)
at android.app.Activity.performCreate(Activity.java:6705)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2664)
… 9 more

Hi @developernotes, I used the latest commit you mentioned (Latest sqlcipher-for-android-v3.5.6.zip). I removed the initial check in method keydatabase of SQLiteDatabase

try {
Cursor cursor = rawQuery(“select count(*) from sqlite_master;”, new String[]{});
if(cursor != null){
cursor.moveToFirst();
int count = cursor.getInt(0);
cursor.close();
}
} catch (RuntimeException e) {
Log.e(TAG, e.getMessage(), e);
throw e;
}

then it turns out another issue i post here before: https://github.com/sqlcipher/android-database-sqlcipher/issues/324

Hello @llmagicll

It would seem you are having a different issue than what we are investigating. When you leaving the query in place (querying sqlite_master) that executes following the keying operating against the database, what behavior do you experience? When you are receiving result 21 (SQLITE_MISUSE) following the removal of the query against sqlite_master, was that with the library you built yourself, our our provided library?

1. When you leaving the query in place (querying sqlite_master) that executes following the keying operating against the database

It works the same as original. It just skips the exception of null mCursor and leading net.sqlcipher.database.SQLiteMisuseException after playing one day later.

2 When you are receiving result 21 (SQLITE_MISUSE) following the removal of the query against sqlite_master, was that with the library you built yourself, our our provided library?

I used the library built myself with the latest commit from github

Due to too many crash report by users. We temporarily disabled multidex by removing serval SDKs and services. And the issue doesn’t happen anymore. We are still figuring it out and will update any further progress to the issue. Thanks @developernotes

Now that you have both disabled multiplex, and several other SDK’s and it is not presenting the erroneous behavior, does enabling multiplex while keeping the other SDK’s removed from the application still allow SQLCipher for Android to operate properly?