Really really delay SMS processing until sqlcipher migration completes

Blocking the SMS job on the screen lock isn't enough, since then
the job races against the migration.

Fixes #7390
This commit is contained in:
Moxie Marlinspike 2018-02-26 14:02:12 -08:00
parent a0a9e412b4
commit 18aa202695
6 changed files with 87 additions and 4 deletions

View File

@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
import org.thoughtcrime.securesms.jobs.GcmRefreshJob; import org.thoughtcrime.securesms.jobs.GcmRefreshJob;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirementProvider; import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirementProvider;
import org.thoughtcrime.securesms.jobs.requirements.ServiceRequirementProvider; import org.thoughtcrime.securesms.jobs.requirements.ServiceRequirementProvider;
import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirementProvider;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess; import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.service.DirectoryRefreshListener; import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.thoughtcrime.securesms.service.ExpiringMessageManager;
@ -121,7 +122,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
.withJobSerializer(new JavaJobSerializer()) .withJobSerializer(new JavaJobSerializer())
.withRequirementProviders(new MasterSecretRequirementProvider(this), .withRequirementProviders(new MasterSecretRequirementProvider(this),
new ServiceRequirementProvider(this), new ServiceRequirementProvider(this),
new NetworkRequirementProvider(this)) new NetworkRequirementProvider(this),
new SqlCipherMigrationRequirementProvider())
.withConsumerThreads(5) .withConsumerThreads(5)
.build(); .build();
} }

View File

@ -696,6 +696,10 @@ public class SmsDatabase extends MessagingDatabase {
return threadDeleted; return threadDeleted;
} }
public void ensureMigration() {
databaseHelper.getWritableDatabase();
}
private boolean isDuplicate(IncomingTextMessage message, long threadId) { private boolean isDuplicate(IncomingTextMessage message, long threadId) {
SQLiteDatabase database = databaseHelper.getReadableDatabase(); SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?", Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",

View File

@ -10,9 +10,11 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult; import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirement;
import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
@ -33,6 +35,7 @@ public class SmsReceiveJob extends ContextJob {
.withPersistence() .withPersistence()
.withWakeLock(true) .withWakeLock(true)
.withRequirement(new MasterSecretRequirement(context)) .withRequirement(new MasterSecretRequirement(context))
.withRequirement(new SqlCipherMigrationRequirement(context))
.create()); .create());
this.pdus = pdus; this.pdus = pdus;
@ -43,7 +46,7 @@ public class SmsReceiveJob extends ContextJob {
public void onAdded() {} public void onAdded() {}
@Override @Override
public void onRun() { public void onRun() throws MigrationPendingException {
Log.w(TAG, "onRun()"); Log.w(TAG, "onRun()");
Optional<IncomingTextMessage> message = assembleMessageFragments(pdus, subscriptionId); Optional<IncomingTextMessage> message = assembleMessageFragments(pdus, subscriptionId);
@ -68,7 +71,7 @@ public class SmsReceiveJob extends ContextJob {
@Override @Override
public boolean onShouldRetry(Exception exception) { public boolean onShouldRetry(Exception exception) {
return false; return exception instanceof MigrationPendingException;
} }
private boolean isBlocked(IncomingTextMessage message) { private boolean isBlocked(IncomingTextMessage message) {
@ -80,8 +83,13 @@ public class SmsReceiveJob extends ContextJob {
return false; return false;
} }
private Optional<InsertResult> storeMessage(IncomingTextMessage message) { private Optional<InsertResult> storeMessage(IncomingTextMessage message) throws MigrationPendingException {
SmsDatabase database = DatabaseFactory.getSmsDatabase(context); SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
database.ensureMigration();
if (TextSecurePreferences.getNeedsSqlCipherMigration(context)) {
throw new MigrationPendingException();
}
if (message.isSecureMessage()) { if (message.isSecureMessage()) {
IncomingTextMessage placeholder = new IncomingTextMessage(message, ""); IncomingTextMessage placeholder = new IncomingTextMessage(message, "");
@ -111,4 +119,8 @@ public class SmsReceiveJob extends ContextJob {
return Optional.of(new IncomingTextMessage(messages)); return Optional.of(new IncomingTextMessage(messages));
} }
private class MigrationPendingException extends Exception {
}
} }

View File

@ -0,0 +1,31 @@
package org.thoughtcrime.securesms.jobs.requirements;
import android.content.Context;
import android.support.annotation.NonNull;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.dependencies.ContextDependent;
import org.whispersystems.jobqueue.requirements.Requirement;
public class SqlCipherMigrationRequirement implements Requirement, ContextDependent {
@SuppressWarnings("unused")
private static final String TAG = SqlCipherMigrationRequirement.class.getSimpleName();
private transient Context context;
public SqlCipherMigrationRequirement(@NonNull Context context) {
this.context = context;
}
@Override
public void setContext(Context context) {
this.context = context;
}
@Override
public boolean isPresent() {
return !TextSecurePreferences.getNeedsSqlCipherMigration(context);
}
}

View File

@ -0,0 +1,31 @@
package org.thoughtcrime.securesms.jobs.requirements;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.whispersystems.jobqueue.requirements.RequirementListener;
import org.whispersystems.jobqueue.requirements.RequirementProvider;
public class SqlCipherMigrationRequirementProvider implements RequirementProvider {
private RequirementListener listener;
public SqlCipherMigrationRequirementProvider() {
EventBus.getDefault().register(this);
}
@Override
public void setListener(RequirementListener listener) {
this.listener = listener;
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(SqlCipherNeedsMigrationEvent event) {
if (listener != null) listener.onRequirementStatusChanged();
}
public static class SqlCipherNeedsMigrationEvent {
}
}

View File

@ -14,7 +14,9 @@ import android.support.v4.app.NotificationCompat;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import org.greenrobot.eventbus.EventBus;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirementProvider;
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference; import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
import java.io.IOException; import java.io.IOException;
@ -127,6 +129,7 @@ public class TextSecurePreferences {
public static void setNeedsSqlCipherMigration(@NonNull Context context, boolean value) { public static void setNeedsSqlCipherMigration(@NonNull Context context, boolean value) {
setBooleanPreference(context, NEEDS_SQLCIPHER_MIGRATION, value); setBooleanPreference(context, NEEDS_SQLCIPHER_MIGRATION, value);
EventBus.getDefault().post(new SqlCipherMigrationRequirementProvider.SqlCipherNeedsMigrationEvent());
} }
public static boolean getNeedsSqlCipherMigration(@NonNull Context context) { public static boolean getNeedsSqlCipherMigration(@NonNull Context context) {