From 34697da10c7e082aec6a023a2fb9949f109bb30b Mon Sep 17 00:00:00 2001 From: Kr328 <39107975+Kr328@users.noreply.github.com> Date: Tue, 18 Feb 2020 00:30:59 +0800 Subject: [PATCH] new method to detect default network --- .../kr328/clash/service/ClashService.kt | 11 +- .../github/kr328/clash/service/TunService.kt | 2 + .../service/net/DefaultNetworkChannel.kt | 130 ++++++++---------- 3 files changed, 69 insertions(+), 74 deletions(-) diff --git a/service/src/main/java/com/github/kr328/clash/service/ClashService.kt b/service/src/main/java/com/github/kr328/clash/service/ClashService.kt index 03d44f8..3a0974f 100644 --- a/service/src/main/java/com/github/kr328/clash/service/ClashService.kt +++ b/service/src/main/java/com/github/kr328/clash/service/ClashService.kt @@ -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() } } diff --git a/service/src/main/java/com/github/kr328/clash/service/TunService.kt b/service/src/main/java/com/github/kr328/clash/service/TunService.kt index 28f2393..2576720 100644 --- a/service/src/main/java/com/github/kr328/clash/service/TunService.kt +++ b/service/src/main/java/com/github/kr328/clash/service/TunService.kt @@ -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 diff --git a/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkChannel.kt b/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkChannel.kt index 9145530..91643f1 100644 --- a/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkChannel.kt +++ b/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkChannel.kt @@ -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?> 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 +// } +// } } \ No newline at end of file