google-ar / arcore-android-sdk

ARCore SDK for Android Studio
https://developers.google.com/ar
Other
4.91k stars 1.2k forks source link

Crash - IllegalStateException: maxImages (16) has already been acquired (SharedCamera) #1637

Open DanPetras opened 5 months ago

DanPetras commented 5 months ago

SPECIFIC ISSUE ENCOUNTERED

Crash from Crashlytics

VERSIONS USED

STEPS TO REPRODUCE THE ISSUE

Fatal Exception: java.lang.IllegalStateException: maxImages (16) has already been acquired, call #close before acquiring more.
       at android.media.ImageReader.acquireNextImage(ImageReader.java:661)
       at android.media.ImageReader.acquireLatestImage(ImageReader.java:541)
       at com.google.ar.core.SharedCamera.lambda$setDummyOnImageAvailableListener$0(SharedCamera.java:1)
       at com.google.ar.core.SharedCamera.a(SharedCamera.java)
       at com.google.ar.core.ap.onImageAvailable(ap.java)
       at android.media.ImageReader$1.run(ImageReader.java:947)
       at android.os.Handler.handleCallback(Handler.java:958)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:205)
       at android.os.Looper.loop(Looper.java:294)
       at android.os.HandlerThread.run(HandlerThread.java:67)

WORKAROUNDS (IF ANY)

The exception can't be caught as the call is made on another thread inside the AR core lib.

ADDITIONAL COMMENTS

The app is using AR core with the shared camera feature. The Crashlytics is reporting Device state 100% In background

15kingben commented 5 months ago

setDummyOnImageAvailableListener should not retain any images, so this is probably an issue that the acquired images are not being released from somewhere else. Are all images, either ARCore frames or images acquired from the SharedCamera, being promptly closed?

DanPetras commented 4 months ago

We are rendering the camera preview with com.google.ar.core.Session.setCameraTextureName(OpenGL TEXTURE_EXTERNAL_OES texture name) and not calling com.google.ar.core.Frame.acquireCameraImage() at all. We use separate android.hardware.camera2.CameraCaptureSession with separate android.media.ImageReader and closing images acquired this way as soon as possible (after converting and encoding to file). I don't see how this affects the setDummyOnImageAvailableListener but I just might not know, can you elaborate? Can be images acquired from setDummyOnImageAvailableListener accessed by any other means from app code that I don't know of? Thanks.

15kingben commented 4 months ago

This is triggered by Session.pause(), and simply puts OnImageAvailableListener to ARCore's image readers to avoid buffer starvation which does:

Image image = reader.acquireLatestImage();
if (image != null) {
  image.close();
}

So those images are not being used anywhere. However, acquireLatestImage could fail if the app has already acquired and failed to release 16 other images.

DanPetras commented 4 months ago

How can the app acquire images from the same ImageReader that setDummyOnImageAvailableListener is using? I'm not aware that we do such thing.

From what you wrote, it seems that the ImageReader buffer is already full when setDummyOnImageAvailableListener is called. Is the app causing this (the filled buffer) or ARCore itself?

We are using com.google.ar.core.Config.updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE (if that changes anything).

DanPetras commented 1 day ago

I checked it several times already and I'm sure I'm closing all the images obtained by com.google.ar.core.Frame.acquireCameraImage().

Like this:

frame.acquireCameraImage().use { /* convert image to bitmap */ }

The only other images I acquire are from my own android.media.ImageReader which has maxImages set to 5, so there is no chance that I could acquire 16 images from that. I'm also pretty sure that all of those images are closed too.

Is there something else that could be acquiring those 16 images before we call com.google.ar.core.Session.pause()?