Skip to content

Commit b59848a

Browse files
Fix a few crashes (#1933)
* Add stack to API exception and catches a few exceptions * Try catch PathManager * Cancellation handling * Cancellation handling and comments * Tidy up cancellation handling in fetchSnodePoolFromSeedWithFallback
1 parent 65af806 commit b59848a

File tree

7 files changed

+72
-21
lines changed

7 files changed

+72
-21
lines changed

app/src/main/java/org/session/libsession/messaging/open_groups/OfficialCommunityRepository.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ class OfficialCommunityRepository @Inject constructor(
100100
)
101101
}
102102
}
103+
}.onFailure {
104+
if (it is CancellationException) throw it
103105
})
104106
}
105107
}

app/src/main/java/org/session/libsession/network/onion/PathManager.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,13 @@ open class PathManager @Inject constructor(
9393
scope.launch {
9494
_paths.drop(1).collectLatest { paths ->
9595
if (paths.isEmpty()) storage.clearOnionRequestPaths()
96-
else storage.setOnionRequestPaths(paths)
96+
else {
97+
try {
98+
storage.setOnionRequestPaths(paths)
99+
} catch (e: Exception) {
100+
Log.e("Onion Request", "Failed to persist paths to storage, keeping in-memory only", e)
101+
}
102+
}
97103
}
98104
}
99105
}

app/src/main/java/org/session/libsession/network/snode/SnodeDirectory.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.session.libsession.network.snode
22

33
import android.content.Context
44
import dagger.hilt.android.qualifiers.ApplicationContext
5+
import kotlinx.coroutines.CancellationException
56
import kotlinx.coroutines.CoroutineScope
67
import kotlinx.coroutines.launch
78
import kotlinx.coroutines.sync.Mutex
@@ -175,6 +176,8 @@ class SnodeDirectory @Inject constructor(
175176
}
176177
.result
177178
}.onFailure { e ->
179+
if (e is CancellationException) throw e
180+
178181
lastError = e
179182
Log.w("SnodeDirectory", "Seed node failed: $target", e)
180183
}
@@ -277,11 +280,17 @@ class SnodeDirectory @Inject constructor(
277280
if (now >= last && now - last < POOL_REFRESH_INTERVAL_MS) return
278281

279282
scope.launch {
280-
refreshPoolFromSnodes(
281-
totalSnodeQueries = 3,
282-
minAppearance = 2,
283-
distinctQuerySubnetPrefix = 24,
284-
)
283+
try {
284+
refreshPoolFromSnodes(
285+
totalSnodeQueries = 3,
286+
minAppearance = 2,
287+
distinctQuerySubnetPrefix = 24,
288+
)
289+
} catch (e: Throwable) {
290+
if (e is CancellationException) throw e
291+
292+
Log.w("SnodeDirectory", "Error refreshing snode pool", e)
293+
}
285294
}
286295
}
287296

app/src/main/java/org/thoughtcrime/securesms/api/AutoRetryApiExecutor.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class AutoRetryApiExecutor<Req, Res>(
1818
private val actualExecutor: ApiExecutor<Req, Res>,
1919
) : ApiExecutor<Req, Res> {
2020
override suspend fun send(ctx: ApiExecutorContext, req: Req): Res {
21+
val initStack = Throwable().stackTrace
22+
2123
var numRetried = 0
2224
while (true) {
2325
try {
@@ -32,7 +34,16 @@ class AutoRetryApiExecutor<Req, Res>(
3234
Log.e(TAG, "Retrying $req $numRetried times due to error", e)
3335
delay(numRetried * 2000L)
3436
} else {
35-
throw e
37+
// If we know the error is ErrorWithFailureDecision, we can
38+
// safely modify its stacktrace as we know that exception contains
39+
// a cause where it can pinpoint to the direct trace of the error.
40+
// Otherwise, we'll create a new exception to modify the stacktrace, so to
41+
// preserve the original error's stacktrace which may contain important
42+
// information about the error.
43+
44+
val errorToUpdateStack = e.takeIf { it is ErrorWithFailureDecision } ?: RuntimeException(e)
45+
errorToUpdateStack.stackTrace = initStack
46+
throw errorToUpdateStack
3647
}
3748
}
3849
}

app/src/main/java/org/thoughtcrime/securesms/configs/ConfigToDatabaseSync.kt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.configs
22

33
import android.content.Context
44
import dagger.hilt.android.qualifiers.ApplicationContext
5+
import kotlinx.coroutines.CancellationException
56
import kotlinx.coroutines.CoroutineScope
67
import kotlinx.coroutines.Dispatchers
78
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -323,10 +324,19 @@ class ConfigToDatabaseSync @Inject constructor(
323324
messageHashes = cleanedHashes,
324325
swarmAuth = groupAdminAuth
325326
)
326-
swarmApiExecutor.execute(SwarmApiRequest(
327-
swarmPubKeyHex = groupInfoConfig.id.hexString,
328-
api = deleteMessageApi
329-
))
327+
328+
try {
329+
swarmApiExecutor.execute(
330+
SwarmApiRequest(
331+
swarmPubKeyHex = groupInfoConfig.id.hexString,
332+
api = deleteMessageApi
333+
)
334+
)
335+
} catch (e: Exception) {
336+
if (e is CancellationException) throw e
337+
338+
Log.e(TAG, "Failed to delete messages from swarm for group", e)
339+
}
330340
}
331341
}
332342
}

app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2Impl.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.Context
44
import com.google.protobuf.ByteString
55
import com.squareup.phrase.Phrase
66
import dagger.hilt.android.qualifiers.ApplicationContext
7+
import kotlinx.coroutines.CancellationException
78
import kotlinx.coroutines.Dispatchers
89
import kotlinx.coroutines.async
910
import kotlinx.coroutines.flow.filter
@@ -1225,7 +1226,12 @@ class GroupManagerV2Impl @Inject constructor(
12251226

12261227
override fun onBlocked(groupAccountId: AccountId) {
12271228
scope.launch(groupAccountId, "On blocked") {
1228-
respondToInvitation(groupAccountId, false)
1229+
try {
1230+
respondToInvitation(groupAccountId, false)
1231+
} catch (e: Throwable) {
1232+
if (e is CancellationException) throw e
1233+
Log.e(TAG, "Failed to unapprove invitation for group", e)
1234+
}
12291235

12301236
// Remove this group from config regardless
12311237
configFactory.removeGroup(groupAccountId)

app/src/main/java/org/thoughtcrime/securesms/notifications/MarkReadProcessor.kt

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.notifications
22

33
import android.content.Context
44
import dagger.hilt.android.qualifiers.ApplicationContext
5+
import kotlinx.coroutines.CancellationException
56
import kotlinx.coroutines.CoroutineScope
67
import kotlinx.coroutines.GlobalScope
78
import kotlinx.coroutines.launch
@@ -107,17 +108,23 @@ class MarkReadProcessor @Inject constructor(
107108
keySelector = { it.value.expirationInfo.expiresIn },
108109
valueTransform = { it.key }
109110
).forEach { (expiresIn, hashes) ->
110-
swarmApiExecutor.execute(
111-
SwarmApiRequest(
112-
swarmPubKeyHex = userAuth.accountId.hexString,
113-
api = alterTtyFactory.create(
114-
messageHashes = hashes,
115-
auth = userAuth,
116-
alterType = AlterTtlApi.AlterType.Shorten,
117-
newExpiry = snodeClock.currentTimeMillis() + expiresIn
111+
try {
112+
swarmApiExecutor.execute(
113+
SwarmApiRequest(
114+
swarmPubKeyHex = userAuth.accountId.hexString,
115+
api = alterTtyFactory.create(
116+
messageHashes = hashes,
117+
auth = userAuth,
118+
alterType = AlterTtlApi.AlterType.Shorten,
119+
newExpiry = snodeClock.currentTimeMillis() + expiresIn
120+
)
118121
)
119122
)
120-
)
123+
} catch (e: Throwable) {
124+
if (e is CancellationException) throw e
125+
126+
Log.e(TAG, "Failed to shorten expiry for messages with hashes $hashes", e)
127+
}
121128
}
122129
}
123130
}

0 commit comments

Comments
 (0)