kopia lustrzana https://github.com/ryukoposting/Signal-Android
rodzic
a64430c65f
commit
a9149c5dc0
|
@ -79,11 +79,12 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
@NonNull AttachmentSecret attachmentSecret,
|
@NonNull AttachmentSecret attachmentSecret,
|
||||||
@NonNull SQLiteDatabase input,
|
@NonNull SQLiteDatabase input,
|
||||||
@NonNull File output,
|
@NonNull File output,
|
||||||
@NonNull String passphrase)
|
@NonNull String passphrase,
|
||||||
|
@NonNull BackupCancellationSignal cancellationSignal)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
try (OutputStream outputStream = new FileOutputStream(output)) {
|
try (OutputStream outputStream = new FileOutputStream(output)) {
|
||||||
internalExport(context, attachmentSecret, input, outputStream, passphrase, true);
|
internalExport(context, attachmentSecret, input, outputStream, passphrase, true, cancellationSignal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,11 +93,12 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
@NonNull AttachmentSecret attachmentSecret,
|
@NonNull AttachmentSecret attachmentSecret,
|
||||||
@NonNull SQLiteDatabase input,
|
@NonNull SQLiteDatabase input,
|
||||||
@NonNull DocumentFile output,
|
@NonNull DocumentFile output,
|
||||||
@NonNull String passphrase)
|
@NonNull String passphrase,
|
||||||
|
@NonNull BackupCancellationSignal cancellationSignal)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
try (OutputStream outputStream = Objects.requireNonNull(context.getContentResolver().openOutputStream(output.getUri()))) {
|
try (OutputStream outputStream = Objects.requireNonNull(context.getContentResolver().openOutputStream(output.getUri()))) {
|
||||||
internalExport(context, attachmentSecret, input, outputStream, passphrase, true);
|
internalExport(context, attachmentSecret, input, outputStream, passphrase, true, cancellationSignal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +109,7 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
@NonNull String passphrase)
|
@NonNull String passphrase)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
internalExport(context, attachmentSecret, input, outputStream, passphrase, false);
|
internalExport(context, attachmentSecret, input, outputStream, passphrase, false, () -> false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void internalExport(@NonNull Context context,
|
private static void internalExport(@NonNull Context context,
|
||||||
|
@ -115,7 +117,8 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
@NonNull SQLiteDatabase input,
|
@NonNull SQLiteDatabase input,
|
||||||
@NonNull OutputStream fileOutputStream,
|
@NonNull OutputStream fileOutputStream,
|
||||||
@NonNull String passphrase,
|
@NonNull String passphrase,
|
||||||
boolean closeOutputStream)
|
boolean closeOutputStream,
|
||||||
|
@NonNull BackupCancellationSignal cancellationSignal)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
BackupFrameOutputStream outputStream = new BackupFrameOutputStream(fileOutputStream, passphrase);
|
BackupFrameOutputStream outputStream = new BackupFrameOutputStream(fileOutputStream, passphrase);
|
||||||
|
@ -129,23 +132,25 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
Stopwatch stopwatch = new Stopwatch("Backup");
|
Stopwatch stopwatch = new Stopwatch("Backup");
|
||||||
|
|
||||||
for (String table : tables) {
|
for (String table : tables) {
|
||||||
|
throwIfCanceled(cancellationSignal);
|
||||||
if (table.equals(MmsDatabase.TABLE_NAME)) {
|
if (table.equals(MmsDatabase.TABLE_NAME)) {
|
||||||
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringMmsMessage, null, count);
|
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringMmsMessage, null, count, cancellationSignal);
|
||||||
} else if (table.equals(SmsDatabase.TABLE_NAME)) {
|
} else if (table.equals(SmsDatabase.TABLE_NAME)) {
|
||||||
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringSmsMessage, null, count);
|
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringSmsMessage, null, count, cancellationSignal);
|
||||||
} else if (table.equals(GroupReceiptDatabase.TABLE_NAME)) {
|
} else if (table.equals(GroupReceiptDatabase.TABLE_NAME)) {
|
||||||
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(GroupReceiptDatabase.MMS_ID))), null, count);
|
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(GroupReceiptDatabase.MMS_ID))), null, count, cancellationSignal);
|
||||||
} else if (table.equals(AttachmentDatabase.TABLE_NAME)) {
|
} else if (table.equals(AttachmentDatabase.TABLE_NAME)) {
|
||||||
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID))), cursor -> exportAttachment(attachmentSecret, cursor, outputStream), count);
|
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID))), cursor -> exportAttachment(attachmentSecret, cursor, outputStream), count, cancellationSignal);
|
||||||
} else if (table.equals(StickerDatabase.TABLE_NAME)) {
|
} else if (table.equals(StickerDatabase.TABLE_NAME)) {
|
||||||
count = exportTable(table, input, outputStream, cursor -> true, cursor -> exportSticker(attachmentSecret, cursor, outputStream), count);
|
count = exportTable(table, input, outputStream, cursor -> true, cursor -> exportSticker(attachmentSecret, cursor, outputStream), count, cancellationSignal);
|
||||||
} else if (!BLACKLISTED_TABLES.contains(table) && !table.startsWith("sqlite_")) {
|
} else if (!BLACKLISTED_TABLES.contains(table) && !table.startsWith("sqlite_")) {
|
||||||
count = exportTable(table, input, outputStream, null, null, count);
|
count = exportTable(table, input, outputStream, null, null, count, cancellationSignal);
|
||||||
}
|
}
|
||||||
stopwatch.split("table::" + table);
|
stopwatch.split("table::" + table);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (BackupProtos.SharedPreference preference : IdentityKeyUtil.getBackupRecord(context)) {
|
for (BackupProtos.SharedPreference preference : IdentityKeyUtil.getBackupRecord(context)) {
|
||||||
|
throwIfCanceled(cancellationSignal);
|
||||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||||
outputStream.write(preference);
|
outputStream.write(preference);
|
||||||
}
|
}
|
||||||
|
@ -153,6 +158,7 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
stopwatch.split("prefs");
|
stopwatch.split("prefs");
|
||||||
|
|
||||||
for (AvatarHelper.Avatar avatar : AvatarHelper.getAvatars(context)) {
|
for (AvatarHelper.Avatar avatar : AvatarHelper.getAvatars(context)) {
|
||||||
|
throwIfCanceled(cancellationSignal);
|
||||||
if (avatar != null) {
|
if (avatar != null) {
|
||||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||||
outputStream.write(avatar.getFilename(), avatar.getInputStream(), avatar.getLength());
|
outputStream.write(avatar.getFilename(), avatar.getInputStream(), avatar.getLength());
|
||||||
|
@ -171,6 +177,12 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void throwIfCanceled(@NonNull BackupCancellationSignal cancellationSignal) throws BackupCanceledException {
|
||||||
|
if (cancellationSignal.isCanceled()) {
|
||||||
|
throw new BackupCanceledException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static List<String> exportSchema(@NonNull SQLiteDatabase input, @NonNull BackupFrameOutputStream outputStream)
|
private static List<String> exportSchema(@NonNull SQLiteDatabase input, @NonNull BackupFrameOutputStream outputStream)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
|
@ -201,18 +213,20 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
return tables;
|
return tables;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int exportTable(@NonNull String table,
|
private static int exportTable(@NonNull String table,
|
||||||
@NonNull SQLiteDatabase input,
|
@NonNull SQLiteDatabase input,
|
||||||
@NonNull BackupFrameOutputStream outputStream,
|
@NonNull BackupFrameOutputStream outputStream,
|
||||||
@Nullable Predicate<Cursor> predicate,
|
@Nullable Predicate<Cursor> predicate,
|
||||||
@Nullable Consumer<Cursor> postProcess,
|
@Nullable Consumer<Cursor> postProcess,
|
||||||
int count)
|
int count,
|
||||||
|
@NonNull BackupCancellationSignal cancellationSignal)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
String template = "INSERT INTO " + table + " VALUES ";
|
String template = "INSERT INTO " + table + " VALUES ";
|
||||||
|
|
||||||
try (Cursor cursor = input.rawQuery("SELECT * FROM " + table, null)) {
|
try (Cursor cursor = input.rawQuery("SELECT * FROM " + table, null)) {
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
throwIfCanceled(cancellationSignal);
|
||||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||||
|
|
||||||
if (predicate == null || predicate.test(cursor)) {
|
if (predicate == null || predicate.test(cursor)) {
|
||||||
|
@ -506,4 +520,10 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface BackupCancellationSignal {
|
||||||
|
boolean isCanceled();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class BackupCanceledException extends IOException { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,12 +115,16 @@ public final class LocalBackupJob extends BaseJob {
|
||||||
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
||||||
DatabaseFactory.getBackupDatabase(context),
|
DatabaseFactory.getBackupDatabase(context),
|
||||||
tempFile,
|
tempFile,
|
||||||
backupPassword);
|
backupPassword,
|
||||||
|
this::isCanceled);
|
||||||
|
|
||||||
if (!tempFile.renameTo(backupFile)) {
|
if (!tempFile.renameTo(backupFile)) {
|
||||||
Log.w(TAG, "Failed to rename temp file");
|
Log.w(TAG, "Failed to rename temp file");
|
||||||
throw new IOException("Renaming temporary backup file failed!");
|
throw new IOException("Renaming temporary backup file failed!");
|
||||||
}
|
}
|
||||||
|
} catch (FullBackupExporter.BackupCanceledException e) {
|
||||||
|
Log.w(TAG, "Backup cancelled");
|
||||||
|
throw e;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
BackupFileIOError.postNotificationForException(context, e, getRunAttempt());
|
BackupFileIOError.postNotificationForException(context, e, getRunAttempt());
|
||||||
throw e;
|
throw e;
|
||||||
|
|
|
@ -109,12 +109,16 @@ public final class LocalBackupJobApi29 extends BaseJob {
|
||||||
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
||||||
DatabaseFactory.getBackupDatabase(context),
|
DatabaseFactory.getBackupDatabase(context),
|
||||||
temporaryFile,
|
temporaryFile,
|
||||||
backupPassword);
|
backupPassword,
|
||||||
|
this::isCanceled);
|
||||||
|
|
||||||
if (!temporaryFile.renameTo(fileName)) {
|
if (!temporaryFile.renameTo(fileName)) {
|
||||||
Log.w(TAG, "Failed to rename temp file");
|
Log.w(TAG, "Failed to rename temp file");
|
||||||
throw new IOException("Renaming temporary backup file failed!");
|
throw new IOException("Renaming temporary backup file failed!");
|
||||||
}
|
}
|
||||||
|
} catch (FullBackupExporter.BackupCanceledException e) {
|
||||||
|
Log.w(TAG, "Backup cancelled");
|
||||||
|
throw e;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, "Error during backup!", e);
|
Log.w(TAG, "Error during backup!", e);
|
||||||
BackupFileIOError.postNotificationForException(context, e, getRunAttempt());
|
BackupFileIOError.postNotificationForException(context, e, getRunAttempt());
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.backup.BackupDialog;
|
import org.thoughtcrime.securesms.backup.BackupDialog;
|
||||||
import org.thoughtcrime.securesms.backup.FullBackupBase;
|
import org.thoughtcrime.securesms.backup.FullBackupBase;
|
||||||
import org.thoughtcrime.securesms.database.NoExternalStorageException;
|
import org.thoughtcrime.securesms.database.NoExternalStorageException;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
|
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||||
|
@ -250,5 +251,6 @@ public class BackupsPreferenceFragment extends Fragment {
|
||||||
create.setVisibility(View.GONE);
|
create.setVisibility(View.GONE);
|
||||||
folder.setVisibility(View.GONE);
|
folder.setVisibility(View.GONE);
|
||||||
verify.setVisibility(View.GONE);
|
verify.setVisibility(View.GONE);
|
||||||
|
ApplicationDependencies.getJobManager().cancelAllInQueue(LocalBackupJob.QUEUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue