Skip to content

Commit

Permalink
Retry backup verify and rename with delay.
Browse files Browse the repository at this point in the history
  • Loading branch information
cody-signal authored and greyson-signal committed Aug 24, 2022
1 parent 7a7c4c2 commit 05c16e4
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ private static int exportSticker(@NonNull AttachmentSecret attachmentSecret,
return count;
}

private static long calculateVeryOldStreamLength(@NonNull AttachmentSecret attachmentSecret, @Nullable byte[] random, @NonNull String data) throws IOException {
private static long calculateVeryOldStreamLength(@NonNull AttachmentSecret attachmentSecret, @Nullable byte[] random, @NonNull String data) {
long result = 0;

try (InputStream inputStream = openAttachmentStream(attachmentSecret, random, data)) {
Expand All @@ -425,6 +425,10 @@ private static long calculateVeryOldStreamLength(@NonNull AttachmentSecret attac
}
} catch (FileNotFoundException e) {
Log.w(TAG, "Missing attachment: " + e.getMessage());
return 0;
} catch (IOException e) {
Log.w(TAG, "Failed to determine stream length", e);
return 0;
}

return result;
Expand Down Expand Up @@ -708,6 +712,7 @@ private void write(@NonNull OutputStream out, @NonNull BackupProtos.BackupFrame


public void close() throws IOException {
outputStream.flush();
outputStream.close();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import android.net.Uri;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.signal.core.util.Stopwatch;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.backup.BackupEvent;
Expand All @@ -27,11 +29,13 @@
import org.thoughtcrime.securesms.service.NotificationController;
import org.thoughtcrime.securesms.util.BackupUtil;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
* Backup Job for installs requiring Scoped Storage.
Expand All @@ -47,6 +51,10 @@ public final class LocalBackupJobApi29 extends BaseJob {
public static final String TEMP_BACKUP_FILE_PREFIX = ".backup";
public static final String TEMP_BACKUP_FILE_SUFFIX = ".tmp";

private static final int MAX_VERIFY_ATTEMPTS = 5;
private static final int MAX_RENAME_ATTEMPTS = 5;
private static final long WAIT_FOR_SCOPED_STORAGE = TimeUnit.SECONDS.toMillis(2);

LocalBackupJobApi29(@NonNull Parameters parameters) {
super(parameters);
}
Expand Down Expand Up @@ -123,20 +131,17 @@ public void onRun() throws IOException {
this::isCanceled);
stopwatch.split("backup-create");

boolean valid = BackupVerifier.verifyFile(context.getContentResolver().openInputStream(temporaryFile.getUri()), backupPassword, finishedEvent.getCount());
boolean valid = verifyBackup(backupPassword, temporaryFile, finishedEvent);

stopwatch.split("backup-verify");
stopwatch.stop(TAG);

EventBus.getDefault().post(finishedEvent);

if (valid) {
if (!temporaryFile.renameTo(fileName)) {
Log.w(TAG, "Failed to rename temp file");
throw new IOException("Renaming temporary backup file failed!");
}
renameBackup(fileName, temporaryFile);
} else {
BackupFileIOError.VERIFICATION_FAILED.postNotification(context);
}
EventBus.getDefault().post(finishedEvent);
} catch (FullBackupExporter.BackupCanceledException e) {
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, 0, 0));
Log.w(TAG, "Backup cancelled");
Expand Down Expand Up @@ -164,6 +169,37 @@ public void onRun() throws IOException {
}
}

private boolean verifyBackup(String backupPassword, DocumentFile temporaryFile, BackupEvent finishedEvent) {
Boolean valid = null;
int attempts = 0;

while (attempts < MAX_VERIFY_ATTEMPTS && valid == null) {
try {
valid = BackupVerifier.verifyFile(context.getContentResolver().openInputStream(temporaryFile.getUri()), backupPassword, finishedEvent.getCount());
} catch (FileNotFoundException e) {
Log.w(TAG, "Unable to find backup file, attempt: " + (attempts + 1) + "/" + MAX_VERIFY_ATTEMPTS);
ThreadUtil.sleep(WAIT_FOR_SCOPED_STORAGE);
attempts++;
}
}
return valid != null ? valid : false;
}

private void renameBackup(String fileName, DocumentFile temporaryFile) throws IOException {
int attempts = 0;

while (attempts < MAX_RENAME_ATTEMPTS && !temporaryFile.renameTo(fileName)) {
Log.w(TAG, "Unable to rename backup file, attempt: " + (attempts + 1) + "/" + MAX_RENAME_ATTEMPTS);
ThreadUtil.sleep(WAIT_FOR_SCOPED_STORAGE);
attempts++;
}

if (attempts >= MAX_RENAME_ATTEMPTS) {
Log.w(TAG, "Failed to rename temp file");
throw new IOException("Renaming temporary backup file failed!");
}
}

private static void deleteOldTemporaryBackups(@NonNull DocumentFile backupDirectory) {
for (DocumentFile file : backupDirectory.listFiles()) {
if (file.isFile()) {
Expand Down

0 comments on commit 05c16e4

Please sign in to comment.