新增调试信息
This commit is contained in:
@@ -32,12 +32,15 @@
|
||||
android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
|
||||
<application
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<application
|
||||
android:name=".Application"
|
||||
android:banner="@mipmap/ic_banner"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="BearVPN"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:extractNativeLibs="true"
|
||||
tools:targetApi="31">
|
||||
|
||||
<meta-data
|
||||
|
||||
@@ -142,38 +142,42 @@ class BoxService(
|
||||
private var activeProfileName = ""
|
||||
private suspend fun startService(delayStart: Boolean = false) {
|
||||
try {
|
||||
Log.d(TAG, "starting service")
|
||||
// 暂时禁用通知显示
|
||||
// withContext(Dispatchers.Main) {
|
||||
// notification.show(activeProfileName, R.string.status_starting)
|
||||
// }
|
||||
Log.d(TAG, "🚀 [步骤1] 开始启动服务")
|
||||
|
||||
val selectedConfigPath = Settings.activeConfigPath
|
||||
Log.d(TAG, "📂 [步骤2] 配置路径: $selectedConfigPath")
|
||||
if (selectedConfigPath.isBlank()) {
|
||||
Log.e(TAG, "❌ [步骤2] 配置路径为空!")
|
||||
stopAndAlert(Alert.EmptyConfiguration)
|
||||
return
|
||||
}
|
||||
|
||||
activeProfileName = Settings.activeProfileName
|
||||
Log.d(TAG, "📝 [步骤3] Profile名称: $activeProfileName")
|
||||
|
||||
val configOptions = Settings.configOptions
|
||||
Log.d(TAG, "⚙️ [步骤4] 配置选项长度: ${configOptions.length}")
|
||||
if (configOptions.isBlank()) {
|
||||
Log.e(TAG, "❌ [步骤4] 配置选项为空!")
|
||||
stopAndAlert(Alert.EmptyConfiguration)
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "🔨 [步骤5] 开始构建配置...")
|
||||
val content = try {
|
||||
Mobile.buildConfig(selectedConfigPath, configOptions)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, e)
|
||||
Log.e(TAG, "❌ [步骤5] buildConfig失败: ${e.message}", e)
|
||||
Log.e(TAG, "❌ 异常类型: ${e.javaClass.name}")
|
||||
stopAndAlert(Alert.EmptyConfiguration)
|
||||
return
|
||||
}
|
||||
Log.d(TAG, "✅ [步骤5] 配置构建成功, 内容长度: ${content.length}")
|
||||
|
||||
if (Settings.debugMode) {
|
||||
File(workingDir, "current-config.json").writeText(content)
|
||||
}
|
||||
File(workingDir, "current-config.json").writeText(content)
|
||||
Log.d(TAG, "💾 [步骤6] 配置已保存")
|
||||
|
||||
Log.d(TAG, "🔔 [步骤7] 显示通知...")
|
||||
withContext(Dispatchers.Main) {
|
||||
notification.show(activeProfileName, R.string.status_starting)
|
||||
binder.broadcast {
|
||||
@@ -181,31 +185,57 @@ class BoxService(
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "🌐 [步骤8] 启动网络监听...")
|
||||
DefaultNetworkMonitor.start()
|
||||
Libbox.registerLocalDNSTransport(LocalResolver)
|
||||
Libbox.setMemoryLimit(!Settings.disableMemoryLimit)
|
||||
Log.d(TAG, "✅ [步骤8] 网络监听已启动")
|
||||
|
||||
Log.d(TAG, "🎯 [步骤9] 调用 Libbox.newService()...")
|
||||
val newService = try {
|
||||
Libbox.newService(content, platformInterface)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ [步骤9] Libbox.newService() 失败!")
|
||||
Log.e(TAG, "❌ 错误信息: ${e.message}")
|
||||
Log.e(TAG, "❌ 异常类型: ${e.javaClass.name}")
|
||||
Log.e(TAG, "❌ 堆栈跟踪: ${e.stackTraceToString()}")
|
||||
stopAndAlert(Alert.CreateService, e.message)
|
||||
return
|
||||
}
|
||||
Log.d(TAG, "✅ [步骤9] Libbox.newService() 成功!")
|
||||
|
||||
if (delayStart) {
|
||||
Log.d(TAG, "⏳ [步骤10] 延迟1秒...")
|
||||
delay(1000L)
|
||||
}
|
||||
|
||||
newService.start()
|
||||
Log.d(TAG, "▶️ [步骤11] 调用 newService.start()...")
|
||||
try {
|
||||
newService.start()
|
||||
Log.d(TAG, "✅ [步骤11] newService.start() 成功!")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ [步骤11] newService.start() 失败!")
|
||||
Log.e(TAG, "❌ 错误信息: ${e.message}")
|
||||
Log.e(TAG, "❌ 异常类型: ${e.javaClass.name}")
|
||||
Log.e(TAG, "❌ 堆栈跟踪: ${e.stackTraceToString()}")
|
||||
throw e
|
||||
}
|
||||
|
||||
boxService = newService
|
||||
commandServer?.setService(boxService)
|
||||
status.postValue(Status.Started)
|
||||
Log.d(TAG, "📊 [步骤12] 状态已设置为 Started")
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
notification.show(activeProfileName, R.string.status_started)
|
||||
}
|
||||
notification.start()
|
||||
Log.d(TAG, "🎉 [完成] 服务启动成功!")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ [致命错误] startService异常!")
|
||||
Log.e(TAG, "❌ 错误信息: ${e.message}")
|
||||
Log.e(TAG, "❌ 异常类型: ${e.javaClass.name}")
|
||||
Log.e(TAG, "❌ 堆栈跟踪: ${e.stackTraceToString()}")
|
||||
stopAndAlert(Alert.StartService, e.message)
|
||||
return
|
||||
}
|
||||
@@ -335,8 +365,10 @@ class BoxService(
|
||||
try {
|
||||
startCommandServer()
|
||||
} catch (e: Exception) {
|
||||
stopAndAlert(Alert.StartCommandServer, e.message)
|
||||
return@launch
|
||||
// CommandServer 启动失败不是致命错误
|
||||
// 在 Android 12+ SELinux 环境下,chown 操作可能被拒绝
|
||||
// 但这不影响 VPN 核心功能,因此记录警告但继续启动服务
|
||||
Log.w(TAG, "CommandServer failed to start (non-fatal): ${e.message}")
|
||||
}
|
||||
startService()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,382 @@
|
||||
package com.hiddify.hiddify.bg
|
||||
|
||||
import android.app.Service
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.os.PowerManager
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.hiddify.hiddify.Application
|
||||
import com.hiddify.hiddify.R
|
||||
import com.hiddify.hiddify.Settings
|
||||
import com.hiddify.hiddify.constant.Action
|
||||
import com.hiddify.hiddify.constant.Alert
|
||||
import com.hiddify.hiddify.constant.Status
|
||||
import go.Seq
|
||||
import io.nekohasekai.libbox.BoxService
|
||||
import io.nekohasekai.libbox.CommandServer
|
||||
import io.nekohasekai.libbox.CommandServerHandler
|
||||
import io.nekohasekai.libbox.Libbox
|
||||
import io.nekohasekai.libbox.PlatformInterface
|
||||
import io.nekohasekai.libbox.SystemProxyStatus
|
||||
import io.nekohasekai.mobile.Mobile
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
class BoxService(
|
||||
private val service: Service,
|
||||
private val platformInterface: PlatformInterface
|
||||
) : CommandServerHandler {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "A/BoxService"
|
||||
|
||||
private var initializeOnce = false
|
||||
private lateinit var workingDir: File
|
||||
private fun initialize() {
|
||||
if (initializeOnce) return
|
||||
val baseDir = Application.application.filesDir
|
||||
|
||||
baseDir.mkdirs()
|
||||
workingDir = Application.application.getExternalFilesDir(null) ?: return
|
||||
workingDir.mkdirs()
|
||||
val tempDir = Application.application.cacheDir
|
||||
tempDir.mkdirs()
|
||||
Log.d(TAG, "base dir: ${baseDir.path}")
|
||||
Log.d(TAG, "working dir: ${workingDir.path}")
|
||||
Log.d(TAG, "temp dir: ${tempDir.path}")
|
||||
|
||||
// 创建数据库目录 (数据库使用相对路径 ./data,所以在workingDir下创建)
|
||||
val dataDir = File(workingDir, "data")
|
||||
dataDir.mkdirs()
|
||||
Log.d(TAG, "database dir: ${dataDir.path}")
|
||||
|
||||
// 确保数据库目录有读写权限
|
||||
if (!dataDir.canRead() || !dataDir.canWrite()) {
|
||||
Log.w(TAG, "database dir permission issue, trying to fix")
|
||||
dataDir.setReadable(true, false)
|
||||
dataDir.setWritable(true, false)
|
||||
}
|
||||
|
||||
Mobile.setup(baseDir.path, workingDir.path, tempDir.path, false)
|
||||
Libbox.redirectStderr(File(workingDir, "stderr.log").path)
|
||||
initializeOnce = true
|
||||
return
|
||||
}
|
||||
|
||||
fun parseConfig(path: String, tempPath: String, debug: Boolean): String {
|
||||
return try {
|
||||
Mobile.parse(path, tempPath, debug)
|
||||
""
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, e)
|
||||
e.message ?: "invalid config"
|
||||
}
|
||||
}
|
||||
|
||||
fun buildConfig(path: String, options: String): String {
|
||||
return Mobile.buildConfig(path, options)
|
||||
}
|
||||
|
||||
fun start() {
|
||||
val intent = runBlocking {
|
||||
withContext(Dispatchers.IO) {
|
||||
Intent(Application.application, Settings.serviceClass())
|
||||
}
|
||||
}
|
||||
ContextCompat.startForegroundService(Application.application, intent)
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
Application.application.sendBroadcast(
|
||||
Intent(Action.SERVICE_CLOSE).setPackage(
|
||||
Application.application.packageName
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun reload() {
|
||||
Application.application.sendBroadcast(
|
||||
Intent(Action.SERVICE_RELOAD).setPackage(
|
||||
Application.application.packageName
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var fileDescriptor: ParcelFileDescriptor? = null
|
||||
|
||||
private val status = MutableLiveData(Status.Stopped)
|
||||
private val binder = ServiceBinder(status)
|
||||
private val notification = ServiceNotification(status, service)
|
||||
private var boxService: BoxService? = null
|
||||
private var commandServer: CommandServer? = null
|
||||
private var receiverRegistered = false
|
||||
private val receiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
when (intent.action) {
|
||||
Action.SERVICE_CLOSE -> {
|
||||
stopService()
|
||||
}
|
||||
|
||||
Action.SERVICE_RELOAD -> {
|
||||
serviceReload()
|
||||
}
|
||||
|
||||
PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
serviceUpdateIdleMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startCommandServer() {
|
||||
val commandServer =
|
||||
CommandServer(this, 300)
|
||||
commandServer.start()
|
||||
this.commandServer = commandServer
|
||||
}
|
||||
|
||||
private var activeProfileName = ""
|
||||
private suspend fun startService(delayStart: Boolean = false) {
|
||||
try {
|
||||
Log.d(TAG, "starting service")
|
||||
// 暂时禁用通知显示
|
||||
// withContext(Dispatchers.Main) {
|
||||
// notification.show(activeProfileName, R.string.status_starting)
|
||||
// }
|
||||
|
||||
val selectedConfigPath = Settings.activeConfigPath
|
||||
if (selectedConfigPath.isBlank()) {
|
||||
stopAndAlert(Alert.EmptyConfiguration)
|
||||
return
|
||||
}
|
||||
|
||||
activeProfileName = Settings.activeProfileName
|
||||
|
||||
val configOptions = Settings.configOptions
|
||||
if (configOptions.isBlank()) {
|
||||
stopAndAlert(Alert.EmptyConfiguration)
|
||||
return
|
||||
}
|
||||
|
||||
val content = try {
|
||||
Mobile.buildConfig(selectedConfigPath, configOptions)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, e)
|
||||
stopAndAlert(Alert.EmptyConfiguration)
|
||||
return
|
||||
}
|
||||
|
||||
// ✅ 始终保存完整配置以便调试
|
||||
try {
|
||||
File(workingDir, "current-config.json").writeText(content)
|
||||
Log.d(TAG, "✅ 完整配置已保存到: ${workingDir}/current-config.json")
|
||||
Log.d(TAG, "📄 配置长度: ${content.length} 字符")
|
||||
Log.d(TAG, "📄 配置前1000字符:\n${content.substring(0, minOf(1000, content.length))}")
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "保存配置文件失败: $e")
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
notification.show(activeProfileName, R.string.status_starting)
|
||||
binder.broadcast {
|
||||
it.onServiceResetLogs(listOf())
|
||||
}
|
||||
}
|
||||
|
||||
DefaultNetworkMonitor.start()
|
||||
Libbox.registerLocalDNSTransport(LocalResolver)
|
||||
Libbox.setMemoryLimit(!Settings.disableMemoryLimit)
|
||||
|
||||
val newService = try {
|
||||
Libbox.newService(content, platformInterface)
|
||||
} catch (e: Exception) {
|
||||
stopAndAlert(Alert.CreateService, e.message)
|
||||
return
|
||||
}
|
||||
|
||||
if (delayStart) {
|
||||
delay(1000L)
|
||||
}
|
||||
|
||||
newService.start()
|
||||
boxService = newService
|
||||
commandServer?.setService(boxService)
|
||||
status.postValue(Status.Started)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
notification.show(activeProfileName, R.string.status_started)
|
||||
}
|
||||
notification.start()
|
||||
} catch (e: Exception) {
|
||||
stopAndAlert(Alert.StartService, e.message)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override fun serviceReload() {
|
||||
notification.close()
|
||||
status.postValue(Status.Starting)
|
||||
val pfd = fileDescriptor
|
||||
if (pfd != null) {
|
||||
pfd.close()
|
||||
fileDescriptor = null
|
||||
}
|
||||
commandServer?.setService(null)
|
||||
boxService?.apply {
|
||||
runCatching {
|
||||
close()
|
||||
}.onFailure {
|
||||
writeLog("service: error when closing: $it")
|
||||
}
|
||||
Seq.destroyRef(refnum)
|
||||
}
|
||||
boxService = null
|
||||
runBlocking {
|
||||
startService(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSystemProxyStatus(): SystemProxyStatus {
|
||||
val status = SystemProxyStatus()
|
||||
if (service is VPNService) {
|
||||
status.available = service.systemProxyAvailable
|
||||
status.enabled = service.systemProxyEnabled
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
override fun setSystemProxyEnabled(isEnabled: Boolean) {
|
||||
serviceReload()
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
private fun serviceUpdateIdleMode() {
|
||||
if (Application.powerManager.isDeviceIdleMode) {
|
||||
boxService?.pause()
|
||||
} else {
|
||||
boxService?.wake()
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopService() {
|
||||
if (status.value != Status.Started) return
|
||||
status.value = Status.Stopping
|
||||
if (receiverRegistered) {
|
||||
service.unregisterReceiver(receiver)
|
||||
receiverRegistered = false
|
||||
}
|
||||
notification.close()
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
val pfd = fileDescriptor
|
||||
if (pfd != null) {
|
||||
pfd.close()
|
||||
fileDescriptor = null
|
||||
}
|
||||
commandServer?.setService(null)
|
||||
boxService?.apply {
|
||||
runCatching {
|
||||
close()
|
||||
}.onFailure {
|
||||
writeLog("service: error when closing: $it")
|
||||
}
|
||||
Seq.destroyRef(refnum)
|
||||
}
|
||||
boxService = null
|
||||
Libbox.registerLocalDNSTransport(null)
|
||||
DefaultNetworkMonitor.stop()
|
||||
|
||||
commandServer?.apply {
|
||||
close()
|
||||
Seq.destroyRef(refnum)
|
||||
}
|
||||
commandServer = null
|
||||
Settings.startedByUser = false
|
||||
withContext(Dispatchers.Main) {
|
||||
status.value = Status.Stopped
|
||||
service.stopSelf()
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun postServiceClose() {
|
||||
// Not used on Android
|
||||
}
|
||||
|
||||
private suspend fun stopAndAlert(type: Alert, message: String? = null) {
|
||||
Settings.startedByUser = false
|
||||
withContext(Dispatchers.Main) {
|
||||
if (receiverRegistered) {
|
||||
service.unregisterReceiver(receiver)
|
||||
receiverRegistered = false
|
||||
}
|
||||
notification.close()
|
||||
binder.broadcast { callback ->
|
||||
callback.onServiceAlert(type.ordinal, message)
|
||||
}
|
||||
status.value = Status.Stopped
|
||||
}
|
||||
}
|
||||
|
||||
fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (status.value != Status.Stopped) return Service.START_NOT_STICKY
|
||||
status.value = Status.Starting
|
||||
|
||||
if (!receiverRegistered) {
|
||||
ContextCompat.registerReceiver(service, receiver, IntentFilter().apply {
|
||||
addAction(Action.SERVICE_CLOSE)
|
||||
addAction(Action.SERVICE_RELOAD)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)
|
||||
}
|
||||
}, ContextCompat.RECEIVER_NOT_EXPORTED)
|
||||
receiverRegistered = true
|
||||
}
|
||||
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
Settings.startedByUser = true
|
||||
initialize()
|
||||
try {
|
||||
startCommandServer()
|
||||
} catch (e: Exception) {
|
||||
stopAndAlert(Alert.StartCommandServer, e.message)
|
||||
return@launch
|
||||
}
|
||||
startService()
|
||||
}
|
||||
return Service.START_NOT_STICKY
|
||||
}
|
||||
|
||||
fun onBind(intent: Intent): IBinder {
|
||||
return binder
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
binder.close()
|
||||
}
|
||||
|
||||
fun onRevoke() {
|
||||
stopService()
|
||||
}
|
||||
|
||||
fun writeLog(message: String) {
|
||||
binder.broadcast {
|
||||
it.onServiceWriteLog(message)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,17 +47,19 @@ class VPNService : VpnService(), PlatformInterfaceWrapper {
|
||||
}
|
||||
|
||||
override fun autoDetectInterfaceControl(fd: Int) {
|
||||
protect(fd)
|
||||
Log.d(TAG, "🛡️ autoDetectInterfaceControl 被调用, fd=$fd")
|
||||
val result = protect(fd)
|
||||
Log.d(TAG, "🛡️ protect(fd=$fd) 返回: $result")
|
||||
}
|
||||
|
||||
var systemProxyAvailable = false
|
||||
var systemProxyEnabled = false
|
||||
fun addIncludePackage(builder: Builder, packageName: String) {
|
||||
if (packageName == this.packageName) {
|
||||
if (packageName == this.packageName) {
|
||||
Log.d("VpnService","Cannot include myself: $packageName")
|
||||
return
|
||||
}
|
||||
try {
|
||||
try {
|
||||
Log.d("VpnService","Including $packageName")
|
||||
builder.addAllowedApplication(packageName)
|
||||
} catch (e: NameNotFoundException) {
|
||||
@@ -75,6 +77,10 @@ class VPNService : VpnService(), PlatformInterfaceWrapper {
|
||||
override fun openTun(options: TunOptions): Int {
|
||||
if (prepare(this) != null) error("android: missing vpn permission")
|
||||
|
||||
Log.d(TAG, "🔧 openTun 被调用")
|
||||
Log.d(TAG, " MTU: ${options.mtu}")
|
||||
Log.d(TAG, " AutoRoute: ${options.autoRoute}")
|
||||
|
||||
val builder = Builder()
|
||||
.setSession("sing-box")
|
||||
.setMtu(options.mtu)
|
||||
@@ -128,50 +134,87 @@ class VPNService : VpnService(), PlatformInterfaceWrapper {
|
||||
}
|
||||
} else {
|
||||
val inet4RouteAddress = options.inet4RouteRange
|
||||
Log.d(TAG, "📍 Android <13: 配置IPv4路由")
|
||||
if (inet4RouteAddress.hasNext()) {
|
||||
Log.d(TAG, "✅ 找到IPv4路由配置,开始添加...")
|
||||
while (inet4RouteAddress.hasNext()) {
|
||||
val address = inet4RouteAddress.next()
|
||||
Log.d(TAG, " 添加路由: ${address.address()}/${address.prefix()}")
|
||||
builder.addRoute(address.address(), address.prefix())
|
||||
}
|
||||
} else {
|
||||
// ⚠️ 如果没有指定路由,添加默认路由
|
||||
Log.w(TAG, "⚠️ 没有IPv4路由配置,添加默认路由 0.0.0.0/0")
|
||||
builder.addRoute("0.0.0.0", 0)
|
||||
}
|
||||
|
||||
val inet6RouteAddress = options.inet6RouteRange
|
||||
if (inet6RouteAddress.hasNext()) {
|
||||
Log.d(TAG, "✅ 找到IPv6路由配置,开始添加...")
|
||||
while (inet6RouteAddress.hasNext()) {
|
||||
val address = inet6RouteAddress.next()
|
||||
Log.d(TAG, " 添加IPv6路由: ${address.address()}/${address.prefix()}")
|
||||
builder.addRoute(address.address(), address.prefix())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "📱 包过滤配置:")
|
||||
Log.d(TAG, " perAppProxyEnabled: ${Settings.perAppProxyEnabled}")
|
||||
Log.d(TAG, " 当前应用包名: $packageName")
|
||||
|
||||
if (Settings.perAppProxyEnabled) {
|
||||
val appList = Settings.perAppProxyList
|
||||
Log.d(TAG, " ✅ 使用应用级代理,模式: ${Settings.perAppProxyMode}")
|
||||
Log.d(TAG, " 📋 应用列表数量: ${appList.size}")
|
||||
if (Settings.perAppProxyMode == PerAppProxyMode.INCLUDE) {
|
||||
Log.d(TAG, " 🔵 INCLUDE模式 - 只有以下应用使用VPN:")
|
||||
appList.forEach {
|
||||
Log.d(TAG, " - $it")
|
||||
addIncludePackage(builder,it)
|
||||
}
|
||||
Log.d(TAG, " - $packageName (本应用)")
|
||||
addIncludePackage(builder,packageName)
|
||||
} else {
|
||||
Log.d(TAG, " 🔴 EXCLUDE模式 - 以下应用不使用VPN:")
|
||||
appList.forEach {
|
||||
Log.d(TAG, " - $it")
|
||||
addExcludePackage(builder,it)
|
||||
}
|
||||
//addExcludePackage(builder,packageName)
|
||||
// 不排除本应用,让libcore能正常工作
|
||||
// Log.d(TAG, " ⚠️ 本应用也排除VPN")
|
||||
// addExcludePackage(builder,packageName)
|
||||
Log.d(TAG, " ℹ️ 本应用不在排除列表")
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, " ⚙️ 使用配置文件的包过滤规则")
|
||||
val includePackage = options.includePackage
|
||||
if (includePackage.hasNext()) {
|
||||
Log.d(TAG, " 🔵 INCLUDE列表:")
|
||||
while (includePackage.hasNext()) {
|
||||
addIncludePackage(builder,includePackage.next())
|
||||
val pkg = includePackage.next()
|
||||
Log.d(TAG, " - $pkg")
|
||||
addIncludePackage(builder,pkg)
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, " ℹ️ 无INCLUDE规则")
|
||||
}
|
||||
|
||||
val excludePackage = options.excludePackage
|
||||
if (excludePackage.hasNext()) {
|
||||
Log.d(TAG, " 🔴 EXCLUDE列表:")
|
||||
while (excludePackage.hasNext()) {
|
||||
addExcludePackage(builder,excludePackage.next())
|
||||
val pkg = excludePackage.next()
|
||||
Log.d(TAG, " - $pkg")
|
||||
addExcludePackage(builder,pkg)
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, " ℹ️ 无EXCLUDE规则")
|
||||
}
|
||||
//addExcludePackage(builder,packageName)
|
||||
|
||||
// 不排除本应用,让libcore能正常工作
|
||||
// Log.d(TAG, " ⚠️ 始终排除本应用: $packageName")
|
||||
// addExcludePackage(builder,packageName)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user