new method to detect default network

This commit is contained in:
Kr328 committed 2020-02-18 16:50:36 +08:00
1 parent 34697da10c
commit bfa3c8375b
6 files changed
+92 -75

No files matched your search

@@ -114,8 +114,7 @@ class ClashNotification(private val context: ClashService, enableRefresh: Boolea
delay(1000)
}
}
finally {
} finally {
Log.d("Clash Notification Stopped")
}
}
@@ -9,8 +9,10 @@ import android.os.IBinder
import com.github.kr328.clash.core.Clash
import com.github.kr328.clash.service.data.ClashDatabase
import com.github.kr328.clash.service.util.*
import kotlinx.coroutines.*
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
class ClashService : BaseService() {
@@ -98,7 +100,7 @@ class ClashService : BaseService() {
}
private suspend fun reloadProfile() {
if ( !loadLock.tryLock() )
if (!loadLock.tryLock())
return
try {
@@ -7,7 +7,6 @@ import com.github.kr328.clash.core.utils.Log
import com.github.kr328.clash.service.net.DefaultNetworkChannel
import com.github.kr328.clash.service.util.broadcastNetworkChanged
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.broadcast
import java.net.InetAddress
class TunService : VpnService(), CoroutineScope by MainScope() {
@@ -71,18 +70,22 @@ class TunService : VpnService(), CoroutineScope by MainScope() {
Log.i("Network changed to ${d?.second}")
if ( d == null ) {
if (d == null) {
setUnderlyingNetworks(null)
continue
}
setUnderlyingNetworks(arrayOf(d.first))
if ( settings.get(Settings.AUTO_ADD_SYSTEM_DNS) ) {
if (settings.get(Settings.AUTO_ADD_SYSTEM_DNS)) {
withContext(Dispatchers.Default) {
Clash.appendDns(d.second.dnsServers
.map(InetAddress::getHostName)
.filter(String::isNotBlank))
val dnsServers = d.second?.dnsServers ?: emptyList()
Clash.appendDns(
dnsServers
.map(InetAddress::getHostName)
.filter(String::isNotBlank)
)
}
}
@@ -1,6 +1,8 @@
package com.github.kr328.clash.service.data
import androidx.room.*
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
@Entity(
tableName = "profile_select_proxies",
@@ -1,29 +1,41 @@
// from https://github.com/shadowsocks/shadowsocks-android/blob/master/core/src/main/java/com/github/shadowsocks/net/DefaultNetworkListener.kt
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) {
CoroutineScope by scope,
Channel<Pair<Network, LinkProperties?>?> by Channel(Channel.CONFLATED) {
private val sendLock = Mutex()
private val connectivity = context.getSystemService(ConnectivityManager::class.java)!!
private val callback = object : ConnectivityManager.NetworkCallback() {
var current: Network? = null
private val capabilitiesCache = mutableMapOf<Network, NetworkCapabilities?>()
override fun onLost(network: Network) {
if ( current == network )
offer(null)
override fun onAvailable(network: Network) {
sendDefaultNetwork()
}
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
if ( linkProperties.routes.any { it.isDefaultRoute } ) {
offer(network to linkProperties)
current = network
}
override fun onLost(network: Network) {
sendDefaultNetwork()
capabilitiesCache.remove(network)
}
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities?
) {
val cap = capabilitiesCache[network]
if (cap?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
!= networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
)
sendDefaultNetwork()
capabilitiesCache[network] = networkCapabilities
}
}
@@ -35,54 +47,55 @@ class DefaultNetworkChannel(val context: Context, scope: CoroutineScope) :
connectivity.unregisterNetworkCallback(callback)
}
// 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
// }
// }
private fun sendDefaultNetwork() {
if (!sendLock.tryLock())
return
launch {
delay(1000)
val network = detectDefaultNetwork()
val link = network?.let(connectivity::getLinkProperties)
if (network != null)
send(network to link)
else
send(null)
sendLock.unlock()
}
}
private suspend fun detectDefaultNetwork() = withContext(Dispatchers.Default) {
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
}
}
}
@@ -3,9 +3,7 @@ package com.github.kr328.clash.service.util
import android.content.Context
import android.content.Intent
import com.github.kr328.clash.service.Intents
import com.github.kr328.clash.service.data.ClashDatabase
import com.github.kr328.clash.service.data.ClashProfileEntity
import com.github.kr328.clash.service.data.ClashProfileProxyEntity
fun Context.sendBroadcastSelf(intent: Intent) {
this.sendBroadcast(intent.setPackage(this.packageName))