Skip to content

Commit 45a60ce

Browse files
Andrew Coxmeta-codesync[bot]
authored andcommitted
Fix ANR: Prevent synchronous network fetch on Litho layout threads
Reviewed By: defHLT Differential Revision: D91274295 fbshipit-source-id: e52163d4ba267f27c390d6fe935afc17498d759f
1 parent f20566b commit 45a60ce

File tree

3 files changed

+22
-5
lines changed

3 files changed

+22
-5
lines changed

imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineExperiments.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package com.facebook.imagepipeline.core
99

1010
import android.content.Context
1111
import android.graphics.Bitmap
12+
import android.os.Looper
1213
import com.facebook.cache.common.CacheKey
1314
import com.facebook.common.internal.Supplier
1415
import com.facebook.common.internal.Suppliers
@@ -65,6 +66,7 @@ class ImagePipelineExperiments private constructor(builder: Builder) {
6566
val trackedKeysSize: Int
6667
val allowDelay: Boolean
6768
val handOffOnUiThreadOnly: Boolean
69+
val isCriticalThread: () -> Boolean
6870
val shouldStoreCacheEntrySize: Boolean
6971
val shouldIgnoreCacheSizeMismatch: Boolean
7072
val shouldUseDecodingBufferHelper: Boolean
@@ -125,6 +127,7 @@ class ImagePipelineExperiments private constructor(builder: Builder) {
125127
@JvmField var trackedKeysSize = 20
126128
@JvmField var allowDelay = false
127129
@JvmField var handOffOnUiThreadOnly = false
130+
@JvmField var isCriticalThread: (() -> Boolean)? = null
128131
@JvmField var shouldStoreCacheEntrySize = false
129132

130133
@JvmField var shouldIgnoreCacheSizeMismatch = false
@@ -161,6 +164,10 @@ class ImagePipelineExperiments private constructor(builder: Builder) {
161164
this.handOffOnUiThreadOnly = handOffOnUiThreadOnly
162165
}
163166

167+
fun setIsCriticalThread(isCriticalThread: () -> Boolean) = asBuilder {
168+
this.isCriticalThread = isCriticalThread
169+
}
170+
164171
fun setStoreCacheEntrySize(shouldStoreCacheEntrySize: Boolean) = asBuilder {
165172
this.shouldStoreCacheEntrySize = shouldStoreCacheEntrySize
166173
}
@@ -507,6 +514,18 @@ class ImagePipelineExperiments private constructor(builder: Builder) {
507514
animationRenderFpsLimit = builder.animationRenderFpsLimit
508515
allowDelay = builder.allowDelay
509516
handOffOnUiThreadOnly = builder.handOffOnUiThreadOnly
517+
isCriticalThread =
518+
builder.isCriticalThread
519+
?: {
520+
// If handOffOnUiThreadOnly is false, treat every thread as critical so handoff always
521+
// happens
522+
if (!handOffOnUiThreadOnly) {
523+
true
524+
} else {
525+
// Otherwise, only the main thread is critical
526+
Looper.getMainLooper().thread === Thread.currentThread()
527+
}
528+
}
510529
shouldStoreCacheEntrySize = builder.shouldStoreCacheEntrySize
511530
shouldIgnoreCacheSizeMismatch = builder.shouldIgnoreCacheSizeMismatch
512531
shouldUseDecodingBufferHelper = builder.shouldUseDecodingBufferHelper

imagepipeline/src/main/java/com/facebook/imagepipeline/producers/ThreadHandoffProducer.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
package com.facebook.imagepipeline.producers
99

10-
import android.os.Looper
1110
import com.facebook.imagepipeline.instrumentation.FrescoInstrumenter
1211
import com.facebook.imagepipeline.systrace.FrescoSystrace.traceSection
1312
import java.lang.Exception
@@ -27,6 +26,7 @@ class ThreadHandoffProducer<T>(
2726
inputProducer.produceResults(consumer, context)
2827
return
2928
}
29+
3030
val statefulRunnable: StatefulProducerRunnable<T> =
3131
object : StatefulProducerRunnable<T>(consumer, producerListener, context, PRODUCER_NAME) {
3232
override fun onSuccess(ignored: T?) {
@@ -64,10 +64,7 @@ class ThreadHandoffProducer<T>(
6464
}
6565

6666
private fun shouldRunImmediately(context: ProducerContext): Boolean {
67-
if (!context.imagePipelineConfig.experiments.handOffOnUiThreadOnly) {
68-
return false
69-
}
70-
return Looper.getMainLooper().thread !== Thread.currentThread()
67+
return !context.imagePipelineConfig.experiments.isCriticalThread()
7168
}
7269
}
7370
}

imagepipeline/src/test/java/com/facebook/imagepipeline/producers/ThreadHandoffProducerTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class ThreadHandoffProducerTest {
6464

6565
Mockito.doReturn(imagePipelineExperiments).`when`(config).experiments
6666
Mockito.doReturn(false).`when`(imagePipelineExperiments).handOffOnUiThreadOnly
67+
Mockito.doReturn({ true }).`when`(imagePipelineExperiments).isCriticalThread
6768
}
6869

6970
@Test

0 commit comments

Comments
 (0)