Adaptive Keepalive Strategy

Traditional keepalive mechanisms fail on Android. This guide explains LiteP2P's adaptive approach to maintaining connections.

Why Persistent Keepalive Fails

Many developers try to maintain persistent connections using frequent keepalive packets. This approach fails on Android for several reasons:

Doze suspends sockets

All network activity is paused in Doze mode, keepalive packets are never sent

NAT mappings expire

Without traffic, routers close port mappings (typically 30-120 seconds)

Radio sleeps regardless of TCP state

The cellular/WiFi radio enters low-power mode independently

OEM firmware kills idle connections

Aggressive OEMs terminate connections proactively

LiteP2P uses an adaptive keepalive strategy that varies based on app state:

App State Keepalive Rationale
Idle None Use push notifications to wake
Background None Connections will be dropped anyway
Foreground Service Adaptive Maintain connections during active work
Charging + Wi-Fi Optional Low cost, may improve responsiveness

Keepalive Requirements

When keepalive is appropriate, it must be:

  • FSM-driven – Controlled by connection state machine
  • Battery-aware – Adjusts frequency based on power state
  • State-aware – Only active when needed

Implementation

LiteP2P handles keepalive automatically, but you can configure the behavior:

val config = PeerConfig.Builder()
    .setAppId("your-app-id")
    .setKeepalivePolicy(KeepalivePolicy.ADAPTIVE)
    .setKeepaliveInterval(30, TimeUnit.SECONDS) // When active
    .setChargingKeepalive(true) // Enable when charging
    .build()

LiteP2P.initialize(context, config)

Keepalive Policies

enum class KeepalivePolicy {
    NONE,        // Never send keepalive
    ADAPTIVE,    // Smart, state-based (recommended)
    FOREGROUND,  // Only during foreground service
    AGGRESSIVE   // Always when possible (not recommended)
}

Adaptive Behavior

When using KeepalivePolicy.ADAPTIVE, LiteP2P:

  1. Monitors app state – Foreground, background, service active
  2. Checks power state – Battery level, charging status
  3. Detects network type – Wi-Fi vs cellular
  4. Adjusts interval dynamically – More frequent when active, less when idle
// Example of internal adaptive logic
internal fun calculateKeepaliveInterval(): Long {
    return when {
        isCharging && isWifi -> 30_000    // 30 seconds
        isCharging           -> 60_000    // 1 minute
        isWifi               -> 120_000   // 2 minutes
        else                 -> 0         // No keepalive, use push
    }
}

Monitoring Connection Health

// Listen for connection state changes
LiteP2P.getInstance().onConnectionStateChange { state ->
    when (state) {
        ConnectionState.CONNECTED -> {
            Log.d("LiteP2P", "Connection healthy")
        }
        ConnectionState.RECONNECTING -> {
            Log.d("LiteP2P", "Connection lost, attempting reconnect")
        }
        ConnectionState.DISCONNECTED -> {
            Log.d("LiteP2P", "Disconnected, waiting for wake signal")
        }
    }
}
Best Practice

Trust LiteP2P's adaptive keepalive. Don't implement your own keepalive mechanism – it will conflict with the SDK's power-efficient design.