Add more logging around failed backups.

This commit is contained in:
Cody Henthorne 2022-09-07 11:01:27 -04:00 committed by Greyson Parrelli
parent a335130ad4
commit bd5747b7f6
2 changed files with 67 additions and 15 deletions

View file

@ -0,0 +1,41 @@
package androidx.documentfile.provider;
import android.content.Context;
import android.net.Uri;
import android.provider.DocumentsContract;
import androidx.annotation.RequiresApi;
import org.signal.core.util.logging.Log;
/**
* Located in androidx package as {@link TreeDocumentFile} is package protected.
*/
public class DocumentFileHelper {
private static final String TAG = Log.tag(DocumentFileHelper.class);
/**
* System implementation swallows the exception and we are having problems with the rename. This inlines the
* same call and logs the exception. Note this implementation does not update the passed in document file like
* the system implementation. Do not use the provided document file after calling this method.
*
* @return true if rename successful
*/
@RequiresApi(21)
public static boolean renameTo(Context context, DocumentFile documentFile, String displayName) {
if (documentFile instanceof TreeDocumentFile) {
Log.d(TAG, "Renaming document directly");
try {
final Uri result = DocumentsContract.renameDocument(context.getContentResolver(), documentFile.getUri(), displayName);
return result != null;
} catch (Exception e) {
Log.w(TAG, "Unable to rename document file", e);
return false;
}
} else {
Log.d(TAG, "Letting OS rename document: " + documentFile.getClass().getSimpleName());
return documentFile.renameTo(displayName);
}
}
}

View file

@ -1,11 +1,13 @@
package org.thoughtcrime.securesms.jobs;
import android.annotation.SuppressLint;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.documentfile.provider.DocumentFile;
import androidx.documentfile.provider.DocumentFileHelper;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
@ -29,8 +31,8 @@ import org.thoughtcrime.securesms.service.GenericForegroundService;
import org.thoughtcrime.securesms.service.NotificationController;
import org.thoughtcrime.securesms.util.BackupUtil;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@ -51,9 +53,15 @@ 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);
private static final int MAX_STORAGE_ATTEMPTS = 5;
private static final long[] WAIT_FOR_SCOPED_STORAGE = new long[] {
TimeUnit.SECONDS.toMillis(0),
TimeUnit.SECONDS.toMillis(2),
TimeUnit.SECONDS.toMillis(10),
TimeUnit.SECONDS.toMillis(20),
TimeUnit.SECONDS.toMillis(30)
};
LocalBackupJobApi29(@NonNull Parameters parameters) {
super(parameters);
@ -173,28 +181,31 @@ public final class LocalBackupJobApi29 extends BaseJob {
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);
while (attempts < MAX_STORAGE_ATTEMPTS && valid == null) {
ThreadUtil.sleep(WAIT_FOR_SCOPED_STORAGE[attempts]);
try (InputStream cipherStream = context.getContentResolver().openInputStream(temporaryFile.getUri())) {
valid = BackupVerifier.verifyFile(cipherStream, backupPassword, finishedEvent.getCount());
} catch (IOException e) {
attempts++;
Log.w(TAG, "Unable to find backup file, attempt: " + attempts + "/" + MAX_STORAGE_ATTEMPTS);
}
}
return valid != null ? valid : false;
}
@SuppressLint("NewApi")
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);
while (attempts < MAX_STORAGE_ATTEMPTS && !DocumentFileHelper.renameTo(context, temporaryFile, fileName)) {
ThreadUtil.sleep(WAIT_FOR_SCOPED_STORAGE[attempts]);
attempts++;
Log.w(TAG, "Unable to rename backup file, attempt: " + attempts + "/" + MAX_STORAGE_ATTEMPTS);
}
if (attempts >= MAX_RENAME_ATTEMPTS) {
if (attempts >= MAX_STORAGE_ATTEMPTS) {
Log.w(TAG, "Failed to rename temp file");
throw new IOException("Renaming temporary backup file failed!");
}