getsentry / sentry-java

A Sentry SDK for Java, Android and other JVM languages.
https://docs.sentry.io/
MIT License
1.16k stars 435 forks source link

Getting unable to stop activity java.lang.IndexOutOfBoundsException: Index: 3, Size: 2 when integrating Session Replay #3859

Open Wintjen opened 6 days ago

Wintjen commented 6 days ago

Integration

sentry-android

Build System

Gradle

AGP Version

8.3.0

Proguard

Enabled

Version

7.16.0

Steps to Reproduce

  1. Follow steps in Sentry Session Replay setup docs
  2. After adding options.experimental.sessionReplay.onErrorSampleRate = 1.0 and options.experimental.sessionReplay.sessionSampleRate = 1.0 starting my app
  3. App shows splash screen and tries to navigate

Expected Result

App should make it past home screen and continue into the app as normal

Actual Result

The app crashes with the following stack trace

FATAL EXCEPTION: main Process: com.myApp, PID: 15002 java.lang.RuntimeException: Unable to stop activity {com.myApp.splash.SplashScreenActivity}: java.lang.IndexOutOfBoundsException: Index: 3, Size: 2 at android.app.ActivityThread.callActivityOnStop(ActivityThread.java:5202) at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:5174) at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5239) at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:234) at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7898) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936) Caused by: java.lang.IndexOutOfBoundsException: Index: 3, Size: 2 at java.util.ArrayList.get(ArrayList.java:437) at android.view.WindowManagerGlobal.setStoppedState(WindowManagerGlobal.java:658) at android.app.Activity.performStop(Activity.java:8506) at android.app.ActivityThread.callActivityOnStop(ActivityThread.java:5194) at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:5174)  at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5239)  at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:234)  at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)  at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308)  at android.os.Handler.dispatchMessage(Handler.java:106)  at android.os.Looper.loopOnce(Looper.java:201)  at android.os.Looper.loop(Looper.java:288)  at android.app.ActivityThread.main(ActivityThread.java:7898)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936) 

romtsn commented 2 days ago

hi @Wintjen, sorry you're having troubles with replay! Could you be a bit more specific about your setup? Someone's mentioned using foreground service can help reproducing the issue, is this also the case for you?

It's not reproducible in our sample app, so I'm looking for clues to help reproduce this. Do you launch your next activity from SplashScreenActivity in onCreate/onStart?

Wintjen commented 2 days ago

Yes in my splash screen activity, I have an onCreate that does some logic then tries to navigate me to the rest of my application. The crash is happening before this process is finished since we don't ever make it pass the splash screen. My app is working fine till trying to integrate session replay.

Here is my SplashScreenActivity.kt

package com.myApp.splash

import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import com.myApp.appcore.screen.base.extension.observeNonNull
import com.myApp.appcore.screen.common.NavigationResultKeys
import com.myApp.domain.main.TVStartingPointDomainModel
import com.myApp.R
import com.myApp.SplashScreenNavGraphDirections
import com.myApp.main.MainActivity
import dagger.hilt.android.AndroidEntryPoint

@SuppressLint("CustomSplashScreen")
@AndroidEntryPoint
class SplashScreenActivity : AppCompatActivity() {

    private val viewModel: SplashViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_splash)

        observeNonNull(viewModel.loadingDataFinished) {
            navigateToMainActivity(it, intent)
        }

        observeNonNull(viewModel.navigationEvent) {
            when (it) {
                SplashViewModel.NavigationEvent.CONNECTION_LOST -> {
                    findNavController(R.id.nav_host_fragment).navigate(
                        SplashScreenNavGraphDirections.toConnectivity()
                    )
                }
                SplashViewModel.NavigationEvent.CONNECTION_AVAILABLE -> {
                    if (viewModel.loadingDataFinished.isLoadingDataFinished().not()) {
                        viewModel.initializeData()
                    }
                }
                SplashViewModel.NavigationEvent.TO_EXIT -> {
                    findNavController(R.id.nav_host_fragment)
                        .navigate(SplashScreenNavGraphDirections.toError())
                    findNavController(R.id.nav_host_fragment)
                        .navigate(SplashScreenNavGraphDirections.toExit())
                }
            }
        }
        observeNonNull(viewModel.errorsStream) {
            findNavController(R.id.nav_host_fragment).navigate(
                SplashScreenNavGraphDirections.toError()
            )
        }

        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment) as NavHostFragment?
        val navController = navHostFragment?.navController
        navController?.currentBackStackEntry?.savedStateHandle
            ?.getLiveData<Boolean>(NavigationResultKeys.REFRESH_SCREEN_AFTER_ERROR)?.observe(this) {
                if (it)
                    viewModel.initializeData()
                else
                    viewModel.onDeclineRefresh()
            }
    }

    private fun navigateToMainActivity(model: TVStartingPointDomainModel, intent: Intent) {
        startActivity(MainActivity.buildIntent(this, model, intent))
        finish()
    }

    private fun LiveData<TVStartingPointDomainModel>.isLoadingDataFinished() = this.value is
            TVStartingPointDomainModel

    /* Start destination for splash nav graph*/
    class EmptyFragment: Fragment()
}