From b25e3c87724b6147ed1da7c1d6617c39bfce2fbf Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Wed, 15 Jul 2015 16:04:27 -0700 Subject: Camera: Add hidden experimental tearDown method. Bug: 18949148 Change-Id: Ie86ec7d1ec3db54e1154563b2339a208a935f849 --- .../libcameraservice/api2/CameraDeviceClient.cpp | 32 +++++++++++++ .../libcameraservice/api2/CameraDeviceClient.h | 3 ++ .../libcameraservice/common/CameraDeviceBase.h | 5 ++ .../libcameraservice/device2/Camera2Device.cpp | 6 +++ .../libcameraservice/device2/Camera2Device.h | 3 +- .../libcameraservice/device3/Camera3Device.cpp | 31 ++++++++++++ .../libcameraservice/device3/Camera3Device.h | 2 + .../libcameraservice/device3/Camera3Stream.cpp | 55 ++++++++++++++++++++++ .../libcameraservice/device3/Camera3Stream.h | 14 ++++++ .../device3/Camera3StreamInterface.h | 14 ++++++ 10 files changed, 164 insertions(+), 1 deletion(-) (limited to 'services') diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index 3b83f63..c717a56 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -719,6 +719,38 @@ status_t CameraDeviceClient::prepare(int streamId) { return res; } +status_t CameraDeviceClient::tearDown(int streamId) { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + status_t res = OK; + if ( (res = checkPid(__FUNCTION__) ) != OK) return res; + + Mutex::Autolock icl(mBinderSerializationLock); + + // Guard against trying to prepare non-created streams + ssize_t index = NAME_NOT_FOUND; + for (size_t i = 0; i < mStreamMap.size(); ++i) { + if (streamId == mStreamMap.valueAt(i)) { + index = i; + break; + } + } + + if (index == NAME_NOT_FOUND) { + ALOGW("%s: Camera %d: Invalid stream ID (%d) specified, no stream " + "created yet", __FUNCTION__, mCameraId, streamId); + return BAD_VALUE; + } + + // Also returns BAD_VALUE if stream ID was not valid or if the stream is in + // use + res = mDevice->tearDown(streamId); + + return res; +} + + status_t CameraDeviceClient::dump(int fd, const Vector& args) { String8 result; result.appendFormat("CameraDeviceClient[%d] (%p) dump:\n", diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index 0f485ca..1f8b39d 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -111,6 +111,9 @@ public: // Prepare stream by preallocating its buffers virtual status_t prepare(int streamId); + // Tear down stream resources by freeing its unused buffers + virtual status_t tearDown(int streamId); + /** * Interface used by CameraService */ diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h index 06177e3..cd25949 100644 --- a/services/camera/libcameraservice/common/CameraDeviceBase.h +++ b/services/camera/libcameraservice/common/CameraDeviceBase.h @@ -289,6 +289,11 @@ class CameraDeviceBase : public virtual RefBase { virtual status_t prepare(int streamId) = 0; /** + * Free stream resources by dumping its unused gralloc buffers. + */ + virtual status_t tearDown(int streamId) = 0; + + /** * Get the HAL device version. */ virtual uint32_t getDeviceVersion() = 0; diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp index dfe5565..c9c990c 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.cpp +++ b/services/camera/libcameraservice/device2/Camera2Device.cpp @@ -626,6 +626,12 @@ status_t Camera2Device::prepare(int streamId) { return NO_INIT; } +status_t Camera2Device::tearDown(int streamId) { + ATRACE_CALL(); + ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId); + return NO_INIT; +} + uint32_t Camera2Device::getDeviceVersion() { ATRACE_CALL(); return mDeviceVersion; diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h index c9f3a2c..34c1ded 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.h +++ b/services/camera/libcameraservice/device2/Camera2Device.h @@ -85,8 +85,9 @@ class Camera2Device: public CameraDeviceBase { buffer_handle_t *buffer, wp listener); // Flush implemented as just a wait virtual status_t flush(int64_t *lastFrameNumber = NULL); - // Prepare is a no-op + // Prepare and tearDown are no-ops virtual status_t prepare(int streamId); + virtual status_t tearDown(int streamId); virtual uint32_t getDeviceVersion(); virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 9e73b5c..3afbd89 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -1384,6 +1384,37 @@ status_t Camera3Device::prepare(int streamId) { return mPreparerThread->prepare(stream); } +status_t Camera3Device::tearDown(int streamId) { + ATRACE_CALL(); + ALOGV("%s: Camera %d: Tearing down stream %d", __FUNCTION__, mId, streamId); + Mutex::Autolock il(mInterfaceLock); + Mutex::Autolock l(mLock); + + // Teardown can only be accomplished on devices that don't require register_stream_buffers, + // since we cannot call register_stream_buffers except right after configure_streams. + if (mHal3Device->common.version < CAMERA_DEVICE_API_VERSION_3_2) { + ALOGE("%s: Unable to tear down streams on device HAL v%x", + __FUNCTION__, mHal3Device->common.version); + return NO_INIT; + } + + sp stream; + ssize_t outputStreamIdx = mOutputStreams.indexOfKey(streamId); + if (outputStreamIdx == NAME_NOT_FOUND) { + CLOGE("Stream %d does not exist", streamId); + return BAD_VALUE; + } + + stream = mOutputStreams.editValueAt(outputStreamIdx); + + if (stream->hasOutstandingBuffers() || mRequestThread->isStreamPending(stream)) { + CLOGE("Stream %d is a target of a in-progress request", streamId); + return BAD_VALUE; + } + + return stream->tearDown(); +} + uint32_t Camera3Device::getDeviceVersion() { ATRACE_CALL(); Mutex::Autolock il(mInterfaceLock); diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 31b6132..140da98 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -141,6 +141,8 @@ class Camera3Device : virtual status_t prepare(int streamId); + virtual status_t tearDown(int streamId); + virtual uint32_t getDeviceVersion(); virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 4c40bb6..2527fd6 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -364,6 +364,61 @@ status_t Camera3Stream::cancelPrepareLocked() { return res; } +status_t Camera3Stream::tearDown() { + ATRACE_CALL(); + Mutex::Autolock l(mLock); + + status_t res = OK; + + // This function should be only called when the stream is configured. + if (mState != STATE_CONFIGURED) { + ALOGE("%s: Stream %d: Can't tear down stream if stream is not in " + "CONFIGURED state %d", __FUNCTION__, mId, mState); + return INVALID_OPERATION; + } + + // If any buffers have been handed to the HAL, the stream cannot be torn down. + if (getHandoutOutputBufferCountLocked() > 0) { + ALOGE("%s: Stream %d: Can't tear down a stream that has outstanding buffers", + __FUNCTION__, mId); + return INVALID_OPERATION; + } + + // Free buffers by disconnecting and then reconnecting to the buffer queue + // Only unused buffers will be dropped immediately; buffers that have been filled + // and are waiting to be acquired by the consumer and buffers that are currently + // acquired will be freed once they are released by the consumer. + + res = disconnectLocked(); + if (res != OK) { + if (res == -ENOTCONN) { + // queue has been disconnected, nothing left to do, so exit with success + return OK; + } + ALOGE("%s: Stream %d: Unable to disconnect to tear down buffers: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + return res; + } + + mState = STATE_IN_CONFIG; + + res = configureQueueLocked(); + if (res != OK) { + ALOGE("%s: Unable to configure stream %d queue: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + mState = STATE_ERROR; + return res; + } + + // Reset prepared state, since we've reconnected to the queue and can prepare again. + mPrepared = false; + mStreamUnpreparable = false; + + mState = STATE_CONFIGURED; + + return OK; +} + status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) { ATRACE_CALL(); Mutex::Autolock l(mLock); diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index 0543c66..bab2177 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -247,6 +247,20 @@ class Camera3Stream : status_t cancelPrepare(); /** + * Tear down memory for this stream. This frees all unused gralloc buffers + * allocated for this stream, but leaves it ready for operation afterward. + * + * May only be called in the CONFIGURED state, and keeps the stream in + * the CONFIGURED state. + * + * Returns: + * OK if teardown succeeded. + * INVALID_OPERATION if not in the CONFIGURED state + * NO_INIT in case of a serious error from the HAL device + */ + status_t tearDown(); + + /** * Fill in the camera3_stream_buffer with the next valid buffer for this * stream, to hand over to the HAL. * diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h index 6c87a45..c086eaf 100644 --- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h @@ -152,6 +152,20 @@ class Camera3StreamInterface : public virtual RefBase { virtual status_t cancelPrepare() = 0; /** + * Tear down memory for this stream. This frees all unused gralloc buffers + * allocated for this stream, but leaves it ready for operation afterward. + * + * May only be called in the CONFIGURED state, and keeps the stream in + * the CONFIGURED state. + * + * Returns: + * OK if teardown succeeded. + * INVALID_OPERATION if not in the CONFIGURED state + * NO_INIT in case of a serious error from the HAL device + */ + virtual status_t tearDown() = 0; + + /** * Fill in the camera3_stream_buffer with the next valid buffer for this * stream, to hand over to the HAL. * -- cgit v1.1