Commit 590f28c8 authored by Mygod's avatar Mygod

Prevent blocking DNS resolving in BaseService

parent e9524620
...@@ -27,7 +27,6 @@ import android.content.IntentFilter ...@@ -27,7 +27,6 @@ import android.content.IntentFilter
import android.os.* import android.os.*
import android.util.Log import android.util.Log
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.os.BuildCompat
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.Core import com.github.shadowsocks.Core
...@@ -45,7 +44,6 @@ import com.google.firebase.analytics.FirebaseAnalytics ...@@ -45,7 +44,6 @@ import com.google.firebase.analytics.FirebaseAnalytics
import kotlinx.coroutines.* import kotlinx.coroutines.*
import java.io.File import java.io.File
import java.net.BindException import java.net.BindException
import java.net.InetAddress
import java.net.URL import java.net.URL
import java.net.UnknownHostException import java.net.UnknownHostException
import java.util.* import java.util.*
...@@ -290,12 +288,7 @@ object BaseService { ...@@ -290,12 +288,7 @@ object BaseService {
} }
suspend fun preInit() { } suspend fun preInit() { }
suspend fun resolver(host: String): Array<InetAddress> { suspend fun resolver(host: String) = DnsResolverCompat.resolveOnActiveNetwork(host)
return if (BuildCompat.isAtLeastQ()) {
// prefer non-blocking version if available
DnsResolverCompat.resolve(Core.connectivity.activeNetwork ?: return emptyArray(), host)
} else InetAddress.getAllByName(host)
}
suspend fun openConnection(url: URL) = url.openConnection() suspend fun openConnection(url: URL) = url.openConnection()
fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
......
...@@ -27,6 +27,7 @@ import android.net.ParseException ...@@ -27,6 +27,7 @@ import android.net.ParseException
import android.os.CancellationSignal import android.os.CancellationSignal
import android.system.ErrnoException import android.system.ErrnoException
import androidx.core.os.BuildCompat import androidx.core.os.BuildCompat
import com.github.shadowsocks.Core
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async import kotlinx.coroutines.async
...@@ -41,27 +42,34 @@ sealed class DnsResolverCompat { ...@@ -41,27 +42,34 @@ sealed class DnsResolverCompat {
private val instance by lazy { if (BuildCompat.isAtLeastQ()) DnsResolverCompat29 else DnsResolverCompat21 } 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 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 resolve(network: Network, host: String): Array<InetAddress>
abstract suspend fun resolveOnActiveNetwork(host: String): Array<InetAddress>
private object DnsResolverCompat21 : DnsResolverCompat() { private object DnsResolverCompat21 : DnsResolverCompat() {
override suspend fun resolve(network: Network, host: String) = override suspend fun resolve(network: Network, host: String) =
GlobalScope.async(Dispatchers.IO) { network.getAllByName(host) }.await() GlobalScope.async(Dispatchers.IO) { network.getAllByName(host) }.await()
override suspend fun resolveOnActiveNetwork(host: String) =
GlobalScope.async(Dispatchers.IO) { InetAddress.getAllByName(host) }.await()
} }
@TargetApi(29) @TargetApi(29)
private object DnsResolverCompat29 : DnsResolverCompat() { 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> { override suspend fun resolve(network: Network, host: String): Array<InetAddress> {
return suspendCancellableCoroutine { cont -> return suspendCancellableCoroutine { cont ->
val signal = CancellationSignal() val signal = CancellationSignal()
cont.invokeOnCancellation { signal.cancel() } cont.invokeOnCancellation { signal.cancel() }
// retry should be handled by client instead // 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() { signal, object : DnsResolver.InetAddressAnswerCallback() {
override fun onAnswer(answer: MutableList<InetAddress>) = cont.resume(answer.toTypedArray()) override fun onAnswer(answer: MutableList<InetAddress>) = cont.resume(answer.toTypedArray())
override fun onQueryException(exception: ErrnoException) = cont.resumeWithException(exception) override fun onQueryException(exception: ErrnoException) = cont.resumeWithException(exception)
...@@ -69,5 +77,9 @@ sealed class DnsResolverCompat { ...@@ -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