From de91fb27dbc787943a6839c1b33c2771bb4423a9 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 19:35:55 +0800 Subject: [PATCH] Fix VPN icon persisting in status bar after stopping service (#5476) * Initial plan * Fix VPN icon remaining in status bar after stopping service Agent-Logs-Url: https://github.com/2dust/v2rayNG/sessions/4377b941-8f02-4d92-abc6-0f98fd6c9b60 Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com> --- .../com/v2ray/ang/service/V2RayVpnService.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt index 3c70aa3a..90da87bf 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt @@ -93,6 +93,21 @@ class V2RayVpnService : VpnService(), ServiceControl { override fun onDestroy() { super.onDestroy() Log.i(AppConfig.TAG, "StartCore-VPN: Service destroyed") + + // Ensure VPN interface is properly closed when the service is destroyed without + // going through stopAllService() (e.g. when killed unexpectedly). isRunning is + // set to false at the start of stopAllService(), so this guard prevents a double-close. + if (isRunning) { + try { + if (::mInterface.isInitialized) { + mInterface.close() + Log.i(AppConfig.TAG, "StartCore-VPN: VPN interface closed in onDestroy") + } + } catch (e: Exception) { + Log.e(AppConfig.TAG, "StartCore-VPN: Failed to close interface in onDestroy", e) + } + } + NotificationManager.cancelNotification() } @@ -356,9 +371,19 @@ class V2RayVpnService : VpnService(), ServiceControl { //which means the first v2ray core somehow failed to stop and release the port. stopSelf() + // Add a small delay to allow the async core stop operation to complete + // before closing the VPN interface, preventing a race condition that can + // leave the VPN icon in the status bar after stopping the service. + try { + Thread.sleep(100) + } catch (e: InterruptedException) { + Log.w(AppConfig.TAG, "StartCore-VPN: Sleep interrupted", e) + } + try { if (::mInterface.isInitialized) { mInterface.close() + Log.i(AppConfig.TAG, "StartCore-VPN: VPN interface closed") } } catch (e: Exception) { Log.e(AppConfig.TAG, "StartCore-VPN: Failed to close interface", e)