From 89b0167fd2d8b69a7b293e911743963608ec1040 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Tue, 7 Feb 2023 11:19:26 -0500 Subject: [PATCH] Ensure backup job verification can be cancelled. --- .../securesms/backup/BackupVerifier.kt | 38 ++++++++++--------- .../securesms/jobs/LocalBackupJob.java | 2 +- .../securesms/jobs/LocalBackupJobApi29.java | 10 +++-- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupVerifier.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupVerifier.kt index 8e2305c3fc..0bcc2d59ca 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupVerifier.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupVerifier.kt @@ -15,31 +15,35 @@ object BackupVerifier { private val TAG = Log.tag(BackupVerifier::class.java) @JvmStatic - @Throws(IOException::class) - fun verifyFile(cipherStream: InputStream, passphrase: String, expectedCount: Long): Boolean { + @Throws(IOException::class, FullBackupExporter.BackupCanceledException::class) + fun verifyFile(cipherStream: InputStream, passphrase: String, expectedCount: Long, cancellationSignal: FullBackupExporter.BackupCancellationSignal): Boolean { val inputStream = BackupRecordInputStream(cipherStream, passphrase) var count = 0L var frame: BackupFrame = inputStream.readFrame() - while (!frame.end) { - val verified = when { - frame.hasAttachment() -> verifyAttachment(frame.attachment, inputStream) - frame.hasSticker() -> verifySticker(frame.sticker, inputStream) - frame.hasAvatar() -> verifyAvatar(frame.avatar, inputStream) - else -> true + cipherStream.use { + while (!frame.end && !cancellationSignal.isCanceled) { + val verified = when { + frame.hasAttachment() -> verifyAttachment(frame.attachment, inputStream) + frame.hasSticker() -> verifySticker(frame.sticker, inputStream) + frame.hasAvatar() -> verifyAvatar(frame.avatar, inputStream) + else -> true + } + + if (!verified) { + return false + } + + EventBus.getDefault().post(BackupEvent(BackupEvent.Type.PROGRESS_VERIFYING, ++count, expectedCount)) + + frame = inputStream.readFrame() } - - if (!verified) { - return false - } - - EventBus.getDefault().post(BackupEvent(BackupEvent.Type.PROGRESS_VERIFYING, ++count, expectedCount)) - - frame = inputStream.readFrame() } - cipherStream.close() + if (cancellationSignal.isCanceled) { + throw FullBackupExporter.BackupCanceledException() + } return true } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.java index 6b04197d1e..9c3260245a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.java @@ -131,7 +131,7 @@ public final class LocalBackupJob extends BaseJob { this::isCanceled); stopwatch.split("backup-create"); - boolean valid = BackupVerifier.verifyFile(new FileInputStream(tempFile), backupPassword, finishedEvent.getCount()); + boolean valid = BackupVerifier.verifyFile(new FileInputStream(tempFile), backupPassword, finishedEvent.getCount(), this::isCanceled); stopwatch.split("backup-verify"); stopwatch.stop(TAG); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJobApi29.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJobApi29.java index f42ae77000..926a5066eb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJobApi29.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJobApi29.java @@ -189,16 +189,16 @@ public final class LocalBackupJobApi29 extends BaseJob { } } - private boolean verifyBackup(String backupPassword, DocumentFile temporaryFile, BackupEvent finishedEvent) { + private boolean verifyBackup(String backupPassword, DocumentFile temporaryFile, BackupEvent finishedEvent) throws FullBackupExporter.BackupCanceledException { Boolean valid = null; int attempts = 0; - while (attempts < MAX_STORAGE_ATTEMPTS && valid == null) { + while (attempts < MAX_STORAGE_ATTEMPTS && valid == null && !isCanceled()) { ThreadUtil.sleep(WAIT_FOR_SCOPED_STORAGE[attempts]); try (InputStream cipherStream = context.getContentResolver().openInputStream(temporaryFile.getUri())) { try { - valid = BackupVerifier.verifyFile(cipherStream, backupPassword, finishedEvent.getCount()); + valid = BackupVerifier.verifyFile(cipherStream, backupPassword, finishedEvent.getCount(), this::isCanceled); } catch (IOException e) { Log.w(TAG, "Unable to verify backup", e); valid = false; @@ -209,6 +209,10 @@ public final class LocalBackupJobApi29 extends BaseJob { } } + if (isCanceled()) { + throw new FullBackupExporter.BackupCanceledException(); + } + return valid != null ? valid : false; }