diff options
Diffstat (limited to 'services/camera')
-rw-r--r-- | services/camera/libcameraservice/Android.mk | 1 | ||||
-rw-r--r-- | services/camera/libcameraservice/Camera3Device.cpp | 523 | ||||
-rw-r--r-- | services/camera/libcameraservice/Camera3Device.h | 60 |
3 files changed, 426 insertions, 158 deletions
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index 6847bf8..3c84703 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -32,6 +32,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES:= \ libui \ + liblog \ libutils \ libbinder \ libcutils \ diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp index e53dbb5..1433108 100644 --- a/services/camera/libcameraservice/Camera3Device.cpp +++ b/services/camera/libcameraservice/Camera3Device.cpp @@ -25,6 +25,18 @@ #define ALOGVV(...) ((void)0) #endif +// Convenience macro for transient errors +#define CLOGE(fmt, ...) ALOGE("Camera %d: %s: " fmt, mId, __FUNCTION__, \ + ##__VA_ARGS__) + +// Convenience macros for transitioning to the error state +#define SET_ERR(fmt, ...) setErrorState( \ + "%s: " fmt, __FUNCTION__, \ + ##__VA_ARGS__) +#define SET_ERR_L(fmt, ...) setErrorStateLocked( \ + "%s: " fmt, __FUNCTION__, \ + ##__VA_ARGS__) + #include <utils/Log.h> #include <utils/Trace.h> #include <utils/Timers.h> @@ -39,6 +51,8 @@ Camera3Device::Camera3Device(int id): mId(id), mHal3Device(NULL), mStatus(STATUS_UNINITIALIZED), + mNextResultFrameNumber(0), + mNextShutterFrameNumber(0), mListener(NULL) { ATRACE_CALL(); @@ -69,7 +83,7 @@ status_t Camera3Device::initialize(camera_module_t *module) ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId); if (mStatus != STATUS_UNINITIALIZED) { - ALOGE("%s: Already initialized!", __FUNCTION__); + CLOGE("Already initialized!"); return INVALID_OPERATION; } @@ -84,21 +98,18 @@ status_t Camera3Device::initialize(camera_module_t *module) reinterpret_cast<hw_device_t**>(&device)); if (res != OK) { - ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__, - mId, strerror(-res), res); - mStatus = STATUS_ERROR; + SET_ERR_L("Could not open camera: %s (%d)", strerror(-res), res); return res; } /** Cross-check device version */ if (device->common.version != CAMERA_DEVICE_API_VERSION_3_0) { - ALOGE("%s: Could not open camera %d: " + SET_ERR_L("Could not open camera: " "Camera device is not version %x, reports %x instead", - __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_3_0, + CAMERA_DEVICE_API_VERSION_3_0, device->common.version); device->common.close(&device->common); - mStatus = STATUS_ERROR; return BAD_VALUE; } @@ -107,11 +118,10 @@ status_t Camera3Device::initialize(camera_module_t *module) if (res != OK) return res; if (info.device_version != device->common.version) { - ALOGE("%s: HAL reporting mismatched camera_info version (%x)" - " and device version (%x).", __FUNCTION__, + SET_ERR_L("HAL reporting mismatched camera_info version (%x)" + " and device version (%x).", device->common.version, info.device_version); device->common.close(&device->common); - mStatus = STATUS_ERROR; return BAD_VALUE; } @@ -119,10 +129,9 @@ status_t Camera3Device::initialize(camera_module_t *module) res = device->ops->initialize(device, this); if (res != OK) { - ALOGE("%s: Camera %d: Unable to initialize HAL device: %s (%d)", - __FUNCTION__, mId, strerror(-res), res); + SET_ERR_L("Unable to initialize HAL device: %s (%d)", + strerror(-res), res); device->common.close(&device->common); - mStatus = STATUS_ERROR; return BAD_VALUE; } @@ -135,10 +144,9 @@ status_t Camera3Device::initialize(camera_module_t *module) if (mVendorTagOps.get_camera_vendor_section_name != NULL) { res = set_camera_metadata_vendor_tag_ops(&mVendorTagOps); if (res != OK) { - ALOGE("%s: Camera %d: Unable to set tag ops: %s (%d)", - __FUNCTION__, mId, strerror(-res), res); + SET_ERR_L("Unable to set tag ops: %s (%d)", + strerror(-res), res); device->common.close(&device->common); - mStatus = STATUS_ERROR; return res; } } @@ -148,11 +156,10 @@ status_t Camera3Device::initialize(camera_module_t *module) mRequestThread = new RequestThread(this, device); res = mRequestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string()); if (res != OK) { - ALOGE("%s: Camera %d: Unable to start request queue thread: %s (%d)", - __FUNCTION__, mId, strerror(-res), res); + SET_ERR_L("Unable to start request queue thread: %s (%d)", + strerror(-res), res); device->common.close(&device->common); mRequestThread.clear(); - mStatus = STATUS_ERROR; return res; } @@ -179,12 +186,12 @@ status_t Camera3Device::disconnect() { (mStatus == STATUS_ERROR && mRequestThread != NULL)) { res = mRequestThread->clearRepeatingRequests(); if (res != OK) { - ALOGE("%s: Can't stop streaming", __FUNCTION__); + SET_ERR_L("Can't stop streaming"); return res; } res = waitUntilDrainedLocked(); if (res != OK) { - ALOGE("%s: Timeout waiting for HAL to drain", __FUNCTION__); + SET_ERR_L("Timeout waiting for HAL to drain"); return res; } } @@ -225,6 +232,9 @@ status_t Camera3Device::dump(int fd, const Vector<String16> &args) { mStatus == STATUS_ACTIVE ? "ACTIVE" : "Unknown"; lines.appendFormat(" Device status: %s\n", status); + if (mStatus == STATUS_ERROR) { + lines.appendFormat(" Error cause: %s\n", mErrorCause.string()); + } lines.appendFormat(" Stream configuration:\n"); if (mInputStream != NULL) { @@ -238,8 +248,22 @@ status_t Camera3Device::dump(int fd, const Vector<String16> &args) { mOutputStreams[i]->dump(fd,args); } + lines = String8(" In-flight requests:\n"); + if (mInFlightMap.size() == 0) { + lines.append(" None\n"); + } else { + for (size_t i = 0; i < mInFlightMap.size(); i++) { + InFlightRequest r = mInFlightMap.valueAt(i); + lines.appendFormat(" Frame %d | Timestamp: %lld, metadata" + " arrived: %s, buffers left: %d\n", mInFlightMap.keyAt(i), + r.captureTimestamp, r.haveResultMetadata ? "true" : "false", + r.numBuffersLeft); + } + } + write(fd, lines.string(), lines.size()); + if (mHal3Device != NULL) { - lines = String8(" HAL device dump:\n"); + lines = String8(" HAL device dump:\n"); write(fd, lines.string(), lines.size()); mHal3Device->ops->dump(mHal3Device, fd); } @@ -251,7 +275,7 @@ const CameraMetadata& Camera3Device::info() const { ALOGVV("%s: E", __FUNCTION__); if (CC_UNLIKELY(mStatus == STATUS_UNINITIALIZED || mStatus == STATUS_ERROR)) { - ALOGE("%s: Access to static info %s!", __FUNCTION__, + ALOGW("%s: Access to static info %s!", __FUNCTION__, mStatus == STATUS_ERROR ? "when in error state" : "before init"); } @@ -266,23 +290,23 @@ status_t Camera3Device::capture(CameraMetadata &request) { switch (mStatus) { case STATUS_ERROR: - ALOGE("%s: Device has encountered a serious error", __FUNCTION__); + CLOGE("Device has encountered a serious error"); return INVALID_OPERATION; case STATUS_UNINITIALIZED: - ALOGE("%s: Device not initialized", __FUNCTION__); + CLOGE("Device not initialized"); return INVALID_OPERATION; case STATUS_IDLE: case STATUS_ACTIVE: // OK break; default: - ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus); + SET_ERR_L("Unexpected status: %d", mStatus); return INVALID_OPERATION; } sp<CaptureRequest> newRequest = setUpRequestLocked(request); if (newRequest == NULL) { - ALOGE("%s: Can't create capture request", __FUNCTION__); + CLOGE("Can't create capture request"); return BAD_VALUE; } @@ -296,23 +320,23 @@ status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) { switch (mStatus) { case STATUS_ERROR: - ALOGE("%s: Device has encountered a serious error", __FUNCTION__); + CLOGE("Device has encountered a serious error"); return INVALID_OPERATION; case STATUS_UNINITIALIZED: - ALOGE("%s: Device not initialized", __FUNCTION__); + CLOGE("Device not initialized"); return INVALID_OPERATION; case STATUS_IDLE: case STATUS_ACTIVE: // OK break; default: - ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus); + SET_ERR_L("Unexpected status: %d", mStatus); return INVALID_OPERATION; } sp<CaptureRequest> newRepeatingRequest = setUpRequestLocked(request); if (newRepeatingRequest == NULL) { - ALOGE("%s: Can't create repeating request", __FUNCTION__); + CLOGE("Can't create repeating request"); return BAD_VALUE; } @@ -330,8 +354,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked( if (mStatus == STATUS_IDLE) { res = configureStreamsLocked(); if (res != OK) { - ALOGE("%s: Can't set up streams: %s (%d)", - __FUNCTION__, strerror(-res), res); + SET_ERR_L("Can't set up streams: %s (%d)", strerror(-res), res); return NULL; } } @@ -346,17 +369,17 @@ status_t Camera3Device::clearStreamingRequest() { switch (mStatus) { case STATUS_ERROR: - ALOGE("%s: Device has encountered a serious error", __FUNCTION__); + CLOGE("Device has encountered a serious error"); return INVALID_OPERATION; case STATUS_UNINITIALIZED: - ALOGE("%s: Device not initialized", __FUNCTION__); + CLOGE("Device not initialized"); return INVALID_OPERATION; case STATUS_IDLE: case STATUS_ACTIVE: // OK break; default: - ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus); + SET_ERR_L("Unexpected status: %d", mStatus); return INVALID_OPERATION; } @@ -379,10 +402,10 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer, switch (mStatus) { case STATUS_ERROR: - ALOGE("%s: Device has encountered a serious error", __FUNCTION__); + CLOGE("Device has encountered a serious error"); return INVALID_OPERATION; case STATUS_UNINITIALIZED: - ALOGE("%s: Device not initialized", __FUNCTION__); + CLOGE("Device not initialized"); return INVALID_OPERATION; case STATUS_IDLE: // OK @@ -394,13 +417,12 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer, if (res != OK) { ALOGE("%s: Can't pause captures to reconfigure streams!", __FUNCTION__); - mStatus = STATUS_ERROR; return res; } wasActive = true; break; default: - ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus); + SET_ERR_L("Unexpected status: %d", mStatus); return INVALID_OPERATION; } assert(mStatus == STATUS_IDLE); @@ -416,8 +438,7 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer, res = mOutputStreams.add(mNextStreamId, newStream); if (res < 0) { - ALOGE("%s: Can't add new stream to set: %s (%d)", - __FUNCTION__, strerror(-res), res); + SET_ERR_L("Can't add new stream to set: %s (%d)", strerror(-res), res); return res; } @@ -428,8 +449,8 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer, ALOGV("%s: Restarting activity to reconfigure streams", __FUNCTION__); res = configureStreamsLocked(); if (res != OK) { - ALOGE("%s: Can't reconfigure device for new stream %d: %s (%d)", - __FUNCTION__, mNextStreamId, strerror(-res), res); + CLOGE("Can't reconfigure device for new stream %d: %s (%d)", + mNextStreamId, strerror(-res), res); return res; } mRequestThread->setPaused(false); @@ -442,7 +463,7 @@ status_t Camera3Device::createReprocessStreamFromStream(int outputId, int *id) { ATRACE_CALL(); (void)outputId; (void)id; - ALOGE("%s: Unimplemented", __FUNCTION__); + CLOGE("Unimplemented"); return INVALID_OPERATION; } @@ -454,23 +475,23 @@ status_t Camera3Device::getStreamInfo(int id, switch (mStatus) { case STATUS_ERROR: - ALOGE("%s: Device has encountered a serious error", __FUNCTION__); + CLOGE("Device has encountered a serious error"); return INVALID_OPERATION; case STATUS_UNINITIALIZED: - ALOGE("%s: Device not initialized!", __FUNCTION__); + CLOGE("Device not initialized!"); return INVALID_OPERATION; case STATUS_IDLE: case STATUS_ACTIVE: // OK break; default: - ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus); + SET_ERR_L("Unexpected status: %d", mStatus); return INVALID_OPERATION; } ssize_t idx = mOutputStreams.indexOfKey(id); if (idx == NAME_NOT_FOUND) { - ALOGE("%s: Stream %d is unknown", __FUNCTION__, id); + CLOGE("Stream %d is unknown", id); return idx; } @@ -488,24 +509,24 @@ status_t Camera3Device::setStreamTransform(int id, switch (mStatus) { case STATUS_ERROR: - ALOGE("%s: Device has encountered a serious error", __FUNCTION__); + CLOGE("Device has encountered a serious error"); return INVALID_OPERATION; case STATUS_UNINITIALIZED: - ALOGE("%s: Device not initialized", __FUNCTION__); + CLOGE("Device not initialized"); return INVALID_OPERATION; case STATUS_IDLE: case STATUS_ACTIVE: // OK break; default: - ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus); + SET_ERR_L("Unexpected status: %d", mStatus); return INVALID_OPERATION; } ssize_t idx = mOutputStreams.indexOfKey(id); if (idx == NAME_NOT_FOUND) { - ALOGE("%s: Stream %d does not exist", - __FUNCTION__, id); + CLOGE("Stream %d does not exist", + id); return BAD_VALUE; } @@ -520,7 +541,7 @@ status_t Camera3Device::deleteStream(int id) { // CameraDevice semantics require device to already be idle before // deleteStream is called, unlike for createStream. if (mStatus != STATUS_IDLE) { - ALOGE("%s: Device not idle", __FUNCTION__); + CLOGE("Device not idle"); return INVALID_OPERATION; } @@ -531,8 +552,7 @@ status_t Camera3Device::deleteStream(int id) { } else { ssize_t idx = mOutputStreams.indexOfKey(id); if (idx == NAME_NOT_FOUND) { - ALOGE("%s: Stream %d does not exist", - __FUNCTION__, id); + CLOGE("Stream %d does not exist", id); return BAD_VALUE; } deletedStream = mOutputStreams.editValueAt(idx); @@ -542,7 +562,7 @@ status_t Camera3Device::deleteStream(int id) { // Free up the stream endpoint so that it can be used by some other stream res = deletedStream->disconnect(); if (res != OK) { - ALOGE("%s: Can't disconnect deleted stream", __FUNCTION__); + SET_ERR_L("Can't disconnect deleted stream %d", id); // fall through since we want to still list the stream as deleted. } mDeletedStreams.add(deletedStream); @@ -554,7 +574,7 @@ status_t Camera3Device::deleteReprocessStream(int id) { ATRACE_CALL(); (void)id; - ALOGE("%s: Unimplemented", __FUNCTION__); + CLOGE("Unimplemented"); return INVALID_OPERATION; } @@ -567,24 +587,28 @@ status_t Camera3Device::createDefaultRequest(int templateId, switch (mStatus) { case STATUS_ERROR: - ALOGE("%s: Device has encountered a serious error", __FUNCTION__); + CLOGE("Device has encountered a serious error"); return INVALID_OPERATION; case STATUS_UNINITIALIZED: - ALOGE("%s: Device is not initialized!", __FUNCTION__); + CLOGE("Device is not initialized!"); return INVALID_OPERATION; case STATUS_IDLE: case STATUS_ACTIVE: // OK break; default: - ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus); + SET_ERR_L("Unexpected status: %d", mStatus); return INVALID_OPERATION; } const camera_metadata_t *rawRequest; rawRequest = mHal3Device->ops->construct_default_request_settings( mHal3Device, templateId); - if (rawRequest == NULL) return DEAD_OBJECT; + if (rawRequest == NULL) { + SET_ERR_L("HAL is unable to construct default settings for template %d", + templateId); + return DEAD_OBJECT; + } *request = rawRequest; return OK; @@ -611,35 +635,31 @@ status_t Camera3Device::waitUntilDrainedLocked() { // Need to shut down break; default: - ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus); + SET_ERR_L("Unexpected status: %d",mStatus); return INVALID_OPERATION; } if (mRequestThread != NULL) { res = mRequestThread->waitUntilPaused(kShutdownTimeout); if (res != OK) { - ALOGE("%s: Can't stop request thread in %f seconds!", - __FUNCTION__, kShutdownTimeout/1e9); - mStatus = STATUS_ERROR; + SET_ERR_L("Can't stop request thread in %f seconds!", + kShutdownTimeout/1e9); return res; } } if (mInputStream != NULL) { res = mInputStream->waitUntilIdle(kShutdownTimeout); if (res != OK) { - ALOGE("%s: Can't idle input stream %d in %f seconds!", - __FUNCTION__, mInputStream->getId(), kShutdownTimeout/1e9); - mStatus = STATUS_ERROR; + SET_ERR_L("Can't idle input stream %d in %f seconds!", + mInputStream->getId(), kShutdownTimeout/1e9); return res; } } for (size_t i = 0; i < mOutputStreams.size(); i++) { res = mOutputStreams.editValueAt(i)->waitUntilIdle(kShutdownTimeout); if (res != OK) { - ALOGE("%s: Can't idle output stream %d in %f seconds!", - __FUNCTION__, mOutputStreams.keyAt(i), - kShutdownTimeout/1e9); - mStatus = STATUS_ERROR; + SET_ERR_L("Can't idle output stream %d in %f seconds!", + mOutputStreams.keyAt(i), kShutdownTimeout/1e9); return res; } } @@ -673,8 +693,8 @@ status_t Camera3Device::waitForNextFrame(nsecs_t timeout) { if (res == TIMED_OUT) { return res; } else if (res != OK) { - ALOGE("%s: Camera %d: Error waiting for frame: %s (%d)", - __FUNCTION__, mId, strerror(-res), res); + ALOGW("%s: Camera %d: No frame in %lld ns: %s (%d)", + __FUNCTION__, mId, timeout, strerror(-res), res); return res; } } @@ -761,7 +781,7 @@ status_t Camera3Device::pushReprocessBuffer(int reprocessStreamId, ATRACE_CALL(); (void)reprocessStreamId; (void)buffer; (void)listener; - ALOGE("%s: Unimplemented", __FUNCTION__); + CLOGE("Unimplemented"); return INVALID_OPERATION; } @@ -782,8 +802,8 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( if (inputStreams.count > 0) { if (mInputStream == NULL || mInputStream->getId() != inputStreams.data.u8[0]) { - ALOGE("%s: Request references unknown input stream %d", - __FUNCTION__, inputStreams.data.u8[0]); + CLOGE("Request references unknown input stream %d", + inputStreams.data.u8[0]); return NULL; } // Lazy completion of stream configuration (allocation/registration) @@ -791,10 +811,9 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( if (mInputStream->isConfiguring()) { res = mInputStream->finishConfiguration(mHal3Device); if (res != OK) { - ALOGE("%s: Unable to finish configuring input stream %d:" + SET_ERR_L("Unable to finish configuring input stream %d:" " %s (%d)", - __FUNCTION__, mInputStream->getId(), - strerror(-res), res); + mInputStream->getId(), strerror(-res), res); return NULL; } } @@ -806,15 +825,15 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( camera_metadata_entry_t streams = newRequest->mSettings.find(ANDROID_REQUEST_OUTPUT_STREAMS); if (streams.count == 0) { - ALOGE("%s: Zero output streams specified!", __FUNCTION__); + CLOGE("Zero output streams specified!"); return NULL; } for (size_t i = 0; i < streams.count; i++) { int idx = mOutputStreams.indexOfKey(streams.data.u8[i]); if (idx == NAME_NOT_FOUND) { - ALOGE("%s: Request references unknown stream %d", - __FUNCTION__, streams.data.u8[i]); + CLOGE("Request references unknown stream %d", + streams.data.u8[i]); return NULL; } sp<Camera3OutputStream> stream = mOutputStreams.editValueAt(idx); @@ -824,8 +843,8 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( if (stream->isConfiguring()) { res = stream->finishConfiguration(mHal3Device); if (res != OK) { - ALOGE("%s: Unable to finish configuring stream %d: %s (%d)", - __FUNCTION__, stream->getId(), strerror(-res), res); + SET_ERR_L("Unable to finish configuring stream %d: %s (%d)", + stream->getId(), strerror(-res), res); return NULL; } } @@ -842,7 +861,7 @@ status_t Camera3Device::configureStreamsLocked() { status_t res; if (mStatus != STATUS_IDLE) { - ALOGE("%s: Not idle", __FUNCTION__); + CLOGE("Not idle"); return INVALID_OPERATION; } @@ -859,9 +878,7 @@ status_t Camera3Device::configureStreamsLocked() { camera3_stream_t *inputStream; inputStream = mInputStream->startConfiguration(); if (inputStream == NULL) { - ALOGE("%s: Can't start input stream configuration", - __FUNCTION__); - // TODO: Make sure the error flow here is correct + SET_ERR_L("Can't start input stream configuration"); return INVALID_OPERATION; } streams.add(inputStream); @@ -871,9 +888,7 @@ status_t Camera3Device::configureStreamsLocked() { camera3_stream_t *outputStream; outputStream = mOutputStreams.editValueAt(i)->startConfiguration(); if (outputStream == NULL) { - ALOGE("%s: Can't start output stream configuration", - __FUNCTION__); - // TODO: Make sure the error flow here is correct + SET_ERR_L("Can't start output stream configuration"); return INVALID_OPERATION; } streams.add(outputStream); @@ -887,11 +902,33 @@ status_t Camera3Device::configureStreamsLocked() { res = mHal3Device->ops->configure_streams(mHal3Device, &config); if (res != OK) { - ALOGE("%s: Unable to configure streams with HAL: %s (%d)", - __FUNCTION__, strerror(-res), res); + SET_ERR_L("Unable to configure streams with HAL: %s (%d)", + strerror(-res), res); return res; } + // Finish all stream configuration immediately. + // TODO: Try to relax this later back to lazy completion, which should be + // faster + + if (mInputStream != NULL) { + res = mInputStream->finishConfiguration(mHal3Device); + if (res != OK) { + SET_ERR_L("Can't finish configuring input stream %d: %s (%d)", + mInputStream->getId(), strerror(-res), res); + return res; + } + } + + for (size_t i = 0; i < mOutputStreams.size(); i++) { + res = mOutputStreams.editValueAt(i)->finishConfiguration(mHal3Device); + if (res != OK) { + SET_ERR_L("Can't finish configuring output stream %d: %s (%d)", + mOutputStreams[i]->getId(), strerror(-res), res); + return res; + } + } + // Request thread needs to know to avoid using repeat-last-settings protocol // across configure_streams() calls mRequestThread->configurationComplete(); @@ -903,6 +940,59 @@ status_t Camera3Device::configureStreamsLocked() { return OK; } +void Camera3Device::setErrorState(const char *fmt, ...) { + Mutex::Autolock l(mLock); + va_list args; + va_start(args, fmt); + + setErrorStateLockedV(fmt, args); + + va_end(args); +} + +void Camera3Device::setErrorStateV(const char *fmt, va_list args) { + Mutex::Autolock l(mLock); + setErrorStateLockedV(fmt, args); +} + +void Camera3Device::setErrorStateLocked(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + + setErrorStateLockedV(fmt, args); + + va_end(args); +} + +void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) { + // Print out all error messages to log + String8 errorCause = String8::formatV(fmt, args); + ALOGE("Camera %d: %s", mId, errorCause.string()); + + // But only do error state transition steps for the first error + if (mStatus == STATUS_ERROR) return; + + mErrorCause = errorCause; + + mRequestThread->setPaused(true); + mStatus = STATUS_ERROR; +} + +/** + * In-flight request management + */ + +status_t Camera3Device::registerInFlight(int32_t frameNumber, + int32_t numBuffers) { + ATRACE_CALL(); + Mutex::Autolock l(mInFlightLock); + + ssize_t res; + res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers)); + if (res < 0) return res; + + return OK; +} /** * Camera HAL device callback methods @@ -913,58 +1003,115 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { status_t res; - if (result->result == NULL) { - // TODO: Report error upstream - ALOGW("%s: No metadata for frame %d", __FUNCTION__, - result->frame_number); + uint32_t frameNumber = result->frame_number; + if (result->result == NULL && result->num_output_buffers == 0) { + SET_ERR("No result data provided by HAL for frame %d", + frameNumber); return; } + // Get capture timestamp from list of in-flight requests, where it was added + // by the shutter notification for this frame. Then update the in-flight + // status and remove the in-flight entry if all result data has been + // received. nsecs_t timestamp = 0; + { + Mutex::Autolock l(mInFlightLock); + ssize_t idx = mInFlightMap.indexOfKey(frameNumber); + if (idx == NAME_NOT_FOUND) { + SET_ERR("Unknown frame number for capture result: %d", + frameNumber); + return; + } + InFlightRequest &request = mInFlightMap.editValueAt(idx); + timestamp = request.captureTimestamp; + if (timestamp == 0) { + SET_ERR("Called before shutter notify for frame %d", + frameNumber); + return; + } + + if (result->result != NULL) { + if (request.haveResultMetadata) { + SET_ERR("Called multiple times with metadata for frame %d", + frameNumber); + return; + } + request.haveResultMetadata = true; + } + + request.numBuffersLeft -= result->num_output_buffers; + + if (request.numBuffersLeft < 0) { + SET_ERR("Too many buffers returned for frame %d", + frameNumber); + return; + } + + if (request.haveResultMetadata && request.numBuffersLeft == 0) { + mInFlightMap.removeItemsAt(idx, 1); + } + + // Sanity check - if we have too many in-flight frames, something has + // likely gone wrong + if (mInFlightMap.size() > kInFlightWarnLimit) { + CLOGE("In-flight list too large: %d", mInFlightMap.size()); + } + + } + AlgState cur3aState; AlgState new3aState; int32_t aeTriggerId = 0; int32_t afTriggerId = 0; - NotificationListener *listener; + NotificationListener *listener = NULL; - { + // Process the result metadata, if provided + if (result->result != NULL) { Mutex::Autolock l(mOutputLock); - // Push result metadata into queue - mResultQueue.push_back(CameraMetadata()); - // Lets avoid copies! Too bad there's not a #back method - CameraMetadata &captureResult = *(--mResultQueue.end()); + if (frameNumber != mNextResultFrameNumber) { + SET_ERR("Out-of-order capture result metadata submitted! " + "(got frame number %d, expecting %d)", + frameNumber, mNextResultFrameNumber); + return; + } + mNextResultFrameNumber++; + + CameraMetadata &captureResult = + *mResultQueue.insert(mResultQueue.end(), CameraMetadata()); captureResult = result->result; if (captureResult.update(ANDROID_REQUEST_FRAME_COUNT, - (int32_t*)&result->frame_number, 1) != OK) { - ALOGE("%s: Camera %d: Failed to set frame# in metadata (%d)", - __FUNCTION__, mId, result->frame_number); - // TODO: Report error upstream + (int32_t*)&frameNumber, 1) != OK) { + SET_ERR("Failed to set frame# in metadata (%d)", + frameNumber); } else { ALOGVV("%s: Camera %d: Set frame# in metadata (%d)", - __FUNCTION__, mId, result->frame_number); + __FUNCTION__, mId, frameNumber); } - // Get timestamp from result metadata + // Check that there's a timestamp in the result metadata camera_metadata_entry entry = captureResult.find(ANDROID_SENSOR_TIMESTAMP); if (entry.count == 0) { - ALOGE("%s: Camera %d: No timestamp provided by HAL for frame %d!", - __FUNCTION__, mId, result->frame_number); - // TODO: Report error upstream - } else { - timestamp = entry.data.i64[0]; + SET_ERR("No timestamp provided by HAL for frame %d!", + frameNumber); + } + if (timestamp != entry.data.i64[0]) { + SET_ERR("Timestamp mismatch between shutter notify and result" + " metadata for frame %d (%lld vs %lld respectively)", + frameNumber, timestamp, entry.data.i64[0]); } // Get 3A states from result metadata entry = captureResult.find(ANDROID_CONTROL_AE_STATE); if (entry.count == 0) { - ALOGE("%s: Camera %d: No AE state provided by HAL for frame %d!", - __FUNCTION__, mId, result->frame_number); + CLOGE("No AE state provided by HAL for frame %d!", + frameNumber); } else { new3aState.aeState = static_cast<camera_metadata_enum_android_control_ae_state>( @@ -973,8 +1120,8 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { entry = captureResult.find(ANDROID_CONTROL_AF_STATE); if (entry.count == 0) { - ALOGE("%s: Camera %d: No AF state provided by HAL for frame %d!", - __FUNCTION__, mId, result->frame_number); + CLOGE("No AF state provided by HAL for frame %d!", + frameNumber); } else { new3aState.afState = static_cast<camera_metadata_enum_android_control_af_state>( @@ -983,8 +1130,8 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { entry = captureResult.find(ANDROID_CONTROL_AWB_STATE); if (entry.count == 0) { - ALOGE("%s: Camera %d: No AWB state provided by HAL for frame %d!", - __FUNCTION__, mId, result->frame_number); + CLOGE("No AWB state provided by HAL for frame %d!", + frameNumber); } else { new3aState.awbState = static_cast<camera_metadata_enum_android_control_awb_state>( @@ -993,16 +1140,16 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { entry = captureResult.find(ANDROID_CONTROL_AF_TRIGGER_ID); if (entry.count == 0) { - ALOGE("%s: Camera %d: No AF trigger ID provided by HAL for frame %d!", - __FUNCTION__, mId, result->frame_number); + CLOGE("No AF trigger ID provided by HAL for frame %d!", + frameNumber); } else { afTriggerId = entry.data.i32[0]; } entry = captureResult.find(ANDROID_CONTROL_AE_PRECAPTURE_ID); if (entry.count == 0) { - ALOGE("%s: Camera %d: No AE precapture trigger ID provided by HAL" - " for frame %d!", __FUNCTION__, mId, result->frame_number); + CLOGE("No AE precapture trigger ID provided by HAL" + " for frame %d!", frameNumber); } else { aeTriggerId = entry.data.i32[0]; } @@ -1013,7 +1160,8 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { m3AState = new3aState; } // scope for mOutputLock - // Return completed buffers to their streams + // Return completed buffers to their streams with the timestamp + for (size_t i = 0; i < result->num_output_buffers; i++) { Camera3Stream *stream = Camera3Stream::cast(result->output_buffers[i].stream); @@ -1021,23 +1169,22 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { // Note: stream may be deallocated at this point, if this buffer was the // last reference to it. if (res != OK) { - ALOGE("%s: Camera %d: Can't return buffer %d for frame %d to its" - " stream:%s (%d)", __FUNCTION__, mId, i, - result->frame_number, strerror(-res), res); - // TODO: Report error upstream + SET_ERR("Can't return buffer %d for frame %d to its stream: " + " %s (%d)", i, frameNumber, strerror(-res), res); } } - // Dispatch any 3A change events to listeners - if (listener != NULL) { + // Finally, dispatch any 3A change events to listeners if we got metadata + + if (result->result != NULL && listener != NULL) { if (new3aState.aeState != cur3aState.aeState) { ALOGVV("%s: AE state changed from 0x%x to 0x%x", - __FUNCTION__, cur3aState.aeState, new3aState.aeState); + __FUNCTION__, cur3aState.aeState, new3aState.aeState); listener->notifyAutoExposure(new3aState.aeState, aeTriggerId); } if (new3aState.afState != cur3aState.afState) { ALOGVV("%s: AF state changed from 0x%x to 0x%x", - __FUNCTION__, cur3aState.afState, new3aState.afState); + __FUNCTION__, cur3aState.afState, new3aState.afState); listener->notifyAutoFocus(new3aState.afState, afTriggerId); } if (new3aState.awbState != cur3aState.awbState) { @@ -1051,13 +1198,11 @@ void Camera3Device::notify(const camera3_notify_msg *msg) { NotificationListener *listener; { Mutex::Autolock l(mOutputLock); - if (mListener == NULL) return; listener = mListener; } if (msg == NULL) { - ALOGE("%s: Camera %d: HAL sent NULL notify message!", - __FUNCTION__, mId); + SET_ERR("HAL sent NULL notify message!"); return; } @@ -1070,18 +1215,51 @@ void Camera3Device::notify(const camera3_notify_msg *msg) { msg->message.error.error_stream); streamId = stream->getId(); } - listener->notifyError(msg->message.error.error_code, - msg->message.error.frame_number, streamId); + if (listener != NULL) { + listener->notifyError(msg->message.error.error_code, + msg->message.error.frame_number, streamId); + } break; } case CAMERA3_MSG_SHUTTER: { - listener->notifyShutter(msg->message.shutter.frame_number, - msg->message.shutter.timestamp); + ssize_t idx; + uint32_t frameNumber = msg->message.shutter.frame_number; + nsecs_t timestamp = msg->message.shutter.timestamp; + // Verify ordering of shutter notifications + { + Mutex::Autolock l(mOutputLock); + if (frameNumber != mNextShutterFrameNumber) { + SET_ERR("Shutter notification out-of-order. Expected " + "notification for frame %d, got frame %d", + mNextShutterFrameNumber, frameNumber); + break; + } + mNextShutterFrameNumber++; + } + + // Set timestamp for the request in the in-flight tracking + { + Mutex::Autolock l(mInFlightLock); + idx = mInFlightMap.indexOfKey(frameNumber); + if (idx >= 0) { + mInFlightMap.editValueAt(idx).captureTimestamp = timestamp; + } + } + if (idx < 0) { + SET_ERR("Shutter notification for non-existent frame number %d", + frameNumber); + break; + } + + // Call listener, if any + if (listener != NULL) { + listener->notifyShutter(frameNumber, timestamp); + } break; } default: - ALOGE("%s: Camera %d: Unknown notify message from HAL: %d", - __FUNCTION__, mId, msg->type); + SET_ERR("Unknown notify message from HAL: %d", + msg->type); } } @@ -1094,6 +1272,7 @@ Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, Thread(false), mParent(parent), mHal3Device(hal3Device), + mId(getId(parent)), mReconfigured(false), mDoPause(false), mPaused(true), @@ -1133,6 +1312,12 @@ status_t Camera3Device::RequestThread::queueTrigger( return OK; } +int Camera3Device::RequestThread::getId(const wp<Camera3Device> &device) { + sp<Camera3Device> d = device.promote(); + if (d != NULL) return d->mId; + return 0; +} + status_t Camera3Device::RequestThread::queueTriggerLocked( RequestTrigger trigger) { @@ -1145,9 +1330,8 @@ status_t Camera3Device::RequestThread::queueTriggerLocked( case TYPE_INT32: break; default: - ALOGE("%s: Type not supported: 0x%x", - __FUNCTION__, - trigger.getTagType()); + ALOGE("%s: Type not supported: 0x%x", __FUNCTION__, + trigger.getTagType()); return INVALID_OPERATION; } @@ -1240,9 +1424,9 @@ bool Camera3Device::RequestThread::threadLoop() { int32_t triggerCount; res = insertTriggers(nextRequest); if (res < 0) { - ALOGE("RequestThread: Unable to insert triggers " - "(capture request %d, HAL device: %s (%d)", - (mFrameNumber+1), strerror(-res), res); + SET_ERR("RequestThread: Unable to insert triggers " + "(capture request %d, HAL device: %s (%d)", + (mFrameNumber+1), strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; } @@ -1289,7 +1473,7 @@ bool Camera3Device::RequestThread::threadLoop() { request.input_buffer = &inputBuffer; res = nextRequest->mInputStream->getBuffer(&inputBuffer); if (res != OK) { - ALOGE("RequestThread: Can't get input buffer, skipping request:" + SET_ERR("RequestThread: Can't get input buffer, skipping request:" " %s (%d)", strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return true; @@ -1305,7 +1489,7 @@ bool Camera3Device::RequestThread::threadLoop() { res = nextRequest->mOutputStreams.editItemAt(i)-> getBuffer(&outputBuffers.editItemAt(i)); if (res != OK) { - ALOGE("RequestThread: Can't get output buffer, skipping request:" + SET_ERR("RequestThread: Can't get output buffer, skipping request:" "%s (%d)", strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return true; @@ -1315,12 +1499,28 @@ bool Camera3Device::RequestThread::threadLoop() { request.frame_number = mFrameNumber++; + // Log request in the in-flight queue + sp<Camera3Device> parent = mParent.promote(); + if (parent == NULL) { + CLOGE("RequestThread: Parent is gone"); + cleanUpFailedRequest(request, nextRequest, outputBuffers); + return false; + } + + res = parent->registerInFlight(request.frame_number, + request.num_output_buffers); + if (res != OK) { + SET_ERR("RequestThread: Unable to register new in-flight request:" + " %s (%d)", strerror(-res), res); + cleanUpFailedRequest(request, nextRequest, outputBuffers); + return false; + } // Submit request and block until ready for next one res = mHal3Device->ops->process_capture_request(mHal3Device, &request); if (res != OK) { - ALOGE("RequestThread: Unable to submit capture request %d to HAL" + SET_ERR("RequestThread: Unable to submit capture request %d to HAL" " device: %s (%d)", request.frame_number, strerror(-res), res); cleanUpFailedRequest(request, nextRequest, outputBuffers); return false; @@ -1333,7 +1533,7 @@ bool Camera3Device::RequestThread::threadLoop() { // Remove any previously queued triggers (after unlock) res = removeTriggers(mPrevRequest); if (res != OK) { - ALOGE("RequestThread: Unable to remove triggers " + SET_ERR("RequestThread: Unable to remove triggers " "(capture request %d, HAL device: %s (%d)", request.frame_number, strerror(-res), res); return false; @@ -1378,7 +1578,6 @@ void Camera3Device::RequestThread::cleanUpFailedRequest( nextRequest->mOutputStreams.editItemAt(i)->returnBuffer( outputBuffers[i], 0); } - // TODO: Report error upstream } sp<Camera3Device::CaptureRequest> @@ -1462,6 +1661,18 @@ bool Camera3Device::RequestThread::waitIfPaused() { return false; } +void Camera3Device::RequestThread::setErrorState(const char *fmt, ...) { + sp<Camera3Device> parent = mParent.promote(); + if (parent != NULL) { + va_list args; + va_start(args, fmt); + + parent->setErrorStateV(fmt, args); + + va_end(args); + } +} + status_t Camera3Device::RequestThread::insertTriggers( const sp<CaptureRequest> &request) { diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/Camera3Device.h index 7f294e6..6cad08e 100644 --- a/services/camera/libcameraservice/Camera3Device.h +++ b/services/camera/libcameraservice/Camera3Device.h @@ -108,7 +108,8 @@ class Camera3Device : buffer_handle_t *buffer, wp<BufferReleasedListener> listener); private: - static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec + static const size_t kInFlightWarnLimit = 20; + static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec struct RequestTrigger; Mutex mLock; @@ -128,6 +129,9 @@ class Camera3Device : STATUS_ACTIVE } mStatus; + // Tracking cause of fatal errors when in STATUS_ERROR + String8 mErrorCause; + // Mapping of stream IDs to stream instances typedef KeyedVector<int, sp<camera3::Camera3OutputStream> > StreamSet; @@ -172,6 +176,16 @@ class Camera3Device : */ status_t configureStreamsLocked(); + /** + * Set device into an error state due to some fatal failure, and set an + * error message to indicate why. Only the first call's message will be + * used. The message is also sent to the log. + */ + void setErrorState(const char *fmt, ...); + void setErrorStateV(const char *fmt, va_list args); + void setErrorStateLocked(const char *fmt, ...); + void setErrorStateLockedV(const char *fmt, va_list args); + struct RequestTrigger { // Metadata tag number, e.g. android.control.aePrecaptureTrigger uint32_t metadataTag; @@ -249,6 +263,8 @@ class Camera3Device : virtual bool threadLoop(); private: + static int getId(const wp<Camera3Device> &device); + status_t queueTriggerLocked(RequestTrigger trigger); // Mix-in queued triggers into this request int32_t insertTriggers(const sp<CaptureRequest> &request); @@ -272,9 +288,14 @@ class Camera3Device : // Pause handling bool waitIfPaused(); + // Relay error to parent device object setErrorState + void setErrorState(const char *fmt, ...); + wp<Camera3Device> mParent; camera3_device_t *mHal3Device; + const int mId; + Mutex mRequestLock; Condition mRequestSignal; RequestList mRequestQueue; @@ -292,7 +313,7 @@ class Camera3Device : sp<CaptureRequest> mPrevRequest; int32_t mPrevTriggers; - int32_t mFrameNumber; + uint32_t mFrameNumber; Mutex mLatestRequestMutex; Condition mLatestRequestSignal; @@ -308,6 +329,39 @@ class Camera3Device : sp<RequestThread> mRequestThread; /** + * In-flight queue for tracking completion of capture requests. + */ + + struct InFlightRequest { + // Set by notify() SHUTTER call. + nsecs_t captureTimestamp; + // Set by process_capture_result call with valid metadata + bool haveResultMetadata; + // Decremented by calls to process_capture_result with valid output + // buffers + int numBuffersLeft; + + InFlightRequest() : + captureTimestamp(0), + haveResultMetadata(false), + numBuffersLeft(0) { + } + + explicit InFlightRequest(int numBuffers) : + captureTimestamp(0), + haveResultMetadata(false), + numBuffersLeft(numBuffers) { + } + }; + // Map from frame number to the in-flight request state + typedef KeyedVector<uint32_t, InFlightRequest> InFlightMap; + + Mutex mInFlightLock; // Protects mInFlightMap + InFlightMap mInFlightMap; + + status_t registerInFlight(int32_t frameNumber, int32_t numBuffers); + + /** * Output result queue and current HAL device 3A state */ @@ -316,6 +370,8 @@ class Camera3Device : /**** Scope for mOutputLock ****/ + uint32_t mNextResultFrameNumber; + uint32_t mNextShutterFrameNumber; List<CameraMetadata> mResultQueue; Condition mResultSignal; NotificationListener *mListener; |