mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-03 15:11:42 +01:00
Improve web socket behaviors around keep alive and shutdown.
This commit is contained in:
committed by
jeffrey-signal
parent
3804890265
commit
a797bbf850
@@ -342,7 +342,7 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
|
||||
@Override
|
||||
public @NonNull SignalWebSocket.AuthenticatedWebSocket provideAuthWebSocket(@NonNull Supplier<SignalServiceConfiguration> signalServiceConfigurationSupplier, @NonNull Supplier<Network> libSignalNetworkSupplier) {
|
||||
SleepTimer sleepTimer = !SignalStore.account().isFcmEnabled() || SignalStore.internal().isWebsocketModeForced() ? new AlarmSleepTimer(context) : new UptimeSleepTimer();
|
||||
SignalWebSocketHealthMonitor healthMonitor = new SignalWebSocketHealthMonitor(sleepTimer);
|
||||
SignalWebSocketHealthMonitor healthMonitor = new SignalWebSocketHealthMonitor(sleepTimer, true);
|
||||
|
||||
WebSocketFactory authFactory = () -> {
|
||||
DynamicCredentialsProvider credentialsProvider = new DynamicCredentialsProvider();
|
||||
@@ -375,7 +375,7 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
|
||||
@Override
|
||||
public @NonNull SignalWebSocket.UnauthenticatedWebSocket provideUnauthWebSocket(@NonNull Supplier<SignalServiceConfiguration> signalServiceConfigurationSupplier, @NonNull Supplier<Network> libSignalNetworkSupplier) {
|
||||
SleepTimer sleepTimer = !SignalStore.account().isFcmEnabled() || SignalStore.internal().isWebsocketModeForced() ? new AlarmSleepTimer(context) : new UptimeSleepTimer();
|
||||
SignalWebSocketHealthMonitor healthMonitor = new SignalWebSocketHealthMonitor(sleepTimer);
|
||||
SignalWebSocketHealthMonitor healthMonitor = new SignalWebSocketHealthMonitor(sleepTimer, false);
|
||||
|
||||
WebSocketFactory unauthFactory = () -> {
|
||||
Network network = libSignalNetworkSupplier.get();
|
||||
|
||||
@@ -10,13 +10,13 @@ import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.net.SignalWebSocketHealthMonitor.Companion.KEEP_ALIVE_SEND_CADENCE
|
||||
import org.thoughtcrime.securesms.net.SignalWebSocketHealthMonitor.Companion.KEEP_ALIVE_TIMEOUT
|
||||
import org.thoughtcrime.securesms.util.AppForegroundObserver
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.api.util.SleepTimer
|
||||
import org.whispersystems.signalservice.api.websocket.HealthMonitor
|
||||
@@ -30,22 +30,15 @@ import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class SignalWebSocketHealthMonitor(
|
||||
private val sleepTimer: SleepTimer
|
||||
private val sleepTimer: SleepTimer,
|
||||
private val sendKeepAlives: Boolean = true
|
||||
) : HealthMonitor {
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(SignalWebSocketHealthMonitor::class)
|
||||
|
||||
/**
|
||||
* This is the amount of time in between sent keep alives. Must be greater than [KEEP_ALIVE_TIMEOUT]
|
||||
*/
|
||||
private val KEEP_ALIVE_SEND_CADENCE: Duration = OkHttpWebSocketConnection.KEEPALIVE_FREQUENCY_SECONDS.seconds
|
||||
|
||||
/**
|
||||
* This is the amount of time we will wait for a response to the keep alive before we consider the websockets dead.
|
||||
* It is required that this value be less than [KEEP_ALIVE_SEND_CADENCE]
|
||||
*/
|
||||
private val KEEP_ALIVE_TIMEOUT: Duration = 20.seconds
|
||||
private val KEEP_ALIVE_SEND_CADENCE_BACKGROUND: Duration = 60.seconds
|
||||
}
|
||||
|
||||
private val executor: Executor = Executors.newSingleThreadExecutor()
|
||||
@@ -56,7 +49,7 @@ class SignalWebSocketHealthMonitor(
|
||||
private var needsKeepAlive = false
|
||||
private var lastKeepAliveReceived: Duration = 0.seconds
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
private var connectingTimeoutJob: Job? = null
|
||||
private var failedInConnecting: Boolean = false
|
||||
|
||||
@@ -74,7 +67,9 @@ class SignalWebSocketHealthMonitor(
|
||||
.distinctUntilChanged()
|
||||
.subscribeBy { onStateChanged(it) }
|
||||
|
||||
webSocket.addKeepAliveChangeListener { executor.execute(this::updateKeepAliveSenderStatus) }
|
||||
if (sendKeepAlives) {
|
||||
webSocket.addKeepAliveChangeListener { executor.execute(this::updateKeepAliveSenderStatus) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +106,7 @@ class SignalWebSocketHealthMonitor(
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
needsKeepAlive = connectionState == WebSocketConnectionState.CONNECTED
|
||||
needsKeepAlive = connectionState == WebSocketConnectionState.CONNECTED && sendKeepAlives
|
||||
|
||||
if (connectionState != WebSocketConnectionState.CONNECTING) {
|
||||
connectingTimeoutJob?.let {
|
||||
@@ -163,7 +158,7 @@ class SignalWebSocketHealthMonitor(
|
||||
|
||||
/**
|
||||
* Sends periodic heartbeats/keep-alives over the WebSocket to prevent connection timeouts. If
|
||||
* the WebSocket fails to get a return heartbeat after [KEEP_ALIVE_TIMEOUT] seconds, it is forced to be recreated.
|
||||
* the WebSocket fails to get a return heartbeat before the next keep alive is sent, it is forced to be recreated.
|
||||
*/
|
||||
private inner class KeepAliveSender : Thread() {
|
||||
|
||||
@@ -178,11 +173,12 @@ class SignalWebSocketHealthMonitor(
|
||||
var hasSentKeepAlive = false
|
||||
while (shouldKeepRunning && sendKeepAlives()) {
|
||||
try {
|
||||
sleepUntil(keepAliveSentTime + KEEP_ALIVE_SEND_CADENCE)
|
||||
val cadence = if (AppForegroundObserver.isForegrounded()) KEEP_ALIVE_SEND_CADENCE else KEEP_ALIVE_SEND_CADENCE_BACKGROUND
|
||||
sleepUntil(keepAliveSentTime + cadence)
|
||||
|
||||
if (shouldKeepRunning && sendKeepAlives()) {
|
||||
if (hasSentKeepAlive && lastKeepAliveReceived < keepAliveSentTime) {
|
||||
Log.w(TAG, "Missed keep alive, last: ${lastKeepAliveReceived.inWholeMilliseconds} needed by: ${(keepAliveSentTime + KEEP_ALIVE_TIMEOUT).inWholeMilliseconds}")
|
||||
Log.w(TAG, "Missed keep alive, last: ${lastKeepAliveReceived.inWholeMilliseconds} needed by: ${keepAliveSentTime.inWholeMilliseconds}")
|
||||
webSocket?.forceNewWebSocket()
|
||||
}
|
||||
|
||||
@@ -190,6 +186,8 @@ class SignalWebSocketHealthMonitor(
|
||||
webSocket?.sendKeepAlive()
|
||||
hasSentKeepAlive = true
|
||||
}
|
||||
} catch (e: InterruptedException) {
|
||||
// Stopped
|
||||
} catch (e: Throwable) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
@@ -198,7 +196,7 @@ class SignalWebSocketHealthMonitor(
|
||||
}
|
||||
|
||||
fun sleepUntil(time: Duration) {
|
||||
while (System.currentTimeMillis().milliseconds < time) {
|
||||
while (shouldKeepRunning && System.currentTimeMillis().milliseconds < time) {
|
||||
val waitTime = time - System.currentTimeMillis().milliseconds
|
||||
if (waitTime.isPositive()) {
|
||||
try {
|
||||
@@ -212,6 +210,7 @@ class SignalWebSocketHealthMonitor(
|
||||
|
||||
fun shutdown() {
|
||||
shouldKeepRunning = false
|
||||
interrupt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user