You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
4.3 KiB
Kotlin
102 lines
4.3 KiB
Kotlin
/* 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.
|
|
}
|
|
}
|
|
}
|