Recover MMKV data on storage errors (#6085)

This commit is contained in:
eliotcougar authored and GitHub committed 2026-08-16 10:30:56 +08:00
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.work.Configuration
import androidx.work.WorkManager
import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.handler.AppLocaleManager
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.SettingsManager
import com.v2ray.ang.ui.compose.ThemeManager
@@ -35,7 +35,7 @@ class AngApplication : Application() {
override fun onCreate() {
super.onCreate()
MMKV.initialize(this)
MmkvManager.initialize(this)
AppLocaleManager.initialize(this)
@@ -1,5 +1,7 @@
package com.v2ray.ang.handler
import android.content.Context
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
@@ -7,9 +9,14 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshotFlow
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.PREF_IS_BOOTED
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.AssetUrlItem
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_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 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) }
@@ -51,6 +76,29 @@ object MmkvManager {
//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
/**