DynamicCamera: Injection camera switching mechanism in Camera3Device

- When injectCamera() is called, it will first initialize the injection and generate the hal interface, wait until the internal camera creates output streams and configure it, and then continues to replace internal camera and configure the injection stream.
- When stopInjection is called or Device3Camera is disconnected, will close injection and delete the hal interface.

Bug: 181735245
Test: Manual
Change-Id: Ib7209c25e3d2cb9b8d717941660590e68c9435ef
diff --git a/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp b/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
new file mode 100644
index 0000000..f145dac
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
@@ -0,0 +1,393 @@
+/*
+ * 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