Recover MMKV data on storage errors (#6085)
This commit is contained in:
1 parent
36ab5615d9
commit
49fe45c49e
2 files changed
+50
-2
No files matched your search
@@ -5,9 +5,9 @@ import android.content.Context
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.work.Configuration
|
import androidx.work.Configuration
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.tencent.mmkv.MMKV
|
|
||||||
import com.v2ray.ang.AppConfig.ANG_PACKAGE
|
import com.v2ray.ang.AppConfig.ANG_PACKAGE
|
||||||
import com.v2ray.ang.handler.AppLocaleManager
|
import com.v2ray.ang.handler.AppLocaleManager
|
||||||
|
import com.v2ray.ang.handler.MmkvManager
|
||||||
import com.v2ray.ang.handler.SettingsManager
|
import com.v2ray.ang.handler.SettingsManager
|
||||||
import com.v2ray.ang.ui.compose.ThemeManager
|
import com.v2ray.ang.ui.compose.ThemeManager
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ class AngApplication : Application() {
|
|||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
MMKV.initialize(this)
|
MmkvManager.initialize(this)
|
||||||
|
|
||||||
AppLocaleManager.initialize(this)
|
AppLocaleManager.initialize(this)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.v2ray.ang.handler
|
package com.v2ray.ang.handler
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
@@ -7,9 +9,14 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import com.tencent.mmkv.MMKV
|
import com.tencent.mmkv.MMKV
|
||||||
|
import com.tencent.mmkv.MMKVHandler
|
||||||
|
import com.tencent.mmkv.MMKVLogLevel
|
||||||
|
import com.tencent.mmkv.MMKVRecoverStrategic
|
||||||
import com.v2ray.ang.AppConfig.DEFAULT_SUBSCRIPTION_ID
|
import com.v2ray.ang.AppConfig.DEFAULT_SUBSCRIPTION_ID
|
||||||
import com.v2ray.ang.AppConfig.PREF_IS_BOOTED
|
import com.v2ray.ang.AppConfig.PREF_IS_BOOTED
|
||||||
import com.v2ray.ang.AppConfig.PREF_ROUTING_RULESET
|
import com.v2ray.ang.AppConfig.PREF_ROUTING_RULESET
|
||||||
|
import com.v2ray.ang.AppConfig.TAG
|
||||||
|
import com.v2ray.ang.BuildConfig
|
||||||
import com.v2ray.ang.dto.entities.AssetUrlCache
|
import com.v2ray.ang.dto.entities.AssetUrlCache
|
||||||
import com.v2ray.ang.dto.entities.AssetUrlItem
|
import com.v2ray.ang.dto.entities.AssetUrlItem
|
||||||
import com.v2ray.ang.dto.entities.ProfileItem
|
import com.v2ray.ang.dto.entities.ProfileItem
|
||||||
@@ -41,6 +48,24 @@ object MmkvManager {
|
|||||||
private const val KEY_SUB_IDS = "SUB_IDS"
|
private const val KEY_SUB_IDS = "SUB_IDS"
|
||||||
private const val KEY_WEBDAV_CONFIG = "WEBDAV_CONFIG"
|
private const val KEY_WEBDAV_CONFIG = "WEBDAV_CONFIG"
|
||||||
|
|
||||||
|
private val recoveryHandler = object : MMKVHandler {
|
||||||
|
override fun onMMKVCRCCheckFail(mmapID: String) =
|
||||||
|
recoverFromStorageError(mmapID, "CRC check")
|
||||||
|
|
||||||
|
override fun onMMKVFileLengthError(mmapID: String) =
|
||||||
|
recoverFromStorageError(mmapID, "file length check")
|
||||||
|
|
||||||
|
override fun wantLogRedirecting(): Boolean = false
|
||||||
|
|
||||||
|
override fun mmkvLog(
|
||||||
|
level: MMKVLogLevel,
|
||||||
|
file: String,
|
||||||
|
line: Int,
|
||||||
|
function: String,
|
||||||
|
message: String
|
||||||
|
) = Unit
|
||||||
|
}
|
||||||
|
|
||||||
private val mainStorage by lazy { MMKV.mmkvWithID(ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
|
private val mainStorage by lazy { MMKV.mmkvWithID(ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
|
||||||
private val profileFullStorage by lazy { MMKV.mmkvWithID(ID_PROFILE_FULL_CONFIG, MMKV.MULTI_PROCESS_MODE) }
|
private val profileFullStorage by lazy { MMKV.mmkvWithID(ID_PROFILE_FULL_CONFIG, MMKV.MULTI_PROCESS_MODE) }
|
||||||
private val serverRawStorage by lazy { MMKV.mmkvWithID(ID_SERVER_RAW, MMKV.MULTI_PROCESS_MODE) }
|
private val serverRawStorage by lazy { MMKV.mmkvWithID(ID_SERVER_RAW, MMKV.MULTI_PROCESS_MODE) }
|
||||||
@@ -51,6 +76,29 @@ object MmkvManager {
|
|||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes MMKV with best-effort recovery so a damaged store is not silently discarded.
|
||||||
|
*/
|
||||||
|
fun initialize(context: Context) {
|
||||||
|
val logLevel = if (BuildConfig.DEBUG) {
|
||||||
|
MMKVLogLevel.LevelDebug
|
||||||
|
} else {
|
||||||
|
MMKVLogLevel.LevelInfo
|
||||||
|
}
|
||||||
|
MMKV.initialize(
|
||||||
|
context,
|
||||||
|
context.filesDir.resolve("mmkv").absolutePath,
|
||||||
|
null,
|
||||||
|
logLevel,
|
||||||
|
recoveryHandler
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recoverFromStorageError(mmapID: String, error: String): MMKVRecoverStrategic {
|
||||||
|
Log.e(TAG, "MMKV $error failed for $mmapID; attempting data recovery")
|
||||||
|
return MMKVRecoverStrategic.OnErrorRecover
|
||||||
|
}
|
||||||
|
|
||||||
//region Server
|
//region Server
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in new issue
Block a user