Commit 590f28c8 authored by Mygod's avatar Mygod

Prevent blocking DNS resolving in BaseService

parent e9524620
......@@ -27,7 +27,6 @@ import android.content.IntentFilter
import android.os.*
import android.util.Log
import androidx.core.content.getSystemService
import androidx.core.os.BuildCompat
import androidx.core.os.bundleOf
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.Core
......@@ -45,7 +44,6 @@ import com.google.firebase.analytics.FirebaseAnalytics
import kotlinx.coroutines.*
import java.io.File
import java.net.BindException
import java.net.InetAddress
import java.net.URL
import java.net.UnknownHostException
import java.util.*
......@@ -290,12 +288,7 @@ object BaseService {
}
suspend fun preInit() { }
suspend fun resolver(host: String): Array<InetAddress> {
return if (BuildCompat.isAtLeastQ()) {
// prefer non-blocking version if available
DnsResolverCompat.resolve(Core.connectivity.activeNetwork ?: return emptyArray(), host)
} else InetAddress.getAllByName(host)
}
suspend fun resolver(host: String) = DnsResolverCompat.resolveOnActiveNetwork(host)
suspend fun openConnection(url: URL) = url.openConnection()
fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
......
......@@ -27,6 +27,7 @@ import android.net.ParseException
import android.os.CancellationSignal
import android.system.ErrnoException
import androidx.core.os.BuildCompat
import com.github.shadowsocks.Core
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
......@@ -41,27 +42,34 @@ sealed class DnsResolverCompat {
private val instance by lazy { if (BuildCompat.isAtLeastQ()) DnsResolverCompat29 else DnsResolverCompat21 }
override suspend fun resolve(network: Network, host: String) = instance.resolve(network, host)
override suspend fun resolveOnActiveNetwork(host: String) = instance.resolveOnActiveNetwork(host)
}
abstract suspend fun resolve(network: Network, host: String): Array<InetAddress>
abstract suspend fun resolveOnActiveNetwork(host: String): Array<InetAddress>
private object DnsResolverCompat21 : DnsResolverCompat() {
override suspend fun resolve(network: Network, host: String) =
GlobalScope.async(Dispatchers.IO) { network.getAllByName(host) }.await()
override suspend fun resolveOnActiveNetwork(host: String) =
GlobalScope.async(Dispatchers.IO) { InetAddress.getAllByName(host) }.await()
}
@TargetApi(29)
private object DnsResolverCompat29 : DnsResolverCompat() {
/**
* This executor will run on its caller directly. On Q beta 3, this is called in main thread.
* This executor will run on its caller directly. On Q beta 3, this results in calling in main thread.
*/
private val executor = Executor { it.run() }
private object InPlaceExecutor : Executor {
override fun execute(command: Runnable?) = command!!.run()
}
override suspend fun resolve(network: Network, host: String): Array<InetAddress> {
return suspendCancellableCoroutine { cont ->
val signal = CancellationSignal()
cont.invokeOnCancellation { signal.cancel() }
// retry should be handled by client instead
DnsResolver.getInstance().query(network, host, DnsResolver.FLAG_NO_RETRY, executor,
DnsResolver.getInstance().query(network, host, DnsResolver.FLAG_NO_RETRY, InPlaceExecutor,
signal, object : DnsResolver.InetAddressAnswerCallback() {
override fun onAnswer(answer: MutableList<InetAddress>) = cont.resume(answer.toTypedArray())
override fun onQueryException(exception: ErrnoException) = cont.resumeWithException(exception)
......@@ -69,5 +77,9 @@ sealed class DnsResolverCompat {
})
}
}
override suspend fun resolveOnActiveNetwork(host: String): Array<InetAddress> {
return resolve(Core.connectivity.activeNetwork ?: return emptyArray(), host)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment