| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "CamDevSession@3.5-impl" |
| #define ATRACE_TAG ATRACE_TAG_CAMERA |
| #include <android/log.h> |
| |
| #include <vector> |
| #include <utils/Trace.h> |
| #include "CameraDeviceSession.h" |
| |
| namespace android { |
| namespace hardware { |
| namespace camera { |
| namespace device { |
| namespace V3_5 { |
| namespace implementation { |
| |
| CameraDeviceSession::CameraDeviceSession( |
| camera3_device_t* device, |
| const camera_metadata_t* deviceInfo, |
| const sp<V3_2::ICameraDeviceCallback>& callback) : |
| V3_4::implementation::CameraDeviceSession(device, deviceInfo, callback) { |
| |
| mCallback_3_5 = nullptr; |
| |
| auto castResult = ICameraDeviceCallback::castFrom(callback); |
| if (castResult.isOk()) { |
| sp<ICameraDeviceCallback> callback3_5 = castResult; |
| if (callback3_5 != nullptr) { |
| mCallback_3_5 = callback3_5; |
| } |
| } |
| |
| if (mCallback_3_5 != nullptr) { |
| camera_metadata_entry bufMgrVersion = mDeviceInfo.find( |
| ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION); |
| if (bufMgrVersion.count > 0) { |
| mSupportBufMgr = (bufMgrVersion.data.u8[0] == |
| ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5); |
| if (mSupportBufMgr) { |
| request_stream_buffers = sRequestStreamBuffers; |
| return_stream_buffers = sReturnStreamBuffers; |
| } |
| } |
| } |
| } |
| |
| CameraDeviceSession::~CameraDeviceSession() { |
| } |
| |
| Return<void> CameraDeviceSession::configureStreams_3_5( |
| const StreamConfiguration& requestedConfiguration, |
| ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb) { |
| configureStreams_3_4_Impl(requestedConfiguration.v3_4, _hidl_cb, |
| requestedConfiguration.streamConfigCounter, false /*useOverriddenFields*/); |
| return Void(); |
| } |
| |
| Return<void> CameraDeviceSession::signalStreamFlush( |
| const hidl_vec<int32_t>& streamIds, uint32_t streamConfigCounter) { |
| if (mDevice->ops->signal_stream_flush == nullptr) { |
| return Void(); |
| } |
| |
| uint32_t currentCounter = 0; |
| { |
| Mutex::Autolock _l(mStreamConfigCounterLock); |
| currentCounter = mStreamConfigCounter; |
| } |
| |
| if (streamConfigCounter < currentCounter) { |
| ALOGV("%s: streamConfigCounter %d is stale (current %d), skipping signal_stream_flush call", |
| __FUNCTION__, streamConfigCounter, mStreamConfigCounter); |
| return Void(); |
| } |
| |
| std::vector<camera3_stream_t*> streams(streamIds.size()); |
| { |
| Mutex::Autolock _l(mInflightLock); |
| for (size_t i = 0; i < streamIds.size(); i++) { |
| int32_t id = streamIds[i]; |
| if (mStreamMap.count(id) == 0) { |
| ALOGE("%s: unknown streamId %d", __FUNCTION__, id); |
| return Void(); |
| } |
| streams[i] = &mStreamMap[id]; |
| } |
| } |
| |
| mDevice->ops->signal_stream_flush(mDevice, streams.size(), streams.data()); |
| return Void(); |
| } |
| |
| Status CameraDeviceSession::importRequest( |
| const CaptureRequest& request, |
| hidl_vec<buffer_handle_t*>& allBufPtrs, |
| hidl_vec<int>& allFences) { |
| if (mSupportBufMgr) { |
| return importRequestImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ true); |
| } |
| return importRequestImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ false); |
| } |
| |
| void CameraDeviceSession::pushBufferId( |
| const buffer_handle_t& buf, uint64_t bufferId, int streamId) { |
| std::lock_guard<std::mutex> lock(mBufferIdMapLock); |
| |
| // emplace will return existing entry if there is one. |
| auto pair = mBufferIdMaps.emplace(streamId, BufferIdMap{}); |
| BufferIdMap& bIdMap = pair.first->second; |
| bIdMap[buf] = bufferId; |
| } |
| |
| uint64_t CameraDeviceSession::popBufferId( |
| const buffer_handle_t& buf, int streamId) { |
| std::lock_guard<std::mutex> lock(mBufferIdMapLock); |
| |
| auto streamIt = mBufferIdMaps.find(streamId); |
| if (streamIt == mBufferIdMaps.end()) { |
| return BUFFER_ID_NO_BUFFER; |
| } |
| BufferIdMap& bIdMap = streamIt->second; |
| auto it = bIdMap.find(buf); |
| if (it == bIdMap.end()) { |
| return BUFFER_ID_NO_BUFFER; |
| } |
| uint64_t bufId = it->second; |
| bIdMap.erase(it); |
| if (bIdMap.empty()) { |
| mBufferIdMaps.erase(streamIt); |
| } |
| return bufId; |
| } |
| |
| uint64_t CameraDeviceSession::getCapResultBufferId(const buffer_handle_t& buf, int streamId) { |
| if (mSupportBufMgr) { |
| return popBufferId(buf, streamId); |
| } |
| return BUFFER_ID_NO_BUFFER; |
| } |
| |
| Camera3Stream* CameraDeviceSession::getStreamPointer(int32_t streamId) { |
| Mutex::Autolock _l(mInflightLock); |
| if (mStreamMap.count(streamId) == 0) { |
| ALOGE("%s: unknown streamId %d", __FUNCTION__, streamId); |
| return nullptr; |
| } |
| return &mStreamMap[streamId]; |
| } |
| |
| void CameraDeviceSession::cleanupInflightBufferFences( |
| std::vector<int>& fences, std::vector<std::pair<buffer_handle_t, int>>& bufs) { |
| hidl_vec<int> hFences = fences; |
| cleanupInflightFences(hFences, fences.size()); |
| for (auto& p : bufs) { |
| popBufferId(p.first, p.second); |
| } |
| } |
| |
| camera3_buffer_request_status_t CameraDeviceSession::requestStreamBuffers( |
| uint32_t num_buffer_reqs, |
| const camera3_buffer_request_t *buffer_reqs, |
| /*out*/uint32_t *num_returned_buf_reqs, |
| /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs) { |
| ATRACE_CALL(); |
| *num_returned_buf_reqs = 0; |
| hidl_vec<BufferRequest> hBufReqs(num_buffer_reqs); |
| for (size_t i = 0; i < num_buffer_reqs; i++) { |
| hBufReqs[i].streamId = |
| static_cast<Camera3Stream*>(buffer_reqs[i].stream)->mId; |
| hBufReqs[i].numBuffersRequested = buffer_reqs[i].num_buffers_requested; |
| } |
| |
| ATRACE_BEGIN("HIDL requestStreamBuffers"); |
| BufferRequestStatus status; |
| hidl_vec<StreamBufferRet> bufRets; |
| auto err = mCallback_3_5->requestStreamBuffers(hBufReqs, |
| [&status, &bufRets] |
| (BufferRequestStatus s, const hidl_vec<StreamBufferRet>& rets) { |
| status = s; |
| bufRets = std::move(rets); |
| }); |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); |
| return CAMERA3_BUF_REQ_FAILED_UNKNOWN; |
| } |
| ATRACE_END(); |
| |
| switch (status) { |
| case BufferRequestStatus::FAILED_CONFIGURING: |
| return CAMERA3_BUF_REQ_FAILED_CONFIGURING; |
| case BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS: |
| return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS; |
| default: |
| break; // Other status Handled by following code |
| } |
| |
| if (status != BufferRequestStatus::OK && status != BufferRequestStatus::FAILED_PARTIAL && |
| status != BufferRequestStatus::FAILED_UNKNOWN) { |
| ALOGE("%s: unknown buffer request error code %d", __FUNCTION__, status); |
| return CAMERA3_BUF_REQ_FAILED_UNKNOWN; |
| } |
| |
| // Only OK, FAILED_PARTIAL and FAILED_UNKNOWN reaches here |
| if (bufRets.size() != num_buffer_reqs) { |
| ALOGE("%s: expect %d buffer requests returned, only got %zu", |
| __FUNCTION__, num_buffer_reqs, bufRets.size()); |
| return CAMERA3_BUF_REQ_FAILED_UNKNOWN; |
| } |
| |
| *num_returned_buf_reqs = num_buffer_reqs; |
| for (size_t i = 0; i < num_buffer_reqs; i++) { |
| // maybe we can query all streams in one call to avoid frequent locking device here? |
| Camera3Stream* stream = getStreamPointer(bufRets[i].streamId); |
| if (stream == nullptr) { |
| ALOGE("%s: unknown streamId %d", __FUNCTION__, bufRets[i].streamId); |
| return CAMERA3_BUF_REQ_FAILED_UNKNOWN; |
| } |
| returned_buf_reqs[i].stream = stream; |
| } |
| |
| // Handle failed streams |
| for (size_t i = 0; i < num_buffer_reqs; i++) { |
| if (bufRets[i].val.getDiscriminator() == StreamBuffersVal::hidl_discriminator::error) { |
| returned_buf_reqs[i].num_output_buffers = 0; |
| switch (bufRets[i].val.error()) { |
| case StreamBufferRequestError::NO_BUFFER_AVAILABLE: |
| returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_NO_BUFFER_AVAILABLE; |
| break; |
| case StreamBufferRequestError::MAX_BUFFER_EXCEEDED: |
| returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_MAX_BUFFER_EXCEEDED; |
| break; |
| case StreamBufferRequestError::STREAM_DISCONNECTED: |
| returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_STREAM_DISCONNECTED; |
| break; |
| case StreamBufferRequestError::UNKNOWN_ERROR: |
| returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_UNKNOWN_ERROR; |
| break; |
| default: |
| ALOGE("%s: Unknown StreamBufferRequestError %d", |
| __FUNCTION__, bufRets[i].val.error()); |
| return CAMERA3_BUF_REQ_FAILED_UNKNOWN; |
| } |
| } |
| } |
| |
| if (status == BufferRequestStatus::FAILED_UNKNOWN) { |
| return CAMERA3_BUF_REQ_FAILED_UNKNOWN; |
| } |
| |
| // Only BufferRequestStatus::OK and BufferRequestStatus::FAILED_PARTIAL reaches here |
| std::vector<int> importedFences; |
| std::vector<std::pair<buffer_handle_t, int>> importedBuffers; |
| for (size_t i = 0; i < num_buffer_reqs; i++) { |
| if (bufRets[i].val.getDiscriminator() != |
| StreamBuffersVal::hidl_discriminator::buffers) { |
| continue; |
| } |
| int streamId = bufRets[i].streamId; |
| const hidl_vec<StreamBuffer>& hBufs = bufRets[i].val.buffers(); |
| camera3_stream_buffer_t* outBufs = returned_buf_reqs[i].output_buffers; |
| returned_buf_reqs[i].num_output_buffers = hBufs.size(); |
| for (size_t b = 0; b < hBufs.size(); b++) { |
| const StreamBuffer& hBuf = hBufs[b]; |
| camera3_stream_buffer_t& outBuf = outBufs[b]; |
| // maybe add importBuffers API to avoid frequent locking device? |
| Status s = importBuffer(streamId, |
| hBuf.bufferId, hBuf.buffer.getNativeHandle(), |
| /*out*/&(outBuf.buffer), |
| /*allowEmptyBuf*/false); |
| // Buffer import should never fail - restart HAL since something is very wrong. |
| LOG_ALWAYS_FATAL_IF(s != Status::OK, |
| "%s: import stream %d bufferId %" PRIu64 " failed!", |
| __FUNCTION__, streamId, hBuf.bufferId); |
| |
| pushBufferId(*(outBuf.buffer), hBuf.bufferId, streamId); |
| importedBuffers.push_back(std::make_pair(*(outBuf.buffer), streamId)); |
| |
| bool succ = sHandleImporter.importFence(hBuf.acquireFence, outBuf.acquire_fence); |
| // Fence import should never fail - restart HAL since something is very wrong. |
| LOG_ALWAYS_FATAL_IF(!succ, |
| "%s: stream %d bufferId %" PRIu64 "acquire fence is invalid", |
| __FUNCTION__, streamId, hBuf.bufferId); |
| importedFences.push_back(outBuf.acquire_fence); |
| outBuf.stream = returned_buf_reqs[i].stream; |
| outBuf.status = CAMERA3_BUFFER_STATUS_OK; |
| outBuf.release_fence = -1; |
| } |
| returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_OK; |
| } |
| |
| return (status == BufferRequestStatus::OK) ? |
| CAMERA3_BUF_REQ_OK : CAMERA3_BUF_REQ_FAILED_PARTIAL; |
| } |
| |
| void CameraDeviceSession::returnStreamBuffers( |
| uint32_t num_buffers, |
| const camera3_stream_buffer_t* const* buffers) { |
| ATRACE_CALL(); |
| hidl_vec<StreamBuffer> hBufs(num_buffers); |
| |
| for (size_t i = 0; i < num_buffers; i++) { |
| hBufs[i].streamId = |
| static_cast<Camera3Stream*>(buffers[i]->stream)->mId; |
| hBufs[i].buffer = nullptr; // use bufferId |
| hBufs[i].bufferId = popBufferId(*(buffers[i]->buffer), hBufs[i].streamId); |
| if (hBufs[i].bufferId == BUFFER_ID_NO_BUFFER) { |
| ALOGE("%s: unknown buffer is returned to stream %d", |
| __FUNCTION__, hBufs[i].streamId); |
| } |
| // ERROR since the buffer is not for application to consume |
| hBufs[i].status = BufferStatus::ERROR; |
| // skip acquire fence since it's of no use to camera service |
| if (buffers[i]->release_fence != -1) { |
| native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); |
| handle->data[0] = buffers[i]->release_fence; |
| hBufs[i].releaseFence.setTo(handle, /*shouldOwn*/true); |
| } |
| } |
| |
| mCallback_3_5->returnStreamBuffers(hBufs); |
| return; |
| } |
| |
| /** |
| * Static callback forwarding methods from HAL to instance |
| */ |
| camera3_buffer_request_status_t CameraDeviceSession::sRequestStreamBuffers( |
| const struct camera3_callback_ops *cb, |
| uint32_t num_buffer_reqs, |
| const camera3_buffer_request_t *buffer_reqs, |
| /*out*/uint32_t *num_returned_buf_reqs, |
| /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs) { |
| CameraDeviceSession *d = |
| const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); |
| |
| if (num_buffer_reqs == 0 || buffer_reqs == nullptr || num_returned_buf_reqs == nullptr || |
| returned_buf_reqs == nullptr) { |
| ALOGE("%s: bad argument: numBufReq %d, bufReqs %p, numRetBufReq %p, retBufReqs %p", |
| __FUNCTION__, num_buffer_reqs, buffer_reqs, |
| num_returned_buf_reqs, returned_buf_reqs); |
| return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS; |
| } |
| |
| return d->requestStreamBuffers(num_buffer_reqs, buffer_reqs, |
| num_returned_buf_reqs, returned_buf_reqs); |
| } |
| |
| void CameraDeviceSession::sReturnStreamBuffers( |
| const struct camera3_callback_ops *cb, |
| uint32_t num_buffers, |
| const camera3_stream_buffer_t* const* buffers) { |
| CameraDeviceSession *d = |
| const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); |
| |
| d->returnStreamBuffers(num_buffers, buffers); |
| } |
| |
| Return<void> CameraDeviceSession::isReconfigurationRequired( |
| const V3_2::CameraMetadata& oldSessionParams, const V3_2::CameraMetadata& newSessionParams, |
| ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) { |
| if (mDevice->ops->is_reconfiguration_required != nullptr) { |
| const camera_metadata_t *oldParams, *newParams; |
| V3_2::implementation::convertFromHidl(oldSessionParams, &oldParams); |
| V3_2::implementation::convertFromHidl(newSessionParams, &newParams); |
| auto ret = mDevice->ops->is_reconfiguration_required(mDevice, oldParams, newParams); |
| switch (ret) { |
| case 0: |
| _hidl_cb(Status::OK, true); |
| break; |
| case -EINVAL: |
| _hidl_cb(Status::OK, false); |
| break; |
| case -ENOSYS: |
| _hidl_cb(Status::METHOD_NOT_SUPPORTED, true); |
| break; |
| default: |
| _hidl_cb(Status::INTERNAL_ERROR, true); |
| break; |
| }; |
| } else { |
| _hidl_cb(Status::METHOD_NOT_SUPPORTED, true); |
| } |
| |
| return Void(); |
| } |
| |
| } // namespace implementation |
| } // namespace V3_5 |
| } // namespace device |
| } // namespace camera |
| } // namespace hardware |
| } // namespace android |