Camera: fix race in disconnect and deleteStream
Check and return buffers to just deleted streams.
Also disallow deleteStream when camera runs into error to
simplify the stream lifecycle when error happens.
Test: CTS, manual tests
Bug: 63863140
Change-Id: I476737442041aebd393ec05998969d959cda0228
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 2bf73a0..e8fc080 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -85,7 +85,7 @@
virtual binder::Status endConfigure(int operatingMode) override;
- // Returns -EBUSY if device is not idle
+ // Returns -EBUSY if device is not idle or in error state
virtual binder::Status deleteStream(int streamId) override;
virtual binder::Status createStream(
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 0fc3740..471b2c0 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -315,6 +315,7 @@
mInterface->clear();
mOutputStreams.clear();
mInputStream.clear();
+ mDeletedStreams.clear();
mBufferManager.clear();
internalUpdateStatusLocked(STATUS_UNINITIALIZED);
}
@@ -1428,6 +1429,12 @@
return -EBUSY;
}
+ if (mStatus == STATUS_ERROR) {
+ ALOGW("%s: Camera %s: deleteStream not allowed in ERROR state",
+ __FUNCTION__, mId.string());
+ return -EBUSY;
+ }
+
sp<Camera3StreamInterface> deletedStream;
ssize_t outputStreamIdx = mOutputStreams.indexOfKey(id);
if (mInputStream != NULL && id == mInputStream->getId()) {
@@ -2516,16 +2523,60 @@
streamBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
streamBuffer.acquire_fence = -1;
streamBuffer.release_fence = -1;
+
+ // First check if the buffer belongs to deleted stream
+ bool streamDeleted = false;
+ for (auto& stream : mDeletedStreams) {
+ if (streamId == stream->getId()) {
+ streamDeleted = true;
+ // Return buffer to deleted stream
+ camera3_stream* halStream = stream->asHalStream();
+ streamBuffer.stream = halStream;
+ switch (halStream->stream_type) {
+ case CAMERA3_STREAM_OUTPUT:
+ res = stream->returnBuffer(streamBuffer, /*timestamp*/ 0);
+ if (res != OK) {
+ ALOGE("%s: Can't return output buffer for frame %d to"
+ " stream %d: %s (%d)", __FUNCTION__,
+ frameNumber, streamId, strerror(-res), res);
+ }
+ break;
+ case CAMERA3_STREAM_INPUT:
+ res = stream->returnInputBuffer(streamBuffer);
+ if (res != OK) {
+ ALOGE("%s: Can't return input buffer for frame %d to"
+ " stream %d: %s (%d)", __FUNCTION__,
+ frameNumber, streamId, strerror(-res), res);
+ }
+ break;
+ default: // Bi-direcitonal stream is deprecated
+ ALOGE("%s: stream %d has unknown stream type %d",
+ __FUNCTION__, streamId, halStream->stream_type);
+ break;
+ }
+ break;
+ }
+ }
+ if (streamDeleted) {
+ continue;
+ }
+
+ // Then check against configured streams
if (streamId == inputStreamId) {
streamBuffer.stream = mInputStream->asHalStream();
res = mInputStream->returnInputBuffer(streamBuffer);
if (res != OK) {
ALOGE("%s: Can't return input buffer for frame %d to"
- " its stream:%s (%d)", __FUNCTION__,
- frameNumber, strerror(-res), res);
+ " stream %d: %s (%d)", __FUNCTION__,
+ frameNumber, streamId, strerror(-res), res);
}
} else {
- streamBuffer.stream = mOutputStreams.valueFor(streamId)->asHalStream();
+ ssize_t idx = mOutputStreams.indexOfKey(streamId);
+ if (idx == NAME_NOT_FOUND) {
+ ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
+ continue;
+ }
+ streamBuffer.stream = mOutputStreams.valueAt(idx)->asHalStream();
returnOutputBuffers(&streamBuffer, /*size*/1, /*timestamp*/ 0);
}
}