Skip to content

Commit

Permalink
Closes mozilla-mobile#5175: Allow Socorro to distinguish between fata…
Browse files Browse the repository at this point in the history
…l and non-fatal crashes
  • Loading branch information
rocketsroger committed Jan 9, 2020
1 parent 1121929 commit 769e079
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ sealed class Crash {
* A crash caused by an uncaught exception.
*
* @property throwable The [Throwable] that caused the crash.
* @property breadcrumbs List of breadcrumbs to send with the crash report.
*/
data class UncaughtExceptionCrash(
val throwable: Throwable,
Expand Down Expand Up @@ -61,6 +62,7 @@ sealed class Crash {
* @property isFatal Whether or not the crash was fatal or not: If true, the main application process was affected
* by the crash. If false, only an internal process used by Gecko has crashed and the application
* may be able to recover.
* @property breadcrumbs List of breadcrumbs to send with the crash report.
*/
data class NativeCodeCrash(
val minidumpPath: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ import kotlin.random.Random
/* This ID is used for all Mozilla products. Setting as default if no ID is passed in */
private const val MOZILLA_PRODUCT_ID = "{eeb82917-e434-4870-8148-5c03d4caa81b}"

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal const val FATAL_CRASH_NOTE = "This is a fatal crash"

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal const val NONFATAL_CRASH_NOTE = "This is a non-fatal crash"

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal const val CAUGHT_EXCEPTION_NOTE = "This is a caught exception, not a real crash"

Expand All @@ -61,22 +67,23 @@ class MozillaSocorroService(
private val startTime = System.currentTimeMillis()

override fun report(crash: Crash.UncaughtExceptionCrash) {
sendReport(crash.throwable, null, null, false)
sendReport(crash.throwable, null, null, isFatal = true, isCaughtException = false)
}

override fun report(crash: Crash.NativeCodeCrash) {
sendReport(null, crash.minidumpPath, crash.extrasPath, false)
sendReport(null, crash.minidumpPath, crash.extrasPath, isFatal = crash.isFatal, isCaughtException = false)
}

override fun report(throwable: Throwable) {
sendReport(throwable, null, null, true)
sendReport(throwable, null, null, isFatal = false, isCaughtException = true)
}

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun sendReport(
throwable: Throwable?,
miniDumpFilePath: String?,
extrasFilePath: String?,
isFatal: Boolean,
isCaughtException: Boolean
) {
val url = URL(serverUrl)
Expand All @@ -91,7 +98,7 @@ class MozillaSocorroService(
conn.setRequestProperty("Content-Encoding", "gzip")

sendCrashData(conn.outputStream, boundary, throwable, miniDumpFilePath, extrasFilePath,
isCaughtException)
isFatal, isCaughtException)

BufferedReader(InputStreamReader(conn.inputStream)).use {
val response = StringBuffer()
Expand All @@ -110,13 +117,14 @@ class MozillaSocorroService(
}
}

@Suppress("LongParameterList")
@Suppress("LongParameterList", "LongMethod")
private fun sendCrashData(
os: OutputStream,
boundary: String,
throwable: Throwable?,
miniDumpFilePath: String?,
extrasFilePath: String?,
isFatal: Boolean,
isCaughtException: Boolean
) {
val nameSet = mutableSetOf<String>()
Expand Down Expand Up @@ -147,8 +155,10 @@ class MozillaSocorroService(
minidumpFile.delete()
}

if (isCaughtException) {
sendPart(gzipOs, boundary, "Notes", CAUGHT_EXCEPTION_NOTE, nameSet)
when {
isFatal -> sendPart(gzipOs, boundary, "Notes", FATAL_CRASH_NOTE, nameSet)
isCaughtException -> sendPart(gzipOs, boundary, "Notes", CAUGHT_EXCEPTION_NOTE, nameSet)
else -> sendPart(gzipOs, boundary, "Notes", NONFATAL_CRASH_NOTE, nameSet)
}

sendPackageInstallTime(gzipOs, boundary, nameSet)
Expand Down Expand Up @@ -328,7 +338,10 @@ class MozillaSocorroService(
return resultMap
}

private fun getExceptionStackTrace(throwable: Throwable, isCaughtException: Boolean): String {
private fun getExceptionStackTrace(
throwable: Throwable,
isCaughtException: Boolean
): String {
val stringWriter = StringWriter()
val printWriter = PrintWriter(stringWriter)
throwable.printStackTrace(printWriter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ class MozillaSocorroServiceTest {
testContext,
"Test App"
))
doNothing().`when`(service).sendReport(any(), any(), any(), anyBoolean())
doNothing().`when`(service).sendReport(any(), any(), any(), anyBoolean(), anyBoolean())

val crash = Crash.NativeCodeCrash("", true, "", false, arrayListOf())
val crash = Crash.NativeCodeCrash("", true, "", true, arrayListOf())
service.report(crash)

verify(service).report(crash)
verify(service).sendReport(null, crash.minidumpPath, crash.extrasPath, false)
verify(service).sendReport(null, crash.minidumpPath, crash.extrasPath, true, false)
}

@Test
Expand All @@ -49,13 +49,13 @@ class MozillaSocorroServiceTest {
testContext,
"Test App"
))
doNothing().`when`(service).sendReport(any(), any(), any(), anyBoolean())
doNothing().`when`(service).sendReport(any(), any(), any(), anyBoolean(), anyBoolean())

val crash = Crash.UncaughtExceptionCrash(RuntimeException("Test"), arrayListOf())
service.report(crash)

verify(service).report(crash)
verify(service).sendReport(crash.throwable, null, null, false)
verify(service).sendReport(crash.throwable, null, null, true, false)
}

@Test
Expand All @@ -64,13 +64,13 @@ class MozillaSocorroServiceTest {
testContext,
"Test App"
))
doNothing().`when`(service).sendReport(any(), any(), any(), anyBoolean())
doNothing().`when`(service).sendReport(any(), any(), any(), anyBoolean(), anyBoolean())

val throwable = RuntimeException("Test")
service.report(throwable)

verify(service).report(throwable)
verify(service).sendReport(throwable, null, null, true)
verify(service).sendReport(throwable, null, null, false, true)
}

@Test
Expand Down Expand Up @@ -103,10 +103,10 @@ class MozillaSocorroServiceTest {
assert(request.contains("name=ReleaseChannel\r\n\r\nnightly"))
assert(request.contains("name=Android_PackageName\r\n\r\nmozilla.components.lib.crash.test"))
assert(request.contains("name=Android_Device\r\n\r\nrobolectric"))
assertFalse(request.contains("name=Notes\r\n\r\n$CAUGHT_EXCEPTION_NOTE"))
assert(request.contains("name=Notes\r\n\r\n$FATAL_CRASH_NOTE"))

verify(service).report(crash)
verify(service).sendReport(crash.throwable, null, null, false)
verify(service).sendReport(crash.throwable, null, null, true, false)
}

@Test
Expand Down Expand Up @@ -141,7 +141,7 @@ class MozillaSocorroServiceTest {
assert(request.contains("name=Notes\r\n\r\n$CAUGHT_EXCEPTION_NOTE"))

verify(service).report(throwable)
verify(service).sendReport(throwable, null, null, true)
verify(service).sendReport(throwable, null, null, false, true)
}

@Test
Expand Down Expand Up @@ -182,7 +182,7 @@ class MozillaSocorroServiceTest {
assert(request.contains("name=Notes\r\n\r\n$CAUGHT_EXCEPTION_NOTE"))

verify(service).report(throwable)
verify(service).sendReport(throwable, null, null, true)
verify(service).sendReport(throwable, null, null, false, true)
}

@Test
Expand Down Expand Up @@ -224,7 +224,7 @@ class MozillaSocorroServiceTest {
assert(request.contains("name=Notes\r\n\r\n$CAUGHT_EXCEPTION_NOTE"))

verify(service).report(throwable)
verify(service).sendReport(throwable, null, null, true)
verify(service).sendReport(throwable, null, null, false, true)
}

@Test
Expand All @@ -245,7 +245,7 @@ class MozillaSocorroServiceTest {

mockWebServer.shutdown()
verify(service).report(crash)
verify(service).sendReport(crash.throwable, null, null, false)
verify(service).sendReport(crash.throwable, null, null, true, false)
}

@Test
Expand All @@ -260,12 +260,12 @@ class MozillaSocorroServiceTest {
serverUrl = serverUrl.toString()
))

val crash = Crash.NativeCodeCrash(null, true, null, false, arrayListOf())
val crash = Crash.NativeCodeCrash(null, true, null, true, arrayListOf())
service.report(crash)
mockWebServer.shutdown()

verify(service).report(crash)
verify(service).sendReport(null, crash.minidumpPath, crash.extrasPath, false)
verify(service).sendReport(null, crash.minidumpPath, crash.extrasPath, true, false)
}

@Test
Expand Down

0 comments on commit 769e079

Please sign in to comment.