We are using SQLite (actually SQLCipher) on Android 4.4.2 (Nexus 7 tablets) within an obfuscated (Dexguard) Android application. We have ContentProviders to access the SQLite/SQLCipher database. One of these ContentProviders returns messages from a queue table. This queue gets regularly processed - we retrieve the messages from the queue and then iterate over them using cursor.moveToNext():
// Get cursor to iterate unsent messages
Cursor cursor = queueHelper.getMessages(Queue.STATUS_NEW);
try {
// Check if there are any unsent messages
if (cursor == null || cursor.getCount() == 0) {
// No queued messages to send
return;
}
// Send messages
while (cursor.moveToNext()) {
// Do stuff
}
}
This worked reliably during our own development and testing, however in the field we're seeing occasional but repeated issues where, after successfully processing a queued message, the cursor.moveToNext() call above is throwing an IllegalStateException (note, always row 0 col 0):
java.lang.IllegalStateException: get field slot from row 0 col 0 failed
at net.sqlcipher.CursorWindow.getLong_native(Native Method)
at net.sqlcipher.CursorWindow.getLong(:446)
at net.sqlcipher.AbstractWindowedCursor.getLong(:110)
at net.sqlcipher.AbstractCursor.moveToPosition(:199)
at net.sqlcipher.AbstractCursor.moveToNext(:228)
at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
On other occasions this line is instead throwing a CursorIndexOutOfBoundsException (note actual index/size reported changes each time):
net.sqlcipher.CursorIndexOutOfBoundsException: Index 98 requested, with a size of 98
at net.sqlcipher.AbstractCursor.?(:556)
at net.sqlcipher.AbstractWindowedCursor.?(:222)
at net.sqlcipher.AbstractWindowedCursor.getLong(:101)
at net.sqlcipher.AbstractCursor.moveToPosition(:199)
at net.sqlcipher.AbstractCursor.moveToNext(:228)
at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
We haven't been able to reproduce either problem and only have log files to go on. These logs indicate that the problem occurs after successfully processing a row. After this exception, the process is restarted and carries on without issue. We cannot understand why moveToNext could throw either exception - e.g. if it worked on rows 1-10, why would moving to row 11 throw an exception? Documentation for Cursor.moveToNext says:
Move the cursor to the next row.
This method will return false if the cursor is already past the last entry in the result set.
Therefore it should successfully move to next (and return true) or fail (and return false), not throw these odd exceptions.
Does this sound like an issue within our code or could it be a SQLite issue, a SQLCipher issue, or related to our obfuscation process, either with Dexguard, or how we use it? Any advice?