Utilize enqueue job for spawning attachment restore jobs.

This commit is contained in:
Alex Hart
2026-03-26 12:41:41 -03:00
committed by GitHub
parent d72c742ab6
commit 467c154ea6
5 changed files with 80 additions and 9 deletions

View File

@@ -263,6 +263,7 @@ public final class JobManagerFactories {
put(ResumableUploadSpecJob.KEY, new ResumableUploadSpecJob.Factory());
put(RequestGroupV2InfoWorkerJob.KEY, new RequestGroupV2InfoWorkerJob.Factory());
put(RequestGroupV2InfoJob.KEY, new RequestGroupV2InfoJob.Factory());
put(LocalBackupRestoreMediaJob.KEY, new LocalBackupRestoreMediaJob.Factory());
put(RestoreAttachmentJob.KEY, new RestoreAttachmentJob.Factory());
put(RestoreAttachmentThumbnailJob.KEY, new RestoreAttachmentThumbnailJob.Factory());
put(RestoreLocalAttachmentJob.KEY, new RestoreLocalAttachmentJob.Factory());

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.jobs
import android.net.Uri
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.backup.v2.local.ArchiveFileSystem
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobs.protos.LocalBackupRestoreMediaJobData
import java.io.File
/**
* Scans the local backup files directory and enqueues individual [RestoreLocalAttachmentJob]s for each restorable attachment.
*/
class LocalBackupRestoreMediaJob private constructor(
parameters: Parameters,
private val backupDirectoryUri: Uri
) : Job(parameters) {
companion object {
const val KEY = "LocalBackupRestoreMediaJob"
private val TAG = Log.tag(LocalBackupRestoreMediaJob::class)
fun create(backupDirectoryUri: Uri): LocalBackupRestoreMediaJob {
return LocalBackupRestoreMediaJob(
Parameters.Builder()
.setLifespan(Parameters.IMMORTAL)
.setMaxAttempts(1)
.build(),
backupDirectoryUri = backupDirectoryUri
)
}
}
override fun serialize(): ByteArray {
return LocalBackupRestoreMediaJobData(
backupDirectoryUri = backupDirectoryUri.toString()
).encode()
}
override fun getFactoryKey(): String = KEY
override fun run(): Result {
val archiveFileSystem = when (backupDirectoryUri.scheme) {
"content" -> ArchiveFileSystem.openForRestore(context, backupDirectoryUri) ?: run {
Log.w(TAG, "Unable to open backup directory: $backupDirectoryUri")
return Result.failure()
}
else -> ArchiveFileSystem.fromFile(context, File(backupDirectoryUri.path!!))
}
val mediaNameToFileInfo = archiveFileSystem.filesFileSystem.allFiles()
RestoreLocalAttachmentJob.enqueueRestoreLocalAttachmentsJobs(mediaNameToFileInfo)
return Result.success()
}
override fun onFailure() = Unit
class Factory : Job.Factory<LocalBackupRestoreMediaJob> {
override fun create(parameters: Parameters, serializedData: ByteArray?): LocalBackupRestoreMediaJob {
val data = LocalBackupRestoreMediaJobData.ADAPTER.decode(serializedData!!)
return LocalBackupRestoreMediaJob(
parameters = parameters,
backupDirectoryUri = Uri.parse(data.backupDirectoryUri)
)
}
}
}

View File

@@ -29,7 +29,7 @@ import org.thoughtcrime.securesms.backup.v2.local.LocalArchiver
import org.thoughtcrime.securesms.backup.v2.local.SnapshotFileSystem
import org.thoughtcrime.securesms.database.model.databaseprotos.RestoreDecisionState
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.jobs.RestoreLocalAttachmentJob
import org.thoughtcrime.securesms.jobs.LocalBackupRestoreMediaJob
import org.thoughtcrime.securesms.keyvalue.Completed
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
@@ -124,8 +124,7 @@ class RestoreLocalBackupActivityViewModel : ViewModel() {
if (result is Result.Success) {
Log.i(TAG, "Local backup import succeeded")
val mediaNameToFileInfo = archiveFileSystem.filesFileSystem.allFiles()
RestoreLocalAttachmentJob.enqueueRestoreLocalAttachmentsJobs(mediaNameToFileInfo)
AppDependencies.jobManager.add(LocalBackupRestoreMediaJob.create(Uri.parse(backupDirectory)))
val actualBackupId = LocalArchiver.getBackupId(snapshotFileSystem, messageBackupKey)
val expectedBackupId = SignalStore.account.accountEntropyPool

View File

@@ -122,6 +122,10 @@ message BackfillCollapsedMessageJobData {
int64 lastDateReceived = 1;
}
message LocalBackupRestoreMediaJobData {
string backupDirectoryUri = 1;
}
message BackfillDigestJobData {
uint64 attachmentId = 1;
}

View File

@@ -36,9 +36,9 @@ import org.signal.libsignal.zkgroup.profiles.ProfileKey
import org.thoughtcrime.securesms.backup.v2.BackupRepository
import org.thoughtcrime.securesms.backup.v2.ImportResult
import org.thoughtcrime.securesms.backup.v2.RestoreV2Event
import org.thoughtcrime.securesms.backup.v2.local.ArchiveFileSystem
import org.thoughtcrime.securesms.conversation.v2.registerForLifecycle
import org.thoughtcrime.securesms.jobs.RestoreLocalAttachmentJob
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.jobs.EnqueueRestoreLocalAttachmentsJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.registration.ui.shared.RegistrationScreen
@@ -172,10 +172,7 @@ class QuickstartRestoreActivity : BaseActivity() {
withContext(Dispatchers.Main) { restoreStatus = "Restoring attachments..." }
// Enqueue attachment restore jobs via ArchiveFileSystem (which handles the files/ directory)
val archiveFileSystem = ArchiveFileSystem.fromFile(applicationContext, backupDir)
val mediaNameToFileInfo = archiveFileSystem.filesFileSystem.allFiles()
RestoreLocalAttachmentJob.enqueueRestoreLocalAttachmentsJobs(mediaNameToFileInfo)
AppDependencies.jobManager.add(EnqueueRestoreLocalAttachmentsJob.create(Uri.fromFile(backupDir)))
QuickstartInitializer.pendingBackupDir = null