mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 09:49:30 +01:00
Remove BackgroundMessageRetriever and clean up old code.
This commit is contained in:
committed by
Cody Henthorne
parent
9f75c37331
commit
b07d675bb4
@@ -1,144 +0,0 @@
|
||||
package org.thoughtcrime.securesms.messages;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.service.DelayedNotificationController;
|
||||
import org.thoughtcrime.securesms.service.GenericForegroundService;
|
||||
import org.thoughtcrime.securesms.util.PowerManagerCompat;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.WakeLockUtil;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Retrieves messages while the app is in the background via provided {@link MessageRetrievalStrategy}'s.
|
||||
*/
|
||||
public class BackgroundMessageRetriever {
|
||||
|
||||
private static final String TAG = Log.tag(BackgroundMessageRetriever.class);
|
||||
|
||||
private static final String WAKE_LOCK_TAG = "MessageRetriever";
|
||||
|
||||
private static final Semaphore ACTIVE_LOCK = new Semaphore(2);
|
||||
|
||||
public static final long DO_NOT_SHOW_IN_FOREGROUND = DelayedNotificationController.DO_NOT_SHOW;
|
||||
|
||||
/**
|
||||
* @return False if the retrieval failed and should be rescheduled, otherwise true.
|
||||
*/
|
||||
@WorkerThread
|
||||
public boolean retrieveMessages(@NonNull Context context, MessageRetrievalStrategy... strategies) {
|
||||
return retrieveMessages(context, DO_NOT_SHOW_IN_FOREGROUND, strategies);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return False if the retrieval failed and should be rescheduled, otherwise true.
|
||||
*/
|
||||
@WorkerThread
|
||||
public boolean retrieveMessages(@NonNull Context context, long showNotificationAfterMs, MessageRetrievalStrategy... strategies) {
|
||||
if (shouldIgnoreFetch()) {
|
||||
Log.i(TAG, "Skipping retrieval -- app is in the foreground.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ACTIVE_LOCK.tryAcquire()) {
|
||||
Log.i(TAG, "Skipping retrieval -- there's already one enqueued.");
|
||||
return true;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
try (NoExceptionCloseable unused = startDelayedForegroundServiceIfPossible(context, showNotificationAfterMs)) {
|
||||
PowerManager.WakeLock wakeLock = null;
|
||||
|
||||
try {
|
||||
wakeLock = WakeLockUtil.acquire(context, PowerManager.PARTIAL_WAKE_LOCK, TimeUnit.SECONDS.toMillis(60), WAKE_LOCK_TAG);
|
||||
|
||||
TextSecurePreferences.setNeedsMessagePull(context, true);
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
PowerManager powerManager = ServiceUtil.getPowerManager(context);
|
||||
boolean doze = PowerManagerCompat.isDeviceIdleMode(powerManager);
|
||||
boolean network = new NetworkConstraint.Factory(ApplicationContext.getInstance(context)).create().isMet();
|
||||
|
||||
if (doze || !network) {
|
||||
Log.w(TAG, "We may be operating in a constrained environment. Doze: " + doze + " Network: " + network);
|
||||
}
|
||||
|
||||
Log.i(TAG, "Performing normal message fetch.");
|
||||
return executeBackgroundRetrieval(context, startTime, strategies);
|
||||
} finally {
|
||||
WakeLockUtil.release(wakeLock, WAKE_LOCK_TAG);
|
||||
ACTIVE_LOCK.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private NoExceptionCloseable startDelayedForegroundServiceIfPossible(@NonNull Context context, long showNotificationAfterMs) {
|
||||
if (Build.VERSION.SDK_INT < 31) {
|
||||
return GenericForegroundService.startForegroundTaskDelayed(context, context.getString(R.string.BackgroundMessageRetriever_checking_for_messages), showNotificationAfterMs, R.drawable.ic_signal_refresh)::close;
|
||||
} else {
|
||||
return () -> {};
|
||||
}
|
||||
}
|
||||
|
||||
private boolean executeBackgroundRetrieval(@NonNull Context context, long startTime, @NonNull MessageRetrievalStrategy[] strategies) {
|
||||
boolean success = false;
|
||||
|
||||
for (MessageRetrievalStrategy strategy : strategies) {
|
||||
if (shouldIgnoreFetch()) {
|
||||
Log.i(TAG, "Stopping further strategy attempts -- app is in the foreground." + logSuffix(startTime));
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Log.i(TAG, "Attempting strategy: " + strategy.toString() + logSuffix(startTime));
|
||||
|
||||
if (strategy.execute()) {
|
||||
Log.i(TAG, "Strategy succeeded: " + strategy.toString() + logSuffix(startTime));
|
||||
success = true;
|
||||
break;
|
||||
} else {
|
||||
Log.w(TAG, "Strategy failed: " + strategy.toString() + logSuffix(startTime));
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
TextSecurePreferences.setNeedsMessagePull(context, false);
|
||||
} else {
|
||||
Log.w(TAG, "All strategies failed!" + logSuffix(startTime));
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if there is no need to execute a message fetch, because the websocket will take
|
||||
* care of it.
|
||||
*/
|
||||
public static boolean shouldIgnoreFetch() {
|
||||
return ApplicationDependencies.getAppForegroundObserver().isForegrounded();
|
||||
}
|
||||
|
||||
private static String logSuffix(long startTime) {
|
||||
return " (" + (System.currentTimeMillis() - startTime) + " ms elapsed)";
|
||||
}
|
||||
|
||||
private interface NoExceptionCloseable extends AutoCloseable {
|
||||
@Override
|
||||
void close();
|
||||
}
|
||||
}
|
||||
@@ -192,7 +192,7 @@ class IncomingMessageObserver(private val context: Application) {
|
||||
|
||||
private fun isConnectionNecessary(): Boolean {
|
||||
val timeIdle: Long
|
||||
val keepAliveEntries: Set<Map.Entry<String, Long>>
|
||||
val keepAliveEntries: Set<Pair<String, Long>>
|
||||
val appVisibleSnapshot: Boolean
|
||||
|
||||
lock.withLock {
|
||||
@@ -205,7 +205,7 @@ class IncomingMessageObserver(private val context: Application) {
|
||||
Log.d(TAG, "Removed old keep web socket open requests.")
|
||||
}
|
||||
|
||||
keepAliveEntries = keepAliveTokens.entries.toImmutableSet()
|
||||
keepAliveEntries = keepAliveTokens.entries.map { it.key to it.value }.toImmutableSet()
|
||||
}
|
||||
|
||||
val registered = SignalStore.account().isRegistered
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package org.thoughtcrime.securesms.messages;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobTracker;
|
||||
import org.thoughtcrime.securesms.jobs.MarkerJob;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementations are responsible for fetching and processing a batch of messages.
|
||||
*/
|
||||
public abstract class MessageRetrievalStrategy {
|
||||
|
||||
/**
|
||||
* Fetches and processes any pending messages. This method should block until the messages are
|
||||
* actually stored and processed -- not just retrieved.
|
||||
*
|
||||
* @return True if everything was successful up until cancelation, false otherwise.
|
||||
*/
|
||||
@WorkerThread
|
||||
abstract boolean execute();
|
||||
|
||||
protected static class QueueFindingJobListener implements JobTracker.JobListener {
|
||||
private final Set<String> queues = new HashSet<>();
|
||||
|
||||
@Override
|
||||
@AnyThread
|
||||
public void onStateChanged(@NonNull Job job, @NonNull JobTracker.JobState jobState) {
|
||||
synchronized (queues) {
|
||||
queues.add(job.getParameters().getQueue());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull Set<String> getQueues() {
|
||||
synchronized (queues) {
|
||||
return new HashSet<>(queues);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,32 @@
|
||||
package org.thoughtcrime.securesms.messages;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
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.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobTracker;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.jobs.MarkerJob;
|
||||
import org.thoughtcrime.securesms.jobs.PushProcessMessageJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.util.NetworkUtil;
|
||||
import org.thoughtcrime.securesms.util.PowerManagerCompat;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.WakeLockUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -20,25 +35,46 @@ import java.util.concurrent.TimeUnit;
|
||||
/**
|
||||
* Retrieves messages over the websocket.
|
||||
*/
|
||||
public class WebSocketStrategy extends MessageRetrievalStrategy {
|
||||
public class WebSocketStrategy {
|
||||
|
||||
private static final String TAG = Log.tag(WebSocketStrategy.class);
|
||||
|
||||
private static final String KEEP_ALIVE_TOKEN = "WebsocketStrategy";
|
||||
private static final long QUEUE_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
|
||||
private static final long QUEUE_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
|
||||
private static final String WAKELOCK_PREFIX = "websocket-strategy-";
|
||||
|
||||
private final long websocketDrainTimeoutMs;
|
||||
public WebSocketStrategy() {
|
||||
this(TimeUnit.MINUTES.toMillis(1));
|
||||
}
|
||||
|
||||
public WebSocketStrategy(long websocketDrainTimeoutMs) {
|
||||
this.websocketDrainTimeoutMs = websocketDrainTimeoutMs;
|
||||
@WorkerThread
|
||||
public static boolean execute() {
|
||||
return execute(TimeUnit.MINUTES.toMillis(1));
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@Override
|
||||
public boolean execute() {
|
||||
public static boolean execute(long websocketDrainTimeoutMs) {
|
||||
Application context = ApplicationDependencies.getApplication();
|
||||
IncomingMessageObserver observer = ApplicationDependencies.getIncomingMessageObserver();
|
||||
|
||||
PowerManager powerManager = ServiceUtil.getPowerManager(context);
|
||||
boolean doze = PowerManagerCompat.isDeviceIdleMode(powerManager);
|
||||
boolean network = NetworkUtil.isConnected(context);
|
||||
|
||||
if (doze || !network) {
|
||||
Log.w(TAG, "We may be operating in a constrained environment. Doze: " + doze + " Network: " + network);
|
||||
}
|
||||
|
||||
observer.registerKeepAliveToken(KEEP_ALIVE_TOKEN);
|
||||
|
||||
String wakeLockTag = WAKELOCK_PREFIX + System.currentTimeMillis();
|
||||
WakeLock wakeLock = WakeLockUtil.acquire(ApplicationDependencies.getApplication(), PowerManager.PARTIAL_WAKE_LOCK, websocketDrainTimeoutMs + QUEUE_TIMEOUT, wakeLockTag);
|
||||
|
||||
try {
|
||||
return drainAndProcess(websocketDrainTimeoutMs);
|
||||
} finally {
|
||||
WakeLockUtil.release(wakeLock, wakeLockTag);
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private static boolean drainAndProcess(long timeout) {
|
||||
Stopwatch stopwatch = new Stopwatch("websocket-strategy");
|
||||
IncomingMessageObserver observer = ApplicationDependencies.getIncomingMessageObserver();
|
||||
|
||||
@@ -49,7 +85,7 @@ public class WebSocketStrategy extends MessageRetrievalStrategy {
|
||||
|
||||
jobManager.addListener(job -> job.getParameters().getQueue() != null && job.getParameters().getQueue().startsWith(PushProcessMessageJob.QUEUE_PREFIX), queueListener);
|
||||
|
||||
if (!blockUntilWebsocketDrained(observer, websocketDrainTimeoutMs)) {
|
||||
if (!blockUntilWebsocketDrained(observer, timeout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -115,8 +151,21 @@ public class WebSocketStrategy extends MessageRetrievalStrategy {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return Log.tag(WebSocketStrategy.class);
|
||||
protected static class QueueFindingJobListener implements JobTracker.JobListener {
|
||||
private final Set<String> queues = new HashSet<>();
|
||||
|
||||
@Override
|
||||
@AnyThread
|
||||
public void onStateChanged(@NonNull Job job, @NonNull JobTracker.JobState jobState) {
|
||||
synchronized (queues) {
|
||||
queues.add(job.getParameters().getQueue());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull Set<String> getQueues() {
|
||||
synchronized (queues) {
|
||||
return new HashSet<>(queues);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user