Skip to content

Commit b0b82af

Browse files
Alexandre Lissylissyx
authored andcommitted
Bug 1853108 - Extract interesting crash on Android r=kaya,geckoview-reviewers,android-reviewers,owlish,boek,android-l10n-reviewers,delphine,ohall
Differential Revision: https://phabricator.services.mozilla.com/D225780
1 parent 44228d4 commit b0b82af

File tree

23 files changed

+461
-31
lines changed

23 files changed

+461
-31
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
package mozilla.components.browser.engine.gecko.crash
6+
7+
import org.mozilla.geckoview.CrashPullController
8+
import org.mozilla.geckoview.CrashPullController.Delegate
9+
10+
/**
11+
* [CrashPullController.Delegate] implementation
12+
*
13+
* An abstraction that allows a dispatcher to get the list of CrashIDs coming
14+
* from Remote Settings and in charge of performing the correct AppStore
15+
* dispatch for proper UI handling.
16+
*
17+
* @param dispatcher The dispatcher callback that is in charge of performing the
18+
* heavy lifting of dispatching the CrashIDs to the AppStore
19+
*/
20+
class GeckoCrashPullDelegate(
21+
private val dispatcher: (crashIDs: Array<String>) -> Unit,
22+
) : CrashPullController.Delegate {
23+
override fun onCrashPull(crashIDs: Array<String>) {
24+
dispatcher(crashIDs)
25+
}
26+
}

mobile/android/android-components/components/lib/crash/src/main/java/mozilla/components/lib/crash/CrashReporter.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ class CrashReporter internal constructor(
190190
.map { it.toCrash() }
191191
}
192192

193+
/**
194+
* Fetches specific crash reports that are identified by they ID.
195+
*
196+
* @param crashIDs The list of strings representing the crash IDs to find.
197+
*/
198+
suspend fun findCrashReports(crashIDs: Array<String>): List<Crash> {
199+
return database.crashDao().getCrashesFromID(crashIDs)
200+
.map { it.toCrash() }
201+
}
202+
193203
/**
194204
* Get a copy of the crashBreadcrumbs
195205
*/

mobile/android/android-components/components/lib/crash/src/main/java/mozilla/components/lib/crash/db/CrashDao.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ internal interface CrashDao {
5252
)
5353
suspend fun getCrashesWithoutReportsSince(timestampMillis: Long): List<CrashEntity>
5454

55+
/**
56+
* Returns saved crashes that are part of a specific list of IDs.
57+
*/
58+
@RewriteQueriesToDropUnusedColumns
59+
@Transaction
60+
@Query(
61+
"""
62+
SELECT * FROM crashes
63+
LEFT JOIN reports ON crashes.uuid = reports.crash_uuid
64+
WHERE crashes.minidumpPath IN (:crashIDs)
65+
""",
66+
)
67+
suspend fun getCrashesFromID(crashIDs: Array<String>): List<CrashEntity>
68+
5569
/**
5670
* Returns saved crashes that haven't been reported.
5771
*/

mobile/android/android-components/components/lib/crash/src/main/java/mozilla/components/lib/crash/store/CrashAction.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ sealed class CrashAction {
3838
*/
3939
data class Defer(val now: TimeInMillis) : CrashAction()
4040

41+
/**
42+
* [CrashAction] to ask user consent for sending crashes requested over
43+
* Remote Settings.
44+
*/
45+
data class PullCrashes(val crashIDs: Array<String>) : CrashAction()
46+
4147
/**
4248
* [CrashAction] show the user a prompt to send unsent crashes.
4349
*/
@@ -48,8 +54,14 @@ sealed class CrashAction {
4854
*/
4955
data object CancelTapped : CrashAction()
5056

57+
/**
58+
* [CrashAction] to record a setting and a pref that the user does not want
59+
* to see the Remote Settings crash dialog.
60+
*/
61+
data object CancelForEverTapped : CrashAction()
62+
5163
/**
5264
* [CrashAction] to send when a user taps the send report button.
5365
*/
54-
data class ReportTapped(val automaticallySendChecked: Boolean) : CrashAction()
66+
data class ReportTapped(val automaticallySendChecked: Boolean, val crashIDs: Array<String>?) : CrashAction()
5567
}

mobile/android/android-components/components/lib/crash/src/main/java/mozilla/components/lib/crash/store/CrashMiddleware.kt

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ interface CrashReportCache {
4646
* Stores the users response to always send crashes.
4747
*/
4848
suspend fun setAlwaysSend(alwaysSend: Boolean)
49+
50+
/**
51+
* Records that the user does not want to see the remote settings crash pull
52+
* anymore
53+
*/
54+
suspend fun setCrashPullNeverShowAgain(neverShowAgain: Boolean)
4955
}
5056

5157
/**
@@ -62,7 +68,6 @@ class CrashMiddleware(
6268
private val currentTimeInMillis: () -> TimeInMillis = { System.currentTimeMillis() },
6369
private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO),
6470
) {
65-
6671
/**
6772
* Handle any middleware logic before an action reaches the [crashReducer].
6873
*
@@ -117,18 +122,26 @@ class CrashMiddleware(
117122
}
118123
}
119124
CrashAction.CancelTapped -> dispatch(CrashAction.Defer(now = currentTimeInMillis()))
125+
CrashAction.CancelForEverTapped -> scope.launch {
126+
cache.setCrashPullNeverShowAgain(true)
127+
}
120128
is CrashAction.Defer -> scope.launch {
121129
val state = getState()
122130
if (state is CrashState.Deferred) {
123131
cache.setDeferredUntil(state.until)
124132
}
125133
}
126134
is CrashAction.ReportTapped -> scope.launch {
127-
if (action.automaticallySendChecked) {
128-
cache.setAlwaysSend(true)
135+
if (action.crashIDs != null && action.crashIDs.size > 0) {
136+
sendCrashReports(action.crashIDs)
137+
} else {
138+
if (action.automaticallySendChecked) {
139+
cache.setAlwaysSend(true)
140+
}
141+
sendUnsentCrashReports()
129142
}
130-
sendUnsentCrashReports()
131143
}
144+
is CrashAction.PullCrashes -> {} // noop
132145
CrashAction.ShowPrompt -> {} // noop
133146
}
134147
}
@@ -144,4 +157,10 @@ class CrashMiddleware(
144157
crashReporter.submitReport(it)
145158
}
146159
}
160+
161+
private suspend fun sendCrashReports(crashIDs: Array<String>) {
162+
crashReporter.findCrashReports(crashIDs).forEach {
163+
crashReporter.submitReport(it)
164+
}
165+
}
147166
}

mobile/android/android-components/components/lib/crash/src/main/java/mozilla/components/lib/crash/store/CrashReducer.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ fun crashReducer(
2828
}
2929
is CrashAction.Defer -> CrashState.Deferred(action.now + FIVE_DAYS_IN_MILLIS)
3030
CrashAction.ShowPrompt -> CrashState.Reporting
31+
is CrashAction.PullCrashes -> CrashState.ReportingPull(action.crashIDs)
3132
CrashAction.CancelTapped,
33+
CrashAction.CancelForEverTapped,
3234
is CrashAction.ReportTapped,
3335
-> CrashState.Done
3436
}

mobile/android/android-components/components/lib/crash/src/main/java/mozilla/components/lib/crash/store/CrashState.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ sealed class CrashState {
3232
*/
3333
data object Reporting : CrashState()
3434

35+
/**
36+
* Crash reporter is presenting UI to the user to send crash reports that
37+
* were requested over Remote Settings.
38+
*/
39+
data class ReportingPull(val crashIDs: Array<String>) : CrashState()
40+
3541
/**
3642
* Crash reporter is done.
3743
*/

mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ import org.mozilla.fenix.theme.StatusBarColorManager
161161
import org.mozilla.fenix.theme.ThemeManager
162162
import org.mozilla.fenix.utils.Settings
163163
import org.mozilla.fenix.utils.changeAppLauncherIcon
164+
import java.lang.Math
165+
import java.lang.System
164166
import java.lang.ref.WeakReference
165167
import java.util.Locale
166168

@@ -216,6 +218,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
216218

217219
private val crashReporterBinding by lazy {
218220
CrashReporterBinding(
221+
context = this,
219222
store = components.appStore,
220223
onReporting = ::showCrashReporter,
221224
)
@@ -1435,12 +1438,23 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
14351438
messaging.onMessageDisplayed(nextMessage, currentBootUniqueIdentifier)
14361439
}
14371440

1438-
private fun showCrashReporter() {
1441+
private fun showCrashReporter(crashIDs: Array<String>?, ctxt: Context) {
14391442
if (!settings().useNewCrashReporterDialog) {
14401443
return
14411444
}
1445+
1446+
var now = Math.round(System.currentTimeMillis() / DateUtils.SECOND_IN_MILLIS * 1.0)
1447+
if (now < settings().crashPullDontShowBefore) {
1448+
return
1449+
}
1450+
14421451
UnsubmittedCrashDialog(
1443-
dispatcher = { action -> components.appStore.dispatch(AppAction.CrashActionWrapper(action)) },
1452+
dispatcher = { action ->
1453+
components.appStore.dispatch(AppAction.CrashActionWrapper(action))
1454+
settings().crashPullDontShowBefore = now + CRASH_PULL_SILENCE_FOR_DAYS_IN_S
1455+
},
1456+
crashIDs = crashIDs,
1457+
localContext = ctxt,
14441458
).show(supportFragmentManager, UnsubmittedCrashDialog.TAG)
14451459
}
14461460

@@ -1456,5 +1470,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
14561470
// PWA must have been used within last 30 days to be considered "recently used" for the
14571471
// telemetry purposes.
14581472
private const val PWA_RECENTLY_USED_THRESHOLD = DateUtils.DAY_IN_MILLIS * 30L
1473+
1474+
private const val CRASH_PULL_SILENCE_FOR_DAYS_IN_S = 7L * 86400L
14591475
}
14601476
}

mobile/android/fenix/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterBinding.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package org.mozilla.fenix.crashes
66

7+
import android.content.Context
78
import kotlinx.coroutines.flow.Flow
89
import kotlinx.coroutines.flow.distinctUntilChangedBy
910
import mozilla.components.lib.crash.store.CrashState
@@ -14,18 +15,23 @@ import org.mozilla.fenix.components.appstate.AppState
1415
/**
1516
* A binding for observing the [CrashState] in the [AppStore] and displaying the crash reporter.
1617
*
18+
* @param context The [Context] used to open links via Intents.
1719
* @param store The [AppStore] used to observe the [CrashState].
1820
* @param onReporting a callback that is called when [CrashState] is [CrashState.Reporting].
1921
*/
2022
class CrashReporterBinding(
23+
private val context: Context,
2124
store: AppStore,
22-
private val onReporting: () -> Unit,
25+
private val onReporting: (Array<String>?, Context) -> Unit,
2326
) : AbstractBinding<AppState>(store) {
2427
override suspend fun onState(flow: Flow<AppState>) {
2528
flow.distinctUntilChangedBy { state -> state.crashState }
2629
.collect { state ->
2730
if (state.crashState == CrashState.Reporting) {
28-
onReporting()
31+
onReporting(null, context)
32+
}
33+
if (state.crashState is CrashState.ReportingPull) {
34+
onReporting(state.crashState.crashIDs, context)
2935
}
3036
}
3137
}

mobile/android/fenix/app/src/main/java/org/mozilla/fenix/crashes/SettingsCrashReportCache.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,8 @@ class SettingsCrashReportCache(private val settings: Settings) : CrashReportCach
3333
override suspend fun setAlwaysSend(alwaysSend: Boolean) {
3434
settings.crashReportAlwaysSend = alwaysSend
3535
}
36+
37+
override suspend fun setCrashPullNeverShowAgain(neverShowAgain: Boolean) {
38+
settings.crashPullNeverShowAgain = neverShowAgain
39+
}
3640
}

0 commit comments

Comments
 (0)