Merge pull request #2049 from vitorpamplona/claude/tor-exception-handling-2Qy1u

Add error handling to Tor service initialization and control
This commit is contained in:
Vitor Pamplona
2026-03-31 08:29:03 -04:00
committed by GitHub
3 changed files with 46 additions and 21 deletions
@@ -79,16 +79,24 @@ class RelayProxyClientConnector(
client.disconnect()
}
if (it.torStatus is TorServiceStatus.Active) {
it.torStatus.torControlConnection?.signal(TorControlCommands.SIGNAL_DORMANT)
Log.d("ManageRelayServices", "Pausing Tor Activity")
try {
it.torStatus.torControlConnection?.signal(TorControlCommands.SIGNAL_DORMANT)
Log.d("ManageRelayServices", "Pausing Tor Activity")
} catch (e: Exception) {
Log.e("ManageRelayServices") { "Failed to signal Tor dormant: ${e.message}" }
}
}
} else if (it.connectivity is ConnectivityStatus.Active && !client.isActive()) {
Log.d("ManageRelayServices", "Connectivity On: Resuming Relay Services")
if (it.torStatus is TorServiceStatus.Active) {
it.torStatus.torControlConnection?.signal(TorControlCommands.SIGNAL_ACTIVE)
it.torStatus.torControlConnection?.signal(TorControlCommands.SIGNAL_NEWNYM)
Log.d("ManageRelayServices", "Resuming Tor Activity with new nym")
try {
it.torStatus.torControlConnection?.signal(TorControlCommands.SIGNAL_ACTIVE)
it.torStatus.torControlConnection?.signal(TorControlCommands.SIGNAL_NEWNYM)
Log.d("ManageRelayServices", "Resuming Tor Activity with new nym")
} catch (e: Exception) {
Log.e("ManageRelayServices") { "Failed to signal Tor active: ${e.message}" }
}
}
// only calls this if the client is not active. Otherwise goes to the else below
@@ -22,11 +22,13 @@ package com.vitorpamplona.amethyst.ui.tor
import android.content.Context
import com.vitorpamplona.amethyst.model.preferences.TorSharedPreferences
import com.vitorpamplona.quartz.utils.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flowOn
@@ -71,6 +73,9 @@ class TorManager(
}
}
}
}.catch { e ->
Log.e("TorManager") { "Tor service error: ${e.message}" }
emit(TorServiceStatus.Off)
}.flowOn(Dispatchers.IO)
.stateIn(
scope,
@@ -54,18 +54,23 @@ class TorService(
service: IBinder,
) {
launch(Dispatchers.IO) {
// moved torService to a local variable, since we only need it once
val torService = (service as LocalBinder).service
try {
// moved torService to a local variable, since we only need it once
val torService = (service as LocalBinder).service
while (torService.socksPort < 0) {
delay(SOCKS_PORT_POLL_INTERVAL_MS)
while (torService.socksPort < 0) {
delay(SOCKS_PORT_POLL_INTERVAL_MS)
}
val active = TorServiceStatus.Active(torService.socksPort)
active.torControlConnection = torService.torControlConnection
trySend(active)
Log.d("TorService") { "Tor Service Connected ${torService.socksPort}" }
} catch (e: Exception) {
Log.e("TorService") { "Tor service connection failed: ${e.message}" }
trySend(TorServiceStatus.Off)
}
val active = TorServiceStatus.Active(torService.socksPort)
active.torControlConnection = torService.torControlConnection
trySend(active)
Log.d("TorService") { "Tor Service Connected ${torService.socksPort}" }
}
}
@@ -75,11 +80,16 @@ class TorService(
}
}
context.bindService(
currentIntent,
serviceConnection,
BIND_AUTO_CREATE,
)
try {
context.bindService(
currentIntent,
serviceConnection,
BIND_AUTO_CREATE,
)
} catch (e: Exception) {
Log.e("TorService") { "Failed to bind Tor Service: ${e.message}" }
trySend(TorServiceStatus.Off)
}
awaitClose {
Log.d("TorService", "Stopping Tor Service")
@@ -88,8 +98,10 @@ class TorService(
} catch (e: Exception) {
Log.d("TorService") { "Failed to unbind Tor Service: ${e.message}" }
}
launch {
try {
context.stopService(currentIntent)
} catch (e: Exception) {
Log.d("TorService") { "Failed to stop Tor Service: ${e.message}" }
}
trySend(TorServiceStatus.Off)
}