diff --git a/android/app/src/main/kotlin/com/network/proxy/ProxyVpnService.kt b/android/app/src/main/kotlin/com/network/proxy/ProxyVpnService.kt index 75a75a1..1b78ff5 100644 --- a/android/app/src/main/kotlin/com/network/proxy/ProxyVpnService.kt +++ b/android/app/src/main/kotlin/com/network/proxy/ProxyVpnService.kt @@ -7,6 +7,7 @@ import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import android.content.Intent +import android.net.ProxyInfo import android.net.VpnService import android.os.Build import android.os.ParcelFileDescriptor @@ -232,9 +233,9 @@ class ProxyVpnService : VpnService(), ProtectSocket { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { setMetered(false) } -// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { -// setHttpProxy(ProxyInfo.buildDirectProxy(proxyHost, proxyPort)) -// } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + setHttpProxy(ProxyInfo.buildDirectProxy(proxyHost, proxyPort)) + } }.establish() } diff --git a/android/app/src/main/kotlin/com/network/proxy/plugin/ProcessInfoPlugin.kt b/android/app/src/main/kotlin/com/network/proxy/plugin/ProcessInfoPlugin.kt index 5ffeac1..548b7e1 100644 --- a/android/app/src/main/kotlin/com/network/proxy/plugin/ProcessInfoPlugin.kt +++ b/android/app/src/main/kotlin/com/network/proxy/plugin/ProcessInfoPlugin.kt @@ -4,6 +4,10 @@ import com.network.proxy.vpn.util.ProcessInfoManager import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding import io.flutter.plugin.common.MethodChannel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext /** * 进程信息插件 @@ -27,13 +31,23 @@ class ProcessInfoPlugin : AndroidFlutterPlugin() { channel.setMethodCallHandler { call, result -> when (call.method) { "getProcessByPort" -> { -// val host = call.argument("host") + val host = call.argument("host") val port = call.argument("port") - val appInfo = processInfoManager.getProcessInfoByPort(port!!) - result.success(appInfo) + if (port != null) { + CoroutineScope(Dispatchers.IO).launch { + val appInfo = processInfoManager.getProcessInfoByPort(host, port) + withContext(Dispatchers.Main) { + result.success(appInfo) + } + } + } else { + result.error("INVALID_ARGUMENT", "Port is null", null) + } } - else -> result.notImplemented() + else -> { + result.notImplemented() + } } } } diff --git a/android/app/src/main/kotlin/com/network/proxy/vpn/util/ProcessInfoManager.kt b/android/app/src/main/kotlin/com/network/proxy/vpn/util/ProcessInfoManager.kt index 247941d..c78e439 100644 --- a/android/app/src/main/kotlin/com/network/proxy/vpn/util/ProcessInfoManager.kt +++ b/android/app/src/main/kotlin/com/network/proxy/vpn/util/ProcessInfoManager.kt @@ -5,11 +5,19 @@ import android.net.ConnectivityManager import android.os.Build import android.os.Process import android.system.OsConstants +import android.util.Log +import androidx.annotation.RequiresApi +import com.network.proxy.ProxyVpnService import com.network.proxy.plugin.ProcessInfo import com.network.proxy.vpn.Connection +import kotlinx.coroutines.CoroutineScope +import java.io.File import java.net.InetSocketAddress import java.nio.channels.SocketChannel import java.util.concurrent.TimeUnit +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext /** * 进程信息管理器,用于获取进程信息 @@ -32,24 +40,24 @@ class ProcessInfoManager private constructor() { var activity: Context? = null + @RequiresApi(Build.VERSION_CODES.N) fun setConnectionOwnerUid(connection: Connection) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - return - } + CoroutineScope(Dispatchers.IO).launch { - val sourceAddress = - InetSocketAddress(PacketUtil.intToIPAddress(connection.sourceIp), connection.sourcePort) - val destinationAddress = InetSocketAddress( - PacketUtil.intToIPAddress(connection.destinationIp), connection.destinationPort - ) + val sourceAddress = + InetSocketAddress(PacketUtil.intToIPAddress(connection.sourceIp), connection.sourcePort) + val destinationAddress = InetSocketAddress( + PacketUtil.intToIPAddress(connection.destinationIp), connection.destinationPort + ) - val uid = getProcessInfo(sourceAddress, destinationAddress) - val channel = connection.channel - if (uid != null && channel is SocketChannel) { - val localAddress = channel.localAddress as InetSocketAddress - val networkInfo = - NetworkInfo(uid, destinationAddress.hostString, destinationAddress.port) - localPortCache.put(localAddress.port, networkInfo) + val uid = getProcessInfoUid(sourceAddress, destinationAddress) + val channel = connection.channel + if (uid != null && uid != Process.INVALID_UID && channel is SocketChannel) { + val localAddress = channel.localAddress as InetSocketAddress + val networkInfo = + NetworkInfo(uid, destinationAddress.hostString, destinationAddress.port) + localPortCache.put(localAddress.port, networkInfo) + } } } @@ -65,8 +73,8 @@ class ProcessInfoManager private constructor() { } } - - private fun getProcessInfo( + @RequiresApi(Build.VERSION_CODES.N) + private fun getProcessInfoUid( localAddress: InetSocketAddress, remoteAddress: InetSocketAddress ): Int? { // Log.d(TAG, "getProcessInfo: $localAddress $remoteAddress") @@ -74,11 +82,12 @@ class ProcessInfoManager private constructor() { if (activity == null) { return null } + val connectivityManager: ConnectivityManager = activity!!.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val uid = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - connectivityManager.getConnectionOwnerUid( + return connectivityManager.getConnectionOwnerUid( OsConstants.IPPROTO_TCP, localAddress, remoteAddress ) } else { @@ -88,7 +97,7 @@ class ProcessInfoManager private constructor() { InetSocketAddress::class.java, InetSocketAddress::class.java ) - method.invoke( + return method.invoke( connectivityManager, OsConstants.IPPROTO_TCP, localAddress, remoteAddress ) as Int } @@ -96,10 +105,15 @@ class ProcessInfoManager private constructor() { if (uid != Process.INVALID_UID) { return uid } + + Log.w( + "ProcessInfoManager", + "Failed to get UID for local address $localAddress and remote address $remoteAddress" + ) return null } - fun getProcessInfoByPort(localPort: Int): ProcessInfo? { + suspend fun getProcessInfoByPort(host: String?, localPort: Int): ProcessInfo? { val networkInfo = localPortCache.get(localPort) if (networkInfo != null) { val processInfo = getProcessInfo(networkInfo.uid) @@ -109,6 +123,34 @@ class ProcessInfoManager private constructor() { put("remotePort", networkInfo.remotePort) } } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + return withContext(Dispatchers.IO) { + val localAddress = InetSocketAddress(host, localPort) + val remoteAddress = InetSocketAddress(ProxyVpnService.host, ProxyVpnService.port) + + val uid = getProcessInfoUid(localAddress, remoteAddress) + + if (uid == null || uid == Process.INVALID_UID) { + return@withContext null + } + + + val processInfo = getProcessInfo(uid) + if (processInfo != null) { + localPortCache.put( + localPort, NetworkInfo(uid, remoteAddress.hostString, remoteAddress.port) + ) + + return@withContext processInfo + } else { + Log.w("ProcessInfoManager", "No process info found for UID: $uid") + null + } + } + } else { + Log.w("ProcessInfoManager", "Access to /proc/net/tcp is restricted on non-rooted devices.") + } return null }