Camera: Stop repeating request if its output is abandoned
Stop repeating request if any of its output stream is abandoned.
Add a callback to notify the repeating request has been stopped
with frame number of the last frame.
Update NDK with the new callback and behavior.
Bug: 21270879
Change-Id: I3553775c7807a77104aa1650609480ca3321310c
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index b6c9900..63e44fd 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -75,6 +75,7 @@
Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
mInputStream(),
+ mStreamingRequestId(REQUEST_ID_NONE),
mRequestIdCounter(0) {
ATRACE_CALL();
@@ -233,7 +234,7 @@
res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
msg.string());
} else {
- mStreamingRequestList.push_back(submitInfo->mRequestId);
+ mStreamingRequestId = submitInfo->mRequestId;
}
} else {
err = mDevice->captureList(metadataRequestList, &(submitInfo->mLastFrameNumber));
@@ -270,17 +271,9 @@
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
- Vector<int>::iterator it, end;
- for (it = mStreamingRequestList.begin(), end = mStreamingRequestList.end();
- it != end; ++it) {
- if (*it == requestId) {
- break;
- }
- }
-
- if (it == end) {
- String8 msg = String8::format("Camera %d: Did not find request ID %d in list of "
- "streaming requests", mCameraId, requestId);
+ if (mStreamingRequestId != requestId) {
+ String8 msg = String8::format("Camera %d: Canceling request ID %d doesn't match "
+ "current request ID %d", mCameraId, requestId, mStreamingRequestId);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -290,7 +283,7 @@
if (err == OK) {
ALOGV("%s: Camera %d: Successfully cleared streaming request",
__FUNCTION__, mCameraId);
- mStreamingRequestList.erase(it);
+ mStreamingRequestId = REQUEST_ID_NONE;
} else {
res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
"Camera %d: Error clearing streaming request: %s (%d)",
@@ -767,7 +760,7 @@
}
// FIXME: Also need check repeating burst.
- if (!mStreamingRequestList.isEmpty()) {
+ if (mStreamingRequestId != REQUEST_ID_NONE) {
String8 msg = String8::format(
"Camera %d: Try to waitUntilIdle when there are active streaming requests",
mCameraId);
@@ -799,7 +792,7 @@
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
- mStreamingRequestList.clear();
+ mStreamingRequestId = REQUEST_ID_NONE;
status_t err = mDevice->flush(lastFrameNumber);
if (err != OK) {
res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
@@ -982,6 +975,17 @@
}
}
+void CameraDeviceClient::notifyRepeatingRequestError(long lastFrameNumber) {
+ sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
+
+ if (remoteCb != 0) {
+ remoteCb->onRepeatingRequestError(lastFrameNumber);
+ }
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+ mStreamingRequestId = REQUEST_ID_NONE;
+}
+
void CameraDeviceClient::notifyIdle() {
// Thread safe. Don't bother locking.
sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 38137a2..3660a18 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -160,6 +160,7 @@
const CaptureResultExtras& resultExtras);
virtual void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp);
virtual void notifyPrepared(int streamId);
+ virtual void notifyRepeatingRequestError(long lastFrameNumber);
/**
* Interface used by independent components of CameraDeviceClient.
@@ -205,8 +206,9 @@
int32_t id;
} mInputStream;
- // Request ID
- Vector<int> mStreamingRequestList;
+ // Streaming request ID
+ int32_t mStreamingRequestId;
+ static const int32_t REQUEST_ID_NONE = -1;
int32_t mRequestIdCounter;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 2cc150d..c0d6da6 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -306,6 +306,14 @@
}
template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyRepeatingRequestError(long lastFrameNumber) {
+ (void)lastFrameNumber;
+
+ ALOGV("%s: Repeating request was stopped. Last frame number is %ld",
+ __FUNCTION__, lastFrameNumber);
+}
+
+template <typename TClientBase>
int Camera2ClientBase<TClientBase>::getCameraId() const {
return TClientBase::mCameraId;
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 6eea2f4..4f60034 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -73,6 +73,7 @@
virtual void notifyAutoWhitebalance(uint8_t newState,
int triggerId);
virtual void notifyPrepared(int streamId);
+ virtual void notifyRepeatingRequestError(long lastFrameNumber);
int getCameraId() const;
const sp<CameraDeviceBase>&
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index d570d4b..35ec531 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -209,6 +209,7 @@
virtual void notifyAutoExposure(uint8_t newState, int triggerId) = 0;
virtual void notifyAutoWhitebalance(uint8_t newState,
int triggerId) = 0;
+ virtual void notifyRepeatingRequestError(long lastFrameNumber) = 0;
protected:
virtual ~NotificationListener();
};
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index e395935..0de80bd 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2807,6 +2807,11 @@
status_t Camera3Device::RequestThread::clearRepeatingRequests(/*out*/int64_t *lastFrameNumber) {
Mutex::Autolock l(mRequestLock);
+ return clearRepeatingRequestsLocked(lastFrameNumber);
+
+}
+
+status_t Camera3Device::RequestThread::clearRepeatingRequestsLocked(/*out*/int64_t *lastFrameNumber) {
mRepeatingRequests.clear();
if (lastFrameNumber != NULL) {
*lastFrameNumber = mRepeatingLastFrameNumber;
@@ -2961,6 +2966,22 @@
}
}
+void Camera3Device::RequestThread::checkAndStopRepeatingRequest() {
+ Mutex::Autolock l(mRequestLock);
+ // Check all streams needed by repeating requests are still valid. Otherwise, stop
+ // repeating requests.
+ for (const auto& request : mRepeatingRequests) {
+ for (const auto& s : request->mOutputStreams) {
+ if (s->isAbandoned()) {
+ int64_t lastFrameNumber = 0;
+ clearRepeatingRequestsLocked(&lastFrameNumber);
+ mListener->notifyRepeatingRequestError(lastFrameNumber);
+ return;
+ }
+ }
+ }
+}
+
bool Camera3Device::RequestThread::threadLoop() {
ATRACE_CALL();
status_t res;
@@ -2992,6 +3013,8 @@
if (res == TIMED_OUT) {
// Not a fatal error if getting output buffers time out.
cleanUpFailedRequests(/*sendRequestError*/ true);
+ // Check if any stream is abandoned.
+ checkAndStopRepeatingRequest();
return true;
} else if (res != OK) {
cleanUpFailedRequests(/*sendRequestError*/ false);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 349fb4c..0366ef6 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -565,6 +565,9 @@
// ERROR state to mark them as not having valid data. mNextRequests will be cleared.
void cleanUpFailedRequests(bool sendRequestError);
+ // Stop the repeating request if any of its output streams is abandoned.
+ void checkAndStopRepeatingRequest();
+
// Pause handling
bool waitIfPaused();
void unpauseForNewRequests();
@@ -578,6 +581,9 @@
// Handle AE precapture trigger cancel for devices <= CAMERA_DEVICE_API_VERSION_3_2.
void handleAePrecaptureCancelRequest(sp<CaptureRequest> request);
+ // Clear repeating requests. Must be called with mRequestLock held.
+ status_t clearRepeatingRequestsLocked(/*out*/ int64_t *lastFrameNumber = NULL);
+
wp<Camera3Device> mParent;
wp<camera3::StatusTracker> mStatusTracker;
camera3_device_t *mHal3Device;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 1e6452f..d2b98e6 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -157,6 +157,13 @@
if (res != OK) {
ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
+
+ // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
+ // let prepareNextBuffer handle the error.)
+ if (res == NO_INIT && mState == STATE_CONFIGURED) {
+ mState = STATE_ABANDONED;
+ }
+
return res;
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 80dce84..96d62d4 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -323,6 +323,11 @@
return mState == STATE_PREPARING;
}
+bool Camera3Stream::isAbandoned() const {
+ Mutex::Autolock l(mLock);
+ return mState == STATE_ABANDONED;
+}
+
status_t Camera3Stream::prepareNextBuffer() {
ATRACE_CALL();
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 810383d..0755700 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -95,6 +95,8 @@
* STATE_PREPARING => STATE_CONFIGURED:
* When sufficient prepareNextBuffer calls have been made to allocate
* all stream buffers, or cancelPrepare is called.
+ * STATE_CONFIGURED => STATE_ABANDONED:
+ * When the buffer queue of the stream is abandoned.
*
* Status Tracking:
* Each stream is tracked by StatusTracker as a separate component,
@@ -353,6 +355,11 @@
void removeBufferListener(
const sp<Camera3StreamBufferListener>& listener);
+ /**
+ * Return if the buffer queue of the stream is abandoned.
+ */
+ bool isAbandoned() const;
+
protected:
const int mId;
/**
@@ -380,7 +387,8 @@
STATE_IN_CONFIG,
STATE_IN_RECONFIG,
STATE_CONFIGURED,
- STATE_PREPARING
+ STATE_PREPARING,
+ STATE_ABANDONED
} mState;
mutable Mutex mLock;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 3f7e7a7..6cb7a54 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -262,6 +262,11 @@
virtual status_t disconnect() = 0;
/**
+ * Return if the buffer queue of the stream is abandoned.
+ */
+ virtual bool isAbandoned() const = 0;
+
+ /**
* Debug dump of the stream's state.
*/
virtual void dump(int fd, const Vector<String16> &args) const = 0;