Camera抢占逻辑总体流程 - handleEvictionsLocked:
1. 获取所有active pids的oom_adj_scores和process state并更新各clientpriority(里面包含了priorityScore和state值)
active pid:所有使用过cameraservice服务(打开camera)的客户端对应的pid
// std::vector<int> ownerPids(mActiveClientManager.getAllOwners());
ownerPids.push_back(clientPid);
定义每个clientPid的两个容器priorityScores和states,并通过getProcessStatesScoresFromPids给其赋值
// std::vector<int> priorityScores(ownerPids.size());
// std::vector<int> states(ownerPids.size());
这个函数是到系统中查询所有clientPid的score值和state值。
这里通过binder最终调用到了Java服务中,在AMS中注册的服务“processinfo”
最终调用的是AMS的getProcessStatesAndOomScoresForPIDs方法。
ServiceManager.addService("processinfo", new ProcessInfoService(this));
Get priority scores of all active PIDs
这里从AMS返回的priorityScore是进程的ADJ值,state是进程的状态(前台,后台等状态
具体可看ActivityManager.java中PROCESS_STATE_XXX)
// status_t err = ProcessInfoService::getProcessStatesScoresFromPids(
ownerPids.size(), &ownerPids[0], /*out*/&states[0],
/*out*/&priorityScores[0]);
Update all active clients' priorities(为什么会更新?因为防止client发生变化)
将上面获取到的进程状态放到pidToPriorityMap的map中,key为进程pid,
value为ClientPriority
// 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);
2. 根据当前想打开的camera信息创建一个clientdescriptor,调用cameraclientmanager的wouldEvict方法拿到需要Evicted的列表
wouldEvict -> wouldEvictLocked: 详见 2 == 2
3. 如果想打开的camera在 Evicted列表中,则返回camera—in-use或者max-camera—in-use错误
4. 遍历Evicted列表,通知error-camera-disconnected错误给client ()
5. 通过clearcallingIdentity清空远程调用端的uid和pid。用当前本地进程的uid和pid替代(因为cameraclient只能是自己活cameraserver来关闭)清空远程调用端的uid和pid。用当前本地进程的uid和pid替代(因为cameraclient只能是自己活cameraserver来关闭)
6. 遍历Evicted列表,调用每个client的disconnect方法来关闭camera
7. 通过restoreCallingIdentity恢复远程调用端的uid和pid信息,正好是clearcallingIdentitly的反过程
8. 调用mActiveClientManager.waitUntilRemoved等待所有evicted client disconnect完成
9. evictedClients.clear(); mServiceLock.lock();
10. 再次检查当前cameraid对应的device是否可用
2 == 2
wouldEvictLocked 抢占逻辑流程详解:
冲突的定义:(curkey 当前打开的client A camera 0,key 想打开的client B camera 0)
bool conflicting = (
当前打开的client A camera 0 == 想打开的client B camera 0 ||
当前打开的client A 冲突列表中包含想打开的client B camera 0 ||
想打开的client B 冲突列表中包含当前打开的client A camera 0)
与已打开camera存在冲突:
同一个进程:
同一颗camera(已经打开的被抢占)(同一进程重复打开同一camera)
// 如果cameraId相同,则将自己加入evictList。也就是说同一个进程第二次打开一个冲突的设备时,
// 将会把第一次打开的驱逐,第二次将会重新打开。
不同camera(想打开的抢占失败,无法打开)
// 如果cameraId不相同,则会即将第二次打开的进行驱逐。也就是第二次打开将会失败。
不同进程:
已打开优先级低(已经打开的被抢占)(不同进程重复打开同一camera)
// 如果发生冲突,或者 resource cost超过最大值并且当前进程优先级更高,则将进行比较的已经存在的client进行驱逐
已打开优先级高(想打开的抢占失败,无法打开)(不同进程重复打开同一camera)
与已打开camera不存在冲突:
total cost超过最大值100:
已打开优先级低(已经打开的被抢占)
已打开优先级高(想打开的抢占失败,无法打开)
total cost未超过最大值(无需抢占)