From 7f13b62215dbe08da57f42c84867b9e861d86896 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Thu, 29 Mar 2018 23:51:33 -0700 Subject: [PATCH] Revert "Fix SQLiteDatabaseLockedException" This reverts commit 3c532f1ac527beecabe77ec94374a025ecd563e9. --- .../github/shadowsocks/database/LockUtils.kt | 61 ---------------- .../shadowsocks/database/PrivateDatabase.kt | 70 +++++++++---------- .../shadowsocks/database/ProfileManager.kt | 22 ++---- .../shadowsocks/database/PublicDatabase.kt | 11 ++- .../preference/OrmLitePreferenceDataStore.kt | 29 ++++---- 5 files changed, 60 insertions(+), 133 deletions(-) delete mode 100644 mobile/src/main/java/com/github/shadowsocks/database/LockUtils.kt diff --git a/mobile/src/main/java/com/github/shadowsocks/database/LockUtils.kt b/mobile/src/main/java/com/github/shadowsocks/database/LockUtils.kt deleted file mode 100644 index d04a9a18..00000000 --- a/mobile/src/main/java/com/github/shadowsocks/database/LockUtils.kt +++ /dev/null @@ -1,61 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.database - -import android.database.sqlite.SQLiteDatabaseLockedException -import com.j256.ormlite.dao.Dao -import com.j256.ormlite.support.ConnectionSource -import com.j256.ormlite.table.TableUtils -import java.sql.SQLException - -private val Throwable.ultimateCause: Throwable get() { - var result = this - while (true) { - val cause = result.cause ?: return result - result = cause - } -} - -@Throws(SQLException::class) -fun safeWrapper(func: () -> T): T { - while (true) { - try { - return func() - } catch (e: SQLException) { - if (e.ultimateCause !is SQLiteDatabaseLockedException) throw e - } - } -} - -@Throws(SQLException::class) -inline fun ConnectionSource.createTableSafe() = safeWrapper { TableUtils.createTable(this, T::class.java) } -@Throws(SQLException::class) -fun Dao.queryAllSafe(): MutableList = safeWrapper { queryForAll() } -@Throws(SQLException::class) -fun Dao.queryByIdSafe(id: ID?): T? = safeWrapper { queryForId(id) } -@Throws(SQLException::class) -fun Dao.updateSafe(data: T?): Int = safeWrapper { update(data) } -@Throws(SQLException::class) -fun Dao.replaceSafe(data: T?): Dao.CreateOrUpdateStatus? = safeWrapper { createOrUpdate(data) } -@Throws(SQLException::class) -fun Dao.deleteByIdSafe(id: ID?) = safeWrapper { deleteById(id) } -@Throws(SQLException::class) -fun Dao.executeSafe(statement: String?) = safeWrapper { executeRawNoArgs(statement) } diff --git a/mobile/src/main/java/com/github/shadowsocks/database/PrivateDatabase.kt b/mobile/src/main/java/com/github/shadowsocks/database/PrivateDatabase.kt index f77e4862..52215aa4 100644 --- a/mobile/src/main/java/com/github/shadowsocks/database/PrivateDatabase.kt +++ b/mobile/src/main/java/com/github/shadowsocks/database/PrivateDatabase.kt @@ -37,18 +37,18 @@ object PrivateDatabase : OrmLiteSqliteOpenHelper(app, Key.DB_PROFILE, null, 25) @Suppress("UNCHECKED_CAST") val kvPairDao: Dao by lazy { getDao(KeyValuePair::class.java) as Dao } - override fun onCreate(database: SQLiteDatabase?, connectionSource: ConnectionSource) { - connectionSource.createTableSafe() - connectionSource.createTableSafe() + override fun onCreate(database: SQLiteDatabase?, connectionSource: ConnectionSource?) { + TableUtils.createTable(connectionSource, Profile::class.java) + TableUtils.createTable(connectionSource, KeyValuePair::class.java) } - private fun recreate(database: SQLiteDatabase?, connectionSource: ConnectionSource) { + private fun recreate(database: SQLiteDatabase?, connectionSource: ConnectionSource?) { TableUtils.dropTable(connectionSource, Profile::class.java, true) TableUtils.dropTable(connectionSource, KeyValuePair::class.java, true) onCreate(database, connectionSource) } - override fun onUpgrade(database: SQLiteDatabase?, connectionSource: ConnectionSource, + override fun onUpgrade(database: SQLiteDatabase?, connectionSource: ConnectionSource?, oldVersion: Int, newVersion: Int) { if (oldVersion < 7) { recreate(database, connectionSource) @@ -57,38 +57,38 @@ object PrivateDatabase : OrmLiteSqliteOpenHelper(app, Key.DB_PROFILE, null, 25) try { if (oldVersion < 8) { - profileDao.executeSafe("ALTER TABLE `profile` ADD COLUMN udpdns SMALLINT;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN udpdns SMALLINT;") } if (oldVersion < 9) { - profileDao.executeSafe("ALTER TABLE `profile` ADD COLUMN route VARCHAR DEFAULT 'all';") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN route VARCHAR DEFAULT 'all';") } else if (oldVersion < 19) { - profileDao.executeSafe("UPDATE `profile` SET route = 'all' WHERE route IS NULL;") + profileDao.executeRawNoArgs("UPDATE `profile` SET route = 'all' WHERE route IS NULL;") } if (oldVersion < 11) { - profileDao.executeSafe("ALTER TABLE `profile` ADD COLUMN ipv6 SMALLINT;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN ipv6 SMALLINT;") } if (oldVersion < 12) { - profileDao.executeSafe("BEGIN TRANSACTION;") - profileDao.executeSafe("ALTER TABLE `profile` RENAME TO `tmp`;") - connectionSource.createTableSafe() - profileDao.executeSafe( + profileDao.executeRawNoArgs("BEGIN TRANSACTION;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;") + TableUtils.createTable(connectionSource, Profile::class.java) + profileDao.executeRawNoArgs( "INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route," + " proxyApps, bypass, udpdns, ipv6, individual) " + "SELECT id, name, host, localPort, remotePort, password, method, route, 1 - global," + " bypass, udpdns, ipv6, individual FROM `tmp`;") - profileDao.executeSafe("DROP TABLE `tmp`;") - profileDao.executeSafe("COMMIT;") + profileDao.executeRawNoArgs("DROP TABLE `tmp`;") + profileDao.executeRawNoArgs("COMMIT;") } else if (oldVersion < 13) { - profileDao.executeSafe("ALTER TABLE `profile` ADD COLUMN tx LONG;") - profileDao.executeSafe("ALTER TABLE `profile` ADD COLUMN rx LONG;") - profileDao.executeSafe("ALTER TABLE `profile` ADD COLUMN date VARCHAR;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN tx LONG;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN rx LONG;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN date VARCHAR;") } if (oldVersion < 15) { - if (oldVersion >= 12) profileDao.executeSafe("ALTER TABLE `profile` ADD COLUMN userOrder LONG;") + if (oldVersion >= 12) profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN userOrder LONG;") var i = 0L val apps by lazy { app.packageManager.getInstalledApplications(0) } - for (profile in profileDao.queryAllSafe()) { + for (profile in profileDao.queryForAll()) { if (oldVersion < 14) { val uidSet = profile.individual.split('|').filter(TextUtils::isDigitsOnly) .map(String::toInt).toSet() @@ -96,28 +96,28 @@ object PrivateDatabase : OrmLiteSqliteOpenHelper(app, Key.DB_PROFILE, null, 25) .joinToString("\n") { it.packageName } } profile.userOrder = i - profileDao.updateSafe(profile) + profileDao.update(profile) i += 1 } } if (oldVersion < 16) { - profileDao.executeSafe( + profileDao.executeRawNoArgs( "UPDATE `profile` SET route = 'bypass-lan-china' WHERE route = 'bypass-china'") } if (oldVersion < 21) { - profileDao.executeSafe("ALTER TABLE `profile` ADD COLUMN remoteDns VARCHAR DEFAULT '8.8.8.8';") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN remoteDns VARCHAR DEFAULT '8.8.8.8';") } if (oldVersion < 17) { - profileDao.executeSafe("ALTER TABLE `profile` ADD COLUMN plugin VARCHAR;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN plugin VARCHAR;") } else if (oldVersion < 22) { // upgrade kcptun to SIP003 plugin - profileDao.executeSafe("BEGIN TRANSACTION;") - profileDao.executeSafe("ALTER TABLE `profile` RENAME TO `tmp`;") - connectionSource.createTableSafe() - profileDao.executeSafe( + profileDao.executeRawNoArgs("BEGIN TRANSACTION;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;") + TableUtils.createTable(connectionSource, Profile::class.java) + profileDao.executeRawNoArgs( "INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, " + "remoteDns, proxyApps, bypass, udpdns, ipv6, individual, tx, rx, date, userOrder, " + "plugin) " + @@ -125,17 +125,17 @@ object PrivateDatabase : OrmLiteSqliteOpenHelper(app, Key.DB_PROFILE, null, 25) "CASE WHEN kcp = 1 THEN kcpPort ELSE remotePort END, password, method, route, " + "remoteDns, proxyApps, bypass, udpdns, ipv6, individual, tx, rx, date, userOrder, " + "CASE WHEN kcp = 1 THEN 'kcptun ' || kcpcli ELSE NULL END FROM `tmp`;") - profileDao.executeSafe("DROP TABLE `tmp`;") - profileDao.executeSafe("COMMIT;") + profileDao.executeRawNoArgs("DROP TABLE `tmp`;") + profileDao.executeRawNoArgs("COMMIT;") } if (oldVersion < 23) { - profileDao.executeSafe("BEGIN TRANSACTION;") - connectionSource.createTableSafe() - profileDao.executeSafe("COMMIT;") + profileDao.executeRawNoArgs("BEGIN TRANSACTION;") + TableUtils.createTable(connectionSource, KeyValuePair::class.java) + profileDao.executeRawNoArgs("COMMIT;") val old = PreferenceManager.getDefaultSharedPreferences(app) - PublicDatabase.kvPairDao.replaceSafe(KeyValuePair(Key.id).put(old.getInt(Key.id, 0))) - PublicDatabase.kvPairDao.replaceSafe(KeyValuePair(Key.tfo).put(old.getBoolean(Key.tfo, false))) + PublicDatabase.kvPairDao.createOrUpdate(KeyValuePair(Key.id).put(old.getInt(Key.id, 0))) + PublicDatabase.kvPairDao.createOrUpdate(KeyValuePair(Key.tfo).put(old.getBoolean(Key.tfo, false))) } if (oldVersion < 25) { diff --git a/mobile/src/main/java/com/github/shadowsocks/database/ProfileManager.kt b/mobile/src/main/java/com/github/shadowsocks/database/ProfileManager.kt index 2f81a725..15ef7c82 100644 --- a/mobile/src/main/java/com/github/shadowsocks/database/ProfileManager.kt +++ b/mobile/src/main/java/com/github/shadowsocks/database/ProfileManager.kt @@ -48,12 +48,10 @@ object ProfileManager { profile.individual = oldProfile.individual profile.udpdns = oldProfile.udpdns } - val last = safeWrapper { - PrivateDatabase.profileDao.queryRaw(PrivateDatabase.profileDao.queryBuilder() + val last = PrivateDatabase.profileDao.queryRaw(PrivateDatabase.profileDao.queryBuilder() .selectRaw("MAX(userOrder)").prepareStatementString()).firstResult - } if (last != null && last.size == 1 && last[0] != null) profile.userOrder = last[0].toLong() + 1 - PrivateDatabase.profileDao.replaceSafe(profile) + PrivateDatabase.profileDao.createOrUpdate(profile) ProfilesFragment.instance?.profilesAdapter?.add(profile) return profile } @@ -62,10 +60,10 @@ object ProfileManager { * Note: It's caller's responsibility to update DirectBoot profile if necessary. */ @Throws(SQLException::class) - fun updateProfile(profile: Profile) = PrivateDatabase.profileDao.updateSafe(profile) + fun updateProfile(profile: Profile) = PrivateDatabase.profileDao.update(profile) fun getProfile(id: Int): Profile? = try { - PrivateDatabase.profileDao.queryByIdSafe(id) + PrivateDatabase.profileDao.queryForId(id) } catch (ex: SQLException) { Log.e(TAG, "getProfile", ex) app.track(ex) @@ -74,16 +72,13 @@ object ProfileManager { @Throws(SQLException::class) fun delProfile(id: Int) { - PrivateDatabase.profileDao.deleteByIdSafe(id) + PrivateDatabase.profileDao.deleteById(id) ProfilesFragment.instance?.profilesAdapter?.removeId(id) if (id == DataStore.profileId && DataStore.directBootAware) DirectBoot.clean() } fun getFirstProfile(): Profile? = try { - safeWrapper { - PrivateDatabase.profileDao.query( - PrivateDatabase.profileDao.queryBuilder().limit(1L).prepare()).singleOrNull() - } + PrivateDatabase.profileDao.query(PrivateDatabase.profileDao.queryBuilder().limit(1L).prepare()).singleOrNull() } catch (ex: SQLException) { Log.e(TAG, "getFirstProfile", ex) app.track(ex) @@ -91,10 +86,7 @@ object ProfileManager { } fun getAllProfiles(): List? = try { - safeWrapper { - PrivateDatabase.profileDao.query( - PrivateDatabase.profileDao.queryBuilder().orderBy("userOrder", true).prepare()) - } + PrivateDatabase.profileDao.query(PrivateDatabase.profileDao.queryBuilder().orderBy("userOrder", true).prepare()) } catch (ex: SQLException) { Log.e(TAG, "getAllProfiles", ex) app.track(ex) diff --git a/mobile/src/main/java/com/github/shadowsocks/database/PublicDatabase.kt b/mobile/src/main/java/com/github/shadowsocks/database/PublicDatabase.kt index c7cfb394..f1594a04 100644 --- a/mobile/src/main/java/com/github/shadowsocks/database/PublicDatabase.kt +++ b/mobile/src/main/java/com/github/shadowsocks/database/PublicDatabase.kt @@ -34,21 +34,20 @@ object PublicDatabase : OrmLiteSqliteOpenHelper(app.deviceContext, Key.DB_PUBLIC @Suppress("UNCHECKED_CAST") val kvPairDao: Dao by lazy { getDao(KeyValuePair::class.java) as Dao } - override fun onCreate(database: SQLiteDatabase?, connectionSource: ConnectionSource) { - connectionSource.createTableSafe() + override fun onCreate(database: SQLiteDatabase?, connectionSource: ConnectionSource?) { + TableUtils.createTable(connectionSource, KeyValuePair::class.java) } override fun onUpgrade(database: SQLiteDatabase?, connectionSource: ConnectionSource?, oldVersion: Int, newVersion: Int) { if (oldVersion < 1) { - safeWrapper { - PrivateDatabase.kvPairDao.queryBuilder().where().`in`("key", + PrivateDatabase.kvPairDao.queryBuilder().where().`in`("key", Key.id, Key.tfo, Key.serviceMode, Key.portProxy, Key.portLocalDns, Key.portTransproxy).query() - }.forEach { kvPairDao.replaceSafe(it) } + .forEach { kvPairDao.createOrUpdate(it) } } if (oldVersion < 2) { - kvPairDao.replaceSafe(KeyValuePair(Acl.CUSTOM_RULES).put(Acl().fromId(Acl.CUSTOM_RULES).toString())) + kvPairDao.createOrUpdate(KeyValuePair(Acl.CUSTOM_RULES).put(Acl().fromId(Acl.CUSTOM_RULES).toString())) } } diff --git a/mobile/src/main/java/com/github/shadowsocks/preference/OrmLitePreferenceDataStore.kt b/mobile/src/main/java/com/github/shadowsocks/preference/OrmLitePreferenceDataStore.kt index b43d42bd..19849133 100644 --- a/mobile/src/main/java/com/github/shadowsocks/preference/OrmLitePreferenceDataStore.kt +++ b/mobile/src/main/java/com/github/shadowsocks/preference/OrmLitePreferenceDataStore.kt @@ -22,20 +22,17 @@ package com.github.shadowsocks.preference import android.support.v7.preference.PreferenceDataStore import com.github.shadowsocks.database.KeyValuePair -import com.github.shadowsocks.database.deleteByIdSafe -import com.github.shadowsocks.database.queryByIdSafe -import com.github.shadowsocks.database.replaceSafe import com.j256.ormlite.dao.Dao import java.util.HashSet @Suppress("MemberVisibilityCanPrivate", "unused") open class OrmLitePreferenceDataStore(private val kvPairDao: Dao) : PreferenceDataStore() { - fun getBoolean(key: String?) = kvPairDao.queryByIdSafe(key)?.boolean - fun getFloat(key: String?) = kvPairDao.queryByIdSafe(key)?.float - fun getInt(key: String?) = kvPairDao.queryByIdSafe(key)?.int - fun getLong(key: String?) = kvPairDao.queryByIdSafe(key)?.long - fun getString(key: String?) = kvPairDao.queryByIdSafe(key)?.string - fun getStringSet(key: String?) = kvPairDao.queryByIdSafe(key)?.stringSet + fun getBoolean(key: String?) = kvPairDao.queryForId(key)?.boolean + fun getFloat(key: String?) = kvPairDao.queryForId(key)?.float + fun getInt(key: String?) = kvPairDao.queryForId(key)?.int + fun getLong(key: String?) = kvPairDao.queryForId(key)?.long + fun getString(key: String?) = kvPairDao.queryForId(key)?.string + fun getStringSet(key: String?) = kvPairDao.queryForId(key)?.stringSet override fun getBoolean(key: String?, defValue: Boolean) = getBoolean(key) ?: defValue override fun getFloat(key: String?, defValue: Float) = getFloat(key) ?: defValue @@ -49,32 +46,32 @@ open class OrmLitePreferenceDataStore(private val kvPairDao: Dao?) = if (values == null) remove(key) else { - kvPairDao.replaceSafe(KeyValuePair(key).put(values)) + kvPairDao.createOrUpdate(KeyValuePair(key).put(values)) fireChangeListener(key) } fun remove(key: String?) { - kvPairDao.deleteByIdSafe(key) + kvPairDao.deleteById(key) fireChangeListener(key) }