问题描述
安装某三方应用后,启动应用,应用crash. crash log中出现如下类似LOG:
SQLite: No Such Table Error' after copying database from assets
android.database.sqlite.SQLiteException: no such table: xxxxxxxx
crash不一定是报在数据库中,可能是某个逻辑报空指针异常之类的。
但这类问题很可能是因为数据库中查不到数据,导致了空指针异常。
解决方案
出现问题的原因是这类APP创建数据库是用APP的asset目录下copy数据库文件到databases目录下,
而这类数据库如果被用WAL mode打开,就会被数据回滚成只有一个meta表,导致其他表都不存在,
下面这个highlight的位置的修改导致P版本如果没设置SQLiteDatabase.DISABLE_COMPATIBILITY_WAL 这个FLAG
都会默认走WAL mode, 而许多三方APP都没设置这个FLAG导致安装到P版本就会有问题 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index 361b81b..23c07204 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -289,14 +289,19 @@ private void setWalModeFromConfiguration() { if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { - boolean walEnabled = + final boolean walEnabled = (mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0; - if (walEnabled || mConfiguration.useCompatibilityWal) { + // Use compatibility WAL unless an app explicitly set journal/synchronous mode + final boolean useCompatibilityWal = mConfiguration.journalMode == null + && mConfiguration.syncMode == null && mConfiguration.useCompatibilityWal; + if (walEnabled || useCompatibilityWal) {//这个地方的修改导致走了wal mode,去掉useCompatibilityWal 就OK了. setJournalMode("WAL"); setSyncMode(SQLiteGlobal.getWALSyncMode()); } else { - setJournalMode(SQLiteGlobal.getDefaultJournalMode()); - setSyncMode(SQLiteGlobal.getDefaultSyncMode()); + setJournalMode(mConfiguration.journalMode == null + ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode); + setSyncMode(mConfiguration.syncMode == null + ? SQLiteGlobal.getDefaultSyncMode() : mConfiguration.syncMode); } |
正解 应该是通知三方APP 在openDatabase的时候都加上这个FLAG DISABLE_COMPATIBILITY_WAL,因为下面的代码会让APP
默认走WAL mode.
1 2 3 4 |
198 boolean useCompatibilityWal() { 199 return journalMode == null && syncMode == null 200 && (openFlags & SQLiteDatabase.DISABLE_COMPATIBILITY_WAL) == 0; 201 } |
前面修改framework代码的解法如果不带白名单修改,就会导致APP 默认都走 FULL mode, full mode在写数据库方面
性能是要比 WAL mode 差一些。