cameraservice handleEvictionsLocked函数简单分析。

本文介绍 CameraService 如何处理客户端连接请求,包括客户端优先级评估、冲突解决及客户端驱逐流程。通过跟踪代码实现细节,揭示了 Android 系统中摄像头资源管理的核心机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clientPid,
        apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback, const String8& packageName,
        /*out*/
        sp<BasicClient>* client,
        std::shared_ptr<resource_policy::ClientDescriptor<String8, 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.

            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 from same client, but 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 current active client PIDs
        std::vector<int> ownerPids(mActiveClientManager.getAllOwners());
        ownerPids.push_back(clientPid);
        // Use the value +PROCESS_STATE_NONEXISTENT, to avoid taking
        // address of PROCESS_STATE_NONEXISTENT as a reference argument
        // for the vector constructor. PROCESS_STATE_NONEXISTENT does
        // not have an out-of-class definition.
        std::vector<int> priorities(ownerPids.size(), +PROCESS_STATE_NONEXISTENT);
        // Get priorites of all active PIDs
        ProcessInfoService::getProcessStatesFromPids(ownerPids.size(), &ownerPids[0],
                /*out*/&priorities[0]);

        // Update all active clients' priorities
        std::map<int,int> pidToPriorityMap;
     //!++
        ALOGI("Incoming clientPid(%d) packageName(%s) priorities(%d)",clientPid,packageName.string(),priorities[priorities.size() - 1]);
        if(strcmp("mtk_vt_use", packageName) == 0)
        {
            ALOGI("Incoming client is mtk_vt_use, set priorities(old:%d) = 0",priorities[priorities.size() - 1]);
            priorities[priorities.size() - 1] = 0;
        }
        //!--
                //  modify for preventing 3rd party pre-empty begin
	for(size_t n = 0; n< 2; n++ )
	{
		String8 id = String8::format("%zu", n);
		String8 pkg;
		if(mActiveClientManager.getCameraClient(id)!=0)
		{
			pkg = String8(mActiveClientManager.getCameraClient(id)->getPackageName().string());
		}
		else
		{
			ALOGI("Camera[%zu] has no client NOW",n);
			continue;
		}
		if(0 == strcmp("com.mediatek.camera",pkg.string())&& 0 == strcmp("com.google.android.apps.photos",packageName.string()))
		{
			ALOGI("mediatek camera is running, google photo is excluded");
			return BAD_VALUE;
		}
	}
//modify for preventing 3rd party pre-empty end    
        for (size_t i = 0; i < ownerPids.size() - 1; i++) {
            //!++
            //make sure VT has top priority
            if( mActiveClientManager.getCameraClient(cameraId) != 0 &&
                strcmp("mtk_vt_use", String8(mActiveClientManager.getCameraClient(cameraId)->getPackageName().string())) == 0)
          {
                int clientPid_vt = mActiveClientManager.getCameraClient(cameraId)->getClientPid();
                if(clientPid_vt == ownerPids[i])
                {
                    priorities[i] = 0;
                   ALOGI("i(%zu) pid(%d) => mtk_vt_use, set priorities(old:%d) = 0",i,ownerPids[i],priorities[i]);
                }
            }
            else if(strcmp("mtk_vt_use", packageName) == 0)
            {
                priorities[i] = INT_MAX;
              ALOGI("i(%zu) pid(%d) not mtk_vt_use, set priorities(old:%d) = INT_MAX",i,ownerPids[i],priorities[i]);
            }
            ALOGI("i(%zu) pid(%d) priorities(%d),Priority(%d)",i,ownerPids[i],priorities[i],getCameraPriorityFromProcState(priorities[i]));
            //!--
            pidToPriorityMap.emplace(ownerPids[i], getCameraPriorityFromProcState(priorities[i]));
        }
       mActiveClientManager.updatePriorities(pidToPriorityMap);

        // Get state for the given cameraId
        auto state = getCameraState(cameraId);
        if (state == nullptr) {
            ALOGE("CameraService::connect X (PID %d) rejected (no camera device with ID %s)",
               clientPid, cameraId.string());
            // Should never get here because validateConnectLocked should have errored out
            return BAD_VALUE;
        }

        // Make descriptor for incoming client
        clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
                sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
                state->getConflicting(),
                getCameraPriorityFromProcState(priorities[priorities.size() - 1]), clientPid);

        // Find clients that would be evicted
        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
        if (std::find(evicted.begin(), evicted.end(), clientDescriptor) != evicted.end()) {
            ALOGE("CameraService::connect X (PID %d) rejected (existing client(s) with higher"
                    " priority).", clientPid);
            sp<BasicClient> clientSp = clientDescriptor->getValue();
            String8 curTime = getFormattedCurrentTime();
            auto incompatibleClients =
                    mActiveClientManager.getIncompatibleClients(clientDescriptor);

            String8 msg = String8::format("%s : DENIED connect device %s client for package %s "
                  "(PID %d, priority %d) due to eviction policy", curTime.string(),
                    cameraId.string(), packageName.string(), clientPid,
                    getCameraPriorityFromProcState(priorities[priorities.size() - 1]));

            for (auto& i : incompatibleClients) {
                msg.appendFormat("\n   - Blocked by existing device %s client for package %s"
                        "(PID %" PRId32 ", priority %" PRId32 ")", i->getKey().string(),
                        String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(),
                        i->getPriority());
                ALOGE("   Conflicts with: Device %s, client package %s (PID %"
                       PRId32 ", priority %" PRId32 ")", i->getKey().string(),
                        String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(),
                        i->getPriority());
            }

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

            return -EBUSY;
        }
      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().string());
            evictedClients.push_back(i);

            // Log the clients evicted
            logEvent(String8::format("EVICT device %s client held by package %s (PID"
                   " %" PRId32 ", priority %" PRId32 ")\n   - Evicted by device %s client for"
                    " package %s (PID %d, priority %" PRId32 ")",
                    i->getKey().string(), String8{clientSp->getPackageName()}.string(),
                    i->getOwnerId(), i->getPriority(), cameraId.string(),
                    packageName.string(), clientPid,
                    getCameraPriorityFromProcState(priorities[priorities.size() - 1])));

            // Notify the client of disconnection
            clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
                    CaptureResultExtras());
        }
    }
    // 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 = IPCThreadState::self()->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
    }

    IPCThreadState::self()->restoreCallingIdentity(token);
  for (const auto& i : evictedClients) {
        ALOGV("%s: Waiting for disconnect to complete for client for device %s (PID %" PRId32 ")",
                __FUNCTION__, i->getKey().string(), 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().string(),
                    mActiveClientManager.toString().string());
            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().string(), strerror(-ret),
                    ret, mActiveClientManager.toString().string());
            return ret;
        }
    }    evictedClients.clear();


    // Once clients have been disconnected, relock
    mServiceLock.lock();


    // 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;
}

CameraService 是 Android 系统中负责管理和控制相机硬件的关键组件之一。它作为 Camera HAL(Hardware Abstraction Layer,硬件抽象层)和上层应用程序之间的桥梁,实现了对摄像头的各项功能支持。以下是关于 CameraService 的详细介绍: ### CameraService 概述 1. **作用**: CameraService 主要职责是在 Android 设备中协调相机硬件与用户应用之间的工作流程。它接收来自客户端的应用程序请求(如拍照、录像),并通过 Camera HAL 将这些请求转换成实际的硬件操作。 2. **工作流程**: - 应用程序通过 `CameraManager` API 请求打开指定编号的相机设备。 - CameraService 接收到此请求后,初始化对应的 CameraProvider 并加载相应的 CameraDevice。 - 对于每个活跃的 CameraDevice 实例,CameraService 分配一个独立的服务进程来处理捕获图像帧的任务。 - 图像数据流经由 BufferQueue 和 SurfaceTexture 进行预览展示或保存至存储介质。 3. **权限管理**: 访问相机资源涉及重要的隐私保护问题,因此 CameraService 强制实施严格的访问权限检查机制。只有获得适当授权的应用才能成功开启并使用相机功能。 4. **多任务处理能力**: 从 Android 5.0 开始引入的新版 Camera2 API 提供了更好的并发特性,允许同时运行多个摄像头部实例而不影响彼此性能表现,这使得双摄乃至更多镜头组合成为可能。 5. **错误恢复机制**: 当遇到异常情况时(例如突然断电或其他不可预见的问题),CameraService 具备自动重启受影响服务的能力,尽可能减少对外部可见的影响范围。 ### 架构图解 ```plaintext +--+ | v +---------+---------+ | CameraManager API| +---------+---------+ | v +---------+---------+ | CameraService | <- Camera HAL Interaction +---------+---------+ | v +---------+---------+ | Camera Provider & | | Device Management | +---------+---------+ ``` ### 关键特点 - **高效能优化**:针对不同品牌机型做了大量适配调试工作,确保流畅稳定的用户体验。 - **灵活性强**:不仅适用于原生相机App,还开放给第三方开发者自定义实现丰富的摄影特效滤镜等附加价值内容。 - **安全性高**:严格执行Android平台的安全策略框架,防止恶意软件滥用相机接口侵犯他人权益。 ### 使用场景示例 - 用户启动相机应用进行日常拍摄记录生活点滴。 - 第三方直播平台利用CameraService提供的低延迟视频采集途径实现实时互动分享。 - VR/AR虚拟现实增强现实项目依靠精确的深度感知映射创建沉浸式的数字世界体验。 --- 希望以上信息可以帮助您更深入地理解 CameraService 及其在 Android 生态系统内的角色地位。如果有任何疑问或需要了解更多相关内容,请随时告知!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值