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 4d46011..833aae7 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 @@ -8,6 +8,7 @@ import android.os.IBinder import android.os.ParcelFileDescriptor import android.util.Log import com.github.kr328.clash.core.ClashProcessStatus +import com.github.kr328.clash.service.net.DefaultNetworkObserver class TunService : VpnService() { companion object { @@ -28,11 +29,11 @@ class TunService : VpnService() { private const val PRIVATE_VLAN6_CLIENT = "fdfe:dcba:9876::1" } - private var fileDescriptor: ParcelFileDescriptor? = null - private var clash: IClashService? = null + private lateinit var fileDescriptor: ParcelFileDescriptor + private lateinit var clash: IClashService + private lateinit var defaultNetworkObserver: DefaultNetworkObserver private val connection = object: ServiceConnection { override fun onServiceDisconnected(name: ComponentName?) { - clash = null stopSelf() } @@ -66,16 +67,7 @@ class TunService : VpnService() { this@TunService.clash = clash } } - private val networkChangedCallback = object: ConnectivityManager.NetworkCallback() { - override fun onCapabilitiesChanged( - network: Network, - networkCapabilities: NetworkCapabilities - ) { - val connectivity = getSystemService(ConnectivityManager::class.java)!! - setUnderlyingNetworks(connectivity.activeNetwork?.run { arrayOf(this) }) - } - } override fun onCreate() { super.onCreate() @@ -94,13 +86,19 @@ class TunService : VpnService() { .addRoute("::", 0) .setMtu(VPN_MTU) .setBlocking(false) - .setUnderlyingNetworks(null) + .setMeteredCompat(false) .establish() ?: throw NullPointerException("Unable to establish VPN") bindService(Intent(this, ClashService::class.java), connection, Context.BIND_AUTO_CREATE) - getSystemService(ConnectivityManager::class.java)!! - .registerDefaultNetworkCallback(networkChangedCallback) + defaultNetworkObserver = DefaultNetworkObserver(this) { + val data = getSystemService(ConnectivityManager::class.java)!!.getNetworkCapabilities(it) + Log.d(TAG, "Network $data") + + setUnderlyingNetworks(it?.run { arrayOf(this) }) + } + + defaultNetworkObserver.register() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -110,15 +108,14 @@ class TunService : VpnService() { } override fun onDestroy() { - fileDescriptor?.close() + fileDescriptor.close() - clash?.stopTunDevice() - clash?.stop() + clash.stopTunDevice() + clash.stop() unbindService(connection) - getSystemService(ConnectivityManager::class.java)!! - .unregisterNetworkCallback(networkChangedCallback) + defaultNetworkObserver.unregister() super.onDestroy() } @@ -129,4 +126,10 @@ class TunService : VpnService() { } return this } + + private fun Builder.setMeteredCompat(isMetered: Boolean): Builder { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + setMetered(isMetered) + return this + } } \ No newline at end of file diff --git a/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkObserver.kt b/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkObserver.kt new file mode 100644 index 0000000..b486de0 --- /dev/null +++ b/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkObserver.kt @@ -0,0 +1,47 @@ +// 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.ConnectivityManager +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkRequest + +class DefaultNetworkObserver(val context: Context, val listener: (Network?) -> Unit) { + private val connectivity = context.getSystemService(ConnectivityManager::class.java)!! + private val active: Network? + get() = connectivity.activeNetwork + private var current: Network? = null + private val callback = object: ConnectivityManager.NetworkCallback() { + override fun onAvailable(network: Network) { + current = active + + listener(current) + } + + override fun onCapabilitiesChanged( + network: Network, + networkCapabilities: NetworkCapabilities + ) { + if ( current == active ) + listener(active) + } + + override fun onLost(network: Network) { + if ( active == current ) + current = null + + listener(current) + } + } + + fun register() { + listener(active) + + connectivity.registerDefaultNetworkCallback(callback) + } + + fun unregister() { + connectivity.unregisterNetworkCallback(callback) + } +} \ No newline at end of file