diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java index bb4706a772..f6fcce5ed0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java @@ -170,7 +170,8 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider { keysApi, Optional.of(new SecurityEventListener(context)), SignalExecutors.newCachedBoundedExecutor("signal-messages", ThreadUtil.PRIORITY_IMPORTANT_BACKGROUND_THREAD, 1, 16, 30), - ByteUnit.KILOBYTES.toBytes(256)); + ByteUnit.KILOBYTES.toBytes(256), + RemoteConfig::useMessageSendRestFallback); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt index de6a9f85d1..fb3201fd7c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt @@ -1087,5 +1087,13 @@ object RemoteConfig { hotSwappable = false ) + @JvmStatic + @get:JvmName("useMessageSendRestFallback") + val useMessageSendRestFallback: Boolean by remoteBoolean( + key = "android.useMessageSendRestFallback", + defaultValue = false, + hotSwappable = true + ) + // endregion } diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java index 31ada1c468..9df15bd44a 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java @@ -140,6 +140,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutorService; +import java.util.function.BooleanSupplier; import java.util.stream.Collectors; import javax.annotation.Nonnull; @@ -180,6 +181,7 @@ public class SignalServiceMessageSender { private final Scheduler scheduler; private final long maxEnvelopeSize; + private final BooleanSupplier useRestFallback; public SignalServiceMessageSender(PushServiceSocket pushServiceSocket, SignalServiceDataStore store, @@ -189,7 +191,8 @@ public class SignalServiceMessageSender { KeysApi keysApi, Optional eventListener, ExecutorService executor, - long maxEnvelopeSize) + long maxEnvelopeSize, + BooleanSupplier useRestFallback) { CredentialsProvider credentialsProvider = pushServiceSocket.getCredentialsProvider(); @@ -206,6 +209,7 @@ public class SignalServiceMessageSender { this.localPniIdentity = store.pni().getIdentityKeyPair(); this.scheduler = Schedulers.from(executor, false, false); this.keysApi = keysApi; + this.useRestFallback = useRestFallback; } /** @@ -1941,14 +1945,25 @@ public class SignalServiceMessageSender { throw e; } catch (WebSocketUnavailableException e) { String pipe = sealedSenderAccess == null ? "Pipe" : "Unidentified pipe"; - Log.i(TAG, "[sendMessage][" + timestamp + "] " + pipe + " unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); + if (useRestFallback.getAsBoolean()) { + Log.i(TAG, "[sendMessage][" + timestamp + "] " + pipe + " unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); + } else { + Log.i(TAG, "[sendMessage][" + timestamp + "] " + pipe + " unavailable (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); + throw e; + } } catch (IOException e) { String pipe = sealedSenderAccess == null ? "Pipe" : "Unidentified pipe"; Throwable cause = e; if (e.getCause() != null) { cause = e.getCause(); } - Log.w(TAG, "[sendMessage][" + timestamp + "] " + pipe + " failed, falling back... (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")"); + + if (useRestFallback.getAsBoolean()) { + Log.w(TAG, "[sendMessage][" + timestamp + "] " + pipe + " failed, falling back... (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")"); + } else { + Log.w(TAG, "[sendMessage][" + timestamp + "] " + pipe + " failed (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")"); + throw (cause instanceof IOException) ? (IOException) cause : e; + } } if (cancelationSignal != null && cancelationSignal.isCanceled()) { @@ -2137,7 +2152,7 @@ public class SignalServiceMessageSender { content.getContent() ); return Single.just(result); - } catch (Throwable throwable) { + } catch (IOException throwable) { if (cancelationSignal != null && cancelationSignal.isCanceled()) { return Single.error(new CancelationException()); } @@ -2152,10 +2167,20 @@ public class SignalServiceMessageSender { // Non-technical failures shouldn't be retried with socket return Single.error(throwable); } else if (throwable instanceof WebSocketUnavailableException) { - Log.i(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe unavailable, falling back... (" + throwable.getClass().getSimpleName() + ": " + throwable.getMessage() + ")"); - } else if (throwable instanceof IOException) { + if (useRestFallback.getAsBoolean()) { + Log.i(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe unavailable, falling back... (" + throwable.getClass().getSimpleName() + ": " + throwable.getMessage() + ")"); + } else { + Log.i(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe unavailable (" + throwable.getClass().getSimpleName() + ": " + throwable.getMessage() + ")"); + return Single.error(throwable); + } + } else { Throwable cause = throwable.getCause() != null ? throwable.getCause() : throwable; - Log.w(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe failed, falling back... (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")"); + if (useRestFallback.getAsBoolean()) { + Log.w(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe failed, falling back... (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")"); + } else { + Log.w(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe failed (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")"); + return Single.error((cause instanceof IOException) ? cause : throwable); + } } return Single.fromCallable(() -> { @@ -2431,9 +2456,19 @@ public class SignalServiceMessageSender { // Non-technical failures shouldn't be retried with socket throw e; } catch (WebSocketUnavailableException e) { - Log.i(TAG, "[sendGroupMessage][" + timestamp + "] Pipe unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); + if (useRestFallback.getAsBoolean()) { + Log.i(TAG, "[sendGroupMessage][" + timestamp + "] Pipe unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); + } else { + Log.i(TAG, "[sendGroupMessage][" + timestamp + "] Pipe unavailable (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); + throw e; + } } catch (IOException e) { - Log.w(TAG, "[sendGroupMessage][" + timestamp + "] Pipe failed, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); + if (useRestFallback.getAsBoolean()) { + Log.w(TAG, "[sendGroupMessage][" + timestamp + "] Pipe failed, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); + } else { + Log.w(TAG, "[sendGroupMessage][" + timestamp + "] Pipe failed (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); + throw e; + } } SendGroupMessageResponse response = socket.sendGroupMessage(ciphertext, sealedSenderAccess, timestamp, online, urgent, story);