Fix deadlock with web socket health monitor.

fork-5.53.8
Cody Henthorne 2021-12-01 13:14:05 -05:00 zatwierdzone przez Greyson Parrelli
rodzic 4ba4df706e
commit 59ad8bf76a
1 zmienionych plików z 64 dodań i 51 usunięć

Wyświetl plik

@ -5,6 +5,7 @@ import android.app.Application;
import androidx.annotation.NonNull;
import org.greenrobot.eventbus.EventBus;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
@ -17,6 +18,8 @@ import org.whispersystems.signalservice.api.websocket.HealthMonitor;
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState;
import org.whispersystems.signalservice.internal.websocket.WebSocketConnection;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import io.reactivex.rxjava3.schedulers.Schedulers;
@ -35,11 +38,13 @@ public final class SignalWebSocketHealthMonitor implements HealthMonitor {
private static final long KEEP_ALIVE_SEND_CADENCE = TimeUnit.SECONDS.toMillis(WebSocketConnection.KEEPALIVE_TIMEOUT_SECONDS);
private static final long MAX_TIME_SINCE_SUCCESSFUL_KEEP_ALIVE = KEEP_ALIVE_SEND_CADENCE * 3;
private final Executor executor = ThreadUtil.trace(Executors.newSingleThreadExecutor());
private final Application context;
private SignalWebSocket signalWebSocket;
private final SleepTimer sleepTimer;
private volatile KeepAliveSender keepAliveSender;
private KeepAliveSender keepAliveSender;
private final HealthState identified = new HealthState();
private final HealthState unidentified = new HealthState();
@ -50,6 +55,7 @@ public final class SignalWebSocketHealthMonitor implements HealthMonitor {
}
public void monitor(@NonNull SignalWebSocket signalWebSocket) {
executor.execute(() -> {
Preconditions.checkNotNull(signalWebSocket);
Preconditions.checkArgument(this.signalWebSocket == null, "monitor can only be called once");
@ -68,9 +74,11 @@ public final class SignalWebSocketHealthMonitor implements HealthMonitor {
.observeOn(Schedulers.computation())
.distinctUntilChanged()
.subscribe(s -> onStateChange(s, unidentified));
});
}
private synchronized void onStateChange(WebSocketConnectionState connectionState, HealthState healthState) {
private void onStateChange(WebSocketConnectionState connectionState, HealthState healthState) {
executor.execute(() -> {
switch (connectionState) {
case CONNECTED:
TextSecurePreferences.setUnauthorizedReceived(context, false);
@ -96,19 +104,23 @@ public final class SignalWebSocketHealthMonitor implements HealthMonitor {
keepAliveSender.shutdown();
keepAliveSender = null;
}
});
}
@Override
public void onKeepAliveResponse(long sentTimestamp, boolean isIdentifiedWebSocket) {
executor.execute(() -> {
if (isIdentifiedWebSocket) {
identified.lastKeepAliveReceived = System.currentTimeMillis();
} else {
unidentified.lastKeepAliveReceived = System.currentTimeMillis();
}
});
}
@Override
public void onMessageError(int status, boolean isIdentifiedWebSocket) {
executor.execute(() -> {
if (status == 409) {
HealthState healthState = (isIdentifiedWebSocket ? identified : unidentified);
if (healthState.mismatchErrorTracker.addSample(System.currentTimeMillis())) {
@ -116,6 +128,7 @@ public final class SignalWebSocketHealthMonitor implements HealthMonitor {
signalWebSocket.forceNewWebSockets();
}
}
});
}
private boolean isKeepAliveNecessary() {