One of the official Google samples for the Camera2 API suffers from the same BufferQueue has been abandoned
problem as is seen in:
Specifically, the sample app calls a closeCamera()
method from onPause()
of a fragment, where closeCamera()
calls close()
on the CameraCaptureSession
, then close()
on the CameraDevice
, then close()
on the ImageReader
(used for actual picture-taking). After the close()
on CameraDevice
is when a few occurrences of the aforementioned BufferQueue has been abandoned
message appears in LogCat, though I only get the message on some Android 5.1 hardware (Nexus 4 and Nexus 7 2013) and not others (Nexus 5 and Nexus 6).
fadden's comment on this was:
If the consumer side is shut down before entering onPause(), the messages would be expected.
When will TextureView
's "consumer side" will be shut down, and why then?
Google's sample code does not proactively do anything to shut down the TextureView
that I can see. And, since the TextureView
could still be visible when paused, I would have expected that the "consumer side" would not be affected at the time of onPause()
, but perhaps later in onStop()
.
While I realize that this message (despite being an error) is benign, I'm trying to figure out how to get rid of it, if for no other reason than to prevent my being asked time and again why code of mine is logging this error. I am hoping that by understanding more about this "consumer side", I can figure out how better to tidy things up when the user exits a Camera2-using activity or fragment and avoid this error.
As to the actual question - "when is a TextureView's 'Consumer side' closed", I don't know the exact timing, but it is certainly after onPause returns.
Roughly, TextureView contains a GL surface, and once the UI for the activity is no longer visible, those resources are torn down. Once that happens, the SurfaceTexture given out by the TextureView is no longer valid, and any existing users of that SurfaceTexture (or Surfaces made from it) will start receiving those errors. The method TextureView.SurfaceTextureListener.onSurfaceTextureDestroyed should be invoked by TextureView right before this happens.
So as an alternative, you may be able to return false from onSurfaceTextureDestroyed to avoid having it be released during UI teardown, and instead wait for onClosed to fire, and then in onClosed release the TextureView's SurfaceTexture yourself. However, I'm not quite familiar enough with the UI/View side of things to know for sure this'll work, and since some of the underlying native surfaces are released either way, you might still see the abandoned errors with this approach.
If you're curious, the top levels of the relevant code are in TextureView , especially the destroySurface method, though there's a lot you'd need to understand about the whole Android UI system to sort out when exactly the destroySurface method is invoked, and what its effects are.
Are you waiting for the camera's onClosed state callback method to be invoked, before exiting onPause?
Until that callback fires, the camera may still have pending work to do, and the definition of close() is to finish up all pending capture requests before shutting down the device. This can be sped up by calling abortCapture() before calling close().
Some devices (like the N5 and N6) currently block the close() call so that when it returns, all the pending work is done, but this is an implementation detail that I think our sample inadvertently relies on today.
However, we generally want to allow apps to call close() and leave onPause() immediately, to avoid hanging the UI thread on waiting for the camera hardware to shut down. But this isn't yet reality today.
In other words, close() is supposed to be asynchronous, and isn't on all devices. But we'd like it to be possible for you to fire and forget it, so these error messages need to be addressed on the camera device's side (not spam the log when the repeating request target goes away mid-operation).
The other reason just calling close() and exiting onPause() isn't recommended today is that it will prevent other apps from opening the camera in their onResume() calls, which will cause spurious errors when switching between camera apps.
So to summarize:
For now: Wait for CameraDevice.StateCallback#onClosed to be invoked before exiting onPause() after calling CameraDevice#close().
At some future point: Will be safe to just call close() and exit onPause; the framework will properly allow the next app to connect and not spam your log. Sorry this isn't the state today!