cameraservice handleEvictionsLocked函數簡單分析。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章