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

Commit 088adb1e authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

Blind fix for InterruptedException in runBlocking.

KeyguardRemotePreviewManager was using runBlocking to make sure a block
of code that destroys the renderer is called, on the main thread, before
proceeding. It seems like this was exposed to InterruptedExceptions
thrown when the main thread was getting interrupted by something
(presumably something in the framework interrupts blockers of the main
thread under unknown conditions).

The _blind_ fix (blind because it's not clear how to reproduce these
conditions) is to move the work to use launch instead of runBlocking
as we're still interested in doing the work on the main thread (so
listeners are removed from upstream dependencies of the renderer on a
known thread to avoid race conditions) but can live without the
atomicity provided by runBlocking.

Fix: 271691762
Test: manually verified that the lock screen preview in wallpaper
picker's various sections still seems to work, even when accessed
multiple times.

Change-Id: I7f0b1bd46986d87baa8e81c807ff8a7aa56e7959
parent fbcfaf0d
Loading
Loading
Loading
Loading
+20 −6
Original line number Diff line number Diff line
@@ -26,18 +26,21 @@ import android.util.ArrayMap
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.shared.quickaffordance.shared.model.KeyguardQuickAffordancePreviewConstants
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

@SysUISingleton
class KeyguardRemotePreviewManager
@Inject
constructor(
    private val previewRendererFactory: KeyguardPreviewRendererFactory,
    @Application private val applicationScope: CoroutineScope,
    @Main private val mainDispatcher: CoroutineDispatcher,
    @Background private val backgroundHandler: Handler,
) {
@@ -55,7 +58,13 @@ constructor(

            // Destroy any previous renderer associated with this token.
            activePreviews[renderer.hostToken]?.let { destroyObserver(it) }
            observer = PreviewLifecycleObserver(renderer, mainDispatcher, ::destroyObserver)
            observer =
                PreviewLifecycleObserver(
                    renderer,
                    applicationScope,
                    mainDispatcher,
                    ::destroyObserver,
                )
            activePreviews[renderer.hostToken] = observer
            renderer.render()
            renderer.hostToken?.linkToDeath(observer, 0)
@@ -92,13 +101,18 @@ constructor(

    private class PreviewLifecycleObserver(
        private val renderer: KeyguardPreviewRenderer,
        private val scope: CoroutineScope,
        private val mainDispatcher: CoroutineDispatcher,
        private val requestDestruction: (PreviewLifecycleObserver) -> Unit,
    ) : Handler.Callback, IBinder.DeathRecipient {

        private var isDestroyed = false
        private var isDestroyedOrDestroying = false

        override fun handleMessage(message: Message): Boolean {
            if (isDestroyedOrDestroying) {
                return true
            }

            when (message.what) {
                KeyguardQuickAffordancePreviewConstants.MESSAGE_ID_SLOT_SELECTED -> {
                    message.data
@@ -118,14 +132,14 @@ constructor(
        }

        fun onDestroy(): IBinder? {
            if (isDestroyed) {
            if (isDestroyedOrDestroying) {
                return null
            }

            isDestroyed = true
            isDestroyedOrDestroying = true
            val hostToken = renderer.hostToken
            hostToken?.unlinkToDeath(this, 0)
            runBlocking(mainDispatcher) { renderer.destroy() }
            scope.launch(mainDispatcher) { renderer.destroy() }
            return hostToken
        }
    }
+1 −0
Original line number Diff line number Diff line
@@ -189,6 +189,7 @@ class CustomizationProviderTest : SysuiTestCase() {
            )
        underTest.previewManager =
            KeyguardRemotePreviewManager(
                applicationScope = testScope.backgroundScope,
                previewRendererFactory = previewRendererFactory,
                mainDispatcher = testDispatcher,
                backgroundHandler = backgroundHandler,