Skip to content

Commit 273b00d

Browse files
authored
InterruptedException and IOException now excluded exceptions to alert on (#791)
* InterruptedException and IOException now excluded exceptions to alert on * Change IOException to InterruptedIOException and permit crash on DEBUG * Remove UndeliverableException from alerting handler; handled elsewhere
1 parent 07c5c19 commit 273b00d

File tree

1 file changed

+34
-2
lines changed

1 file changed

+34
-2
lines changed

app/src/main/java/com/duckduckgo/app/global/AlertingUncaughtExceptionHandler.kt

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,60 @@
1616

1717
package com.duckduckgo.app.global
1818

19+
import com.duckduckgo.app.browser.BuildConfig
1920
import com.duckduckgo.app.global.exception.UncaughtExceptionRepository
2021
import com.duckduckgo.app.global.exception.UncaughtExceptionSource
2122
import com.duckduckgo.app.statistics.store.OfflinePixelCountDataStore
2223
import kotlinx.coroutines.Dispatchers
2324
import kotlinx.coroutines.GlobalScope
2425
import kotlinx.coroutines.NonCancellable
2526
import kotlinx.coroutines.launch
27+
import java.io.InterruptedIOException
2628

2729
class AlertingUncaughtExceptionHandler(
2830
private val originalHandler: Thread.UncaughtExceptionHandler,
2931
private val offlinePixelCountDataStore: OfflinePixelCountDataStore,
3032
private val uncaughtExceptionRepository: UncaughtExceptionRepository
3133
) : Thread.UncaughtExceptionHandler {
3234

33-
override fun uncaughtException(t: Thread?, originalException: Throwable?) {
35+
override fun uncaughtException(thread: Thread?, originalException: Throwable?) {
3436

37+
if (shouldRecordExceptionAndCrashApp(originalException)) {
38+
recordExceptionAndAllowCrash(thread, originalException)
39+
return
40+
}
41+
42+
if (shouldCrashApp()) {
43+
originalHandler.uncaughtException(thread, originalException)
44+
}
45+
46+
}
47+
48+
/**
49+
* Some exceptions happen due to lifecycle issues, such as our sync service being forced to stop.
50+
* In such cases, we don't need to alert about the exception as they are exceptions essentially signalling that work was interrupted.
51+
* Examples of this would be if the internet was lost during the sync,
52+
* or when two or more sync operations are scheduled to run at the same time; one would run and the rest would be interrupted.
53+
*/
54+
private fun shouldRecordExceptionAndCrashApp(exception: Throwable?): Boolean {
55+
return when (exception) {
56+
is InterruptedException, is InterruptedIOException -> false
57+
else -> true
58+
}
59+
}
60+
61+
/**
62+
* If the exception is one we don't report on, we still want to see a crash when we're in DEBUG builds for safety we aren't ignoring important issues
63+
*/
64+
private fun shouldCrashApp(): Boolean = BuildConfig.DEBUG
65+
66+
private fun recordExceptionAndAllowCrash(thread: Thread?, originalException: Throwable?) {
3567
GlobalScope.launch(Dispatchers.IO + NonCancellable) {
3668
uncaughtExceptionRepository.recordUncaughtException(originalException, UncaughtExceptionSource.GLOBAL)
3769
offlinePixelCountDataStore.applicationCrashCount += 1
3870

3971
// wait until the exception has been fully processed before propagating exception
40-
originalHandler.uncaughtException(t, originalException)
72+
originalHandler.uncaughtException(thread, originalException)
4173
}
4274
}
4375
}

0 commit comments

Comments
 (0)