Schedule message backups when enabled.

This commit is contained in:
Clark
2024-04-23 11:19:51 -04:00
committed by Cody Henthorne
parent 8a972d93e9
commit b043b6e458
7 changed files with 77 additions and 6 deletions

View File

@@ -88,6 +88,7 @@ import org.thoughtcrime.securesms.service.AnalyzeDatabaseAlarmListener;
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.LocalBackupListener;
import org.thoughtcrime.securesms.service.MessageBackupListener;
import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
import org.thoughtcrime.securesms.service.webrtc.ActiveCallManager;
@@ -420,6 +421,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
RotateSignedPreKeyListener.schedule(this);
DirectoryRefreshListener.schedule(this);
LocalBackupListener.schedule(this);
MessageBackupListener.schedule(this);
RotateSenderCertificateListener.schedule(this);
RoutineMessageFetchReceiver.startOrUpdateAlarm(this);
AnalyzeDatabaseAlarmListener.schedule(this);

View File

@@ -10,7 +10,6 @@ import org.signal.core.util.Stopwatch
import org.signal.core.util.logging.Log
import org.signal.core.util.toInt
import org.signal.paging.PagedDataSource
import org.thoughtcrime.securesms.BuildConfig
import org.thoughtcrime.securesms.backup.v2.BackupRestoreManager
import org.thoughtcrime.securesms.conversation.ConversationData
import org.thoughtcrime.securesms.conversation.ConversationMessage
@@ -25,6 +24,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.messagerequests.MessageRequestRepository
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel
private typealias ConversationElement = MappingModel<*>
@@ -125,7 +125,7 @@ class ConversationDataSource(
records = MessageDataFetcher.updateModelsWithData(records, extraData).toMutableList()
stopwatch.split("models")
if (BuildConfig.MESSAGE_BACKUP_RESTORE_ENABLED && SignalStore.backup().restoreState.inProgress) {
if (FeatureFlags.messageBackups() && SignalStore.backup().restoreState.inProgress) {
BackupRestoreManager.prioritizeAttachmentsIfNeeded(records)
stopwatch.split("restore")
}

View File

@@ -30,13 +30,21 @@ class BackupMessagesJob private constructor(parameters: Parameters) : BaseJob(pa
private val TAG = Log.tag(BackupMessagesJob::class.java)
const val KEY = "BackupMessagesJob"
const val QUEUE = "BackupMessagesQueue"
fun enqueue() {
val jobManager = ApplicationDependencies.getJobManager()
jobManager.add(BackupMessagesJob())
}
}
constructor() : this(
Parameters.Builder()
.addConstraint(NetworkConstraint.KEY)
.setMaxAttempts(Parameters.UNLIMITED)
.setMaxInstancesForFactory(2)
.setMaxAttempts(3)
.setMaxInstancesForFactory(1)
.setQueue(QUEUE)
.build()
)

View File

@@ -20,6 +20,8 @@ internal class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
private const val KEY_CDN_READ_CREDENTIALS_TIMESTAMP = "backup.cdn.readCredentials.timestamp"
private const val KEY_RESTORE_STATE = "backup.restoreState"
private const val KEY_NEXT_BACKUP_TIME = "backup.nextBackupTime"
private const val KEY_CDN_BACKUP_DIRECTORY = "backup.cdn.directory"
private const val KEY_CDN_BACKUP_MEDIA_DIRECTORY = "backup.cdn.mediaDirectory"
@@ -45,6 +47,8 @@ internal class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
var restoreState: RestoreState by enumValue(KEY_RESTORE_STATE, RestoreState.NONE, RestoreState.serializer)
var optimizeStorage: Boolean by booleanValue(KEY_OPTIMIZE_STORAGE, false)
var nextBackupTime: Long by longValue(KEY_NEXT_BACKUP_TIME, -1)
var areBackupsEnabled: Boolean by booleanValue(KEY_BACKUPS_ENABLED, false)
/**

View File

@@ -6,7 +6,6 @@ import android.content.Context;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
import org.thoughtcrime.securesms.keyvalue.SettingsValues;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.JavaTimeExtensionsKt;
import org.thoughtcrime.securesms.util.TextSecurePreferences;

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.service
import android.content.Context
import org.thoughtcrime.securesms.jobs.BackupMessagesJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.toMillis
import java.time.LocalDateTime
import java.util.Random
import java.util.concurrent.TimeUnit
class MessageBackupListener : PersistentAlarmManagerListener() {
override fun shouldScheduleExact(): Boolean {
return true
}
override fun getNextScheduledExecutionTime(context: Context): Long {
return SignalStore.backup().nextBackupTime
}
override fun onAlarm(context: Context, scheduledTime: Long): Long {
if (SignalStore.backup().areBackupsEnabled) {
BackupMessagesJob.enqueue()
}
return setNextBackupTimeToIntervalFromNow()
}
companion object {
private val BACKUP_JITTER_WINDOW_SECONDS = Math.toIntExact(TimeUnit.MINUTES.toSeconds(10))
@JvmStatic
fun schedule(context: Context?) {
if (FeatureFlags.messageBackups() && SignalStore.backup().areBackupsEnabled) {
MessageBackupListener().onReceive(context, getScheduleIntent())
}
}
fun setNextBackupTimeToIntervalFromNow(): Long {
val now = LocalDateTime.now()
val hour = SignalStore.settings().backupHour
val minute = SignalStore.settings().backupMinute
var next = now.withHour(hour).withMinute(minute).withSecond(0)
val jitter = Random().nextInt(BACKUP_JITTER_WINDOW_SECONDS) - BACKUP_JITTER_WINDOW_SECONDS / 2
next.plusSeconds(jitter.toLong())
if (now.isAfter(next)) {
next = next.plusDays(1)
}
val nextTime = next.toMillis()
SignalStore.backup().nextBackupTime = nextTime
return nextTime
}
}
}

View File

@@ -741,7 +741,7 @@ public final class FeatureFlags {
* Note: This feature is in active development and is not intended to currently function.
*/
public static boolean messageBackups() {
return getBoolean(MESSAGE_BACKUPS, false);
return BuildConfig.MESSAGE_BACKUP_RESTORE_ENABLED || getBoolean(MESSAGE_BACKUPS, false);
}
/** Whether or not to use the custom CameraX controller class */