From 13470fb0c3aa70d00a565b790178a23a216a46a5 Mon Sep 17 00:00:00 2001 From: Clark Date: Fri, 30 Jun 2023 12:41:00 -0400 Subject: [PATCH] Increase FCM push websocket timeout. --- .../securesms/gcm/FcmFetchForegroundService.kt | 15 +++++++++++++++ .../securesms/gcm/FcmFetchManager.kt | 8 +++++++- .../securesms/messages/WebSocketStrategy.java | 16 +++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchForegroundService.kt b/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchForegroundService.kt index 88613b200f..f611abf939 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchForegroundService.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchForegroundService.kt @@ -5,6 +5,7 @@ import android.app.Service import android.content.Context import android.content.Intent import android.os.IBinder +import android.os.PowerManager import androidx.core.app.NotificationCompat import org.signal.core.util.PendingIntentFlags import org.signal.core.util.logging.Log @@ -12,16 +13,23 @@ import org.thoughtcrime.securesms.MainActivity import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.notifications.NotificationChannels import org.thoughtcrime.securesms.notifications.NotificationIds +import org.thoughtcrime.securesms.util.WakeLockUtil /** * Works with {@link FcmFetchManager} to exists as a service that will keep the app process running in the foreground while we fetch messages. */ class FcmFetchForegroundService : Service() { + private var wakeLock: PowerManager.WakeLock? = null + companion object { private val TAG = Log.tag(FcmFetchForegroundService::class.java) + + private const val WAKELOCK_TAG = "FcmForegroundService" private const val KEY_STOP_SELF = "stop_self" + private val WAKELOCK_TIMEOUT = FcmFetchManager.WEBSOCKET_DRAIN_TIMEOUT + /** * Android's requirement for calling [startForeground] is enforced _even if your service was stopped before it started_. * That means we can't just stop it normally, since we don't know if it got to start yet. @@ -44,10 +52,14 @@ class FcmFetchForegroundService : Service() { postForegroundNotification() return if (intent != null && intent.getBooleanExtra(KEY_STOP_SELF, false)) { + WakeLockUtil.release(wakeLock, WAKELOCK_TAG) stopForeground(true) stopSelf() START_NOT_STICKY } else { + if (wakeLock == null) { + wakeLock = WakeLockUtil.acquire(this, PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TIMEOUT, WAKELOCK_TAG) + } START_STICKY } } @@ -68,7 +80,10 @@ class FcmFetchForegroundService : Service() { override fun onDestroy() { Log.i(TAG, "onDestroy()") + WakeLockUtil.release(wakeLock, WAKELOCK_TAG) FcmFetchManager.onDestroyForegroundFetchService() + + wakeLock = null } override fun onBind(intent: Intent?): IBinder? { diff --git a/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchManager.kt b/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchManager.kt index 771524e5a0..af00babbb4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchManager.kt @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.gcm import android.content.Context import android.content.Intent import android.os.Build +import android.os.PowerManager import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.dependencies.ApplicationDependencies @@ -11,6 +12,7 @@ import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob import org.thoughtcrime.securesms.messages.WebSocketStrategy import org.thoughtcrime.securesms.util.SignalLocalMetrics import org.thoughtcrime.securesms.util.concurrent.SerialMonoLifoExecutor +import kotlin.time.Duration.Companion.minutes /** * Our goals with FCM processing are as follows: @@ -34,6 +36,8 @@ object FcmFetchManager { private const val MAX_BLOCKING_TIME_MS = 500L private val EXECUTOR = SerialMonoLifoExecutor(SignalExecutors.UNBOUNDED) + val WEBSOCKET_DRAIN_TIMEOUT = 5.minutes.inWholeMilliseconds + @Volatile private var activeCount = 0 @@ -46,6 +50,8 @@ object FcmFetchManager { @Volatile private var startForegroundOnDestroy = false + private var wakeLock: PowerManager.WakeLock? = null + /** * @return True if a service was successfully started, otherwise false. */ @@ -140,7 +146,7 @@ object FcmFetchManager { @JvmStatic fun retrieveMessages(context: Context): Boolean { - val success = ApplicationDependencies.getBackgroundMessageRetriever().retrieveMessages(context, WebSocketStrategy()) + val success = ApplicationDependencies.getBackgroundMessageRetriever().retrieveMessages(context, WebSocketStrategy(WEBSOCKET_DRAIN_TIMEOUT)) if (success) { Log.i(TAG, "Successfully retrieved messages.") diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/WebSocketStrategy.java b/app/src/main/java/org/thoughtcrime/securesms/messages/WebSocketStrategy.java index b2e3b1e28c..82d89db293 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/WebSocketStrategy.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/WebSocketStrategy.java @@ -4,6 +4,7 @@ import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import org.signal.core.util.Stopwatch; +import org.signal.core.util.ThreadUtil; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.jobmanager.JobManager; @@ -26,6 +27,15 @@ public class WebSocketStrategy extends MessageRetrievalStrategy { private static final String KEEP_ALIVE_TOKEN = "WebsocketStrategy"; private static final long QUEUE_TIMEOUT = TimeUnit.SECONDS.toMillis(30); + private final long websocketDrainTimeoutMs; + public WebSocketStrategy() { + this(TimeUnit.MINUTES.toMillis(1)); + } + + public WebSocketStrategy(long websocketDrainTimeoutMs) { + this.websocketDrainTimeoutMs = websocketDrainTimeoutMs; + } + @WorkerThread @Override public boolean execute() { @@ -39,7 +49,7 @@ public class WebSocketStrategy extends MessageRetrievalStrategy { jobManager.addListener(job -> job.getParameters().getQueue() != null && job.getParameters().getQueue().startsWith(PushProcessMessageJob.QUEUE_PREFIX), queueListener); - if (!blockUntilWebsocketDrained(observer)) { + if (!blockUntilWebsocketDrained(observer, websocketDrainTimeoutMs)) { return false; } @@ -63,7 +73,7 @@ public class WebSocketStrategy extends MessageRetrievalStrategy { } } - private static boolean blockUntilWebsocketDrained(IncomingMessageObserver observer) { + private static boolean blockUntilWebsocketDrained(IncomingMessageObserver observer, long timeoutMs) { CountDownLatch latch = new CountDownLatch(1); observer.addDecryptionDrainedListener(new Runnable() { @@ -74,7 +84,7 @@ public class WebSocketStrategy extends MessageRetrievalStrategy { }); try { - if (latch.await(1, TimeUnit.MINUTES)) { + if (latch.await(timeoutMs, TimeUnit.MILLISECONDS)) { return true; } else { Log.w(TAG, "Hit timeout while waiting for decryptions to drain!");