【camera-framework 003】从Java应用打开一个相机的全流程2

基于Android 14


记录一下:当前版本纯看代码梳理的,想要了解一个概要的逻辑,初期架构上是会比较混乱的,只建议作为药引
后续记得更新类图架构,补充hal buffer 捕获的相关数据结构

在这里插入图片描述

这里追踪 相机打开流程,从 camera service 到 HAL impl
frameworks/av/services/camera/libcameraservice/CameraService.cpp log tag
#define LOG_TAG “CameraService”

2.4 connectDevice

frameworks/av/services/camera/libcameraservice/CameraService.cpp
1 resolveCameraId解析可能重新映射的相机Id用于packageName。 这将返回相机Id,以便在inputCameraId被重新映射到给定packageName的不同Id时使用。否则,它返回inputCameraId。 如果没有提供packageName,它将从clientUid推断出来。
2 调用connectHelper去做连接前准备,以及连接camera

Status CameraService::connectDevice(
        // cameraCb 之前追踪过,实际对应 CameraDeviceImpl # mCallbacks  
        const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
        // java的 CameraManager # openCamera 使用的 String cameraId
        const std::string& unresolvedCameraId,
        const std::string& clientPackageName,
        const std::optional<std::string>& clientFeatureId,
        int clientUid, int oomScoreOffset, int targetSdkVersion,
        bool overrideToPortrait,
        /*out*/
        sp<hardware::camera2::ICameraDeviceUser>* device) {

    ATRACE_CALL();
    Status ret = Status::ok();
    sp<CameraDeviceClient> client = nullptr;
    std::string clientPackageNameAdj = clientPackageName;
    int callingPid = CameraThreadState::getCallingPid();
    bool systemNativeClient = false;
    if (doesClientHaveSystemUid() && (clientPackageNameAdj.size() == 0)) {
        std::string systemClient =
                fmt::sprintf("client.pid<%d>", CameraThreadState::getCallingPid());
        clientPackageNameAdj = systemClient;
        systemNativeClient = true;
    }
    // 1 解析可能重新映射的相机Id用于packageName。 这将返回相机Id,以便在inputCameraId被重新映射到给定packageName的不同Id时使用。
    // 否则,它返回inputCameraId。 如果没有提供packageName,它将从clientUid推断出来。
    const std::string cameraId = resolveCameraId(
            unresolvedCameraId,
            CameraThreadState::getCallingUid(),
            clientPackageNameAdj);

    if (oomScoreOffset < 0) {
        std::string msg =
                fmt::sprintf("Cannot increase the priority of a client %s pid %d for "
                        "camera id %s", clientPackageNameAdj.c_str(), callingPid,
                        cameraId.c_str());
        ALOGE("%s: %s", __FUNCTION__, msg.c_str());
        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.c_str());
    }

    ……

    // enforce system camera permissions
    if (oomScoreOffset > 0
            && !hasPermissionsForSystemCamera(cameraId, callingPid,
                    CameraThreadState::getCallingUid())
            && !isTrustedCallingUid(CameraThreadState::getCallingUid())) {
        std::string msg = fmt::sprintf("Cannot change the priority of a client %s pid %d for "
                        "camera id %s without SYSTEM_CAMERA permissions",
                        clientPackageNameAdj.c_str(), callingPid, cameraId.c_str());
        ALOGE("%s: %s", __FUNCTION__, msg.c_str());
        return STATUS_ERROR(ERROR_PERMISSION_DENIED, msg.c_str());
    }
    // 2 真正去连接camera 的操作
    ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb,
            cameraId, /*api1CameraId*/-1, clientPackageNameAdj, systemNativeClient, clientFeatureId,
            clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, oomScoreOffset,
            targetSdkVersion, overrideToPortrait, /*forceSlowJpegMode*/false, unresolvedCameraId,
            /*out*/client);

    if(!ret.isOk()) {
        logRejected(cameraId, callingPid, clientPackageNameAdj, toStdString(ret.toString8()));
        return ret;
    }

    *device = client;
    Mutex::Autolock lock(mServiceLock);

    // Clear the previous cached logs and reposition the
    // file offset to beginning of the file to log new data.
    // If either truncate or lseek fails, close the previous file and create a new one.
   ……
    return ret;
}

2.4.1 resolveCameraId

解析可能重新映射的相机Id用于packageName。 这将返回相机Id,以便在inputCameraId被重新映射到给定packageName的不同Id时使用。否则,它返回inputCameraId。 如果没有提供packageName,它将从clientUid推断出来。


std::string CameraService::resolveCameraId(
    const std::string& inputCameraId,
    int clientUid,
    const std::string& packageName) {
    std::string packageNameVal = packageName;
    if (packageName.empty()) {
        packageNameVal = getPackageNameFromUid(clientUid);
    }
    if (clientUid < AID_APP_START || packageNameVal.empty()) {
        // We shouldn't remap cameras for processes with system/vendor UIDs.
        return inputCameraId;
    }
    Mutex::Autolock lock(mCameraIdRemappingLock);
    if (auto packageMapIter = mCameraIdRemapping.find(packageNameVal);
        packageMapIter != mCameraIdRemapping.end()) {
        auto packageMap = packageMapIter->second;
        if (auto replacementIdIter = packageMap.find(inputCameraId);
            replacementIdIter != packageMap.end()) {
            ALOGI("%s: resolveCameraId: remapping cameraId %s for %s to %s",
                    __FUNCTION__, inputCameraId.c_str(),
                    packageNameVal.c_str(),
                    replacementIdIter->second.c_str());
            return replacementIdIter->second;
        }
    }
    return inputCameraId;
}

2.5 connectHelper

1 合法性检查
2 处理活动客户端退出,并更新服务状态,并检查对应的camera 是否可用
3 通知camerafashlight,相机服务将打开一个相机设备。camerashlight将释放可能导致相机打开失败的资源。相机服务必须在打开相机设备之前调用此函数。(note:手机打开闪光灯,再去打开camera,会发现闪光灯会被关闭)
4 API level检查, c2 API 创建 CameraDeviceClient
5 CameraDeviceClient # initialize, 真正去打开摄像机,若失败,返回对应错误码;CameraDeviceClient # initialize -> HidlCamera3Device::initialize -> CameraProviderManager.cpp # openHidlSession (在这里启动并初始化此相机设备以供活动使用,并返回用于活动操作的会话句柄。这个操作之后相机被真正的打开了)

// Single implementation shared between the various connect calls
// 
// @param cameraCb: cameraCb 之前追踪过,实际对应 CameraDeviceImpl # mCallbacks  
// @param originalCameraId: Java 一路传递下来的camera id
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const std::string& cameraId,
        int api1CameraId, const std::string& clientPackageNameMaybe, bool systemNativeClient,
        const std::optional<std::string>& clientFeatureId, int clientUid, int clientPid,
        apiLevel effectiveApiLevel, bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion,
        bool overrideToPortrait, bool forceSlowJpegMode, const std::string& originalCameraId,
        /*out*/sp<CLIENT>& device) {
    binder::Status ret = binder::Status::ok();
    
    int packagePid = (clientPid == USE_CALLING_PID) ?
        CameraThreadState::getCallingPid() : clientPid;
    ……
    // 这个log 会打印
    ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) and "
            "Camera API version %d", packagePid, clientPackageName.c_str(), cameraId.c_str(),
            static_cast<int>(effectiveApiLevel));
……

    sp<CLIENT> client = nullptr;
    int facing = -1;
    int orientation = 0;

    {
        // 一个 camera id可能有多个应用向访问和使用,锁需要加锁保护
        // Acquire mServiceLock and prevent other clients from connecting
        std::unique_ptr<AutoConditionLock> lock =
                AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);

        if (lock == nullptr) {
            ALOGE("CameraService::connect (PID %d) rejected (too many other clients connecting)."
                    , clientPid);
            return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
                    "Cannot open camera %s for \"%s\" (PID %d): Too many other clients connecting",
                    cameraId.c_str(), clientPackageName.c_str(), clientPid);
        }
        // 1 合法性检查
        // Enforce client permissions and do basic validity checks
        if(!(ret = validateConnectLocked(cameraId, clientPackageName,
                /*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {
            return ret;
        }

        // Check the shim parameters after acquiring lock, if they have already been updated and
        // we were doing a shim update, return immediately
        // 在获得锁后检查shim参数,如果它们已经被更新并且我们正在进行shim更新,请立即返回
        if (shimUpdateOnly) {            
            auto cameraState = getCameraState(cameraId);
            if (cameraState != nullptr) {
                if (!cameraState->getShimParams().isEmpty()) return ret;
            }
        }
        // 检查是否出错
        status_t err;

        sp<BasicClient> clientTmp = nullptr;
        std::shared_ptr<resource_policy::ClientDescriptor<std::string, sp<BasicClient>>> partial;
        //2 处理活动客户端退出,并更新服务状态,并检查对应的camera 是否可用
        //只在持有mServiceLock的情况下调用。
        if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,
                IInterface::asBinder(cameraCb), clientPackageName, oomScoreOffset,
                systemNativeClient, /*out*/&clientTmp, /*out*/&partial)) != NO_ERROR) {
            switch (err) {
                case -ENODEV:
                    return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
                            "No camera device with ID \"%s\" currently available",
                            cameraId.c_str());
                case -EBUSY:
                    return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
                            "Higher-priority client using camera, ID \"%s\" currently unavailable",
                            cameraId.c_str());
                case -EUSERS:
                    return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
                            "Too many cameras already open, cannot open camera \"%s\"",
                            cameraId.c_str());
                default:
                    return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                            "Unexpected error %s (%d) opening camera \"%s\"",
                            strerror(-err), err, cameraId.c_str());
            }
        }

        if (clientTmp.get() != nullptr) {
            // Handle special case for API1 MediaRecorder where the existing client is returned
            device = static_cast<CLIENT*>(clientTmp.get());
            return ret;
        }

        // give flashlight a chance to close devices if necessary.
        // 3 通知camerafashlight,相机服务将打开一个相机设备。camerashlight将释放可能导致相机打开失败的资源。
        // 相机服务必须在打开相机设备之前调用此函数。(note:手机打开闪光灯,再去打开camera,会发现闪光灯会被关闭)
        mFlashlight->prepareDeviceOpen(cameraId);

        int portraitRotation;        
        auto deviceVersionAndTransport =
                getDeviceVersion(cameraId, overrideToPortrait, /*out*/&portraitRotation,
                        /*out*/&facing, /*out*/&orientation);
        if (facing == -1) {
            ALOGE("%s: Unable to get camera device \"%s\"  facing", __FUNCTION__, cameraId.c_str());
            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                    "Unable to get camera device \"%s\" facing", cameraId.c_str());
        }
        
        // 4 创建 CameraDeviceClient
        sp<BasicClient> tmp = nullptr; // 保存c2 API 对应CameraDeviceClient的实例
        bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
                mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);
        if(!(ret = makeClient(this, cameraCb, clientPackageName, systemNativeClient,
                clientFeatureId, cameraId, api1CameraId, facing,
                orientation, clientPid, clientUid, getpid(),
                deviceVersionAndTransport, effectiveApiLevel, overrideForPerfClass,
                overrideToPortrait, forceSlowJpegMode, originalCameraId,
                /*out*/&tmp)).isOk()) {
            return ret;
        }
        client = static_cast<CLIENT*>(tmp.get());

        LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
                __FUNCTION__);

        std::string monitorTags = isClientWatched(client.get()) ? mMonitorTags : std::string();
        // 5 CameraDeviceClient # initialize, 真正去打开摄像机,若失败,返回对应错误码
        err = client->initialize(mCameraProviderManager, monitorTags);
        if (err != OK) {
            ALOGE("%s: Could not initialize client from HAL.", __FUNCTION__);
            // Errors could be from the HAL module open call or from AppOpsManager
            mServiceLock.unlock();
            client->disconnect();
            mServiceLock.lock();
            switch(err) {
                case BAD_VALUE:
                    return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
                            "Illegal argument to HAL module for camera \"%s\"", cameraId.c_str());
                case -EBUSY:
                    return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
                            "Camera \"%s\" is already open", cameraId.c_str());
                case -EUSERS:
                    return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
                            "Too many cameras already open, cannot open camera \"%s\"",
                            cameraId.c_str());
                case PERMISSION_DENIED:
                    return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
                            "No permission to open camera \"%s\"", cameraId.c_str());
                case -EACCES:
                    return STATUS_ERROR_FMT(ERROR_DISABLED,
                            "Camera \"%s\" disabled by policy", cameraId.c_str());
                case -ENODEV:
                default:
                    return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                            "Failed to initialize camera \"%s\": %s (%d)", cameraId.c_str(),
                            strerror(-err), err);
            }
        }
        ……
    return ret;
}

2.5.1 handleEvictionsLocked

1 如果我们使用API1,则应该返回具有相同远程的此相机ID的任何现有客户端, 而不是驱逐以允许MediaRecorder正常工作。 先在基本都是用 更高级的 API
2 camera 状态检查,如果转态为空,直接返回 错误码 BAD_VALUE
3 检查processinfo 服务, 如果processinfo服务不可用,并且客户端是汽车特权客户端,用于安全关键用例, 如后视镜和环绕视图,需要在android启动完成之前可用,则使用硬编码的进程状态和优先级评分值。 由于这种情况是在android系统服务启动之前,客户端是本机客户端, 因此使用NATIVE_ADJ作为优先级分数和状态为PROCESS_STATE_BOUND_TOP,因为这样的汽车应用程序需要在顶部可见。
3.2 获取活跃的client PIDs, 并获取对应的优先级,更新所有的 client 属性, 最后,为传入的客户端创建描述符。我们存储了oomScoreOffset, 因为我们以后可能会在新的handleEvictionsLocked中需要它,而ProcessInfoService不会考虑到这一点。
4 查找所有可能被驱逐的 clients,对于后台高优先级clients 持有camera无法被驱逐的场景处理,返回对应的错误码
4.2 对于可以被驱逐的,通知客户端断开连接
5 清理被驱逐的clients对应的资源,以及disconnet过程错误检查
6 再次检查设备是否被拔出,如果给定ID的设备可以连接,则返回NO_ERROR

status_t CameraService::handleEvictionsLocked(const std::string& cameraId, int clientPid,
        apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback,
        const std::string& packageName, int oomScoreOffset, bool systemNativeClient,
        /*out*/
        sp<BasicClient>* client,
        std::shared_ptr<resource_policy::ClientDescriptor<std::string, sp<BasicClient>>>* partial) {
    ATRACE_CALL();
    status_t ret = NO_ERROR;
    std::vector<DescriptorPtr> evictedClients;
    DescriptorPtr clientDescriptor;
    {
        if (effectiveApiLevel == API_1) {
            // If we are using API1, any existing client for this camera ID with the same remote
            // should be returned rather than evicted to allow MediaRecorder to work properly.
        // 1) 如果我们使用API1,则应该返回具有相同远程的此相机ID的任何现有客户端,
            // 而不是驱逐以允许MediaRecorder正常工作。
            // 先在基本都是用 更高级的 API

            auto current = mActiveClientManager.get(cameraId);
            if (current != nullptr) {
                auto clientSp = current->getValue();
                if (clientSp.get() != nullptr) { // should never be needed
                    if (!clientSp->canCastToApiClient(effectiveApiLevel)) {
                        ALOGW("CameraService connect called with a different"
                                " API level, evicting prior client...");
                    } else if (clientSp->getRemote() == remoteCallback) {
                        ALOGI("CameraService::connect X (PID %d) (second call from same"
                                " app binder, returning the same client)", clientPid);
                        *client = clientSp;
                        return NO_ERROR;
                    }
                }
            }
        }

        // Get state for the given cameraId
     // 2)获取给定 camera 的状态,如果转态为空,直接返回 错误码 BAD_VALUE
        auto state = getCameraState(cameraId);
        if (state == nullptr) {
            ALOGE("CameraService::connect X (PID %d) rejected (no camera device with ID %s)",
                clientPid, cameraId.c_str());
            // Should never get here because validateConnectLocked should have errored out
            return BAD_VALUE;
        }

        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder = sm->checkService(String16(kProcessInfoServiceName));
        if (!binder && isAutomotivePrivilegedClient(CameraThreadState::getCallingUid())) {
            // If processinfo service is not available and the client is automotive privileged
            // client used for safety critical uses cases such as rear-view and surround-view which
            // needs to be available before android boot completes, then use the hardcoded values
            // for the process state and priority score. As this scenario is before android system
            // services are up and client is native client, hence using NATIVE_ADJ as the priority
            // score and state as PROCESS_STATE_BOUND_TOP as such automotive apps need to be
            // visible on the top.
            // 3)如果processinfo服务不可用,并且客户端是汽车特权客户端,用于安全关键用例,
            // 如后视镜和环绕视图,需要在android启动完成之前可用,则使用硬编码的进程状态和优先级评分值。
            // 由于这种情况是在android系统服务启动之前,客户端是本机客户端,
            // 因此使用NATIVE_ADJ作为优先级分数和状态为PROCESS_STATE_BOUND_TOP,因为这样的汽车应用程序需要在顶部可见。
            clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
                    sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
                    state->getConflicting(), resource_policy::NATIVE_ADJ, clientPid,
                    ActivityManager::PROCESS_STATE_BOUND_TOP, oomScoreOffset, systemNativeClient);
        } else {
            // 3.2)获取活跃的client PIDs, 并获取对应的优先级,更新所有的 client 属性,
            // 最后,为传入的客户端创建描述符。我们存储了oomScoreOffset,
            // 因为我们以后可能会在新的handleEvictionsLocked中需要它,而ProcessInfoService不会考虑到这一点。
            
            // Get current active client PIDs
            std::vector<int> ownerPids(mActiveClientManager.getAllOwners());
            ownerPids.push_back(clientPid);

            std::vector<int> priorityScores(ownerPids.size());
            std::vector<int> states(ownerPids.size());

            // Get priority scores of all active PIDs
            status_t err = ProcessInfoService::getProcessStatesScoresFromPids(ownerPids.size(),
                    &ownerPids[0], /*out*/&states[0], /*out*/&priorityScores[0]);
            if (err != OK) {
                ALOGE("%s: Priority score query failed: %d", __FUNCTION__, err);
                return err;
            }

            // Update all active clients' priorities
            std::map<int,resource_policy::ClientPriority> pidToPriorityMap;
            for (size_t i = 0; i < ownerPids.size() - 1; i++) {
                pidToPriorityMap.emplace(ownerPids[i],
                        resource_policy::ClientPriority(priorityScores[i], states[i],
                        /* isVendorClient won't get copied over*/ false,
                        /* oomScoreOffset won't get copied over*/ 0));
            }
            mActiveClientManager.updatePriorities(pidToPriorityMap);

            int32_t actualScore = priorityScores[priorityScores.size() - 1];
            int32_t actualState = states[states.size() - 1];

            // Make descriptor for incoming client. We store the oomScoreOffset
            // since we might need it later on new handleEvictionsLocked and
            // ProcessInfoService would not take that into account.
            clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
                    sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
                    state->getConflicting(), actualScore, clientPid, actualState,
                    oomScoreOffset, systemNativeClient);
        }

        resource_policy::ClientPriority clientPriority = clientDescriptor->getPriority();

        // Find clients that would be evicted
        // 4。1)查找所有可能被驱逐的 clients,进行相应处理
        auto evicted = mActiveClientManager.wouldEvict(clientDescriptor);

        // If the incoming client was 'evicted,' higher priority clients have the camera in the
        // background, so we cannot do evictions
        // 对于后台高优先级clients 持有camera无法被驱逐的场景处理,返回对应的错误码
        if (std::find(evicted.begin(), evicted.end(), clientDescriptor) != evicted.end()) {
            ALOGE("CameraService::connect X (PID %d) rejected (existing client(s) with higher"
                    " priority).", clientPid);


            // Log the client's attempt
            Mutex::Autolock l(mLogLock);
            mEventLog.add(msg);

            auto current = mActiveClientManager.get(cameraId);
            if (current != nullptr) {
                return -EBUSY; // CAMERA_IN_USE
            } else {
                return -EUSERS; // MAX_CAMERAS_IN_USE
            }
        }
        // 4.2 对于可以被驱逐的,通知客户端断开连接
        for (auto& i : evicted) {
            sp<BasicClient> clientSp = i->getValue();
            if (clientSp.get() == nullptr) {
                ALOGE("%s: Invalid state: Null client in active client list.", __FUNCTION__);

                // TODO: Remove this
                LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, null client in active list",
                        __FUNCTION__);
                mActiveClientManager.remove(i);
                continue;
            }

            ALOGE("CameraService::connect evicting conflicting client for camera ID %s",
                    i->getKey().c_str());
            evictedClients.push_back(i);

            // Log the clients evicted
            logEvent(fmt::sprintf("EVICT device %s client held by package %s (PID"
                    " %" PRId32 ", score %" PRId32 ", state %" PRId32 ")\n - Evicted by device %s client for"
                    " package %s (PID %d, score %" PRId32 ", state %" PRId32 ")",
                    i->getKey().c_str(), clientSp->getPackageName().c_str(),
                    i->getOwnerId(), i->getPriority().getScore(),
                    i->getPriority().getState(), cameraId.c_str(),
                    packageName.c_str(), clientPid, clientPriority.getScore(),
                    clientPriority.getState()));

            // Notify the client of disconnection
            clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
                    CaptureResultExtras());
        }
    }
    
     // 5 清理被驱逐的clients对应的资源,以及disconnet过程错误检查

    // Do not hold mServiceLock while disconnecting clients, but retain the condition blocking
    // other clients from connecting in mServiceLockWrapper if held
    mServiceLock.unlock();

    // Clear caller identity temporarily so client disconnect PID checks work correctly
    int64_t token = CameraThreadState::clearCallingIdentity();

    // Destroy evicted clients
    for (auto& i : evictedClients) {
        // Disconnect is blocking, and should only have returned when HAL has cleaned up
        i->getValue()->disconnect(); // Clients will remove themselves from the active client list
    }

    CameraThreadState::restoreCallingIdentity(token);

    for (const auto& i : evictedClients) {
        ALOGV("%s: Waiting for disconnect to complete for client for device %s (PID %" PRId32 ")",
                __FUNCTION__, i->getKey().c_str(), i->getOwnerId());
        ret = mActiveClientManager.waitUntilRemoved(i, DEFAULT_DISCONNECT_TIMEOUT_NS);
        if (ret == TIMED_OUT) {
            ALOGE("%s: Timed out waiting for client for device %s to disconnect, "
                    "current clients:\n%s", __FUNCTION__, i->getKey().c_str(),
                    mActiveClientManager.toString().c_str());
            return -EBUSY;
        }
        if (ret != NO_ERROR) {
            ALOGE("%s: Received error waiting for client for device %s to disconnect: %s (%d), "
                    "current clients:\n%s", __FUNCTION__, i->getKey().c_str(), strerror(-ret),
                    ret, mActiveClientManager.toString().c_str());
            return ret;
        }
    }

    evictedClients.clear();

    // Once clients have been disconnected, relock
    mServiceLock.lock();
    //  6 再次检查设备是否被拔出,如果给定ID的设备可以连接,则返回NO_ERROR
    // Check again if the device was unplugged or something while we weren't holding mServiceLock
    if ((ret = checkIfDeviceIsUsable(cameraId)) != NO_ERROR) {
        return ret;
    }

    *partial = clientDescriptor;
    return NO_ERROR;
}

2.5.2 checkIfDeviceIsUsable

//如果给定ID的设备可以连接,则返回NO_ERROR

status_t CameraService::checkIfDeviceIsUsable(const std::string& cameraId) const {    
auto cameraState = getCameraState(cameraId);
    int callingPid = CameraThreadState::getCallingPid();
    if (cameraState == nullptr) {
        ALOGE("CameraService::connect X (PID %d) rejected (invalid camera ID %s)", callingPid,
                cameraId.c_str());
        return -ENODEV;
    }

    StatusInternal currentStatus = cameraState->getStatus();
    if (currentStatus == StatusInternal::NOT_PRESENT) {
        ALOGE("CameraService::connect X (PID %d) rejected (camera %s is not connected)",
                callingPid, cameraId.c_str());
        return -ENODEV;
    } else if (currentStatus == StatusInternal::ENUMERATING) {
        ALOGE("CameraService::connect X (PID %d) rejected, (camera %s is initializing)",
                callingPid, cameraId.c_str());
        return -EBUSY;
    }

    return NO_ERROR;
}

2.5.3 prepareDeviceOpen

frameworks/av/services/camera/libcameraservice/CameraFlashlight.cpp # prepareDeviceOpen
通知camerafashlight,相机服务将打开一个相机设备。camerashlight将释放可能导致相机打开失败的资源。相机服务必须在打开相机设备之前调用此函数。(note:手机打开闪光灯,再去打开camera,会发现闪光灯会被关闭)

status_t CameraFlashlight::prepareDeviceOpen(const std::string& cameraId) {
    ALOGV("%s: prepare for device open", __FUNCTION__);

    Mutex::Autolock l(mLock);
    if (!mFlashlightMapInitialized) {
        ALOGE("%s: findFlashUnits() must be called before this method.",
               __FUNCTION__);
        return NO_INIT;
    }

    if (isBackwardCompatibleMode(cameraId)) {
        // framework is going to open a camera device, all flash light control
        // should be closed for backward compatible support.
        mFlashControl.clear();

        if (mOpenedCameraIds.size() == 0) {
            // notify torch unavailable for all cameras with a flash
            std::vector<std::string> ids = mProviderManager->getCameraDeviceIds();
            int numCameras = static_cast<int>(ids.size());
            for (int i = 0; i < numCameras; i++) {
                if (hasFlashUnitLocked(ids[i])) {
                    mCallbacks->onTorchStatusChanged(
                            ids[i], TorchModeStatus::NOT_AVAILABLE);
                }
            }
        }

        // close flash control that may be opened by calling hasFlashUnitLocked.
        mFlashControl.clear();
    }

    if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) {
        mOpenedCameraIds.add(cameraId);
    }

    return OK;
}

2.5.4 makeClient

frameworks/av/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp

bool targetPerfClassPrimaryCamera(
        const std::set<std::string>& perfClassPrimaryCameraIds, const std::string& cameraId,
        int targetSdkVersion) {
    bool isPerfClassPrimaryCamera =
            perfClassPrimaryCameraIds.find(cameraId) != perfClassPrimaryCameraIds.end();
    return targetSdkVersion >= SDK_VERSION_S && isPerfClassPrimaryCamera;
}

frameworks/av/services/camera/libcameraservice/CameraService.cpp # makeClient

Status CameraService::makeClient(const sp<CameraService>& cameraService,
        const sp<IInterface>& cameraCb, const std::string& packageName, bool systemNativeClient,
        const std::optional<std::string>& featureId,  const std::string& cameraId,
        int api1CameraId, int facing, int sensorOrientation, int clientPid, uid_t clientUid,
        int servicePid, std::pair<int, IPCTransport> deviceVersionAndTransport,
        apiLevel effectiveApiLevel, bool overrideForPerfClass, bool overrideToPortrait,
        bool forceSlowJpegMode, const std::string& originalCameraId,
        /*out*/sp<BasicClient>* client) {
    // 1 For HIDL devices 做版本支持检测,非支持版本直接报错并return ERROR_INVALID_OPERATION
    if (deviceVersionAndTransport.second == IPCTransport::HIDL) {
        // Create CameraClient based on device version reported by the HAL.
        int deviceVersion = deviceVersionAndTransport.first;
        switch(deviceVersion) {
            case CAMERA_DEVICE_API_VERSION_1_0:
                ALOGE("Camera using old HAL version: %d", deviceVersion);
                return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
                        "Camera device \"%s\" HAL version %d no longer supported",
                        cameraId.c_str(), deviceVersion);
                break;
            case CAMERA_DEVICE_API_VERSION_3_0:
            case CAMERA_DEVICE_API_VERSION_3_1:
            case CAMERA_DEVICE_API_VERSION_3_2:
            case CAMERA_DEVICE_API_VERSION_3_3:
            case CAMERA_DEVICE_API_VERSION_3_4:
            case CAMERA_DEVICE_API_VERSION_3_5:
            case CAMERA_DEVICE_API_VERSION_3_6:
            case CAMERA_DEVICE_API_VERSION_3_7:
                break;
            default:
                // Should not be reachable
                ALOGE("Unknown camera device HAL version: %d", deviceVersion);
                return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                        "Camera device \"%s\" has unknown HAL version %d",
                        cameraId.c_str(), deviceVersion);
        }
    }
    // 2 依据 api level创建 对应的 camera client, c2 是  CameraDeviceClient  
    if (effectiveApiLevel == API_1) { // Camera1 API route
        sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
        *client = new Camera2Client(cameraService, tmp, cameraService->mCameraServiceProxyWrapper,
                packageName, featureId, cameraId,
                api1CameraId, facing, sensorOrientation,
                clientPid, clientUid, servicePid, overrideForPerfClass, overrideToPortrait,
                forceSlowJpegMode);
        ALOGI("%s: Camera1 API (legacy), override to portrait %d, forceSlowJpegMode %d",
                __FUNCTION__, overrideToPortrait, forceSlowJpegMode);
    } else { // Camera2 API route
        sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
                static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
        *client = new CameraDeviceClient(cameraService, tmp,
                cameraService->mCameraServiceProxyWrapper, packageName, systemNativeClient,
                featureId, cameraId, facing, sensorOrientation, clientPid, clientUid, servicePid,
                overrideForPerfClass, overrideToPortrait, originalCameraId);
        ALOGI("%s: Camera2 API, override to portrait %d", __FUNCTION__, overrideToPortrait);
    }
    return Status::ok();
}
2.5.4.1 CameraDeviceClient
CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
        const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
        std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
        const std::string& clientPackageName,
        bool systemNativeClient,
        const std::optional<std::string>& clientFeatureId,
        const std::string& cameraId,
        int cameraFacing,
        int sensorOrientation,
        int clientPid,
        uid_t clientUid,
        int servicePid,
        bool overrideForPerfClass,
        bool overrideToPortrait,
        const std::string& originalCameraId) :
    Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper, clientPackageName,
            systemNativeClient, clientFeatureId, cameraId, /*API1 camera ID*/ -1, cameraFacing,
            sensorOrientation, clientPid, clientUid, servicePid, overrideForPerfClass,
            overrideToPortrait),
    mInputStream(),
    mStreamingRequestId(REQUEST_ID_NONE),
    mRequestIdCounter(0),
    mOverrideForPerfClass(overrideForPerfClass),
    mOriginalCameraId(originalCameraId) {
    ATRACE_CALL();
    ALOGI("CameraDeviceClient %s: Opened", cameraId.c_str());
}

2.5.5 CameraDeviceClient # initialize

1、 2.5.5.1 Camera2ClientBase # initialize,在这里启动并初始化此相机设备以供活动使用,并返回用于活动操作的会话句柄。这个操作之后相机被真正的打开了
2、 mFrameProcessor = new FrameProcessorBase(mDevice), 创建输出帧元数据处理线程。这个线程等待来自帧生成器的新帧,并根据需要对它们进行分析。并注册 FilteredListener,当 有数据可获取是,调用 CameraDeviceClient::onResultAvailable
3、缓存该设备对应的物理摄像头id以及该设备的高分辨率传感器+物理摄像头id

status_t CameraDeviceClient::initialize(sp<CameraProviderManager> manager,
        const std::string& monitorTags) {
    return initializeImpl(manager, monitorTags);
}

template<typename TProviderPtr>
status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr,
        const std::string& monitorTags) {
    ATRACE_CALL();
    status_t res;
    // 1 在这里启动并初始化此相机设备以供活动使用,并返回用于活动操作的会话句柄。这个操作之后相机被真正的打开了
    res = Camera2ClientBase::initialize(providerPtr, monitorTags);
    if (res != OK) {
        return res;
    }
    // 2 创建输出帧元数据处理线程。这个线程等待来自帧生成器的新帧,并根据需要对它们进行分析。
    mFrameProcessor = new FrameProcessorBase(mDevice);
    std::string threadName = std::string("CDU-") + mCameraIdStr + "-FrameProc";
    res = mFrameProcessor->run(threadName.c_str());
    if (res != OK) {
        ALOGE("%s: Unable to start frame processor thread: %s (%d)",
                __FUNCTION__, strerror(-res), res);
        return res;
    }

    mFrameProcessor->registerListener(camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID,
                                      camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MAX_ID,
                                      /*listener*/this,
                                      /*sendPartials*/true);

  

   ……
    // 3 缓存该设备对应的物理摄像头id以及该设备的高分辨率传感器+物理摄像头id
    mProviderManager = providerPtr;
    // Cache physical camera ids corresponding to this device and also the high
    // resolution sensors in this device + physical camera ids
    mProviderManager->isLogicalCamera(mCameraIdStr, &mPhysicalCameraIds);
    if (supportsUltraHighResolutionCapture(mCameraIdStr)) {
        mHighResolutionSensors.insert(mCameraIdStr);
    }
    for (auto &physicalId : mPhysicalCameraIds) {
        if (supportsUltraHighResolutionCapture(physicalId)) {
            mHighResolutionSensors.insert(physicalId);
        }
    }
    return OK;
}
2.5.5.1 Camera2ClientBase # initialize

frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp # initialize
这里我们需要追踪 providerTransport 支持的是IPCTransport::HIDL,还是 IPCTransport::AIDL

template <typename TClientBase>
status_t Camera2ClientBase<TClientBase>::initialize(sp<CameraProviderManager> manager,
        const std::string& monitorTags) {
    return initializeImpl(manager, monitorTags);
}

template <typename TClientBase>
template <typename TProviderPtr>
status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr,
        const std::string& monitorTags) {
    ATRACE_CALL();
    ALOGV("%s: Initializing client for camera %s", __FUNCTION__,
          TClientBase::mCameraIdStr.c_str());
    status_t res;

    IPCTransport providerTransport = IPCTransport::INVALID;
    // 获取 providerTransport, client->initialize(mCameraProviderManager, monitorTags);
    // providerPtr实际上是 CameraService 参数 mCameraProviderManager,
    // mCameraProviderManager = new CameraProviderManager();
    res = providerPtr->getCameraIdIPCTransport(TClientBase::mCameraIdStr,
            &providerTransport);
    if (res != OK) {
        return res;
    }
    switch (providerTransport) {
        case IPCTransport::HIDL:
            mDevice =
                    new HidlCamera3Device(mCameraServiceProxyWrapper,
                            TClientBase::mCameraIdStr, mOverrideForPerfClass,
                            TClientBase::mOverrideToPortrait, mLegacyClient);
            break;
        case IPCTransport::AIDL:
            mDevice =
                    new AidlCamera3Device(mCameraServiceProxyWrapper,
                            TClientBase::mCameraIdStr, mOverrideForPerfClass,
                            TClientBase::mOverrideToPortrait, mLegacyClient);
             break;
        default:
            ALOGE("%s Invalid transport for camera id %s", __FUNCTION__,
                    TClientBase::mCameraIdStr.c_str());
            return NO_INIT;
    }
    if (mDevice == NULL) {
        ALOGE("%s: Camera %s: No device connected",
                __FUNCTION__, TClientBase::mCameraIdStr.c_str());
        return NO_INIT;
    }

    // Verify ops permissions
    res = TClientBase::startCameraOps();
    if (res != OK) {
        TClientBase::finishCameraOps();
        return res;
    }
    // 请看 2.5.5.5 HidlCamera3Device::initialize
    res = mDevice->initialize(providerPtr, monitorTags);
    if (res != OK) {
        ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
                __FUNCTION__, TClientBase::mCameraIdStr.c_str(), strerror(-res), res);
        TClientBase::finishCameraOps();
        return res;
    }

    wp<NotificationListener> weakThis(this);
    res = mDevice->setNotifyCallback(weakThis);
    if (res != OK) {
        ALOGE("%s: Camera %s: Unable to set notify callback: %s (%d)",
                __FUNCTION__, TClientBase::mCameraIdStr.c_str(), strerror(-res), res);
        return res;
    }

    return OK;
}
2.5.5.5 HidlCamera3Device # initialize
status_t HidlCamera3Device::initialize(sp<CameraProviderManager> manager,
        const std::string& monitorTags) {
    ATRACE_CALL();
    Mutex::Autolock il(mInterfaceLock);
    Mutex::Autolock l(mLock);

    ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.c_str());
    if (mStatus != STATUS_UNINITIALIZED) {
        CLOGE("Already initialized!");
        return INVALID_OPERATION;
    }
    if (manager == nullptr) return INVALID_OPERATION;

    sp<ICameraDeviceSession> session;
    ATRACE_BEGIN("CameraHal::openSession");
    // 1 Open an active session to a camera device.
    status_t res = manager->openHidlSession(mId, this,
            /*out*/ &session);
    ATRACE_END();
    if (res != OK) {
        SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
        return res;
    }

 
   
    ……
    std::shared_ptr<RequestMetadataQueue> queue;
    // 2 检索与processCaptureRequest一起使用的队列。如果客户端决定使用快速消息队列传递请求元数据,
    auto requestQueueRet = session->getCaptureRequestMetadataQueue(
        [&queue](const auto& descriptor) {
            queue = std::make_shared<RequestMetadataQueue>(descriptor);
            if (!queue->isValid() || queue->availableToWrite() <= 0) {
                ALOGE("HAL returns empty request metadata fmq, not use it");
                queue = nullptr;
                // don't use the queue onwards.
            }
        });
    if (!requestQueueRet.isOk()) {
        ALOGE("Transaction error when getting request metadata fmq: %s, not use it",
                requestQueueRet.description().c_str());
        return DEAD_OBJECT;
    }

    std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
    // 3 检索与ICameraDeviceCallback.processCaptureResult一起使用的队列。
    auto resultQueueRet = session->getCaptureResultMetadataQueue(
        [&resQueue](const auto& descriptor) {
            resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
            if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
                ALOGE("HAL returns empty result metadata fmq, not use it");
                resQueue = nullptr;
                // Don't use the resQueue onwards.
            }
        });
    if (!resultQueueRet.isOk()) {
        ALOGE("Transaction error when getting result metadata queue from camera session: %s",
                resultQueueRet.description().c_str());
        return DEAD_OBJECT;
    }
    ……

    return initializeCommonLocked();
}


2.5.5.5.1 openHidlSession

frameworks/av/services/camera/libcameraservice/common/CameraProviderManager.cpp # openHidlSession
在这里启动并初始化此相机设备以供活动使用,并返回用于活动操作的会话句柄。这个操作之后相机被真正的打开了

status_t CameraProviderManager::openHidlSession(const std::string &id,
        const sp<device::V3_2::ICameraDeviceCallback>& callback,
        /*out*/
        sp<device::V3_2::ICameraDeviceSession> *session) {

    std::lock_guard<std::mutex> lock(mInterfaceMutex);

    auto deviceInfo = findDeviceInfoLocked(id);
    if (deviceInfo == nullptr) return NAME_NOT_FOUND;

    auto *hidlDeviceInfo3 = static_cast<HidlProviderInfo::HidlDeviceInfo3*>(deviceInfo);
    sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
    if (parentProvider == nullptr) {
        return DEAD_OBJECT;
    }
    const sp<provider::V2_4::ICameraProvider> provider =
            static_cast<HidlProviderInfo *>(parentProvider.get())->startProviderInterface();
    if (provider == nullptr) {
        return DEAD_OBJECT;
    }
    std::shared_ptr<HalCameraProvider> halCameraProvider =
            std::make_shared<HidlHalCameraProvider>(provider, provider->descriptor);
    saveRef(DeviceMode::CAMERA, id, halCameraProvider);

    Status status;
    hardware::Return<void> ret;
    auto interface = hidlDeviceInfo3->startDeviceInterface();
    if (interface == nullptr) {
        return DEAD_OBJECT;
    }
    // 2 启动并初始化此相机设备以供活动使用,并返回用于活动操作的会话句柄。
    // 这个操作之后相机被真正的打开了
    ret = interface->open(callback, [&status, &session]
            (Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
                status = s;
                if (status == Status::OK) {
                    *session = cameraSession;
                }
            });
    if (!ret.isOk()) {
        removeRef(DeviceMode::CAMERA, id);
        ALOGE("%s: Transaction error opening a session for camera device %s: %s",
                __FUNCTION__, id.c_str(), ret.description().c_str());
        return DEAD_OBJECT;
    }
    return HidlProviderInfo::mapToStatusT(status);
}
  • 20
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值