| /* |
| * Copyright (C) 2021 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 "Camera3DeviceInjectionMethods" |
| #define ATRACE_TAG ATRACE_TAG_CAMERA |
| //#define LOG_NDEBUG 0 |
| |
| #include <utils/Log.h> |
| #include <utils/Trace.h> |
| |
| #include "common/CameraProviderManager.h" |
| #include "device3/Camera3Device.h" |
| |
| namespace android { |
| |
| using hardware::camera::device::V3_2::ICameraDeviceSession; |
| |
| Camera3Device::Camera3DeviceInjectionMethods::Camera3DeviceInjectionMethods( |
| wp<Camera3Device> parent) |
| : mParent(parent) { |
| ALOGV("%s: Created injection camera methods", __FUNCTION__); |
| } |
| |
| Camera3Device::Camera3DeviceInjectionMethods::~Camera3DeviceInjectionMethods() { |
| ALOGV("%s: Removed injection camera methods", __FUNCTION__); |
| injectionDisconnectImpl(); |
| } |
| |
| status_t Camera3Device::Camera3DeviceInjectionMethods::injectionInitialize( |
| const String8& injectedCamId, sp<CameraProviderManager> manager, |
| const sp<android::hardware::camera::device::V3_2::ICameraDeviceCallback>& |
| callback) { |
| ATRACE_CALL(); |
| Mutex::Autolock lock(mInjectionLock); |
| |
| if (manager == nullptr) { |
| ALOGE("%s: manager does not exist!", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| sp<Camera3Device> parent = mParent.promote(); |
| if (parent == nullptr) { |
| ALOGE("%s: parent does not exist!", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| mInjectedCamId = injectedCamId; |
| sp<ICameraDeviceSession> session; |
| ATRACE_BEGIN("Injection CameraHal::openSession"); |
| status_t res = manager->openSession(injectedCamId.string(), callback, |
| /*out*/ &session); |
| ATRACE_END(); |
| if (res != OK) { |
| ALOGE("Injection camera could not open camera session: %s (%d)", |
| strerror(-res), res); |
| return res; |
| } |
| |
| std::shared_ptr<RequestMetadataQueue> queue; |
| auto requestQueueRet = |
| session->getCaptureRequestMetadataQueue([&queue](const auto& descriptor) { |
| queue = std::make_shared<RequestMetadataQueue>(descriptor); |
| if (!queue->isValid() || queue->availableToWrite() <= 0) { |
| ALOGE("Injection camera HAL returns empty request metadata fmq, not " |
| "use it"); |
| queue = nullptr; |
| // don't use the queue onwards. |
| } |
| }); |
| if (!requestQueueRet.isOk()) { |
| ALOGE("Injection camera transaction error when getting request metadata fmq: " |
| "%s, not use it", requestQueueRet.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| |
| std::unique_ptr<ResultMetadataQueue>& resQueue = parent->mResultMetadataQueue; |
| auto resultQueueRet = session->getCaptureResultMetadataQueue( |
| [&resQueue](const auto& descriptor) { |
| resQueue = std::make_unique<ResultMetadataQueue>(descriptor); |
| if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) { |
| ALOGE("Injection camera HAL returns empty result metadata fmq, not use " |
| "it"); |
| resQueue = nullptr; |
| // Don't use the resQueue onwards. |
| } |
| }); |
| if (!resultQueueRet.isOk()) { |
| ALOGE("Injection camera transaction error when getting result metadata queue " |
| "from camera session: %s", resultQueueRet.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| IF_ALOGV() { |
| session->interfaceChain( |
| [](::android::hardware::hidl_vec<::android::hardware::hidl_string> |
| interfaceChain) { |
| ALOGV("Injection camera session interface chain:"); |
| for (const auto& iface : interfaceChain) { |
| ALOGV(" %s", iface.c_str()); |
| } |
| }); |
| } |
| |
| ALOGV("%s: Injection camera interface = new HalInterface()", __FUNCTION__); |
| mInjectedCamHalInterface = |
| new HalInterface(session, queue, parent->mUseHalBufManager, |
| parent->mSupportOfflineProcessing); |
| if (mInjectedCamHalInterface == nullptr) { |
| ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__); |
| return DEAD_OBJECT; |
| } |
| |
| return OK; |
| } |
| |
| status_t Camera3Device::Camera3DeviceInjectionMethods::injectCamera( |
| camera3::camera_stream_configuration& injectionConfig, |
| std::vector<uint32_t>& injectionBufferSizes) { |
| status_t res = NO_ERROR; |
| mInjectionConfig = injectionConfig; |
| mInjectionBufferSizes = injectionBufferSizes; |
| |
| if (mInjectedCamHalInterface == nullptr) { |
| ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__); |
| return DEAD_OBJECT; |
| } |
| |
| sp<Camera3Device> parent = mParent.promote(); |
| if (parent == nullptr) { |
| ALOGE("%s: parent does not exist!", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| nsecs_t maxExpectedDuration = parent->getExpectedInFlightDuration(); |
| bool wasActive = false; |
| if (parent->mStatus == STATUS_ACTIVE) { |
| ALOGV("%s: Let the device be IDLE and the request thread is paused", |
| __FUNCTION__); |
| parent->mPauseStateNotify = true; |
| res = parent->internalPauseAndWaitLocked(maxExpectedDuration); |
| if (res != OK) { |
| ALOGE("%s: Can't pause captures to inject camera!", __FUNCTION__); |
| return res; |
| } |
| wasActive = true; |
| } |
| |
| ALOGV("%s: Injection camera: replaceHalInterface", __FUNCTION__); |
| res = replaceHalInterface(mInjectedCamHalInterface, true); |
| if (res != OK) { |
| ALOGE("%s: Failed to replace the new HalInterface!", __FUNCTION__); |
| injectionDisconnectImpl(); |
| return res; |
| } |
| |
| res = parent->mRequestThread->setHalInterface(mInjectedCamHalInterface); |
| if (res != OK) { |
| ALOGE("%s: Failed to set new HalInterface in RequestThread!", __FUNCTION__); |
| replaceHalInterface(mBackupHalInterface, false); |
| injectionDisconnectImpl(); |
| return res; |
| } |
| |
| parent->mNeedConfig = true; |
| res = injectionConfigureStreams(injectionConfig, injectionBufferSizes); |
| parent->mNeedConfig = false; |
| if (res != OK) { |
| ALOGE("Can't injectionConfigureStreams device for streams: %d: %s " |
| "(%d)", parent->mNextStreamId, strerror(-res), res); |
| replaceHalInterface(mBackupHalInterface, false); |
| injectionDisconnectImpl(); |
| return res; |
| } |
| |
| if (wasActive) { |
| ALOGV("%s: Restarting activity to inject camera", __FUNCTION__); |
| // Reuse current operating mode and session parameters for new stream |
| // config. |
| parent->internalUpdateStatusLocked(STATUS_ACTIVE); |
| } |
| |
| return OK; |
| } |
| |
| status_t Camera3Device::Camera3DeviceInjectionMethods::stopInjection() { |
| status_t res = NO_ERROR; |
| |
| sp<Camera3Device> parent = mParent.promote(); |
| if (parent == nullptr) { |
| ALOGE("%s: parent does not exist!", __FUNCTION__); |
| return DEAD_OBJECT; |
| } |
| |
| nsecs_t maxExpectedDuration = parent->getExpectedInFlightDuration(); |
| bool wasActive = false; |
| if (parent->mStatus == STATUS_ACTIVE) { |
| ALOGV("%s: Let the device be IDLE and the request thread is paused", |
| __FUNCTION__); |
| parent->mPauseStateNotify = true; |
| res = parent->internalPauseAndWaitLocked(maxExpectedDuration); |
| if (res != OK) { |
| ALOGE("%s: Can't pause captures to stop injection!", __FUNCTION__); |
| return res; |
| } |
| wasActive = true; |
| } |
| |
| res = replaceHalInterface(mBackupHalInterface, false); |
| if (res != OK) { |
| ALOGE("%s: Failed to restore the backup HalInterface!", __FUNCTION__); |
| injectionDisconnectImpl(); |
| return res; |
| } |
| injectionDisconnectImpl(); |
| |
| if (wasActive) { |
| ALOGV("%s: Restarting activity to stop injection", __FUNCTION__); |
| // Reuse current operating mode and session parameters for new stream |
| // config. |
| parent->internalUpdateStatusLocked(STATUS_ACTIVE); |
| } |
| |
| return OK; |
| } |
| |
| bool Camera3Device::Camera3DeviceInjectionMethods::isInjecting() { |
| if (mInjectedCamHalInterface == nullptr) { |
| return false; |
| } else { |
| return true; |
| } |
| } |
| |
| const String8& Camera3Device::Camera3DeviceInjectionMethods::getInjectedCamId() |
| const { |
| return mInjectedCamId; |
| } |
| |
| void Camera3Device::Camera3DeviceInjectionMethods::getInjectionConfig( |
| /*out*/ camera3::camera_stream_configuration* injectionConfig, |
| /*out*/ std::vector<uint32_t>* injectionBufferSizes) { |
| if (injectionConfig == nullptr || injectionBufferSizes == nullptr) { |
| ALOGE("%s: Injection configuration arguments must not be null!", __FUNCTION__); |
| return; |
| } |
| |
| *injectionConfig = mInjectionConfig; |
| *injectionBufferSizes = mInjectionBufferSizes; |
| } |
| |
| |
| status_t Camera3Device::Camera3DeviceInjectionMethods::injectionConfigureStreams( |
| camera3::camera_stream_configuration& injectionConfig, |
| std::vector<uint32_t>& injectionBufferSizes) { |
| ATRACE_CALL(); |
| status_t res = NO_ERROR; |
| |
| sp<Camera3Device> parent = mParent.promote(); |
| if (parent == nullptr) { |
| ALOGE("%s: parent does not exist!", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| if (parent->mOperatingMode < 0) { |
| ALOGE("Invalid operating mode: %d", parent->mOperatingMode); |
| return BAD_VALUE; |
| } |
| |
| // Start configuring the streams |
| ALOGV("%s: Injection camera %s: Starting stream configuration", __FUNCTION__, |
| mInjectedCamId.string()); |
| |
| parent->mPreparerThread->pause(); |
| |
| // Do the HAL configuration; will potentially touch stream |
| // max_buffers, usage, and priv fields, as well as data_space and format |
| // fields for IMPLEMENTATION_DEFINED formats. |
| |
| const camera_metadata_t* sessionBuffer = parent->mSessionParams.getAndLock(); |
| res = mInjectedCamHalInterface->configureInjectedStreams( |
| sessionBuffer, &injectionConfig, injectionBufferSizes, |
| parent->mDeviceInfo); |
| parent->mSessionParams.unlock(sessionBuffer); |
| |
| if (res == BAD_VALUE) { |
| // HAL rejected this set of streams as unsupported, clean up config |
| // attempt and return to unconfigured state |
| ALOGE("Set of requested outputs not supported by HAL"); |
| parent->cancelStreamsConfigurationLocked(); |
| return BAD_VALUE; |
| } else if (res != OK) { |
| // Some other kind of error from configure_streams - this is not |
| // expected |
| ALOGE("Unable to configure streams with HAL: %s (%d)", strerror(-res), |
| res); |
| return res; |
| } |
| |
| for (size_t i = 0; i < parent->mOutputStreams.size(); i++) { |
| sp<camera3::Camera3OutputStreamInterface> outputStream = |
| parent->mOutputStreams[i]; |
| mInjectedCamHalInterface->onStreamReConfigured(outputStream->getId()); |
| } |
| |
| // Request thread needs to know to avoid using repeat-last-settings protocol |
| // across configure_streams() calls |
| parent->mRequestThread->configurationComplete( |
| parent->mIsConstrainedHighSpeedConfiguration, parent->mSessionParams, |
| parent->mGroupIdPhysicalCameraMap); |
| |
| parent->internalUpdateStatusLocked(STATUS_CONFIGURED); |
| |
| ALOGV("%s: Injection camera %s: Stream configuration complete", __FUNCTION__, |
| mInjectedCamId.string()); |
| |
| auto rc = parent->mPreparerThread->resume(); |
| |
| if (rc != OK) { |
| ALOGE("%s: Injection camera %s: Preparer thread failed to resume!", |
| __FUNCTION__, mInjectedCamId.string()); |
| return rc; |
| } |
| |
| return OK; |
| } |
| |
| void Camera3Device::Camera3DeviceInjectionMethods::injectionDisconnectImpl() { |
| ATRACE_CALL(); |
| ALOGI("%s: Injection camera disconnect", __FUNCTION__); |
| |
| mBackupHalInterface = nullptr; |
| HalInterface* interface = nullptr; |
| { |
| Mutex::Autolock lock(mInjectionLock); |
| if (mInjectedCamHalInterface != nullptr) { |
| interface = mInjectedCamHalInterface.get(); |
| // Call close without internal mutex held, as the HAL close may need |
| // to wait on assorted callbacks,etc, to complete before it can |
| // return. |
| } |
| } |
| |
| if (interface != nullptr) { |
| interface->close(); |
| } |
| |
| { |
| Mutex::Autolock lock(mInjectionLock); |
| if (mInjectedCamHalInterface != nullptr) { |
| mInjectedCamHalInterface->clear(); |
| mInjectedCamHalInterface = nullptr; |
| } |
| } |
| } |
| |
| status_t Camera3Device::Camera3DeviceInjectionMethods::replaceHalInterface( |
| sp<HalInterface> newHalInterface, bool keepBackup) { |
| Mutex::Autolock lock(mInjectionLock); |
| if (newHalInterface.get() == nullptr) { |
| ALOGE("%s: The newHalInterface does not exist, to stop replacing.", |
| __FUNCTION__); |
| return DEAD_OBJECT; |
| } |
| |
| sp<Camera3Device> parent = mParent.promote(); |
| if (parent == nullptr) { |
| ALOGE("%s: parent does not exist!", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| if (keepBackup && mBackupHalInterface == nullptr) { |
| mBackupHalInterface = parent->mInterface; |
| } else if (!keepBackup) { |
| mBackupHalInterface = nullptr; |
| } |
| parent->mInterface = newHalInterface; |
| |
| return OK; |
| } |
| |
| }; // namespace android |