Skip to content

Commit 3f69cd4

Browse files
authored
更新 PacketCaptureVpnService.kt
1 parent a031869 commit 3f69cd4

1 file changed

Lines changed: 49 additions & 48 deletions

File tree

app/src/main/java/com/netmonitor/app/service/PacketCaptureVpnService.kt

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,32 @@ import android.content.Intent
55
import android.net.VpnService
66
import android.os.ParcelFileDescriptor
77
import androidx.core.app.NotificationCompat
8+
import com.netmonitor.app.Constants
89
import com.netmonitor.app.MainActivity
910
import com.netmonitor.app.NetMonitorApp
1011
import com.netmonitor.app.R
1112
import com.netmonitor.app.model.PacketInfo
13+
import com.netmonitor.app.util.PacketBus
1214
import kotlinx.coroutines.*
1315
import java.io.FileInputStream
1416
import java.io.FileOutputStream
15-
import java.nio.ByteBuffer
1617

18+
/**
19+
* VPN 抓包服务
20+
*
21+
* 改进点:
22+
* - 移除 companion object 中的静态回调 onPacketCaptured,改用 PacketBus (SharedFlow)
23+
* 解决内存泄漏:不再持有 ViewModel/Activity 的引用
24+
* - VPN 配置参数统一引用 Constants
25+
* - 通知 ID 统一引用 Constants
26+
*/
1727
class PacketCaptureVpnService : VpnService() {
1828

1929
private var vpnInterface: ParcelFileDescriptor? = null
2030
private var captureJob: Job? = null
2131
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
2232

23-
override fun onStartCommand(
24-
intent: Intent?,
25-
flags: Int,
26-
startId: Int
27-
): Int {
33+
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
2834
when (intent?.action) {
2935
ACTION_START -> startCapture()
3036
ACTION_STOP -> stopCapture()
@@ -35,13 +41,13 @@ class PacketCaptureVpnService : VpnService() {
3541
private fun startCapture() {
3642
val builder = Builder()
3743
.setSession("NetMonitor VPN")
38-
.addAddress("10.0.0.2", 32)
39-
.addRoute("0.0.0.0", 0)
40-
.addRoute("::", 0)
41-
.addDnsServer("8.8.8.8")
42-
.addDnsServer("8.8.4.4")
43-
.addDnsServer("2001:4860:4860::8888")
44-
.setMtu(1500)
44+
.addAddress(Constants.VPN_ADDRESS, 32)
45+
.addRoute(Constants.VPN_ROUTE_V4, 0)
46+
.addRoute(Constants.VPN_ROUTE_V6, 0)
47+
.addDnsServer(Constants.VPN_DNS_PRIMARY)
48+
.addDnsServer(Constants.VPN_DNS_SECONDARY)
49+
.addDnsServer(Constants.VPN_DNS_V6)
50+
.setMtu(Constants.VPN_MTU)
4551
.setBlocking(false)
4652

4753
// 排除自身流量,防止回环
@@ -51,7 +57,7 @@ class PacketCaptureVpnService : VpnService() {
5157

5258
vpnInterface = builder.establish() ?: return
5359

54-
startForeground(NOTIFICATION_ID, createNotification())
60+
startForeground(Constants.NOTIFICATION_ID_CAPTURE, createNotification())
5561

5662
captureJob = scope.launch {
5763
val fd = vpnInterface!!.fileDescriptor
@@ -77,7 +83,7 @@ class PacketCaptureVpnService : VpnService() {
7783
}
7884
}
7985

80-
private fun processPacket(data: ByteArray, length: Int) {
86+
private suspend fun processPacket(data: ByteArray, length: Int) {
8187
try {
8288
val version = (data[0].toInt() shr 4) and 0xF
8389
val srcIp: String
@@ -93,13 +99,13 @@ class PacketCaptureVpnService : VpnService() {
9399
protocol = data[9].toInt() and 0xFF
94100
headerLength = (data[0].toInt() and 0x0F) * 4
95101
srcIp = "${data[12].toInt() and 0xFF}" +
96-
".${data[13].toInt() and 0xFF}" +
97-
".${data[14].toInt() and 0xFF}" +
98-
".${data[15].toInt() and 0xFF}"
102+
".${data[13].toInt() and 0xFF}" +
103+
".${data[14].toInt() and 0xFF}" +
104+
".${data[15].toInt() and 0xFF}"
99105
dstIp = "${data[16].toInt() and 0xFF}" +
100-
".${data[17].toInt() and 0xFF}" +
101-
".${data[18].toInt() and 0xFF}" +
102-
".${data[19].toInt() and 0xFF}"
106+
".${data[17].toInt() and 0xFF}" +
107+
".${data[18].toInt() and 0xFF}" +
108+
".${data[19].toInt() and 0xFF}"
103109
}
104110
6 -> {
105111
protocol = data[6].toInt() and 0xFF
@@ -115,18 +121,18 @@ class PacketCaptureVpnService : VpnService() {
115121
protoName = "TCP"
116122
if (length >= headerLength + 4) {
117123
srcPort = ((data[headerLength].toInt() and 0xFF) shl 8) or
118-
(data[headerLength + 1].toInt() and 0xFF)
124+
(data[headerLength + 1].toInt() and 0xFF)
119125
dstPort = ((data[headerLength + 2].toInt() and 0xFF) shl 8) or
120-
(data[headerLength + 3].toInt() and 0xFF)
126+
(data[headerLength + 3].toInt() and 0xFF)
121127
}
122128
}
123129
17 -> {
124130
protoName = "UDP"
125131
if (length >= headerLength + 4) {
126132
srcPort = ((data[headerLength].toInt() and 0xFF) shl 8) or
127-
(data[headerLength + 1].toInt() and 0xFF)
133+
(data[headerLength + 1].toInt() and 0xFF)
128134
dstPort = ((data[headerLength + 2].toInt() and 0xFF) shl 8) or
129-
(data[headerLength + 3].toInt() and 0xFF)
135+
(data[headerLength + 3].toInt() and 0xFF)
130136
}
131137
}
132138
1 -> protoName = "ICMP"
@@ -139,7 +145,8 @@ class PacketCaptureVpnService : VpnService() {
139145
else
140146
PacketInfo.Direction.INBOUND
141147

142-
onPacketCaptured?.invoke(
148+
// ✅ 改用 PacketBus 替代静态回调,不再持有外部引用
149+
PacketBus.emit(
143150
PacketInfo(
144151
protocol = protoName,
145152
sourceIp = srcIp,
@@ -150,8 +157,7 @@ class PacketCaptureVpnService : VpnService() {
150157
direction = direction
151158
)
152159
)
153-
} catch (_: Exception) {
154-
}
160+
} catch (_: Exception) { }
155161
}
156162

157163
private fun formatIpv6(data: ByteArray, offset: Int): String {
@@ -173,24 +179,22 @@ class PacketCaptureVpnService : VpnService() {
173179
stopSelf()
174180
}
175181

176-
private fun createNotification() =
177-
NotificationCompat.Builder(
178-
this, NetMonitorApp.CHANNEL_CAPTURE
179-
)
180-
.setContentTitle("抓包服务运行中")
181-
.setContentText("正在捕获网络数据包...")
182-
.setSmallIcon(R.drawable.ic_capture)
183-
.setContentIntent(
184-
PendingIntent.getActivity(
185-
this, 0,
186-
Intent(this, MainActivity::class.java),
187-
PendingIntent.FLAG_UPDATE_CURRENT or
188-
PendingIntent.FLAG_IMMUTABLE
189-
)
182+
private fun createNotification() = NotificationCompat.Builder(
183+
this, NetMonitorApp.CHANNEL_CAPTURE
184+
)
185+
.setContentTitle(getString(R.string.capture_running_title))
186+
.setContentText(getString(R.string.capture_running_text))
187+
.setSmallIcon(R.drawable.ic_capture)
188+
.setContentIntent(
189+
PendingIntent.getActivity(
190+
this, 0,
191+
Intent(this, MainActivity::class.java),
192+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
190193
)
191-
.setOngoing(true)
192-
.setSilent(true)
193-
.build()
194+
)
195+
.setOngoing(true)
196+
.setSilent(true)
197+
.build()
194198

195199
override fun onDestroy() {
196200
super.onDestroy()
@@ -204,8 +208,5 @@ class PacketCaptureVpnService : VpnService() {
204208
companion object {
205209
const val ACTION_START = "com.netmonitor.action.START_CAPTURE"
206210
const val ACTION_STOP = "com.netmonitor.action.STOP_CAPTURE"
207-
const val NOTIFICATION_ID = 1002
208-
209-
var onPacketCaptured: ((PacketInfo) -> Unit)? = null
210211
}
211212
}

0 commit comments

Comments
 (0)