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() client.disconnect()
} }
if (it.torStatus is TorServiceStatus.Active) { if (it.torStatus is TorServiceStatus.Active) {
it.torStatus.torControlConnection?.signal(TorControlCommands.SIGNAL_DORMANT) try {
Log.d("ManageRelayServices", "Pausing Tor Activity") 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()) { } else if (it.connectivity is ConnectivityStatus.Active && !client.isActive()) {
Log.d("ManageRelayServices", "Connectivity On: Resuming Relay Services") Log.d("ManageRelayServices", "Connectivity On: Resuming Relay Services")
if (it.torStatus is TorServiceStatus.Active) { if (it.torStatus is TorServiceStatus.Active) {
it.torStatus.torControlConnection?.signal(TorControlCommands.SIGNAL_ACTIVE) try {
it.torStatus.torControlConnection?.signal(TorControlCommands.SIGNAL_NEWNYM) it.torStatus.torControlConnection?.signal(TorControlCommands.SIGNAL_ACTIVE)
Log.d("ManageRelayServices", "Resuming Tor Activity with new nym") 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 // 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 android.content.Context
import com.vitorpamplona.amethyst.model.preferences.TorSharedPreferences import com.vitorpamplona.amethyst.model.preferences.TorSharedPreferences
import com.vitorpamplona.quartz.utils.Log
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flowOn 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) }.flowOn(Dispatchers.IO)
.stateIn( .stateIn(
scope, scope,
@@ -54,18 +54,23 @@ class TorService(
service: IBinder, service: IBinder,
) { ) {
launch(Dispatchers.IO) { launch(Dispatchers.IO) {
// moved torService to a local variable, since we only need it once try {
val torService = (service as LocalBinder).service // moved torService to a local variable, since we only need it once
val torService = (service as LocalBinder).service
while (torService.socksPort < 0) { while (torService.socksPort < 0) {
delay(SOCKS_PORT_POLL_INTERVAL_MS) 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( try {
currentIntent, context.bindService(
serviceConnection, currentIntent,
BIND_AUTO_CREATE, serviceConnection,
) BIND_AUTO_CREATE,
)
} catch (e: Exception) {
Log.e("TorService") { "Failed to bind Tor Service: ${e.message}" }
trySend(TorServiceStatus.Off)
}
awaitClose { awaitClose {
Log.d("TorService", "Stopping Tor Service") Log.d("TorService", "Stopping Tor Service")
@@ -88,8 +98,10 @@ class TorService(
} catch (e: Exception) { } catch (e: Exception) {
Log.d("TorService") { "Failed to unbind Tor Service: ${e.message}" } Log.d("TorService") { "Failed to unbind Tor Service: ${e.message}" }
} }
launch { try {
context.stopService(currentIntent) context.stopService(currentIntent)
} catch (e: Exception) {
Log.d("TorService") { "Failed to stop Tor Service: ${e.message}" }
} }
trySend(TorServiceStatus.Off) trySend(TorServiceStatus.Off)
} }