I have reports on my Google Play Console of very enigmatic error in my app that is using CameraX. It is a low-level fdsan error that I cannot fix with what seems like a very safely written code. Here is the (most relevant in my opinion) usage of CameraX in my code:
class CameraConfig(private val context: Context) {
private val cameraExecutor = Executors.newSingleThreadExecutor()
private var cameraProvider: ProcessCameraProvider? = null
private var camera: Camera? = null
private val cameraSelector: CameraSelector by lazy {
CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
}
private val preview: Preview by lazy {
Preview.Builder().build()
}
private val resolutionSelector: ResolutionSelector by lazy {
ResolutionSelector.Builder().build()
}
private val imageAnalysis: ImageAnalysis by lazy {
ImageAnalysis.Builder().apply {
setResolutionSelector(resolutionSelector)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setOutputImageRotationEnabled(true)
}
}.build()
}
fun startCamera(lifecycleOwner: LifecycleOwner, previewView: PreviewView) {
try {
ProcessCameraProvider.configureInstance(Camera2Config.defaultConfig())
} catch (illegalStateException: IllegalStateException) { /* no-op */ }
val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
cameraProviderFuture.addListener({
cameraProvider = cameraProviderFuture.get().apply {
try {
unbindAll()
preview.surfaceProvider = previewView.surfaceProvider
camera = bindToLifecycle(
lifecycleOwner,
cameraSelector,
preview,
imageAnalysis
).apply {
configureAutoFocus(previewView, this)
}
} catch (exception: Exception) {
Log.e("CameraConfig", "Error when starting camera", exception)
}
}
}, ContextCompat.getMainExecutor(context))
}
fun stopCamera() {
imageAnalysis.clearAnalyzer()
cameraProvider?.let {
it.unbindAll()
camera = null
}
if (!cameraExecutor.isShutdown) {
cameraExecutor.shutdownNow()
}
}
private fun configureAutoFocus(previewView: PreviewView, camera: Camera) {
previewView.afterMeasured {
val previewViewWidth = previewView.width.toFloat()
val previewViewHeight = previewView.height.toFloat()
val autoFocusPoint = SurfaceOrientedMeteringPointFactory(
previewViewWidth, previewViewHeight
).createPoint(previewViewWidth / 2.0f, previewViewHeight / 2.0f)
try {
camera.cameraControl.startFocusAndMetering(
FocusMeteringAction
.Builder(autoFocusPoint, FocusMeteringAction.FLAG_AF)
.setAutoCancelDuration(2, TimeUnit.SECONDS)
.build()
)
} catch (exception: CameraInfoUnavailableException) {
Log.d("CameraConfig", "Cannot access camera", exception)
}
}
}
private inline fun View.afterMeasured(crossinline block: () -> Unit) {
if (measuredWidth > 0 && measuredHeight > 0) {
block()
} else {
viewTreeObserver.addOnGlobalLayoutListener(
object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (measuredWidth > 0 && measuredHeight > 0) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
block()
}
}
}
)
}
}
fun setAnalyzer(analyzer: ImageAnalysis.Analyzer) {
imageAnalysis.setAnalyzer(cameraExecutor, analyzer)
}
}
This seems like the most generic usage of CameraX with nothing too special. It is following the official guidelines, yet this error is being reported:
Thread: fdsan: attempted to close file descriptor 214, expected to be unowned, actually owned by unique_fd 0xe5d47e98
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
pid: 0, tid: 3190 >>> my.package.name <<<
backtrace:
#00 pc 0x0000000000066010 /apex/com.android.runtime/lib/bionic/libc.so (fdsan_error(char const*, ...)+352)
#01 pc 0x0000000000065d57 /apex/com.android.runtime/lib/bionic/libc.so (android_fdsan_close_with_tag+486)
#02 pc 0x000000000006639f /apex/com.android.runtime/lib/bionic/libc.so (close+6)
#03 pc 0x000000000002da13 /system/lib/libmedia_jni.so (Image_createSurfacePlanes(_JNIEnv*, _jobject*, int, int, int)+374)
#04 pc 0x000000000037aa07 /data/misc/apexdata/com.android.art/dalvik-cache/arm/boot.oat (art_jni_trampoline+86)
#05 pc 0x00000000000a046c /apex/com.android.art/lib/libart.so (nterp_helper+2908)
#06 pc 0x0000000000333d6e /system/framework/framework.jar (android.media.ImageWriter$WriterSurfaceImage.getPlanes+62)
#07 pc 0x00000000000a0400 /apex/com.android.art/lib/libart.so (nterp_helper+2800)
#08 pc 0x000000000022a612 /data/app/~~uiXrYUvYrHwe5z3MVedk2g==/my.package.name-mrHk4sdqYu3mfkEaStJqkg==/base.apk (androidx.camera.core.ImageProcessingUtil.e+278)
#09 pc 0x00000000000a00f4 /apex/com.android.art/lib/libart.so (nterp_helper+2020)
#10 pc 0x000000000011e090 /data/app/~~uiXrYUvYrHwe5z3MVedk2g==/my.package.name-mrHk4sdqYu3mfkEaStJqkg==/base.apk (B.O.c+204)
#11 pc 0x00000000000a0400 /apex/com.android.art/lib/libart.so (nterp_helper+2800)
#12 pc 0x000000000011ed8c /data/app/~~uiXrYUvYrHwe5z3MVedk2g==/my.package.name-mrHk4sdqYu3mfkEaStJqkg==/base.apk (B.T.f+128)
#13 pc 0x00000000000a0400 /apex/com.android.art/lib/libart.so (nterp_helper+2800)
#14 pc 0x000000000011e2f8 /data/app/~~uiXrYUvYrHwe5z3MVedk2g==/my.package.name-mrHk4sdqYu3mfkEaStJqkg==/base.apk (B.O.b+12)
#15 pc 0x00000000000a0dac /apex/com.android.art/lib/libart.so (nterp_helper+5276)
#16 pc 0x000000000010e7a2 /data/app/~~uiXrYUvYrHwe5z3MVedk2g==/my.package.name-mrHk4sdqYu3mfkEaStJqkg==/base.apk (A.f.b+62)
#17 pc 0x00000000001547c9 /data/app/~~uiXrYUvYrHwe5z3MVedk2g==/my.package.name-mrHk4sdqYu3mfkEaStJqkg==/oat/arm/base.odex (B.c.run+9112)
#18 pc 0x00000000005ab7f9 /data/misc/apexdata/com.android.art/dalvik-cache/arm/boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+840)
#19 pc 0x00000000005a9279 /data/misc/apexdata/com.android.art/dalvik-cache/arm/boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+64)
#20 pc 0x000000000049e357 /data/misc/apexdata/com.android.art/dalvik-cache/arm/boot.oat (java.lang.Thread.run+70)
#21 pc 0x00000000000a4775 /apex/com.android.art/lib/libart.so (art_quick_invoke_stub_internal+68)
#22 pc 0x00000000005ad1f1 /apex/com.android.art/lib/libart.so (art_quick_invoke_stub+248)
#23 pc 0x0000000000208e25 /apex/com.android.art/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+120)
#24 pc 0x0000000000518223 /apex/com.android.art/lib/libart.so (art::Thread::CreateCallback(void*)+1106)
#25 pc 0x00000000000ad143 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+40)
#26 pc 0x00000000000642dd /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+30)
There is the line where androidx.camera.core.ImageProcessingUtil
is mentioned, so only this leads me to think the issue is related to CameraX.
I have no idea how to even try to replicate this issue, let alone fix it. I have not seen anyone on the internet having this issue and I'm wondering if there is anybody who will have any clue as to what is going on around here.
Source: View source