11package eu.darken.capod
22
33import android.app.Application
4+ import android.os.Looper
45import dagger.hilt.android.HiltAndroidApp
56import eu.darken.capod.common.coroutine.AppScope
7+ import eu.darken.capod.common.debug.Bugs
68import eu.darken.capod.common.debug.autoreport.AutomaticBugReporter
79import eu.darken.capod.common.debug.logging.LogCatLogger
810import eu.darken.capod.common.debug.logging.Logging
911import eu.darken.capod.common.debug.logging.asLog
12+ import eu.darken.capod.common.debug.logging.Logging.Priority.ERROR
13+ import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
1014import eu.darken.capod.common.debug.logging.log
1115import eu.darken.capod.common.debug.logging.logTag
1216import eu.darken.capod.common.flow.throttleLatest
@@ -23,6 +27,7 @@ import kotlinx.coroutines.flow.map
2327import kotlinx.coroutines.flow.onEach
2428import kotlinx.coroutines.launch
2529import javax.inject.Inject
30+ import kotlin.system.exitProcess
2631
2732@HiltAndroidApp
2833open class App : Application () {
@@ -37,6 +42,20 @@ open class App : Application() {
3742 super .onCreate()
3843 if (BuildConfig .DEBUG ) Logging .install(LogCatLogger ())
3944
45+ var foregroundExceptionHandled = false
46+ val oldHandler = Thread .getDefaultUncaughtExceptionHandler()
47+ Thread .setDefaultUncaughtExceptionHandler { thread, throwable ->
48+ if (throwable.isForegroundServiceTimingException() && ! foregroundExceptionHandled) {
49+ foregroundExceptionHandled = true
50+ log(TAG , WARN ) { " Suppressed foreground service timing exception: ${throwable.asLog()} " }
51+ Bugs .report(tag = TAG , " Foreground service timing exception suppressed" , exception = throwable)
52+ Looper .loop()
53+ return @setDefaultUncaughtExceptionHandler
54+ }
55+ log(TAG , ERROR ) { " UNCAUGHT EXCEPTION: ${throwable.asLog()} " }
56+ if (oldHandler != null ) oldHandler.uncaughtException(thread, throwable) else exitProcess(1 )
57+ }
58+
4059 autoReporting.setup(this )
4160
4261 log(TAG ) { " onCreate() done! ${Exception ().asLog()} " }
@@ -64,5 +83,14 @@ open class App : Application() {
6483
6584 companion object {
6685 internal val TAG = logTag(" CAP" )
86+
87+ private fun Throwable.isForegroundServiceTimingException (): Boolean {
88+ var current: Throwable ? = this
89+ while (current != null ) {
90+ if (current.javaClass.simpleName == " ForegroundServiceDidNotStartInTimeException" ) return true
91+ current = current.cause
92+ }
93+ return false
94+ }
6795 }
6896}
0 commit comments