Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firebase Performance does not send app start traces on some devices (API 34 Pixel 7) #5920

Open
PhilGlass opened this issue May 2, 2024 · 0 comments

Comments

@PhilGlass
Copy link

PhilGlass commented May 2, 2024

Firebase Component: Performance 20.5.2 (BOM 32.8.0)

Steps to reproduce:

  • Install an app that uses Firebase Performance on an Android 14 (API 34) Pixel 7.
    • Note that this does not reproduce on an API 34 emulator. I haven't tried other physical devices.
  • Open the app.
  • Observe that there are no app start traces sent.

I noticed this when I was trying to figure out why we aren't getting any app start traces at all. That turned out to be because we were manually initializing Firebase. But even after switching back to the automatic initialization I didn't see any app start traces being sent on my development device, an Android 14 (API 34) Pixel 7. When I installed the app on an API 24 emulator I did see app start traces being sent.

As described in the linked issue, when I ran with a debugger attached (using adb shell am set-debug-app so I could attach as early as possible) I was seeing that this:

// if no activity has ever been created.
if (trace.onCreateTime == null) {
trace.isStartedFromBackground = true;
}
}

was being executed before onActivityCreated is able to set onCreateTime:

Which meant that the ordering assumptions described here:

/**
* We use StartFromBackgroundRunnable to detect if app is started from background or foreground.
* If app is started from background, we do not generate AppStart trace. This runnable is posted
* to main UI thread from FirebasePerfEarly. If app is started from background, this runnable will
* be executed before any activity's onCreate() method. If app is started from foreground,
* activity's onCreate() method is executed before this runnable.
*/
public static class StartFromBackgroundRunnable implements Runnable {

don't hold, Firebase Performance considers every launch to be a background launch and never sends app start traces.

Relevant Code:

Here's a simple demonstration that mimics the ordering assumptions Firebase Performance is making. Copy-paste this provider into a new sample project:

class SampleProvider : ContentProvider() {
    private var activityCreated = false
    private var mainThreadRunnableRun = false

    override fun onCreate(): Boolean {
        (context!!.applicationContext as Application).registerActivityLifecycleCallbacks(object :
            ActivityLifecycleCallbacks {
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                Log.d(
                    "FirebasePerf",
                    "onActivityCreated: mainThreadRunnableRun = $mainThreadRunnableRun"
                )
                activityCreated = true
            }

            override fun onActivityStarted(activity: Activity) {}
            override fun onActivityResumed(activity: Activity) {}
            override fun onActivityPaused(activity: Activity) {}
            override fun onActivityStopped(activity: Activity) {}
            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
            override fun onActivityDestroyed(activity: Activity) {}
        })

        Handler(Looper.getMainLooper()).post {
            Log.d("FirebasePerf", "mainThreadRunnable.run(): activityCreated = $activityCreated")
            mainThreadRunnableRun = true
        }

        return true
    }

    override fun query(
        uri: Uri,
        projection: Array<out String>?,
        selection: String?,
        selectionArgs: Array<out String>?,
        sortOrder: String?
    ): Cursor? {
        TODO("Not yet implemented")
    }

    override fun getType(uri: Uri): String? {
        TODO("Not yet implemented")
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        TODO("Not yet implemented")
    }

    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
        TODO("Not yet implemented")
    }

    override fun update(
        uri: Uri,
        values: ContentValues?,
        selection: String?,
        selectionArgs: Array<out String>?
    ): Int {
        TODO("Not yet implemented")
    }
}

You'll need to register it in the manifest, install it on an Android 14 (API 34) Pixel 7 and launch the default activity. Then you'll see this in logcat:

15:13:17.036 FirebasePerf              D  mainThreadRunnable.run(): activityCreated = false
15:13:17.352 FirebasePerf              D  onActivityCreated: mainThreadRunnableRun = true

which demonstrates that the runnable posted to the main thread executes before the Activity's onCreate, even when the process was started in order to launch an activity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants