Perform individual decryptions inside a database transaction.

Required a lot of random locking work to prevent deadlocking, but
overall this results in about a 2x speed increase for decryptions.
This commit is contained in:
Greyson Parrelli
2021-02-19 14:18:05 -05:00
committed by Cody Henthorne
parent d56607a686
commit 28f3ded4bd
24 changed files with 309 additions and 85 deletions

View File

@@ -335,7 +335,7 @@ dependencies {
implementation project(':video')
implementation 'org.signal:zkgroup-android:0.7.0'
implementation 'org.whispersystems:signal-client-android:0.1.6'
implementation 'org.whispersystems:signal-client-android:0.1.7'
implementation 'com.google.protobuf:protobuf-javalite:3.10.0'
implementation 'org.signal:argon2:13.1@aar'

View File

@@ -11,6 +11,7 @@ import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessageDatabase;
@@ -27,13 +28,12 @@ import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.VerifySpan;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import java.io.IOException;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
public class ConfirmIdentityDialog extends AlertDialog {
@SuppressWarnings("unused")
@@ -94,7 +94,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
{
@Override
protected Void doInBackground(Void... params) {
synchronized (SESSION_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(Recipient.resolved(recipientId).requireServiceId(), 1);
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext());

View File

@@ -63,6 +63,7 @@ import androidx.fragment.app.FragmentTransaction;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.components.camera.CameraView;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@@ -91,14 +92,13 @@ import org.whispersystems.libsignal.fingerprint.Fingerprint;
import org.whispersystems.libsignal.fingerprint.FingerprintParsingException;
import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException;
import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Locale;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
/**
* Activity for verifying identity keys.
*
@@ -620,7 +620,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
new AsyncTask<Recipient, Void, Void>() {
@Override
protected Void doInBackground(Recipient... params) {
synchronized (SESSION_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
if (isChecked) {
Log.i(TAG, "Saving identity: " + params[0].getId());
DatabaseFactory.getIdentityDatabase(getActivity())

View File

@@ -8,15 +8,15 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.whispersystems.signalservice.api.SignalSessionLock;
import java.util.List;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
public class UntrustedSendDialog extends AlertDialog.Builder implements DialogInterface.OnClickListener {
private final List<IdentityRecord> untrustedRecords;
@@ -43,7 +43,7 @@ public class UntrustedSendDialog extends AlertDialog.Builder implements DialogIn
final IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(getContext());
SimpleTask.run(() -> {
synchronized (SESSION_LOCK) {
try(SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
for (IdentityRecord identityRecord : untrustedRecords) {
identityDatabase.setApproval(identityRecord.getRecipientId(), true);
}

View File

@@ -8,14 +8,14 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.whispersystems.signalservice.api.SignalSessionLock;
import java.util.List;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
public class UnverifiedSendDialog extends AlertDialog.Builder implements DialogInterface.OnClickListener {
private final List<IdentityRecord> untrustedRecords;
@@ -44,7 +44,7 @@ public class UnverifiedSendDialog extends AlertDialog.Builder implements DialogI
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
synchronized (SESSION_LOCK) {
try(SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
for (IdentityRecord identityRecord : untrustedRecords) {
identityDatabase.setVerified(identityRecord.getRecipientId(),
identityRecord.getIdentityKey(),

View File

@@ -141,6 +141,7 @@ import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog
import org.thoughtcrime.securesms.conversation.ui.groupcall.GroupCallViewModel;
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewModel;
import org.thoughtcrime.securesms.conversationlist.model.MessageResult;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.crypto.SecurityEvent;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.DraftDatabase;
@@ -279,6 +280,7 @@ import org.thoughtcrime.securesms.wallpaper.ChatWallpaperDimLevelUtil;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalSessionLock;
import java.io.IOException;
import java.util.ArrayList;
@@ -295,7 +297,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import static org.thoughtcrime.securesms.TransportOption.Type;
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
/**
* Activity for displaying a message thread, as well as
@@ -3620,7 +3621,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
synchronized (SESSION_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
for (IdentityRecord identityRecord : unverifiedIdentities) {
identityDatabase.setVerified(identityRecord.getRecipientId(),
identityRecord.getIdentityKey(),

View File

@@ -12,6 +12,7 @@ import com.annimon.stream.Stream;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.IdentityDatabase;
@@ -25,12 +26,11 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.signalservice.api.SignalSessionLock;
import java.util.Collection;
import java.util.List;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
final class SafetyNumberChangeRepository {
private static final String TAG = SafetyNumberChangeRepository.class.getSimpleName();
@@ -90,7 +90,7 @@ final class SafetyNumberChangeRepository {
private TrustAndVerifyResult trustOrVerifyChangedRecipientsInternal(@NonNull List<ChangedRecipient> changedRecipients) {
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
synchronized (SESSION_LOCK) {
try(SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
for (ChangedRecipient changedRecipient : changedRecipients) {
IdentityRecord identityRecord = changedRecipient.getIdentityRecord();
@@ -110,7 +110,7 @@ final class SafetyNumberChangeRepository {
@WorkerThread
private TrustAndVerifyResult trustOrVerifyChangedRecipientsAndResendInternal(@NonNull List<ChangedRecipient> changedRecipients,
@NonNull MessageRecord messageRecord) {
synchronized (SESSION_LOCK) {
try(SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
for (ChangedRecipient changedRecipient : changedRecipients) {
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(changedRecipient.getRecipient().requireServiceId(), 1);
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context);

View File

@@ -0,0 +1,31 @@
package org.thoughtcrime.securesms.crypto;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.whispersystems.signalservice.api.SignalSessionLock;
/**
* An implementation of {@link SignalSessionLock} that effectively re-uses our database lock.
*/
public enum DatabaseSessionLock implements SignalSessionLock {
INSTANCE;
@Override
public Lock acquire() {
SQLiteDatabase db = DatabaseFactory.getInstance(ApplicationDependencies.getApplication()).getRawDatabase();
if (db.isDbLockedByCurrentThread()) {
return () -> {};
}
db.beginTransaction();
return () -> {
db.setTransactionSuccessful();
db.endTransaction();
};
}
}

View File

@@ -5,6 +5,7 @@ import android.content.Context;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.SessionUtil;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
@@ -18,6 +19,7 @@ import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.state.IdentityKeyStore;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalSessionLock;
import java.util.concurrent.TimeUnit;
@@ -45,7 +47,7 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
}
public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) {
synchronized (LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
Recipient recipient = Recipient.external(context, address.getName());
Optional<IdentityRecord> identityRecord = identityDatabase.getIdentity(recipient.getId());
@@ -91,7 +93,7 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
@Override
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
synchronized (LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
if (DatabaseFactory.getRecipientDatabase(context).containsPhoneOrUuid(address.getName())) {
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
RecipientId ourRecipientId = Recipient.self().getId();

View File

@@ -4,12 +4,14 @@ import android.content.Context;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.whispersystems.libsignal.InvalidKeyIdException;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.PreKeyStore;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.libsignal.state.SignedPreKeyStore;
import org.whispersystems.signalservice.api.SignalSessionLock;
import java.util.List;
@@ -18,8 +20,6 @@ public class TextSecurePreKeyStore implements PreKeyStore, SignedPreKeyStore {
@SuppressWarnings("unused")
private static final String TAG = TextSecurePreKeyStore.class.getSimpleName();
private static final Object FILE_LOCK = new Object();
@NonNull
private final Context context;
@@ -29,7 +29,7 @@ public class TextSecurePreKeyStore implements PreKeyStore, SignedPreKeyStore {
@Override
public PreKeyRecord loadPreKey(int preKeyId) throws InvalidKeyIdException {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
PreKeyRecord preKeyRecord = DatabaseFactory.getPreKeyDatabase(context).getPreKey(preKeyId);
if (preKeyRecord == null) throw new InvalidKeyIdException("No such key: " + preKeyId);
@@ -39,7 +39,7 @@ public class TextSecurePreKeyStore implements PreKeyStore, SignedPreKeyStore {
@Override
public SignedPreKeyRecord loadSignedPreKey(int signedPreKeyId) throws InvalidKeyIdException {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
SignedPreKeyRecord signedPreKeyRecord = DatabaseFactory.getSignedPreKeyDatabase(context).getSignedPreKey(signedPreKeyId);
if (signedPreKeyRecord == null) throw new InvalidKeyIdException("No such signed prekey: " + signedPreKeyId);
@@ -49,21 +49,21 @@ public class TextSecurePreKeyStore implements PreKeyStore, SignedPreKeyStore {
@Override
public List<SignedPreKeyRecord> loadSignedPreKeys() {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
return DatabaseFactory.getSignedPreKeyDatabase(context).getAllSignedPreKeys();
}
}
@Override
public void storePreKey(int preKeyId, PreKeyRecord record) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
DatabaseFactory.getPreKeyDatabase(context).insertPreKey(preKeyId, record);
}
}
@Override
public void storeSignedPreKey(int signedPreKeyId, SignedPreKeyRecord record) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
DatabaseFactory.getSignedPreKeyDatabase(context).insertSignedPreKey(signedPreKeyId, record);
}
}
@@ -87,5 +87,4 @@ public class TextSecurePreKeyStore implements PreKeyStore, SignedPreKeyStore {
public void removeSignedPreKey(int signedPreKeyId) {
DatabaseFactory.getSignedPreKeyDatabase(context).removeSignedPreKey(signedPreKeyId);
}
}

View File

@@ -5,6 +5,7 @@ import android.content.Context;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.SessionDatabase;
import org.thoughtcrime.securesms.recipients.Recipient;
@@ -13,6 +14,7 @@ import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.protocol.CiphertextMessage;
import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.signalservice.api.SignalServiceSessionStore;
import org.whispersystems.signalservice.api.SignalSessionLock;
import java.util.Collections;
import java.util.List;
@@ -21,8 +23,6 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
private static final String TAG = TextSecureSessionStore.class.getSimpleName();
private static final Object FILE_LOCK = new Object();
@NonNull private final Context context;
public TextSecureSessionStore(@NonNull Context context) {
@@ -31,7 +31,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
@Override
public SessionRecord loadSession(@NonNull SignalProtocolAddress address) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
RecipientId recipientId = Recipient.external(context, address.getName()).getId();
SessionRecord sessionRecord = DatabaseFactory.getSessionDatabase(context).load(recipientId, address.getDeviceId());
@@ -46,7 +46,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
@Override
public void storeSession(@NonNull SignalProtocolAddress address, @NonNull SessionRecord record) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
RecipientId id = Recipient.external(context, address.getName()).getId();
DatabaseFactory.getSessionDatabase(context).store(id, address.getDeviceId(), record);
}
@@ -54,7 +54,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
@Override
public boolean containsSession(SignalProtocolAddress address) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
if (DatabaseFactory.getRecipientDatabase(context).containsPhoneOrUuid(address.getName())) {
RecipientId recipientId = Recipient.external(context, address.getName()).getId();
SessionRecord sessionRecord = DatabaseFactory.getSessionDatabase(context).load(recipientId, address.getDeviceId());
@@ -70,7 +70,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
@Override
public void deleteSession(SignalProtocolAddress address) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
if (DatabaseFactory.getRecipientDatabase(context).containsPhoneOrUuid(address.getName())) {
RecipientId recipientId = Recipient.external(context, address.getName()).getId();
DatabaseFactory.getSessionDatabase(context).delete(recipientId, address.getDeviceId());
@@ -82,7 +82,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
@Override
public void deleteAllSessions(String name) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
if (DatabaseFactory.getRecipientDatabase(context).containsPhoneOrUuid(name)) {
RecipientId recipientId = Recipient.external(context, name).getId();
DatabaseFactory.getSessionDatabase(context).deleteAllFor(recipientId);
@@ -92,7 +92,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
@Override
public List<Integer> getSubDeviceSessions(String name) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
if (DatabaseFactory.getRecipientDatabase(context).containsPhoneOrUuid(name)) {
RecipientId recipientId = Recipient.external(context, name).getId();
return DatabaseFactory.getSessionDatabase(context).getSubDevices(recipientId);
@@ -105,7 +105,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
@Override
public void archiveSession(SignalProtocolAddress address) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
if (DatabaseFactory.getRecipientDatabase(context).containsPhoneOrUuid(address.getName())) {
RecipientId recipientId = Recipient.external(context, address.getName()).getId();
archiveSession(recipientId, address.getDeviceId());
@@ -114,7 +114,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
}
public void archiveSession(@NonNull RecipientId recipientId, int deviceId) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
SessionRecord session = DatabaseFactory.getSessionDatabase(context).load(recipientId, deviceId);
if (session != null) {
session.archiveCurrentState();
@@ -124,7 +124,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
}
public void archiveSiblingSessions(@NonNull SignalProtocolAddress address) {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
if (DatabaseFactory.getRecipientDatabase(context).containsPhoneOrUuid(address.getName())) {
RecipientId recipientId = Recipient.external(context, address.getName()).getId();
List<SessionDatabase.SessionRow> sessions = DatabaseFactory.getSessionDatabase(context).getAllFor(recipientId);
@@ -142,7 +142,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
}
public void archiveAllSessions() {
synchronized (FILE_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
List<SessionDatabase.SessionRow> sessions = DatabaseFactory.getSessionDatabase(context).getAll();
for (SessionDatabase.SessionRow row : sessions) {

View File

@@ -0,0 +1,32 @@
package org.thoughtcrime.securesms.database;
import android.content.Context;
import androidx.annotation.NonNull;
import net.sqlcipher.database.SQLiteDatabase;
import java.io.Closeable;
public final class DatabaseLock {
public static @NonNull Lock acquire(@NonNull Context context) {
SQLiteDatabase db = DatabaseFactory.getInstance(context).getRawDatabase();
if (db.isDbLockedByCurrentThread()) {
return () -> {};
}
db.beginTransaction();
return () -> {
db.setTransactionSuccessful();
db.endTransaction();
};
}
public interface Lock extends Closeable {
@Override
void close();
}
}

View File

@@ -4,27 +4,20 @@ import android.app.Application;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.greenrobot.eventbus.EventBus;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.components.TypingStatusRepository;
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.database.DatabaseObserver;
import org.thoughtcrime.securesms.database.JobDatabase;
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
import org.thoughtcrime.securesms.jobmanager.Constraint;
import org.thoughtcrime.securesms.jobmanager.ConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobmanager.JobMigrator;
import org.thoughtcrime.securesms.jobmanager.impl.FactoryJobPredicate;
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage;
import org.thoughtcrime.securesms.jobs.FastJobStorage;
import org.thoughtcrime.securesms.jobs.GroupCallUpdateSendJob;
import org.thoughtcrime.securesms.jobs.JobManagerFactories;
@@ -36,7 +29,6 @@ import org.thoughtcrime.securesms.jobs.PushProcessMessageJob;
import org.thoughtcrime.securesms.jobs.PushTextSendJob;
import org.thoughtcrime.securesms.jobs.ReactionSendJob;
import org.thoughtcrime.securesms.jobs.TypingSendJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.megaphone.MegaphoneRepository;
import org.thoughtcrime.securesms.messages.BackgroundMessageRetriever;
import org.thoughtcrime.securesms.messages.IncomingMessageObserver;
@@ -57,23 +49,18 @@ import org.thoughtcrime.securesms.util.EarlyMessageCache;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.FrameRateTracker;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
import org.whispersystems.signalservice.api.util.CredentialsProvider;
import org.whispersystems.signalservice.api.util.SleepTimer;
import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
import org.whispersystems.signalservice.api.websocket.ConnectivityListener;
import java.util.UUID;
import okhttp3.Response;
/**
* Implementation of {@link ApplicationDependencies.Provider} that provides real app dependencies.
*/
@@ -117,6 +104,7 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr
return new SignalServiceMessageSender(provideSignalServiceNetworkAccess().getConfiguration(context),
new DynamicCredentialsProvider(context),
new SignalProtocolStoreImpl(context),
DatabaseSessionLock.INSTANCE,
BuildConfig.SIGNAL_AGENT,
TextSecurePreferences.isMultiDevice(context),
Optional.fromNullable(IncomingMessageObserver.getPipe()),

View File

@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.jobs;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
@@ -26,6 +25,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.database.PushDatabase;
@@ -111,7 +111,11 @@ public final class PushDecryptMessageJob extends BaseJob {
JobManager jobManager = ApplicationDependencies.getJobManager();
try {
List<Job> jobs = handleMessage(envelope);
List<Job> jobs;
try (DatabaseSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
jobs = handleMessage(envelope);
}
for (Job job: jobs) {
jobManager.add(job);
@@ -156,7 +160,7 @@ public final class PushDecryptMessageJob extends BaseJob {
try {
SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context);
SignalServiceAddress localAddress = new SignalServiceAddress(Optional.of(TextSecurePreferences.getLocalUuid(context)), Optional.of(TextSecurePreferences.getLocalNumber(context)));
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, axolotlStore, UnidentifiedAccessUtil.getCertificateValidator());
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, axolotlStore, DatabaseSessionLock.INSTANCE, UnidentifiedAccessUtil.getCertificateValidator());
SignalServiceContent content = cipher.decrypt(envelope);

View File

@@ -9,6 +9,7 @@ import androidx.annotation.StringRes;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@@ -35,12 +36,11 @@ import org.whispersystems.libsignal.state.IdentityKeyStore;
import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.libsignal.state.SessionStore;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
import java.util.List;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
public class IdentityUtil {
private static final String TAG = IdentityUtil.class.getSimpleName();
@@ -147,7 +147,7 @@ public class IdentityUtil {
}
public static void saveIdentity(Context context, String user, IdentityKey identityKey) {
synchronized (SESSION_LOCK) {
try(SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
IdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context);
SessionStore sessionStore = new TextSecureSessionStore(context);
SignalProtocolAddress address = new SignalProtocolAddress(user, 1);
@@ -164,7 +164,7 @@ public class IdentityUtil {
}
public static void processVerifiedMessage(Context context, VerifiedMessage verifiedMessage) {
synchronized (SESSION_LOCK) {
try(SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
Recipient recipient = Recipient.externalPush(context, verifiedMessage.getDestination());
Optional<IdentityRecord> identityRecord = identityDatabase.getIdentity(recipient.getId());

View File

@@ -426,11 +426,11 @@ dependencyVerification {
['org.threeten:threetenbp:1.3.6',
'f4c23ffaaed717c3b99c003e0ee02d6d66377fd47d866fec7d971bd8644fc1a7'],
['org.whispersystems:signal-client-android:0.1.6',
['org.whispersystems:signal-client-android:0.1.7',
'1fade2c159934cd34782474fc4a1010b822e7cd22026ac5da1b25098c99ad6f6'],
['org.whispersystems:signal-client-java:0.1.6',
'34f79d5dd063c70d93570734b6e5649ad6176d9288e6beb382b2d62692e8952c'],
['org.whispersystems:signal-client-java:0.1.7',
'59dd701f9564c2130177ddaca374d14ce54927075955288f85ff8f55565a78f0'],
['pl.tajchert:waitingdots:0.1.0',
'2835d49e0787dbcb606c5a60021ced66578503b1e9fddcd7a5ef0cd5f095ba2c'],