new method to detect default network

This commit is contained in:
Kr328 committed 2020-02-18 00:30:59 +08:00
1 parent 3e7d7f5d60
commit 34697da10c
3 files changed
+69 -74

No files matched your search

@@ -11,6 +11,7 @@ import com.github.kr328.clash.service.data.ClashDatabase
import com.github.kr328.clash.service.util.*
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.sync.Mutex
class ClashService : BaseService() {
companion object {
@@ -20,6 +21,7 @@ class ClashService : BaseService() {
var isServiceRunning = false
}
private val loadLock = Mutex()
private val service = this
private lateinit var notification: ClashNotification
private var stopReason: String? = null
@@ -96,10 +98,13 @@ class ClashService : BaseService() {
}
private suspend fun reloadProfile() {
val active = ClashDatabase.getInstance(service).openClashProfileDao()
.queryActiveProfile() ?: return stopSelf("Empty active profile")
if ( !loadLock.tryLock() )
return
try {
val active = ClashDatabase.getInstance(service).openClashProfileDao()
.queryActiveProfile() ?: return stopSelf("Empty active profile")
Clash.loadProfile(
resolveProfile(active.id),
resolveBase(active.id)
@@ -115,6 +120,8 @@ class ClashService : BaseService() {
broadcastProfileLoaded(this, active)
} catch (e: Exception) {
stopSelf("Load profile failure")
} finally {
loadLock.unlock()
}
}
@@ -69,6 +69,8 @@ class TunService : VpnService(), CoroutineScope by MainScope() {
while (isActive) {
val d = defaultNetworkChannel.receive()
Log.i("Network changed to ${d?.second}")
if ( d == null ) {
setUnderlyingNetworks(null)
continue
@@ -3,36 +3,27 @@ package com.github.kr328.clash.service.net
import android.content.Context
import android.net.*
import com.github.kr328.clash.core.utils.Log
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.sync.Mutex
class DefaultNetworkChannel(val context: Context, scope: CoroutineScope) :
CoroutineScope by scope, Channel<Pair<Network, LinkProperties>?> by Channel(Channel.CONFLATED) {
private var currentNetwork: Network? = null
private val detectDelayLock = Mutex()
private val connectivity = context.getSystemService(ConnectivityManager::class.java)!!
private val callback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
sendDefaultNetwork(true)
}
var current: Network? = null
override fun onLost(network: Network) {
sendDefaultNetwork(true)
}
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
if ( network == currentNetwork &&
!networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) )
sendDefaultNetwork(true)
if ( current == network )
offer(null)
}
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
if ( network == currentNetwork )
sendDefaultNetwork(false)
if ( linkProperties.routes.any { it.isDefaultRoute } ) {
offer(network to linkProperties)
current = network
}
}
}
@@ -44,59 +35,54 @@ class DefaultNetworkChannel(val context: Context, scope: CoroutineScope) :
connectivity.unregisterNetworkCallback(callback)
}
private fun sendDefaultNetwork(ignoreSameNetwork: Boolean) {
if (detectDelayLock.tryLock()) {
launch {
delay(1000)
val network = detectDefaultNetwork()
if ( ignoreSameNetwork && network == currentNetwork )
return@launch
currentNetwork = network
val linkProperties = network?.let { connectivity.getLinkProperties(it) }
if ( network != null && linkProperties != null )
send(network to linkProperties)
else
send(null)
detectDelayLock.unlock()
}
}
}
private suspend fun detectDefaultNetwork(): Network? = withContext(Dispatchers.Default) {
return@withContext try {
connectivity.allNetworks
.asSequence()
.mapNotNull { network ->
connectivity.getNetworkCapabilities(network)?.let { it to network }
}
.filterNot {
it.first.hasTransport(NetworkCapabilities.TRANSPORT_VPN) ||
!it.first.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
.sortedBy {
when {
it.first.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> 0
it.first.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> 1
it.first.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> 2
it.first.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN) -> 3
it.first.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> 4
else -> 5
} + if (it.first.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED))
-1000
else
0
}
.map {
it.second
}
.firstOrNull()
} catch (e: Exception) {
null
}
}
// private fun sendDefaultNetwork() {
// if (detectDelayLock.tryLock()) {
// launch {
// delay(1000)
//
// val network = detectDefaultNetwork()
// val linkProperties = network?.let { connectivity.getLinkProperties(it) }
//
// if ( network != null && linkProperties != null )
// send(network to linkProperties)
// else
// send(null)
//
// detectDelayLock.unlock()
// }
// }
// }
//
// private suspend fun detectDefaultNetwork(): Network? = withContext(Dispatchers.Default) {
// return@withContext try {
// connectivity.allNetworks
// .asSequence()
// .mapNotNull { network ->
// connectivity.getNetworkCapabilities(network)?.let { it to network }
// }
// .filterNot {
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_VPN) ||
// !it.first.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
// }
// .sortedBy {
// when {
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> 0
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> 1
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> 2
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN) -> 3
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> 4
// else -> 5
// } + if (it.first.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED))
// -1000
// else
// 0
// }
// .map {
// it.second
// }
// .firstOrNull()
// } catch (e: Exception) {
// null
// }
// }
}