diff --git a/app/src/main/java/io/legado/app/help/ContentProcessor.kt b/app/src/main/java/io/legado/app/help/ContentProcessor.kt index e3162fa2e..68d580e83 100644 --- a/app/src/main/java/io/legado/app/help/ContentProcessor.kt +++ b/app/src/main/java/io/legado/app/help/ContentProcessor.kt @@ -8,6 +8,9 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.config.AppConfig import io.legado.app.help.config.ReadBookConfig +import io.legado.app.utils.RegexTimeoutException +import io.legado.app.utils.msg +import io.legado.app.utils.replace import io.legado.app.utils.toastOnUi import splitties.init.appCtx import java.lang.ref.WeakReference @@ -134,13 +137,22 @@ class ContentProcessor private constructor( if (item.pattern.isNotEmpty()) { kotlin.runCatching { mContent = if (item.isRegex) { - mContent.replace(item.pattern.toRegex(), item.replacement) + mContent.replace(item.pattern.toRegex(), item.replacement, 1000L) } else { mContent.replace(item.pattern, item.replacement) } }.onFailure { - AppLog.put("${item.name}替换出错\n${it.localizedMessage}", it) - appCtx.toastOnUi("${item.name}替换出错") + when (it) { + is RegexTimeoutException -> { + item.isEnabled = false + appDb.replaceRuleDao.update(item) + return it.msg + } + else -> { + AppLog.put("${item.name}替换出错\n${it.localizedMessage}", it) + appCtx.toastOnUi("${item.name}替换出错") + } + } } } } diff --git a/app/src/main/java/io/legado/app/help/CrashHandler.kt b/app/src/main/java/io/legado/app/help/CrashHandler.kt index 72f10574c..a13c38161 100644 --- a/app/src/main/java/io/legado/app/help/CrashHandler.kt +++ b/app/src/main/java/io/legado/app/help/CrashHandler.kt @@ -9,6 +9,7 @@ import io.legado.app.utils.FileUtils import io.legado.app.utils.getFile import io.legado.app.utils.longToastOnUi import io.legado.app.utils.msg +import splitties.init.appCtx import java.io.PrintWriter import java.io.StringWriter import java.text.SimpleDateFormat @@ -26,17 +27,6 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler { */ private var mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler() - /** - * 存储异常和参数信息 - */ - private val paramsMap = HashMap() - - /** - * 格式化时间 - */ - @SuppressLint("SimpleDateFormat") - private val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss") - init { //设置该CrashHandler为系统默认的 Thread.setDefaultUncaughtExceptionHandler(this) @@ -56,62 +46,71 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler { */ private fun handleException(ex: Throwable?) { if (ex == null) return - //收集设备参数信息 - collectDeviceInfo() //保存日志文件 saveCrashInfo2File(ex) context.longToastOnUi(ex.msg) Thread.sleep(3000) } - /** - * 收集设备参数信息 - */ - private fun collectDeviceInfo() { - kotlin.runCatching { - //获取系统信息 - paramsMap["MANUFACTURER"] = Build.MANUFACTURER - paramsMap["BRAND"] = Build.BRAND - //获取app版本信息 - AppConst.appInfo.let { - paramsMap["versionName"] = it.versionName - paramsMap["versionCode"] = it.versionCode.toString() + companion object { + /** + * 存储异常和参数信息 + */ + private val paramsMap by lazy { + val map = HashMap() + kotlin.runCatching { + //获取系统信息 + map["MANUFACTURER"] = Build.MANUFACTURER + map["BRAND"] = Build.BRAND + //获取app版本信息 + AppConst.appInfo.let { + map["versionName"] = it.versionName + map["versionCode"] = it.versionCode.toString() + } } + map } - } - /** - * 保存错误信息到文件中 - */ - private fun saveCrashInfo2File(ex: Throwable) { - val sb = StringBuilder() - for ((key, value) in paramsMap) { - sb.append(key).append("=").append(value).append("\n") - } + /** + * 格式化时间 + */ + @SuppressLint("SimpleDateFormat") + private val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss") - val writer = StringWriter() - val printWriter = PrintWriter(writer) - ex.printStackTrace(printWriter) - var cause: Throwable? = ex.cause - while (cause != null) { - cause.printStackTrace(printWriter) - cause = cause.cause - } - printWriter.close() - val result = writer.toString() - sb.append(result) - val timestamp = System.currentTimeMillis() - val time = format.format(Date()) - val fileName = "crash-$time-$timestamp.log" - context.externalCacheDir?.let { rootFile -> - rootFile.getFile("crash").listFiles()?.forEach { - if (it.lastModified() < System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7)) { - it.delete() + /** + * 保存错误信息到文件中 + */ + fun saveCrashInfo2File(ex: Throwable) { + val sb = StringBuilder() + for ((key, value) in paramsMap) { + sb.append(key).append("=").append(value).append("\n") + } + + val writer = StringWriter() + val printWriter = PrintWriter(writer) + ex.printStackTrace(printWriter) + var cause: Throwable? = ex.cause + while (cause != null) { + cause.printStackTrace(printWriter) + cause = cause.cause + } + printWriter.close() + val result = writer.toString() + sb.append(result) + val timestamp = System.currentTimeMillis() + val time = format.format(Date()) + val fileName = "crash-$time-$timestamp.log" + appCtx.externalCacheDir?.let { rootFile -> + rootFile.getFile("crash").listFiles()?.forEach { + if (it.lastModified() < System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7)) { + it.delete() + } } + FileUtils.createFileIfNotExist(rootFile, "crash", fileName) + .writeText(sb.toString()) } - FileUtils.createFileIfNotExist(rootFile, "crash", fileName) - .writeText(sb.toString()) } + } } diff --git a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt index 43323e519..4f0de7360 100644 --- a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt @@ -33,6 +33,7 @@ import splitties.systemservices.clipboardManager import splitties.systemservices.connectivityManager import java.io.File import java.io.FileOutputStream +import kotlin.system.exitProcess inline fun Context.startActivity(configIntent: Intent.() -> Unit = {}) { val intent = Intent(this, A::class.java) @@ -168,6 +169,7 @@ fun Context.restart() { startActivity(intent) //杀掉以前进程 Process.killProcess(Process.myPid()) + exitProcess(0) } } diff --git a/app/src/main/java/io/legado/app/utils/RegexExtensions.kt b/app/src/main/java/io/legado/app/utils/RegexExtensions.kt index 1fcf83922..ad85fd6bc 100644 --- a/app/src/main/java/io/legado/app/utils/RegexExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/RegexExtensions.kt @@ -1,10 +1,37 @@ package io.legado.app.utils +import io.legado.app.exception.NoStackTraceException +import io.legado.app.help.CrashHandler import kotlinx.coroutines.suspendCancellableCoroutine +import splitties.init.appCtx +import kotlin.concurrent.thread +import kotlin.coroutines.resume -suspend fun CharSequence.regexReplace(regex: String, replacement: String, timeout: Long): String { - return suspendCancellableCoroutine { - - +suspend fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): String { + return suspendCancellableCoroutine { block -> + val thread = thread { + try { + val result = regex.replace(this, replacement) + block.resume(result) + } catch (e: Exception) { + block.cancel(e) + } + } + mainHandler.postDelayed({ + if (thread.isAlive) { + val timeoutMsg = "替换超时,将在3秒后重启应用\n替换规则$regex\n替换内容:${this}" + val exception = RegexTimeoutException(timeoutMsg) + block.cancel(exception) + appCtx.longToastOnUi(timeoutMsg) + CrashHandler.saveCrashInfo2File(exception) + mainHandler.postDelayed({ + if (thread.isAlive) { + appCtx.restart() + } + }, 3000) + } + }, timeout) } } + +class RegexTimeoutException(msg: String) : NoStackTraceException(msg) \ No newline at end of file