@@ -14,10 +14,9 @@ import androidx.core.content.getSystemService
1414import com.follow.clash.FlClashApplication
1515import com.follow.clash.GlobalState
1616import com.follow.clash.RunState
17+ import com.follow.clash.core.Core
1718import com.follow.clash.extensions.awaitResult
18- import com.follow.clash.extensions.getProtocol
1919import com.follow.clash.extensions.resolveDns
20- import com.follow.clash.models.Process
2120import com.follow.clash.models.StartForegroundParams
2221import com.follow.clash.models.VpnOptions
2322import com.follow.clash.services.BaseServiceInterface
@@ -40,17 +39,20 @@ import kotlin.concurrent.withLock
4039data object VpnPlugin : FlutterPlugin , MethodChannel .MethodCallHandler {
4140 private lateinit var flutterMethodChannel: MethodChannel
4241 private var flClashService: BaseServiceInterface ? = null
43- private lateinit var options: VpnOptions
42+ private var options: VpnOptions ? = null
43+ private var isBind: Boolean = false
4444 private lateinit var scope: CoroutineScope
4545 private var lastStartForegroundParams: StartForegroundParams ? = null
4646 private var timerJob: Job ? = null
47+ private val uidPageNameMap = mutableMapOf<Int , String >()
4748
4849 private val connectivity by lazy {
4950 FlClashApplication .getAppContext().getSystemService<ConnectivityManager >()
5051 }
5152
5253 private val connection = object : ServiceConnection {
5354 override fun onServiceConnected (className : ComponentName , service : IBinder ) {
55+ isBind = true
5456 flClashService = when (service) {
5557 is FlClashVpnService .LocalBinder -> service.getService()
5658 is FlClashService .LocalBinder -> service.getService()
@@ -60,6 +62,7 @@ data object VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
6062 }
6163
6264 override fun onServiceDisconnected (arg : ComponentName ) {
65+ isBind = false
6366 flClashService = null
6467 }
6568 }
@@ -90,69 +93,16 @@ data object VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
9093 result.success(true )
9194 }
9295
93- " setProtect" -> {
94- val fd = call.argument<Int >(" fd" )
95- if (fd != null && flClashService is FlClashVpnService ) {
96- try {
97- (flClashService as FlClashVpnService ).protect(fd)
98- result.success(true )
99- } catch (e: RuntimeException ) {
100- result.success(false )
101- }
102- } else {
103- result.success(false )
104- }
105- }
106-
107- " resolverProcess" -> {
108- val data = call.argument<String >(" data" )
109- val process = if (data != null ) Gson ().fromJson(
110- data, Process ::class .java
111- ) else null
112- val metadata = process?.metadata
113- if (metadata == null ) {
114- result.success(null )
115- return
116- }
117- val protocol = metadata.getProtocol()
118- if (protocol == null ) {
119- result.success(null )
120- return
121- }
122- scope.launch {
123- withContext(Dispatchers .Default ) {
124- if (Build .VERSION .SDK_INT < Build .VERSION_CODES .Q ) {
125- result.success(null )
126- return @withContext
127- }
128- val src = InetSocketAddress (metadata.sourceIP, metadata.sourcePort)
129- val dst = InetSocketAddress (
130- metadata.destinationIP.ifEmpty { metadata.host },
131- metadata.destinationPort
132- )
133- val uid = try {
134- connectivity?.getConnectionOwnerUid(protocol, src, dst)
135- } catch (_: Exception ) {
136- null
137- }
138- if (uid == null || uid == - 1 ) {
139- result.success(null )
140- return @withContext
141- }
142- val packages =
143- FlClashApplication .getAppContext().packageManager?.getPackagesForUid(uid)
144- result.success(packages?.first())
145- }
146- }
147- }
148-
14996 else -> {
15097 result.notImplemented()
15198 }
15299 }
153100 }
154101
155102 fun handleStart (options : VpnOptions ): Boolean {
103+ if (options.enable != this .options?.enable) {
104+ this .flClashService = null
105+ }
156106 this .options = options
157107 when (options.enable) {
158108 true -> handleStartVpn()
@@ -162,10 +112,9 @@ data object VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
162112 }
163113
164114 private fun handleStartVpn () {
165- GlobalState .getCurrentAppPlugin()
166- ?.requestVpnPermission {
167- handleStartService()
168- }
115+ GlobalState .getCurrentAppPlugin()?.requestVpnPermission {
116+ handleStartService()
117+ }
169118 }
170119
171120 fun requestGc () {
@@ -235,6 +184,7 @@ data object VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
235184 }
236185
237186 private fun startForegroundJob () {
187+ stopForegroundJob()
238188 timerJob = CoroutineScope (Dispatchers .Main ).launch {
239189 while (isActive) {
240190 startForeground()
@@ -256,26 +206,58 @@ data object VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
256206 GlobalState .runLock.withLock {
257207 if (GlobalState .runState.value == RunState .START ) return
258208 GlobalState .runState.value = RunState .START
259- val fd = flClashService?.start(options)
260- flutterMethodChannel.invokeMethod(
261- " started" , fd
209+ val fd = flClashService?.start(options!! )
210+ Core .startTun(
211+ fd = fd ? : 0 ,
212+ protect = this ::protect,
213+ resolverProcess = this ::resolverProcess,
262214 )
263- startForegroundJob();
215+ startForegroundJob()
264216 }
265217 }
266218
219+ private fun protect (fd : Int ): Boolean {
220+ return (flClashService as ? FlClashVpnService )?.protect(fd) == true
221+ }
222+
223+ private fun resolverProcess (
224+ protocol : Int ,
225+ source : InetSocketAddress ,
226+ target : InetSocketAddress ,
227+ uid : Int ,
228+ ): String {
229+ val nextUid = if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
230+ connectivity?.getConnectionOwnerUid(protocol, source, target) ? : - 1
231+ } else {
232+ uid
233+ }
234+ if (nextUid == - 1 ) {
235+ return " "
236+ }
237+ if (! uidPageNameMap.containsKey(nextUid)) {
238+ uidPageNameMap[nextUid] =
239+ FlClashApplication .getAppContext().packageManager?.getPackagesForUid(nextUid)
240+ ?.first() ? : " "
241+ }
242+ return uidPageNameMap[nextUid] ? : " "
243+ }
244+
267245 fun handleStop () {
268246 GlobalState .runLock.withLock {
269247 if (GlobalState .runState.value == RunState .STOP ) return
270248 GlobalState .runState.value = RunState .STOP
271249 stopForegroundJob()
250+ Core .stopTun()
272251 flClashService?.stop()
273252 GlobalState .handleTryDestroy()
274253 }
275254 }
276255
277256 private fun bindService () {
278- val intent = when (options.enable) {
257+ if (isBind) {
258+ FlClashApplication .getAppContext().unbindService(connection)
259+ }
260+ val intent = when (options?.enable == true ) {
279261 true -> Intent (FlClashApplication .getAppContext(), FlClashVpnService ::class .java)
280262 false -> Intent (FlClashApplication .getAppContext(), FlClashService ::class .java)
281263 }
0 commit comments