我们在混淆的(Dexguard)Android 应用程序中在 Android 4.4.2(Nexus 7 平板电脑)上使用 SQLite(实际上是 SQLCipher)。我们有 ContentProviders 来访问 SQLite/SQLCipher 数据库。这些 ContentProvider 之一从队列表返回消息。这个队列被定期处理——我们从队列中检索消息,然后使用 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
}
}
这在我们自己的开发和测试过程中可靠地工作,但是在该领域我们看到偶尔但重复的问题,在成功处理排队的消息后,上面的 cursor.moveToNext() 调用抛出 IllegalStateException (注意,总是行 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)
在其他情况下,此行会抛出 CursorIndexOutOfBoundsException (注意每次报告的实际索引/大小更改):
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)
我们无法重现这两个问题,只有日志文件可以继续。这些日志表明问题发生在成功处理一行之后。在此异常之后,该过程将重新启动并继续进行而没有问题。我们无法理解为什么 moveToNext 会抛出任何一个异常——例如,如果它适用于第 1-10 行,为什么移动到第 11 行会抛出异常?Cursor.moveToNext的文档说:
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.
因此它应该成功移动到下一个(并返回 true)或失败(并返回 false),而不是抛出这些奇怪的异常。
这听起来像是我们代码中的问题,还是 SQLite 问题、SQLCipher 问题,或者与我们的混淆过程有关,无论是使用 Dexguard 还是我们如何使用它?有什么建议吗?