[Android] VPNService may miss foreground-service deadline when started from Quick Settings tile (v1.14.0)
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 38.1k
- Forks
- 4.6k
- Avg merge
- 19d 15h
- Merged PRs (30d)
- 1
Description
Operating system
Android (exact system version and device model are not included in the exported crash bundle)
Installation type
sing-box for Android graphical client
Graphical client version
1.14.0 (version code 730); core version 1.14.0; go1.26.7, android/arm64
Description
The Android client crashed while starting the VPN service from the Quick Settings tile.
The exported crash report contains:
android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException:
Context.startForegroundService() did not then call Service.startForeground():
ServiceRecord{... u0 io.nekohasekai.sfa/.bg.VPNService}
The captured call path is:
TileService.onClick
-> TileService.toggleService
-> BoxService$Companion.start
-> VPNService
Crash bundle timestamp: 2026-09-03T04:21:34+0000.
This is an Android foreground-service startup failure. It is not a proxy-node or core network error; the crash occurs before the VPN service has successfully entered its normal running state.
Trigger / reproduction
Observed sequence:
- Configure a profile in the Android graphical client.
- Leave the VPN service stopped.
- Tap the sing-box Quick Settings tile to start the service.
- The process can crash with
ForegroundServiceDidNotStartInTimeException.
The attached diagnostic export records the failure, but does not include the Android system version or device model. A deterministic reproduction rate is not yet known.
Source-level evidence
Auditing SagerNet/sing-box-for-android commit 5d5479d8bb60f7eb45e86402a8aa3a6131dd9ba3 (v1.14.0) shows the following ordering:
BoxService.kt:342-371:onStartCommand()registers a receiver, launchesGlobalScope.launch(Dispatchers.IO), and returnsService.START_NOT_STICKYwithout callingstartForeground().BoxService.kt:96-101: the coroutine startsCommandServerfirst, includingcommandServer.start().BoxService.kt:106-110: only after that does it enterstartService()and callnotification.show().ServiceNotification.kt:84-99: this creates the notification channel and finally callsservice.startForeground().VPNService.kt:27-29: the Android service delegatesonStartCommand()directly toBoxService.TileService.kt:38-53: the stopped Quick Settings tile callsBoxService.start().
Therefore the effective path is:
startForegroundService()
-> onStartCommand()
-> asynchronous IO coroutine
-> CommandServer.start()
-> notification channel/building on Main
-> startForeground()
This deferred promotion can miss Android's foreground-service deadline, especially on automatic or system-triggered starts. The source explains the failure mode, but the crash export does not prove which individual operation consumed the deadline.
AndroidManifest.xml:128-133 declares VPNService with foregroundServiceType="systemExempted". The crash report does not contain a SecurityException or an explicit foreground-service-type permission error, so type eligibility is a secondary hypothesis rather than the primary observed failure.
Expected behavior
The service should promote itself to the foreground promptly after onStartCommand() begins, before asynchronous command-server/configuration initialization.
Related report
This appears related to SagerNet/sing-box#4114, which reports the same exception for io.nekohasekai.sfa/.bg.VPNService on Android 16 during Always-on VPN / BootReceiver startup. That issue was later closed automatically as stale without a maintainer diagnosis or confirmed fix.
Questions
Could the maintainers confirm whether the delayed startForeground() ordering is intentional, and whether the Android client should promote VPNService before starting CommandServer? If this is expected to be ROM-specific, please also clarify the supported foreground-service startup path for Android 16 and system-triggered VPN starts.
The original diagnostic archive is not attached because its configuration.json contains private proxy-node credentials; the crash stack and source evidence above are sufficient to identify the lifecycle path.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read bg/BoxService.kt and follow VPNService.kt and TileService.kt to trace onStartCommand() through command-server startup and notification promotion. Inspect ServiceNotification.kt and AndroidManifest.xml for the foreground-service setup. Done means the VPN service reaches startForeground() promptly during Quick Settings and other system-triggered starts without breaking initialization.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 62/100