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

Commit 62a0d6a0 authored by Ruben Brunk's avatar Ruben Brunk Committed by Android Git Automerger
Browse files

am ee42e7d5: am b65ce67e: am 3ba0c6ec: Merge "Fix deadlock conditions in...

am ee42e7d5: am b65ce67e: am 3ba0c6ec: Merge "Fix deadlock conditions in Camera3Device." into mnc-dev

* commit 'ee42e7d5':
  Fix deadlock conditions in Camera3Device.
parents 823f9a48 ee42e7d5
Loading
Loading
Loading
Loading
+43 −20
Original line number Original line Diff line number Diff line
@@ -60,6 +60,7 @@ Camera3Device::Camera3Device(int id):
        mIsConstrainedHighSpeedConfiguration(false),
        mIsConstrainedHighSpeedConfiguration(false),
        mHal3Device(NULL),
        mHal3Device(NULL),
        mStatus(STATUS_UNINITIALIZED),
        mStatus(STATUS_UNINITIALIZED),
        mStatusWaiters(0),
        mUsePartialResult(false),
        mUsePartialResult(false),
        mNumPartialResults(1),
        mNumPartialResults(1),
        mNextResultFrameNumber(0),
        mNextResultFrameNumber(0),
@@ -191,7 +192,8 @@ status_t Camera3Device::initialize(CameraModule *module)
    mDeviceVersion = device->common.version;
    mDeviceVersion = device->common.version;
    mDeviceInfo = info.static_camera_characteristics;
    mDeviceInfo = info.static_camera_characteristics;
    mHal3Device = device;
    mHal3Device = device;
    mStatus = STATUS_UNCONFIGURED;

    internalUpdateStatusLocked(STATUS_UNCONFIGURED);
    mNextStreamId = 0;
    mNextStreamId = 0;
    mDummyStreamId = NO_STREAM;
    mDummyStreamId = NO_STREAM;
    mNeedConfig = true;
    mNeedConfig = true;
@@ -296,7 +298,7 @@ status_t Camera3Device::disconnect() {
            mHal3Device = NULL;
            mHal3Device = NULL;
        }
        }


        mStatus = STATUS_UNINITIALIZED;
        internalUpdateStatusLocked(STATUS_UNINITIALIZED);
    }
    }


    ALOGV("%s: X", __FUNCTION__);
    ALOGV("%s: X", __FUNCTION__);
@@ -1166,6 +1168,13 @@ status_t Camera3Device::waitUntilDrainedLocked() {
    return res;
    return res;
}
}



void Camera3Device::internalUpdateStatusLocked(Status status) {
    mStatus = status;
    mRecentStatusUpdates.add(mStatus);
    mStatusChanged.broadcast();
}

// Pause to reconfigure
// Pause to reconfigure
status_t Camera3Device::internalPauseAndWaitLocked() {
status_t Camera3Device::internalPauseAndWaitLocked() {
    mRequestThread->setPaused(true);
    mRequestThread->setPaused(true);
@@ -1196,23 +1205,40 @@ status_t Camera3Device::internalResumeLocked() {
    return OK;
    return OK;
}
}


status_t Camera3Device::waitUntilStateThenRelock(bool active,
status_t Camera3Device::waitUntilStateThenRelock(bool active, nsecs_t timeout) {
        nsecs_t timeout) {
    status_t res = OK;
    status_t res = OK;
    if (active == (mStatus == STATUS_ACTIVE)) {

        // Desired state already reached
    size_t startIndex = 0;
        return res;
    if (mStatusWaiters == 0) {
        // Clear the list of recent statuses if there are no existing threads waiting on updates to
        // this status list
        mRecentStatusUpdates.clear();
    } else {
        // If other threads are waiting on updates to this status list, set the position of the
        // first element that this list will check rather than clearing the list.
        startIndex = mRecentStatusUpdates.size();
    }
    }


    mStatusWaiters++;

    bool stateSeen = false;
    bool stateSeen = false;
    do {
    do {
        mRecentStatusUpdates.clear();
        if (active == (mStatus == STATUS_ACTIVE)) {
            // Desired state is current
            break;
        }


        res = mStatusChanged.waitRelative(mLock, timeout);
        res = mStatusChanged.waitRelative(mLock, timeout);
        if (res != OK) break;
        if (res != OK) break;


        // Check state change history during wait
        // This is impossible, but if not, could result in subtle deadlocks and invalid state
        for (size_t i = 0; i < mRecentStatusUpdates.size(); i++) {
        // transitions.
        LOG_ALWAYS_FATAL_IF(startIndex > mRecentStatusUpdates.size(),
                "%s: Skipping status updates in Camera3Device, may result in deadlock.",
                __FUNCTION__);

        // Encountered desired state since we began waiting
        for (size_t i = startIndex; i < mRecentStatusUpdates.size(); i++) {
            if (active == (mRecentStatusUpdates[i] == STATUS_ACTIVE) ) {
            if (active == (mRecentStatusUpdates[i] == STATUS_ACTIVE) ) {
                stateSeen = true;
                stateSeen = true;
                break;
                break;
@@ -1220,6 +1246,8 @@ status_t Camera3Device::waitUntilStateThenRelock(bool active,
        }
        }
    } while (!stateSeen);
    } while (!stateSeen);


    mStatusWaiters--;

    return res;
    return res;
}
}


@@ -1461,9 +1489,7 @@ void Camera3Device::notifyStatus(bool idle) {
        }
        }
        ALOGV("%s: Camera %d: Now %s", __FUNCTION__, mId,
        ALOGV("%s: Camera %d: Now %s", __FUNCTION__, mId,
                idle ? "idle" : "active");
                idle ? "idle" : "active");
        mStatus = idle ? STATUS_CONFIGURED : STATUS_ACTIVE;
        internalUpdateStatusLocked(idle ? STATUS_CONFIGURED : STATUS_ACTIVE);
        mRecentStatusUpdates.add(mStatus);
        mStatusChanged.signal();


        // Skip notifying listener if we're doing some user-transparent
        // Skip notifying listener if we're doing some user-transparent
        // state changes
        // state changes
@@ -1672,7 +1698,7 @@ status_t Camera3Device::configureStreamsLocked() {


        // Return state to that at start of call, so that future configures
        // Return state to that at start of call, so that future configures
        // properly clean things up
        // properly clean things up
        mStatus = STATUS_UNCONFIGURED;
        internalUpdateStatusLocked(STATUS_UNCONFIGURED);
        mNeedConfig = true;
        mNeedConfig = true;


        ALOGV("%s: Camera %d: Stream configuration failed", __FUNCTION__, mId);
        ALOGV("%s: Camera %d: Stream configuration failed", __FUNCTION__, mId);
@@ -1719,11 +1745,8 @@ status_t Camera3Device::configureStreamsLocked() {


    mNeedConfig = false;
    mNeedConfig = false;


    if (mDummyStreamId == NO_STREAM) {
    internalUpdateStatusLocked((mDummyStreamId == NO_STREAM) ?
        mStatus = STATUS_CONFIGURED;
            STATUS_CONFIGURED : STATUS_UNCONFIGURED);
    } else {
        mStatus = STATUS_UNCONFIGURED;
    }


    ALOGV("%s: Camera %d: Stream configuration complete", __FUNCTION__, mId);
    ALOGV("%s: Camera %d: Stream configuration complete", __FUNCTION__, mId);


@@ -1831,7 +1854,7 @@ void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) {
    mErrorCause = errorCause;
    mErrorCause = errorCause;


    mRequestThread->setPaused(true);
    mRequestThread->setPaused(true);
    mStatus = STATUS_ERROR;
    internalUpdateStatusLocked(STATUS_ERROR);


    // Notify upstream about a device error
    // Notify upstream about a device error
    if (mListener != NULL) {
    if (mListener != NULL) {
+11 −0
Original line number Original line Diff line number Diff line
@@ -207,7 +207,11 @@ class Camera3Device :
        STATUS_CONFIGURED,
        STATUS_CONFIGURED,
        STATUS_ACTIVE
        STATUS_ACTIVE
    }                          mStatus;
    }                          mStatus;

    // Only clear mRecentStatusUpdates, mStatusWaiters from waitUntilStateThenRelock
    Vector<Status>             mRecentStatusUpdates;
    Vector<Status>             mRecentStatusUpdates;
    int                        mStatusWaiters;

    Condition                  mStatusChanged;
    Condition                  mStatusChanged;


    // Tracking cause of fatal errors when in STATUS_ERROR
    // Tracking cause of fatal errors when in STATUS_ERROR
@@ -277,6 +281,13 @@ class Camera3Device :
     */
     */
    virtual CameraMetadata getLatestRequestLocked();
    virtual CameraMetadata getLatestRequestLocked();


    /**
     * Update the current device status and wake all waiting threads.
     *
     * Must be called with mLock held.
     */
    void internalUpdateStatusLocked(Status status);

    /**
    /**
     * Pause processing and flush everything, but don't tell the clients.
     * Pause processing and flush everything, but don't tell the clients.
     * This is for reconfiguring outputs transparently when according to the
     * This is for reconfiguring outputs transparently when according to the