sqlcipher / android-database-sqlcipher

Android SQLite API based on SQLCipher
https://www.zetetic.net/sqlcipher/sqlcipher-for-android/
Other
2.73k stars 564 forks source link

Database gets corrupted if the database is open while the application is updated #629

Open manabreak opened 11 months ago

manabreak commented 11 months ago

Expected Behavior

The database should work normally after the application is updated.

Actual Behavior

Database gets corrupted.

Steps to Reproduce

While performing database operations, update the application (e.g. automatic update via Google Play) and restart the application.

SQLCipher for Android version: 4.5.3 (with Jetpack Room 2.4.3)

Additional info

This is visible as a SQLiteException in Crashlytics, spiking every time we update our application. We perform database operations in the background once per hour, and with a large userbase, it seems that a lot of users have the background DB operations running when the app starts updating itself.

sjlombardo commented 11 months ago

This report is a bit light on details, for example the exact exception being reported, whether you have been able to inspect a database that is supposedly in a corrupted state, what operations are running at the time the application updates, etc.

In terms of initial suggestions, we would recommend updating to 4.5.4. There was a change in that version that fixed an issue where the use of an incorrect encryption key could be mistakenly reported as database corruption. If something is happening during or immediately after the update that affects the key, it is possible that a corruption exception was being thrown incorrectly. I would update to that version, and then see if the incidents of corruption reports changes (i.e. they switch to a different error).

sjlombardo commented 11 months ago

Hello @manabreak - disregard the note about the issue I mentioned. That was with the separate sqlcipher-android project that is now replacing android-database-sqlcipher.

Can you provide the details above, te exact exception being reported, whether you have been able to inspect a database that is supposedly in a corrupted state, what operations are running at the time the application updates?

manabreak commented 11 months ago

Sorry for the lack of details, was in a hurry on Friday. That said, there's not much to work with here. The exception in Crashlytics looks like this:

Fatal Exception: java.lang.RuntimeException: Unable to create application com.example.BaseApplication: net.sqlcipher.database.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master;
       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7228)
       at android.app.ActivityThread.access$1500(ActivityThread.java:269)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2166)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:239)
       at android.app.ActivityThread.main(ActivityThread.java:8218)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:626)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1015)

Which is followed by the caused-by stack trace:

Caused by net.sqlcipher.database.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master;
       at net.sqlcipher.database.SQLiteCompiledSql.native_compile(SQLiteCompiledSql.java)
       at net.sqlcipher.database.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:89)
       at net.sqlcipher.database.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:62)
       at net.sqlcipher.database.SQLiteProgram.<init>(SQLiteProgram.java:91)
       at net.sqlcipher.database.SQLiteQuery.<init>(SQLiteQuery.java:48)
       at net.sqlcipher.database.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:60)
       at net.sqlcipher.database.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:2016)
       at net.sqlcipher.database.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1902)
       at net.sqlcipher.database.SQLiteDatabase.keyDatabase(SQLiteDatabase.java:2669)
       at net.sqlcipher.database.SQLiteDatabase.openDatabaseInternal(SQLiteDatabase.java:2599)
       at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1247)
       at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1214)
       at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1186)
       at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1135)
       at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1089)

This exception is thrown when we are trying to open the database. This only happens in production, and we haven't had anyone reaching to us regarding this issue, so we haven't been able to inspect the databases. There might be any number of operations going on when the apps update since we don't have access to the production cases. The app synchronizes data to the local database quite often, and with a large-ish user base, it spikes quite heavily after each app update.

dazza5000 commented 7 months ago

This can happen if you are using the wrong/a different passphrase when re-opening the db.