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
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +189,7 @@ class CustomizationProviderTest : SysuiTestCase() {
|
||||
)
|
||||
underTest.previewManager =
|
||||
KeyguardRemotePreviewManager(
|
||||
applicationScope = testScope.backgroundScope,
|
||||
previewRendererFactory = previewRendererFactory,
|
||||
mainDispatcher = testDispatcher,
|
||||
backgroundHandler = backgroundHandler,
|
||||
|
||||
Reference in New Issue
Block a user