For #18426: add ApplicationStartReasonProvider.

We need to know this state to add a correct COLD MAIN probe.
upstream-sync
Michael Comella 3 years ago committed by Michael Comella
parent 520634165e
commit edd49b286d

@ -1187,6 +1187,40 @@ metrics:
notification_emails:
- fenix-core@mozilla.com
expires: "2021-08-01"
start_reason_process_error:
type: boolean
description: |
The `AppStartReasonProvider.ProcessLifecycleObserver.onCreate` was
unexpectedly called twice. We can use this metric to validate our
assumptions about how these APIs are called. This probe can be removed
once we validate these assumptions.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18426
data_reviews:
- TODO
data_sensitivity:
- technical
notification_emails:
- perf-android-fe@mozilla.com
- mcomella@mozilla.com
expires: "2021-08-11"
start_reason_activity_error:
type: boolean
description: |
The `AppStartReasonProvider.ActivityLifecycleCallbacks.onCreate` was
unexpectedly called twice. We can use this metric to validate our
assumptions about how these APIs are called. This probe can be removed
once we validate these assumptions.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18426
data_reviews:
- TODO
data_sensitivity:
- technical
notification_emails:
- perf-android-fe@mozilla.com
- mcomella@mozilla.com
expires: "2021-08-11"
preferences:
show_search_suggestions:

@ -51,6 +51,7 @@ import org.mozilla.fenix.components.metrics.MetricServiceType
import org.mozilla.fenix.components.metrics.SecurePrefsTelemetry
import org.mozilla.fenix.ext.measureNoInline
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.perf.AppStartReasonProvider
import org.mozilla.fenix.perf.ProfilerMarkerFactProcessor
import org.mozilla.fenix.perf.StartupTimeline
import org.mozilla.fenix.perf.StorageStatsMetrics
@ -190,6 +191,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
// runStorageMaintenance()
// }
components.appStartReasonProvider.registerInAppOnCreate(this)
initVisualCompletenessQueueAndQueueTasks()
components.appStartupTelemetry.onFenixApplicationOnCreate()

@ -28,6 +28,7 @@ import org.mozilla.fenix.perf.StrictModeManager
import org.mozilla.fenix.components.metrics.AppStartupTelemetry
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.perf.AppStartReasonProvider
import org.mozilla.fenix.perf.lazyMonitored
import org.mozilla.fenix.utils.ClipboardHandler
import org.mozilla.fenix.utils.Mockable
@ -170,4 +171,6 @@ class Components(private val context: Context) {
httpClient = core.client
)
}
val appStartReasonProvider by lazyMonitored { AppStartReasonProvider() }
}

@ -0,0 +1,101 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.perf
import android.app.Activity
import android.app.Application
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.GleanMetrics.Metrics
import org.mozilla.fenix.android.DefaultActivityLifecycleCallbacks
private val logger = Logger("AppStartReasonProvider")
/**
* Provides the reason this [Application] instance was started: see [StartReason] for options
* and [reason] for details.
*
* [registerInAppOnCreate] must be called for this class to work correctly.
*
* This class relies on specific lifecycle method call orders and main thread Runnable scheduling
* that could potentially change between OEMs and OS versions: **be careful when using it.** This
* implementation was tested on the Moto G5 Android 8.1.0 and the Pixel 2 Android 11.
*/
class AppStartReasonProvider {
enum class StartReason {
/** We don't know yet what caused this [Application] instance to be started. */
TO_BE_DETERMINED,
/** This [Application] instance was started due to an Activity trying to start. */
ACTIVITY,
/**
* This [Application] instance was started due to a component that is not an Activity:
* this may include Services, BroadcastReceivers, and ContentProviders. It may be possible
* to distinguish between these but it hasn't been necessary to do so yet.
*/
NON_ACTIVITY,
}
/**
* The reason this [Application] instance was started. This will not be set immediately
* but is expected to be available by the time the first frame is drawn for the foreground Activity.
*/
var reason = StartReason.TO_BE_DETERMINED
private set
/**
* Registers the handlers needed by this class: this is expected to be called from
* [Application.onCreate].
*/
fun registerInAppOnCreate(application: Application) {
ProcessLifecycleOwner.get().lifecycle.addObserver(ProcessLifecycleObserver())
application.registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks())
}
private inner class ProcessLifecycleObserver : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
Handler(Looper.getMainLooper()).post {
// If the Application was started by an Activity, this Runnable should execute
// after we learn the Activity was created. If the App was started by a Service,
// this Runnable should execute before the first Activity is created.
reason = when (reason) {
StartReason.TO_BE_DETERMINED -> StartReason.NON_ACTIVITY
StartReason.ACTIVITY -> reason /* the start reason is already known: do nothing. */
StartReason.NON_ACTIVITY -> {
Metrics.startReasonProcessError.set(true)
logger.error("AppStartReasonProvider.Process...onCreate unexpectedly called twice")
reason
}
}
}
owner.lifecycle.removeObserver(this) // we don't update the state further.
}
}
private inner class ActivityLifecycleCallbacks : DefaultActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, bundle: Bundle?) {
// See ProcessLifecycleObserver.onCreate for details.
reason = when (reason) {
StartReason.TO_BE_DETERMINED -> StartReason.ACTIVITY
StartReason.NON_ACTIVITY -> reason /* the start reason is already known: do nothing. */
StartReason.ACTIVITY -> {
Metrics.startReasonActivityError.set(true)
logger.error("AppStartReasonProvider.Activity...onCreate unexpectedly called twice")
reason
}
}
activity.application.unregisterActivityLifecycleCallbacks(this) // we don't update the state further.
}
}
}

@ -331,6 +331,8 @@ In addition to those built-in metrics, the following metrics are added to the pi
| metrics.recently_used_pwa_count |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |A counter that indicates how many PWAs a user has recently used. Threshold for "recency" set in HomeActivity#PWA_RECENTLY_USED_THRESHOLD. Currently we are not told by the OS when a PWA is removed by the user, so we use the "recently used" heuristic to judge how many PWAs are still active, as a proxy for "installed". This value will only be set if the user has at least *one* recently used PWA. If they have 0, this metric will not be sent, resulting in a null value during analysis on the server-side. To disambiguate between a failed `recently_used_pwa_count` metric and 0 recent PWAs, please see `has_recent_pwas`. |[mozilla-mobile/fenix#11982](https://github.com/mozilla-mobile/fenix/pull/11982#pullrequestreview-437963817), [mozilla-mobile/fenix#15713](https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068)||2021-08-01 |2 |
| metrics.search_count |[labeled_counter](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html) |The labels for this counter are `<search-engine-name>.<source>`. If the search engine is bundled with Fenix `search-engine-name` will be the name of the search engine. If it's a custom search engine (defined: https://github.com/mozilla-mobile/fenix/issues/1607) the value will be `custom`. `source` will be: `action`, `suggestion`, `widget`, `shortcut`, `topsite` (depending on the source from which the search started). Also added the `other` option for the source but it should never enter on this case. |[mozilla-mobile/fenix#1677](https://github.com/mozilla-mobile/fenix/pull/1677), [mozilla-mobile/fenix#5216](https://github.com/mozilla-mobile/fenix/pull/5216), [mozilla-mobile/fenix#7310](https://github.com/mozilla-mobile/fenix/pull/7310), [mozilla-mobile/fenix#15713](https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068)||2021-08-01 |1, 2 |
| metrics.search_widget_installed |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |Whether or not the search widget is installed |[mozilla-mobile/fenix#10958](https://github.com/mozilla-mobile/fenix/pull/10958), [mozilla-mobile/fenix#15713](https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068)||2021-08-01 |2 |
| metrics.start_reason_activity_error |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |The `AppStartReasonProvider.ActivityLifecycleCallbacks.onCreate` was unexpectedly called twice. We can use this metric to validate our assumptions about how these APIs are called. This probe can be removed once we validate these assumptions. |[Review 1](TODO)||2021-08-11 |1 |
| metrics.start_reason_process_error |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |The `AppStartReasonProvider.ProcessLifecycleObserver.onCreate` was unexpectedly called twice. We can use this metric to validate our assumptions about how these APIs are called. This probe can be removed once we validate these assumptions. |[Review 1](TODO)||2021-08-11 |1 |
| metrics.tab_view_setting |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string that indicates the setting for tab view: GRID, LIST |[mozilla-mobile/fenix#15811](https://github.com/mozilla-mobile/fenix/pull/15811#issuecomment-706402952)||2021-08-01 |2 |
| metrics.tabs_open_count |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |A counter that indicates how many NORMAL tabs a user has open. This value will only be set if the user has at least *one* open tab. If they have 0, this ping will not get sent, resulting in a null value. To disambiguate between a failed `tabs_open_count` ping and 0 open tabs, please see `has_open_tabs`. |[mozilla-mobile/fenix#12024](https://github.com/mozilla-mobile/fenix/pull/12024), [mozilla-mobile/fenix#15713](https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068)||2021-08-01 |2 |
| metrics.toolbar_position |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string that indicates the new position of the toolbar TOP or BOTTOM |[mozilla-mobile/fenix#6608](https://github.com/mozilla-mobile/fenix/pull/6608), [mozilla-mobile/fenix#15713](https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068)||2021-08-01 |2 |

Loading…
Cancel
Save