Fix SQL crash in backup restore by preventing job from running until restore complete.

This commit is contained in:
Cody Henthorne
2023-06-14 10:28:34 -04:00
committed by GitHub
parent 9c0c25ef99
commit 305edf1928
6 changed files with 78 additions and 1 deletions

View File

@@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.backup.BackupPassphrase;
import org.thoughtcrime.securesms.backup.FullBackupImporter;
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.jobmanager.impl.DataRestoreConstraint;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import java.io.IOException;
@@ -38,6 +39,7 @@ final class NewDeviceServerTask implements ServerTask {
EventBus.getDefault().register(this);
try {
DataRestoreConstraint.setRestoringData(true);
SQLiteDatabase database = SignalDatabase.getBackupDatabase();
String passphrase = "deadbeef";
@@ -66,6 +68,7 @@ final class NewDeviceServerTask implements ServerTask {
EventBus.getDefault().post(new Status(0, Status.State.FAILURE_UNKNOWN));
} finally {
EventBus.getDefault().unregister(this);
DataRestoreConstraint.setRestoringData(false);
}
long end = System.currentTimeMillis();

View File

@@ -0,0 +1,34 @@
package org.thoughtcrime.securesms.jobmanager.impl
import android.app.job.JobInfo
import org.thoughtcrime.securesms.jobmanager.Constraint
/**
* Constraint that, when added, means that a job cannot be performed while a backup restore or device transfer
* is occurring.
*/
object DataRestoreConstraint : Constraint {
const val KEY = "DataRestoreConstraint"
@JvmStatic
var isRestoringData: Boolean = false
set(value) {
field = value
DataRestoreConstraintObserver.onChange()
}
override fun isMet(): Boolean {
return !isRestoringData
}
override fun getFactoryKey(): String = KEY
override fun applyToJobInfo(jobInfoBuilder: JobInfo.Builder) = Unit
class Factory : Constraint.Factory<DataRestoreConstraint> {
override fun create(): DataRestoreConstraint {
return DataRestoreConstraint
}
}
}

View File

@@ -0,0 +1,27 @@
package org.thoughtcrime.securesms.jobmanager.impl
import org.thoughtcrime.securesms.jobmanager.ConstraintObserver
/**
* An observer for the [DataRestoreConstraint]. This class expects to be told when a change happens,
* since the points at which it happens are triggered by application code.
*/
object DataRestoreConstraintObserver : ConstraintObserver {
private const val REASON = "DataRestoreConstraint"
private var notifier: ConstraintObserver.Notifier? = null
override fun register(notifier: ConstraintObserver.Notifier) {
this.notifier = notifier
}
/**
* Let the observer know that the change number state has changed.
*/
fun onChange() {
if (DataRestoreConstraint.isMet) {
notifier?.onConstraintMet(REASON)
}
}
}

View File

@@ -12,8 +12,11 @@ import org.thoughtcrime.securesms.jobmanager.JobMigration;
import org.thoughtcrime.securesms.jobmanager.impl.AutoDownloadEmojiConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.impl.ChangeNumberConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.ChangeNumberConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.impl.ChargingConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.ChargingConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.impl.DataRestoreConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.DataRestoreConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.impl.DecryptionsDrainedConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.DecryptionsDrainedConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
@@ -292,6 +295,7 @@ public final class JobManagerFactories {
put(AutoDownloadEmojiConstraint.KEY, new AutoDownloadEmojiConstraint.Factory(application));
put(ChangeNumberConstraint.KEY, new ChangeNumberConstraint.Factory());
put(ChargingConstraint.KEY, new ChargingConstraint.Factory());
put(DataRestoreConstraint.KEY, new DataRestoreConstraint.Factory());
put(DecryptionsDrainedConstraint.KEY, new DecryptionsDrainedConstraint.Factory());
put(NetworkConstraint.KEY, new NetworkConstraint.Factory(application));
put(NetworkOrCellServiceConstraint.KEY, new NetworkOrCellServiceConstraint.Factory(application));
@@ -307,7 +311,9 @@ public final class JobManagerFactories {
new NetworkConstraintObserver(application),
new SqlCipherMigrationConstraintObserver(),
new DecryptionsDrainedConstraintObserver(),
new NotInCallConstraintObserver());
new NotInCallConstraintObserver(),
ChangeNumberConstraintObserver.INSTANCE,
DataRestoreConstraintObserver.INSTANCE);
}
public static List<JobMigration> getJobMigrations(@NonNull Application application) {

View File

@@ -4,6 +4,7 @@ import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.impl.DataRestoreConstraint
import org.thoughtcrime.securesms.transport.RetryLaterException
import java.lang.Exception
import java.lang.IllegalStateException
@@ -24,6 +25,7 @@ class RebuildMessageSearchIndexJob private constructor(params: Parameters) : Bas
private constructor() : this(
Parameters.Builder()
.setQueue("RebuildMessageSearchIndex")
.addConstraint(DataRestoreConstraint.KEY)
.setMaxAttempts(3)
.build()
)

View File

@@ -49,6 +49,8 @@ import org.thoughtcrime.securesms.backup.FullBackupImporter;
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
import org.thoughtcrime.securesms.database.NoExternalStorageException;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.jobmanager.impl.DataRestoreConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.DataRestoreConstraintObserver;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.registration.viewmodel.RegistrationViewModel;
@@ -282,6 +284,7 @@ public final class RestoreBackupFragment extends LoggingFragment {
protected BackupImportResult doInBackground(Void... voids) {
try {
Log.i(TAG, "Starting backup restore.");
DataRestoreConstraint.setRestoringData(true);
SQLiteDatabase database = SignalDatabase.getBackupDatabase();
@@ -310,6 +313,8 @@ public final class RestoreBackupFragment extends LoggingFragment {
} catch (IOException e) {
Log.w(TAG, e);
return BackupImportResult.FAILURE_UNKNOWN;
} finally {
DataRestoreConstraint.setRestoringData(false);
}
}