-
Notifications
You must be signed in to change notification settings - Fork 7
/
EmbraceInternalErrorService.kt
132 lines (116 loc) · 4.48 KB
/
EmbraceInternalErrorService.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package io.embrace.android.embracesdk.logging
import io.embrace.android.embracesdk.config.ConfigService
import io.embrace.android.embracesdk.internal.clock.Clock
import io.embrace.android.embracesdk.payload.LegacyExceptionError
import io.embrace.android.embracesdk.session.lifecycle.ProcessStateService
import java.net.BindException
import java.net.ConnectException
import java.net.HttpRetryException
import java.net.NoRouteToHostException
import java.net.PortUnreachableException
import java.net.ProtocolException
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.net.UnknownServiceException
/**
* Intercepts Embrace SDK's exceptions errors and forwards them to the Embrace API.
*/
internal class EmbraceInternalErrorService(
private val processStateService: ProcessStateService,
private val clock: Clock
) : InternalErrorService {
private var configService: ConfigService? = null
private var err: LegacyExceptionError? = null
override val currentExceptionError: LegacyExceptionError?
get() = err
// ignore network-related exceptions since they are expected
private val ignoredExceptionClasses by lazy {
setOf<Class<*>>(
BindException::class.java,
ConnectException::class.java,
HttpRetryException::class.java,
NoRouteToHostException::class.java,
PortUnreachableException::class.java,
ProtocolException::class.java,
SocketException::class.java,
SocketTimeoutException::class.java,
UnknownHostException::class.java,
UnknownServiceException::class.java
)
}
private val ignoredExceptionStrings by lazy {
ignoredExceptionClasses.map { it.name }
}
override fun setConfigService(configService: ConfigService?) {
this.configService = configService
}
private fun ignoreThrowableCause(
throwable: Throwable?,
capturedThrowable: HashSet<Throwable>
): Boolean {
return if (throwable != null) {
if (ignoredExceptionClasses.contains(throwable.javaClass)) {
true
} else {
/* if Hashset#add returns true means that the throwable was properly added,
if it returns false, the object already exists in the set so we return false
because we are in presence of a cycle in the Throwable cause */
val addResult = capturedThrowable.add(throwable)
addResult && ignoreThrowableCause(throwable.cause, capturedThrowable)
}
} else {
false
}
}
@Synchronized
override fun handleInternalError(throwable: Throwable) {
if (ignoredExceptionClasses.contains(throwable.javaClass)) {
return
} else {
val capturedThrowable = HashSet<Throwable>()
if (ignoreThrowableCause(throwable.cause, capturedThrowable)) {
return
}
}
// If the exception has been wrapped in another exception, the ignored exception name will
// show up as the start of the message, delimited by a semicolon.
val message = throwable.message
if (message != null && ignoredExceptionStrings.contains(
message.split(":".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()[0]
)
) {
return
}
if (err == null) {
err = LegacyExceptionError()
}
// if the config service has not been set yet, capture the exception
if (configService == null || configService?.dataCaptureEventBehavior?.isInternalExceptionCaptureEnabled() == true) {
err?.addException(
throwable,
getApplicationState(),
clock
)
}
}
private fun getApplicationState(): String = when {
processStateService.isInBackground -> APPLICATION_STATE_BACKGROUND
else -> APPLICATION_STATE_FOREGROUND
}
@Synchronized
override fun resetExceptionErrorObject() {
err = null
}
companion object {
/**
* Signals to the API that the application was in the foreground.
*/
private const val APPLICATION_STATE_FOREGROUND = "foreground"
/**
* Signals to the API that the application was in the background.
*/
private const val APPLICATION_STATE_BACKGROUND = "background"
}
}