/* * 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 #include #include "common/CameraProviderManager.h" #include "device3/Camera3Device.h" namespace android { using hardware::camera::device::V3_2::ICameraDeviceSession; Camera3Device::Camera3DeviceInjectionMethods::Camera3DeviceInjectionMethods( wp 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 manager, const sp& callback) { ATRACE_CALL(); Mutex::Autolock lock(mInjectionLock); if (manager == nullptr) { ALOGE("%s: manager does not exist!", __FUNCTION__); return INVALID_OPERATION; } sp parent = mParent.promote(); if (parent == nullptr) { ALOGE("%s: parent does not exist!", __FUNCTION__); return INVALID_OPERATION; } mInjectedCamId = injectedCamId; sp 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 queue; auto requestQueueRet = session->getCaptureRequestMetadataQueue([&queue](const auto& descriptor) { queue = std::make_shared(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& resQueue = parent->mResultMetadataQueue; auto resultQueueRet = session->getCaptureResultMetadataQueue( [&resQueue](const auto& descriptor) { resQueue = std::make_unique(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& injectionBufferSizes) { status_t res = NO_ERROR; mInjectionConfig = injectionConfig; mInjectionBufferSizes = injectionBufferSizes; if (mInjectedCamHalInterface == nullptr) { ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__); return DEAD_OBJECT; } sp 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 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* 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& injectionBufferSizes) { ATRACE_CALL(); status_t res = NO_ERROR; sp 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 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 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 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