Service Lifecycle

SkillDev tools

VPN/proxy service lifecycle, coordinators, status, telemetry, handovers, and remembered policy.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Service Lifecycle skill

What this skill tells your AI

The instructions your AI receives, as published by po4yka/ripdpi in .agents/skills/service-lifecycle/SKILL.md and read by ahel’s review.

Overview

The Android services are thin shells now. Real lifecycle behavior lives in runtime coordinators plus ServiceStatusReporter, not in a single global app-state singleton.

Service work in this repo usually touches one or more of:

  • start/stop orchestration
  • remembered-policy replay
  • handover-triggered restarts
  • active-policy signature tracking
  • ServiceStateStore status, events, and telemetry
  • hidden first-seen-network quick_v1 diagnostics probes after successful handovers

Architecture

ServiceController.start(mode)
  -> START_ACTION / STOP_ACTION intent
  -> RipDpiVpnService or RipDpiProxyService
  -> ProxyServiceRuntimeCoordinator / VpnServiceRuntimeCoordinator
  -> ConnectionPolicyResolver
  -> proxy / tunnel runtime start-stop-restart
  -> ServiceStatusReporter
  -> ServiceStateStore

Key Components

ComponentLocationRole
ServiceController / DefaultServiceControllercore/service/.../ServiceManager.ktApp entry point for start/stop
RipDpiVpnServicecore/service/.../RipDpiVpnService.ktAndroid VPN service shell
RipDpiProxyServicecore/service/.../RipDpiProxyService.ktAndroid foreground proxy service shell
BaseServiceRuntimeCoordinatorcore/service/.../ServiceRuntimeCoordinator.ktShared mutex, lifecycle state machine, stop/start/handover flow
ProxyServiceRuntimeCoordinatorcore/service/.../ProxyServiceRuntimeCoordinator.ktProxy-mode runtime orchestration
VpnServiceRuntimeCoordinatorcore/service/.../VpnServiceRuntimeCoordinator.ktVPN-mode proxy+tunnel orchestration, resolver refresh, DNS failover
ServiceStatusReportercore/service/.../ServiceStatusReporter.ktMaps runtime changes into UI-facing status/events/telemetry
ServiceStateStorecore/data/.../ServiceStateStore.ktShared StateFlow / SharedFlow store observed by the app
ConnectionPolicyResolvercore/service/.../ConnectionPolicyResolver.ktResolves live or remembered policy for the current network
NetworkHandoverMonitorcore/service/.../NetworkHandoverMonitor.ktDetects actionable network changes
ActiveConnectionPolicyStorecore/service/.../ActiveConnectionPolicyStore.ktPersists active policy metadata for diagnostics and telemetry

State Management

interface ServiceStateStore {
    val status: StateFlow<Pair<AppStatus, Mode>>
    val events: SharedFlow<ServiceEvent>
    val telemetry: StateFlow<ServiceTelemetrySnapshot>

    fun setStatus(status: AppStatus, mode: Mode)
    fun emitFailed(sender: Sender, reason: FailureReason)
    fun updateTelemetry(snapshot: ServiceTelemetrySnapshot)
}

Runtime code should usually write through ServiceStatusReporter. That keeps status, events, and telemetry consistent.

Lifecycle Pattern

Start/stop logic is serialized inside the coordinator mutex:

suspend fun start() {
    mutex.withLock {
        val resolution = resolveInitialConnectionPolicy()
        applyActiveConnectionPolicy(...)
        startResolvedRuntime(...)
        serviceRuntimeRegistry.register(session)
        updateStatus(ServiceStatus.Connected)
        startNetworkHandoverMonitoring()
        startModeTelemetryUpdates()
    }
}

The VPN coordinator adds:

  • VpnTunnelRuntime startup and shutdown
  • resolver refresh via VpnResolverRefreshPlanner
  • encrypted-DNS recovery via VpnEncryptedDnsFailoverController

The proxy coordinator adds:

  • ProxyRuntimeSupervisor startup and shutdown
  • proxy telemetry polling
  • proxy exit handling and failure classification

Where To Make Changes

  1. Change Android service classes only for Android-framework concerns such as intents, foreground-service behavior, or onRevoke().
  2. Change ProxyServiceRuntimeCoordinator or VpnServiceRuntimeCoordinator for runtime orchestration.
  3. Change ServiceStatusReporter for UI-visible status, failure, or telemetry projection.
  4. Change ConnectionPolicyResolver, NetworkHandoverMonitor, or resolver refresh logic when the behavior depends on network context.
  5. Treat ServiceTelemetrySnapshot and ServiceEvent as compatibility-sensitive contracts used by tests, diagnostics, and exports.

Common Mistakes

MistakeFix
Patching only the Android service shellMost lifecycle logic lives in the coordinator layer now
Writing directly to ServiceStateStore from arbitrary runtime codePrefer ServiceStatusReporter so fields stay coherent
Ignoring the coordinator mutex or lifecycle state machineStart/stop/handover paths must stay serialized
Forgetting remembered-policy or handover side effectsService restarts affect policy replay, telemetry, and hidden diagnostics probes
Treating telemetry fields as disposableServiceTelemetrySnapshot is part of the repo’s compatibility surface

Signals

GitHub stars
69
Forks
4
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
service-lifecycle
Source
github.com/po4yka/ripdpi