Camera: Use separate lock for status tracker access sync

A race condition is possible during access to status tracker
in 'disonnect' and inflight updates like 'registerInFlight' and
'removeInFlightMapEntryLocked'. To avoid this, access is serialized
using 'mLock'. However 'mLock' is also used in other contexts which
under the right conditions could result in a deadlock. One such instance
could occur during consecutive reprocess requests. The request thread
while holding the request lock will try to obtain a free input buffer.
In case the input stream doesn't have any free buffers left, it will
block on an internal condition and wait. In the meantime if another
capture request gets submitted, then the request itself will block on
the request lock within request thread while holding 'mLock' inside
submit helper. This will not allow incoming input buffer results
to get processed as they could call 'removeInFlightMapEntryLocked' and
try to acquire the already locked 'mLock'. The deadlock will continue
until the input stream timeout expires, which will fail the request.
 One way to resolve this is by adding a separate lock which will only be
used for the status tracker access synchronization.

Bug: 79972865
Test: Camera CTS
Change-Id: Ic63f891202ba102f6408ed714c5eef29b41404e3
gugelfrei
Emilian Peev 6 years ago
parent e8924ce00f
commit 26d975de2f

@ -263,6 +263,7 @@ status_t Camera3Device::initializeCommonLocked() {
status_t Camera3Device::disconnect() {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock stLock(mTrackerLock);
ALOGI("%s: E", __FUNCTION__);
@ -2699,8 +2700,9 @@ status_t Camera3Device::registerInFlight(uint32_t frameNumber,
if (res < 0) return res;
if (mInFlightMap.size() == 1) {
// hold mLock to prevent race with disconnect
Mutex::Autolock l(mLock);
// Hold a separate dedicated tracker lock to prevent race with disconnect and also
// avoid a deadlock during reprocess requests.
Mutex::Autolock l(mTrackerLock);
if (mStatusTracker != nullptr) {
mStatusTracker->markComponentActive(mInFlightStatusId);
}
@ -2733,8 +2735,9 @@ void Camera3Device::removeInFlightMapEntryLocked(int idx) {
// Indicate idle inFlightMap to the status tracker
if (mInFlightMap.size() == 0) {
// hold mLock to prevent race with disconnect
Mutex::Autolock l(mLock);
// Hold a separate dedicated tracker lock to prevent race with disconnect and also
// avoid a deadlock during reprocess requests.
Mutex::Autolock l(mTrackerLock);
if (mStatusTracker != nullptr) {
mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
}

@ -1208,6 +1208,9 @@ class Camera3Device :
static callbacks_notify_t sNotify;
// Synchronizes access to status tracker between inflight updates and disconnect.
// b/79972865
Mutex mTrackerLock;
}; // class Camera3Device
}; // namespace android

Loading…
Cancel
Save