Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 59f8b090 authored by Matt Pietal's avatar Matt Pietal
Browse files

Transition race condition fix part 2

Hold the mutex long enough to ensure the transition
starts/emits.

The theory is that unlocking the mutex early could transitions that
held the mutex to then resume, potentially reaching calls to start
prior to the first transition.

Fixes: 409585200
Test: atest KeyguardTransitionRepositoryImplTest
Flag: com.android.systemui.transition_race_condition_part2
Change-Id: If2089e66912d2f53bc14c8b2266b92d7e8d42445
parent d6300a6b
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1621,6 +1621,16 @@ flag {
  bug: "362719719"
}

flag {
  name: "transition_race_condition_part2"
  namespace: "systemui"
  description: "Thread-safe keyguard transitions"
  bug: "409585200"
  metadata {
       purpose: PURPOSE_BUGFIX
  }
}

flag {
   name: "media_projection_request_attribution_fix"
   namespace: "systemui"
+27 −3
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.util.Log
import com.android.app.animation.Interpolators
import com.android.app.tracing.coroutines.flow.traceAs
import com.android.app.tracing.coroutines.withContextTraced as withContext
import com.android.systemui.Flags.transitionRaceConditionPart2
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -192,9 +193,14 @@ constructor(

        // Animators must be started on the main thread.
        return withContext("$TAG#startTransition", mainDispatcher) {
            if (!transitionRaceConditionPart2()) {
                withContextMutex.unlock()
            }
            if (lastStep.from == info.from && lastStep.to == info.to) {
                Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
                if (transitionRaceConditionPart2()) {
                    withContextMutex.unlock()
                }
                return@withContext null
            }
            val isAnimatorRunning = lastAnimator?.isRunning() ?: false
@@ -264,6 +270,9 @@ constructor(
                animator.addListener(animatorListener)
                animator.addUpdateListener(updateListener)
                animator.start()
                if (transitionRaceConditionPart2()) {
                    withContextMutex.unlock()
                }
                return@withContext null
            }
                ?: run {
@@ -274,6 +283,9 @@ constructor(

                    // No animator, so it's manual. Provide a mechanism to callback
                    updateTransitionId = UUID.randomUUID()
                    if (transitionRaceConditionPart2()) {
                        withContextMutex.unlock()
                    }
                    return@withContext updateTransitionId
                }
        }
@@ -289,9 +301,15 @@ constructor(
        // requires the same lock
        withContextMutex.lock()
        withContext("$TAG#updateTransition", mainDispatcher) {
            if (!transitionRaceConditionPart2()) {
                withContextMutex.unlock()
            }

            updateTransitionInternal(transitionId, value, state)

            if (transitionRaceConditionPart2()) {
                withContextMutex.unlock()
            }
        }
    }

@@ -303,7 +321,9 @@ constructor(
        withContextMutex.lock()

        return withContext("$TAG#forceFinishCurrentTransition", mainDispatcher) {
            if (!transitionRaceConditionPart2()) {
                withContextMutex.unlock()
            }

            Log.d(TAG, "forceFinishCurrentTransition() - emitting FINISHED early.")

@@ -319,6 +339,10 @@ constructor(
                // Ask the listener to emit FINISHED and clean up its state.
                animatorListener?.onAnimationEnd(this)
            }

            if (transitionRaceConditionPart2()) {
                withContextMutex.unlock()
            }
        }
    }