Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android SQLite database gets corrupted

Tags:

android

sqlite

This link describes my problem exactly: http://old.nabble.com/Android-database-corruption-td28044218.html#a28044218

There are about 300 people using my Android App right now and every once and while I get a crash report to the server with this stack trace:

android.database.sqlite.SQLiteDatabaseCorruptException: database disk image is malformed
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2596)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621)
    at android.app.ActivityThread.access$2200(ActivityThread.java:126)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:4595)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    at dalvik.system.NativeStart.main(Native Method) Caused by: android.database.sqlite.SQLiteDatabaseCorruptException: database disk image is malformed
    at android.database.sqlite.SQLiteQuery.native_fill_window(Native Method)
    at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:75)
    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:295)
    at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:276)
    at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:171)
    at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:248)

The result is the app crashing and all the data in the DB being lost.

One thing to note is that every time I read or write to the database I get a new SQLiteDatabase and close it as soon as I'm done. I did this in an attempt to prevent these kind of corruption errors.

I also tried synchronizing all DB reads and writes using a single static object and that didn't seem to help.

Is it possible this is just a SQLite bug?

I found a similar bug with the built-in email app here: http://code.google.com/p/android/issues/detail?id=5610.

Here is my code:

public class KeyValueTableAdapter extends BaseTableAdapter {

    private String tableName;
    private String keyColumnName;
    private String valueColumnName;

    public KeyValueTableAdapter(Context context, String tableName, String keyColumnName, String valueColumnName) {
        super(context);
        this.tableName = tableName;
        this.keyColumnName = keyColumnName;
        this.valueColumnName = valueColumnName;
    }

    protected String getStringValue(int key) {
        Cursor cursor = null;
        SQLiteDatabase db = null;
        String value;

        try {
            db = dbOpenHelper.getReadableDatabase();
            cursor = db.query(true, tableName, new String[] { valueColumnName }, keyColumnName + "=" + key, null, null, null, null, null);

            if ((cursor.getCount() == 0) || !cursor.moveToFirst()) {
                value = null;
            } else {
                value = cursor.getString(0);
            }
        } finally {
            if (cursor != null) cursor.close();
            if (db != null) db.close();
            dbOpenHelper.close();
        }

        return value;
    }
}


public abstract class BaseTableAdapter {

    protected DbOpenHelper dbOpenHelper;

    public BaseTableAdapter(Context context) {
        this.dbOpenHelper = new DbOpenHelper(context, DatabaseSettings.DATABASE_NAME, null, DatabaseSettings.DATABASE_VERSION);
    }

}
like image 618
Brandon O'Rourke Avatar asked May 05 '10 15:05

Brandon O'Rourke


People also ask

Can SQLite get corrupted?

An SQLite database is highly resistant to corruption. If an application crash, or an operating-system crash, or even a power failure occurs in the middle of a transaction, the partially written transaction should be automatically rolled back the next time the database file is accessed.

How can I tell if SQLite database is corrupted?

To verify that you're truly suffering from database corruption, enter the following command into the shell: sqlite> PRAGMA integrity_check; If the response is anything other than ok, the database is integrity checks have failed and needs to be repaired.

How can I recover SQLite database in Android?

We can retrieve anything from database using an object of the Cursor class. We will call a method of this class called rawQuery and it will return a resultset with the cursor pointing to the table. We can move the cursor forward and retrieve the data. This method return the total number of columns of the table.


1 Answers

Most likely the database process(es) is getting killed during an I/O. For example by a task killer, or if you're allowing db write operations to continue during a time when the app should shutdown or sleep...

See if you can reproduce the issue by putting your app in a DB write loop and using a task killer on it.

Scenario: 32 bytes being written to the database, the writer task gets killed after only writing 10, result: database left in inconsistent and possibly corrupt state.

Also see: Android process killer

EDIT: opening and closing the DB for each read/write? stop that! :)

like image 171
Brad Hein Avatar answered Oct 04 '22 05:10

Brad Hein