This commit is contained in:
Fabian Freund
2026-05-23 08:45:24 +02:00
parent fd53d77d14
commit 7341196e3f
2 changed files with 54 additions and 9 deletions
@@ -38,13 +38,37 @@ class FlutterTorPlugin : FlutterPlugin, TorApi {
@Volatile
private var serviceConnected = CompletableDeferred<Unit>()
private fun startTorService(ctx: Context) {
val intent = Intent(ctx, TorService::class.java).apply {
action = TorService.ACTION_START
}
ContextCompat.startForegroundService(ctx, intent)
}
private fun rebindTorService(createIfNeeded: Boolean) {
Log.w(TAG, "Rebinding TorService (createIfNeeded=$createIfNeeded)")
unbindTorService()
serviceConnected = CompletableDeferred()
bindTorService(createIfNeeded)
}
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
Log.d(TAG, "onAttachedToEngine")
context = flutterPluginBinding.applicationContext
val appContext = flutterPluginBinding.applicationContext
context = appContext
binaryMessenger = flutterPluginBinding.binaryMessenger
// Setup Pigeon API
TorApi.setUp(flutterPluginBinding.binaryMessenger, this)
// PT control is needed before TorService is bound (for MOAT bridge
// discovery), so expose it at engine attach time using the process-wide
// singleton controller.
IPtProxyController.setUp(
flutterPluginBinding.binaryMessenger,
ProxyImpl(
controller = PluggableTransportManager.getInstance(appContext).controller,
),
)
// Reconnect to an already-running TorService without creating a new idle instance.
bindTorService(createIfNeeded = false)
@@ -55,6 +79,7 @@ class FlutterTorPlugin : FlutterPlugin, TorApi {
// Cleanup Pigeon API
TorApi.setUp(binding.binaryMessenger, null)
IPtProxyController.setUp(binding.binaryMessenger, null)
// Unbind service
unbindTorService()
@@ -72,7 +97,18 @@ class FlutterTorPlugin : FlutterPlugin, TorApi {
private fun bindTorService(createIfNeeded: Boolean) {
val ctx = context ?: return
val messenger = binaryMessenger ?: return
if (serviceConnection != null) return
if (serviceConnection != null) {
if (createIfNeeded && torService == null) {
try {
Log.d(TAG, "TorService bind pending; requesting foreground start")
startTorService(ctx)
} catch (e: Exception) {
Log.e(TAG, "startForegroundService failed during pending bind", e)
serviceConnection = null
}
}
return
}
val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
@@ -107,7 +143,7 @@ class FlutterTorPlugin : FlutterPlugin, TorApi {
try {
if (createIfNeeded) {
ContextCompat.startForegroundService(ctx, intent)
startTorService(ctx)
}
val flags = if (createIfNeeded) Context.BIND_AUTO_CREATE else 0
@@ -140,9 +176,24 @@ class FlutterTorPlugin : FlutterPlugin, TorApi {
* Wait for service to be connected. Triggers a rebind if needed.
*/
private suspend fun waitForService(): TorService {
torService?.let { return it }
if (serviceConnection == null) {
bindTorService(createIfNeeded = true)
} else if (torService == null) {
Log.d(TAG, "TorService not connected yet; escalating lazy bind")
bindTorService(createIfNeeded = true)
}
val connected = withTimeoutOrNull(5_000L) {
serviceConnected.await()
torService
}
if (connected != null) {
return connected
}
rebindTorService(createIfNeeded = true)
return withTimeoutOrNull(SERVICE_CONNECTION_TIMEOUT_MS) {
serviceConnected.await()
torService
@@ -11,7 +11,6 @@ import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import eu.weblibre.flutter_tor.generated.IPtProxyController
import eu.weblibre.flutter_tor.generated.TorConfiguration
import eu.weblibre.flutter_tor.generated.TorStatus
import io.flutter.plugin.common.BinaryMessenger
@@ -83,11 +82,6 @@ class TorService : Service() {
logHandler = LogStreamHandler(messenger)
torManager = TorManager(applicationContext, logHandler!!)
IPtProxyController.setUp(
messenger,
ProxyImpl(controller = torManager!!.pluggableTransportManager.controller)
)
Log.d(TAG, "Service initialized with messenger")
}
}