diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/DatabaseSessionLock.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/DatabaseSessionLock.java index baa2b1a311..eb38050d1a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/DatabaseSessionLock.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/DatabaseSessionLock.java @@ -13,6 +13,10 @@ public enum DatabaseSessionLock implements SignalSessionLock { INSTANCE; + public static final long NO_OWNER = -1; + + private volatile long ownerThreadId = NO_OWNER; + @Override public Lock acquire() { SQLiteDatabase db = DatabaseFactory.getInstance(ApplicationDependencies.getApplication()).getRawDatabase(); @@ -23,9 +27,34 @@ public enum DatabaseSessionLock implements SignalSessionLock { db.beginTransaction(); + ownerThreadId = Thread.currentThread().getId(); + return () -> { + ownerThreadId = -1; db.setTransactionSuccessful(); db.endTransaction(); }; } + + /** + * Important: Only truly useful for debugging. Do not rely on this for functionality. There's tiny + * windows where this state might not be fully accurate. + * + * @return True if it's likely that some other thread owns this lock, and it's not you. + */ + public boolean isLikelyHeldByOtherThread() { + long ownerThreadId = this.ownerThreadId; + return ownerThreadId != -1 && ownerThreadId == Thread.currentThread().getId(); + } + + /** + * Important: Only truly useful for debugging. Do not rely on this for functionality. There's a + * tiny window where a thread may still own the lock, but the state we track around it has been + * cleared. + * + * @return The ID of the thread that likely owns this lock, or {@link #NO_OWNER} if no one owns it. + */ + public long getLikeyOwnerThreadId() { + return ownerThreadId; + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java index 3605fb91f2..a25ac0e431 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java @@ -113,7 +113,14 @@ public class IncomingMessageProcessor { stopwatch.split("queue-check"); + long ownerThreadId = DatabaseSessionLock.INSTANCE.getLikeyOwnerThreadId(); + if (ownerThreadId != DatabaseSessionLock.NO_OWNER && ownerThreadId != Thread.currentThread().getId()) { + Log.i(TAG, "It is likely that some other thread has this lock. Owner: " + ownerThreadId + ", Us: " + Thread.currentThread().getId()); + } + try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) { + Log.i(TAG, "Acquired lock while processing message " + envelope.getTimestamp() + "."); + DecryptionResult result = MessageDecryptionUtil.decrypt(context, envelope); stopwatch.split("decrypt");