Sqlite error on Android: error code 11: database disk image is malformed

10

I have a version of the Application in production, where it is allowed to mark a message as a favorite, but this totally random error happens causing database corruption and resulting in application failure.

I know that I do a little risky operations according to the SQLite staff themselves.

The procedure is as follows:

  • start the upgrade procedure
  • copies the user database to a temporary file
  • copies the new database to the device
  • attaches the old base to the new
  • copies required data (such as favorite messages)
  • Detach temporary base
  • exclude temporary base

This procedure is done on thousands of devices, mostly everything is fine, but it has started to become a frequent case.

Does anyone know how to minimize this?

ERROR:

java.lang.RuntimeException: Unable to start activity ComponentInfo{br.com.redrails.torpedos/br.com.redrails.torpedos.MainActivity}: android.database.sqlite.SQLiteDatabaseCorruptException: error code 11: database disk image is malformed
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1970)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1995)
    at android.app.ActivityThread.access$600(ActivityThread.java:128)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1161)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4514)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: android.database.sqlite.SQLiteDatabaseCorruptException: error code 11: database disk image is malformed
    at android.database.sqlite.SQLiteStatement.native_1x1_long(Native Method)
    at android.database.sqlite.SQLiteStatement.simpleQueryForLong(SQLiteStatement.java:138)
    at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:791)
    at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:779)
    at br.com.redrails.torpedos.MensagemDAO.reloadQuantidadeTotal(MensagemDAO.java:144)
    at br.com.redrails.torpedos.MensagemDAO.getQuantidadeTotal(MensagemDAO.java:149)
    at br.com.redrails.torpedos.MainActivity.onCreate(MainActivity.java:85)
    at android.app.Activity.performCreate(Activity.java:4465)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1053)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1934)
    ... 11 more
    
asked by anonymous 15.12.2013 / 12:33

2 answers

1

A few months ago we started getting many reports of users complaining about crashes in one of our apps. During the investigation of the problem, it was clear that the error was due to some corruption in the SQLite file. I observed that this problem also existed from a certain period until then. I also saw that this error occurred in particular with newer devices that have more processing cores and higher clock and that in older devices less powerful and especially with only one core this error occurred very little or simply did not occur. This led me to conclude that the problem was competition. That here was linked to access by multiple Threads to SQLite .

After some research and testing I have seen the following points:

For each database, only one SqliteOpenHelper should exist. As it may seem, there are no multiple connections to the database. A SqliteOpenHelper has only one connection. Ever. Even though the getWritableDatabase and getReadableDatabase methods make it appear that there are two different connections, it just does not happen: it's the same connection.

This ensures that there are no collisions, concurrent access, to the database file.

In the case of the application in question, there were multiple SqliteOpenHelper and multiple Threads. The solution was a general refactoring in persistence with the goal of only having SqliteOpenHelper for each database (in this case there were three). There was thus a strong reduction in the occurrences of the problem, however there were still occurrences.

Finally, database access methods were synchronized to avoid concurrent access to SqliteOpenHelper . This was a measure that did not affect the performance of the application, but that should be analyzed for each case.

In short:

  • Keep only SqliteOpenHelper per database
  • If necessary and workable, synchronize access
  • 04.02.2014 / 12:28
    1

    I think it's worth studying the possibility of implementing a PUSH service to synchronize your databases, so everything would be done invisibly to the user and also in a more secure way.

    A good place to create free WS and also use free PUSH for both Android and iOS is link

        
    03.01.2014 / 20:19