Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6adf0ea authored by Igor Murashkin's avatar Igor Murashkin
Browse files

Camera: Hotplug - conditionally transition to PRESENT when clients disconnect

Fixes an issue where a client could unconditionally transition to PRESENT
after a client disconnects, even though the underlying HAL status was actually
NOT_PRESENT or ENUMERATING.

Bug: 8780114
Change-Id: I68adb5fc819eec3b046ddcb2507b84bedc999a0f
parent 98e099ac
Loading
Loading
Loading
Loading
+30 −7
Original line number Diff line number Diff line
@@ -928,8 +928,15 @@ void CameraService::Client::disconnect() {
    ALOGV("Client::disconnect");
    BasicClient::disconnect();
    mCameraService->setCameraFree(mCameraId);

    StatusVector rejectSourceStates;
    rejectSourceStates.push_back(ICameraServiceListener::STATUS_NOT_PRESENT);
    rejectSourceStates.push_back(ICameraServiceListener::STATUS_ENUMERATING);

    // Transition to PRESENT if the camera is not in either of above 2 states
    mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT,
                                 mCameraId);
                                 mCameraId,
                                 &rejectSourceStates);
}

CameraService::Client::OpsCallback::OpsCallback(wp<BasicClient> client):
@@ -1111,15 +1118,11 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
}

void CameraService::updateStatus(ICameraServiceListener::Status status,
                                 int32_t cameraId) {
                                 int32_t cameraId,
                                 const StatusVector *rejectSourceStates) {
    // do not lock mServiceLock here or can get into a deadlock from
    //  connect() -> ProClient::disconnect -> updateStatus
    Mutex::Autolock lock(mStatusMutex);
    updateStatusUnsafe(status, cameraId);
}

void CameraService::updateStatusUnsafe(ICameraServiceListener::Status status,
                                       int32_t cameraId) {

    ICameraServiceListener::Status oldStatus = mStatusList[cameraId];

@@ -1139,6 +1142,26 @@ void CameraService::updateStatusUnsafe(ICameraServiceListener::Status status,
            return;
        }

        if (rejectSourceStates != NULL) {
            const StatusVector &rejectList = *rejectSourceStates;
            StatusVector::const_iterator it = rejectList.begin();

            /**
             * Sometimes we want to conditionally do a transition.
             * For example if a client disconnects, we want to go to PRESENT
             * only if we weren't already in NOT_PRESENT or ENUMERATING.
             */
            for (; it != rejectList.end(); ++it) {
                if (oldStatus == *it) {
                    ALOGV("%s: Rejecting status transition for Camera ID %d, "
                          " since the source state was was in one of the bad "
                          " states.", __FUNCTION__, cameraId);
                    mStatusList[cameraId] = oldStatus;
                    return;
                }
            }
        }

        /**
          * ProClients lose their exclusive lock.
          * - Done before the CameraClient can initialize the HAL device,
+3 −5
Original line number Diff line number Diff line
@@ -341,14 +341,12 @@ private:
    ICameraServiceListener::Status
                        getStatus(int cameraId) const;

    typedef Vector<ICameraServiceListener::Status> StatusVector;
    // Broadcast the new status if it changed (locks the service mutex)
    void                updateStatus(
                            ICameraServiceListener::Status status,
                            int32_t cameraId);
    // Call this one when the service mutex is already held (idempotent)
    void                updateStatusUnsafe(
                            ICameraServiceListener::Status status,
                            int32_t cameraId);
                            int32_t cameraId,
                            const StatusVector *rejectSourceStates = NULL);

    // IBinder::DeathRecipient implementation
    virtual void        binderDied(const wp<IBinder> &who);