mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-01 22:58:57 +01:00
Add Crash activity (#8216)
* Add Crash activity When the application crashes this sends them to a different activity with the cause message and an option to dump the crash logs * Review changes
This commit is contained in:
@@ -30,6 +30,8 @@ import eu.kanade.domain.DomainModule
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.domain.ui.model.ThemeMode
|
||||
import eu.kanade.tachiyomi.crash.CrashActivity
|
||||
import eu.kanade.tachiyomi.crash.GlobalExceptionHandler
|
||||
import eu.kanade.tachiyomi.data.coil.DomainMangaKeyer
|
||||
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
|
||||
import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
|
||||
@@ -74,6 +76,8 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||
override fun onCreate() {
|
||||
super<Application>.onCreate()
|
||||
|
||||
GlobalExceptionHandler.initialize(applicationContext, CrashActivity::class.java)
|
||||
|
||||
// TLS 1.3 support for Android < 10
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
Security.insertProviderAt(Conscrypt.newProvider(), 1)
|
||||
|
||||
25
app/src/main/java/eu/kanade/tachiyomi/crash/CrashActivity.kt
Normal file
25
app/src/main/java/eu/kanade/tachiyomi/crash/CrashActivity.kt
Normal file
@@ -0,0 +1,25 @@
|
||||
package eu.kanade.tachiyomi.crash
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import eu.kanade.presentation.crash.CrashScreen
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.util.view.setComposeContent
|
||||
|
||||
class CrashActivity : BaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val exception = GlobalExceptionHandler.getThrowableFromIntent(intent)
|
||||
setComposeContent {
|
||||
CrashScreen(
|
||||
exception = exception,
|
||||
onRestartClick = {
|
||||
finishAffinity()
|
||||
startActivity(Intent(this@CrashActivity, MainActivity::class.java))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package eu.kanade.tachiyomi.crash
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.Json
|
||||
import logcat.LogPriority
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class GlobalExceptionHandler private constructor(
|
||||
private val applicationContext: Context,
|
||||
private val defaultHandler: Thread.UncaughtExceptionHandler,
|
||||
private val activityToBeLaunched: Class<*>,
|
||||
) : Thread.UncaughtExceptionHandler {
|
||||
|
||||
object ThrowableSerializer : KSerializer<Throwable> {
|
||||
override val descriptor: SerialDescriptor =
|
||||
PrimitiveSerialDescriptor("Throwable", PrimitiveKind.STRING)
|
||||
|
||||
override fun deserialize(decoder: Decoder): Throwable =
|
||||
Throwable(message = decoder.decodeString())
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Throwable) =
|
||||
encoder.encodeString(value.stackTraceToString())
|
||||
}
|
||||
|
||||
override fun uncaughtException(thread: Thread, exception: Throwable) {
|
||||
try {
|
||||
logcat(priority = LogPriority.ERROR, throwable = exception)
|
||||
launchActivity(applicationContext, activityToBeLaunched, exception)
|
||||
exitProcess(0)
|
||||
} catch (_: Exception) {
|
||||
defaultHandler.uncaughtException(thread, exception)
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchActivity(
|
||||
applicationContext: Context,
|
||||
activity: Class<*>,
|
||||
exception: Throwable,
|
||||
) {
|
||||
val intent = Intent(applicationContext, activity).apply {
|
||||
putExtra(INTENT_EXTRA, Json.encodeToString(ThrowableSerializer, exception))
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
}
|
||||
applicationContext.startActivity(intent)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val INTENT_EXTRA = "Throwable"
|
||||
|
||||
fun initialize(
|
||||
applicationContext: Context,
|
||||
activityToBeLaunched: Class<*>,
|
||||
) {
|
||||
val handler = GlobalExceptionHandler(
|
||||
applicationContext,
|
||||
Thread.getDefaultUncaughtExceptionHandler() as Thread.UncaughtExceptionHandler,
|
||||
activityToBeLaunched,
|
||||
)
|
||||
Thread.setDefaultUncaughtExceptionHandler(handler)
|
||||
}
|
||||
|
||||
fun getThrowableFromIntent(intent: Intent): Throwable? {
|
||||
return try {
|
||||
Json.decodeFromString(ThrowableSerializer, intent.getStringExtra(INTENT_EXTRA)!!)
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e) { "Wasn't able to retrive throwable from intent" }
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.util.lang.withNonCancellableContext
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
||||
@@ -20,7 +21,7 @@ class CrashLogUtil(private val context: Context) {
|
||||
setSmallIcon(R.drawable.ic_tachi)
|
||||
}
|
||||
|
||||
suspend fun dumpLogs() {
|
||||
suspend fun dumpLogs() = withNonCancellableContext {
|
||||
try {
|
||||
val file = context.createFileInCacheDir("tachiyomi_crash_logs.txt")
|
||||
Runtime.getRuntime().exec("logcat *:E -d -f ${file.absolutePath}").waitFor()
|
||||
|
||||
Reference in New Issue
Block a user