Trace database methods.

This commit is contained in:
Greyson Parrelli
2020-12-04 18:18:08 -05:00
parent 42d61518b3
commit 831cd2f297
37 changed files with 554 additions and 347 deletions

View File

@@ -34,8 +34,6 @@ import com.bumptech.glide.Glide;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import net.sqlcipher.database.SQLiteDatabase;
import org.json.JSONArray;
import org.json.JSONException;
import org.thoughtcrime.securesms.attachments.Attachment;

View File

@@ -171,7 +171,7 @@ public class DatabaseFactory {
}
public static SQLiteDatabase getBackupDatabase(Context context) {
return getInstance(context).databaseHelper.getReadableDatabase();
return getInstance(context).databaseHelper.getReadableDatabase().getSqlCipherDatabase();
}
public static void upgradeRestored(Context context, SQLiteDatabase database){
@@ -241,7 +241,7 @@ public class DatabaseFactory {
SQLCipherMigrationHelper.migrateCiphertext(context, masterSecret,
legacyOpenHelper.getWritableDatabase(),
databaseHelper.getWritableDatabase(),
databaseHelper.getWritableDatabase().getSqlCipherDatabase(),
listener);
}
}

View File

@@ -8,8 +8,6 @@ import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.tracing.Trace;

View File

@@ -13,8 +13,6 @@ import androidx.annotation.WorkerThread;
import com.annimon.stream.Stream;
import com.google.protobuf.InvalidProtocolBufferException;
import net.sqlcipher.database.SQLiteDatabase;
import org.signal.storageservice.protos.groups.AccessControl;
import org.signal.storageservice.protos.groups.Member;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;

View File

@@ -7,8 +7,6 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.tracing.Trace;

View File

@@ -23,8 +23,6 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.sqlcipher.database.SQLiteDatabase;
import org.greenrobot.eventbus.EventBus;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.database.identity.IdentityRecordList;

View File

@@ -7,8 +7,6 @@ import androidx.annotation.NonNull;
import com.annimon.stream.Stream;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.jobmanager.persistence.ConstraintSpec;
import org.thoughtcrime.securesms.jobmanager.persistence.DependencySpec;

View File

@@ -6,8 +6,6 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet;
import org.thoughtcrime.securesms.tracing.Trace;

View File

@@ -7,8 +7,6 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.recipients.RecipientId;

View File

@@ -6,8 +6,6 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.database.model.MegaphoneRecord;
import org.thoughtcrime.securesms.logging.Log;

View File

@@ -10,8 +10,6 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.recipients.RecipientId;

View File

@@ -12,7 +12,6 @@ import com.annimon.stream.Stream;
import com.google.android.mms.pdu_alt.NotificationInd;
import com.google.protobuf.InvalidProtocolBufferException;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteStatement;
import org.thoughtcrime.securesms.database.documents.Document;

View File

@@ -29,7 +29,6 @@ import com.annimon.stream.Stream;
import com.google.android.mms.pdu_alt.NotificationInd;
import com.google.android.mms.pdu_alt.PduHeaders;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteStatement;
import org.json.JSONArray;

View File

@@ -24,7 +24,6 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteQueryBuilder;
import org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId;

View File

@@ -7,8 +7,6 @@ import android.database.Cursor;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.logging.Log;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.libsignal.InvalidKeyException;

View File

@@ -6,8 +6,6 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.tracing.Trace;

View File

@@ -12,7 +12,6 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import net.sqlcipher.database.SQLiteConstraintException;
import net.sqlcipher.database.SQLiteDatabase;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import org.signal.zkgroup.groups.GroupMasterKey;
@@ -35,7 +34,6 @@ import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.profiles.ProfileName;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;

View File

@@ -6,7 +6,6 @@ import android.content.Context;
import androidx.annotation.NonNull;
import net.sqlcipher.Cursor;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.recipients.RecipientId;

View File

@@ -0,0 +1,332 @@
package org.thoughtcrime.securesms.database;
import android.content.ContentValues;
import androidx.annotation.Nullable;
import com.google.android.gms.vision.Tracker;
import net.sqlcipher.Cursor;
import net.sqlcipher.SQLException;
import net.sqlcipher.database.SQLiteQueryStats;
import net.sqlcipher.database.SQLiteStatement;
import net.sqlcipher.database.SQLiteTransactionListener;
import org.thoughtcrime.securesms.tracing.Tracer;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* This is a wrapper around {@link net.sqlcipher.database.SQLiteDatabase}. There's difficulties
* making a subclass, so instead we just match the interface. Callers should just need to change
* their import statements.
*/
public class SQLiteDatabase {
public static final int CONFLICT_ROLLBACK = 1;
public static final int CONFLICT_ABORT = 2;
public static final int CONFLICT_FAIL = 3;
public static final int CONFLICT_IGNORE = 4;
public static final int CONFLICT_REPLACE = 5;
public static final int CONFLICT_NONE = 0;
private static final String KEY_QUERY = "query";
private static final String KEY_TABLE = "table";
private static final String KEY_THREAD = "thread";
private static final String NAME_LOCK = "LOCK";
private final net.sqlcipher.database.SQLiteDatabase wrapped;
private final Tracer tracer;
public SQLiteDatabase(net.sqlcipher.database.SQLiteDatabase wrapped) {
this.wrapped = wrapped;
this.tracer = Tracer.getInstance();
}
private void traceLockStart() {
tracer.start(NAME_LOCK, Tracer.TrackId.DB_LOCK, KEY_THREAD, Thread.currentThread().getName());
}
private void traceLockEnd() {
tracer.end(NAME_LOCK, Tracer.TrackId.DB_LOCK);
}
private void trace(String methodName, Runnable runnable) {
tracer.start(methodName);
runnable.run();
tracer.end(methodName);
}
private void traceSql(String methodName, String query, boolean locked, Runnable returnable) {
if (locked) {
traceLockStart();
}
tracer.start(methodName, KEY_QUERY, query);
returnable.run();
tracer.end(methodName);
if (locked) {
traceLockEnd();
}
}
private <E> E traceSql(String methodName, String query, boolean locked, Returnable<E> returnable) {
return traceSql(methodName, null, query, locked, returnable);
}
private <E> E traceSql(String methodName, String table, String query, boolean locked, Returnable<E> returnable) {
if (locked) {
traceLockStart();
}
Map<String, String> params = new HashMap<>();
if (query != null) {
params.put(KEY_QUERY, query);
}
if (table != null) {
params.put(KEY_TABLE, table);
}
tracer.start(methodName, params);
E result = returnable.run();
tracer.end(methodName);
if (locked) {
traceLockEnd();
}
return result;
}
public net.sqlcipher.database.SQLiteDatabase getSqlCipherDatabase() {
return wrapped;
}
private interface Returnable<E> {
E run();
}
// =======================================================
// Traced
// =======================================================
public void beginTransaction() {
traceLockStart();
trace("beginTransaction()", wrapped::beginTransaction);
}
public void endTransaction() {
trace("endTransaction()", wrapped::endTransaction);
traceLockEnd();
}
public void setTransactionSuccessful() {
trace("setTransactionSuccessful()", wrapped::setTransactionSuccessful);
}
public Cursor query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) {
return traceSql("query(9)", table, selection, false, () -> wrapped.query(distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit));
}
public Cursor queryWithFactory(net.sqlcipher.database.SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) {
return traceSql("queryWithFactory()", table, selection, false, () -> wrapped.queryWithFactory(cursorFactory, distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit));
}
public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) {
return traceSql("query(7)", table, selection, false, () -> wrapped.query(table, columns, selection, selectionArgs, groupBy, having, orderBy));
}
public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) {
return traceSql("query(8)", table, selection, false, () -> wrapped.query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit));
}
public Cursor rawQuery(String sql, String[] selectionArgs) {
return traceSql("rawQuery(2a)", sql, false, () -> wrapped.rawQuery(sql, selectionArgs));
}
public Cursor rawQuery(String sql, Object[] args) {
return traceSql("rawQuery(2b)", sql, false,() -> wrapped.rawQuery(sql, args));
}
public Cursor rawQueryWithFactory(net.sqlcipher.database.SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable) {
return traceSql("rawQueryWithFactory()", sql, false, () -> wrapped.rawQueryWithFactory(cursorFactory, sql, selectionArgs, editTable));
}
public Cursor rawQuery(String sql, String[] selectionArgs, int initialRead, int maxRead) {
return traceSql("rawQuery(4)", sql, false, () -> rawQuery(sql, selectionArgs, initialRead, maxRead));
}
public long insert(String table, String nullColumnHack, ContentValues values) {
return traceSql("insert()", table, null, true, () -> wrapped.insert(table, nullColumnHack, values));
}
public long insertOrThrow(String table, String nullColumnHack, ContentValues values) throws SQLException {
return traceSql("insertOrThrow()", table, null, true, () -> wrapped.insertOrThrow(table, nullColumnHack, values));
}
public long replace(String table, String nullColumnHack, ContentValues initialValues) {
return traceSql("replace()", table, null, true,() -> wrapped.replace(table, nullColumnHack, initialValues));
}
public long replaceOrThrow(String table, String nullColumnHack, ContentValues initialValues) throws SQLException {
return traceSql("replaceOrThrow()", table, null, true, () -> wrapped.replaceOrThrow(table, nullColumnHack, initialValues));
}
public long insertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, int conflictAlgorithm) {
return traceSql("insertWithOnConflict()", table, null, true, () -> wrapped.insertWithOnConflict(table, nullColumnHack, initialValues, conflictAlgorithm));
}
public int delete(String table, String whereClause, String[] whereArgs) {
return traceSql("delete()", table, whereClause, true, () -> wrapped.delete(table, whereClause, whereArgs));
}
public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
return traceSql("update()", table, whereClause, true, () -> wrapped.update(table, values, whereClause, whereArgs));
}
public int updateWithOnConflict(String table, ContentValues values, String whereClause, String[] whereArgs, int conflictAlgorithm) {
return traceSql("updateWithOnConflict()", table, whereClause, true, () -> wrapped.updateWithOnConflict(table, values, whereClause, whereArgs, conflictAlgorithm));
}
public void execSQL(String sql) throws SQLException {
traceSql("execSQL(1)", sql, true, () -> wrapped.execSQL(sql));
}
public void rawExecSQL(String sql) {
traceSql("rawExecSQL()", sql, true, () -> wrapped.rawExecSQL(sql));
}
public void execSQL(String sql, Object[] bindArgs) throws SQLException {
traceSql("execSQL(2)", sql, true, () -> wrapped.execSQL(sql, bindArgs));
}
// =======================================================
// Ignored
// =======================================================
public boolean enableWriteAheadLogging() {
return wrapped.enableWriteAheadLogging();
}
public void disableWriteAheadLogging() {
wrapped.disableWriteAheadLogging();
}
public boolean isWriteAheadLoggingEnabled() {
return wrapped.isWriteAheadLoggingEnabled();
}
public void setForeignKeyConstraintsEnabled(boolean enable) {
wrapped.setForeignKeyConstraintsEnabled(enable);
}
public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
wrapped.beginTransactionWithListener(transactionListener);
}
public void beginTransactionNonExclusive() {
wrapped.beginTransactionNonExclusive();
}
public void beginTransactionWithListenerNonExclusive(SQLiteTransactionListener transactionListener) {
wrapped.beginTransactionWithListenerNonExclusive(transactionListener);
}
public boolean inTransaction() {
return wrapped.inTransaction();
}
public boolean isDbLockedByCurrentThread() {
return wrapped.isDbLockedByCurrentThread();
}
public boolean isDbLockedByOtherThreads() {
return wrapped.isDbLockedByOtherThreads();
}
public boolean yieldIfContendedSafely() {
return wrapped.yieldIfContendedSafely();
}
public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) {
return wrapped.yieldIfContendedSafely(sleepAfterYieldDelay);
}
public int getVersion() {
return wrapped.getVersion();
}
public void setVersion(int version) {
wrapped.setVersion(version);
}
public long getMaximumSize() {
return wrapped.getMaximumSize();
}
public long setMaximumSize(long numBytes) {
return wrapped.setMaximumSize(numBytes);
}
public long getPageSize() {
return wrapped.getPageSize();
}
public void setPageSize(long numBytes) {
wrapped.setPageSize(numBytes);
}
public SQLiteStatement compileStatement(String sql) throws SQLException {
return wrapped.compileStatement(sql);
}
public SQLiteQueryStats getQueryStats(String sql, Object[] args) {
return wrapped.getQueryStats(sql, args);
}
public boolean isReadOnly() {
return wrapped.isReadOnly();
}
public boolean isOpen() {
return wrapped.isOpen();
}
public boolean needUpgrade(int newVersion) {
return wrapped.needUpgrade(newVersion);
}
public final String getPath() {
return wrapped.getPath();
}
public void setLocale(Locale locale) {
wrapped.setLocale(locale);
}
public boolean isInCompiledSqlCache(String sql) {
return wrapped.isInCompiledSqlCache(sql);
}
public void purgeFromCompiledSqlCache(String sql) {
wrapped.purgeFromCompiledSqlCache(sql);
}
public void resetCompiledSqlCache() {
wrapped.resetCompiledSqlCache();
}
public int getMaxSqlCacheSize() {
return wrapped.getMaxSqlCacheSize();
}
public void setMaxSqlCacheSize(int cacheSize) {
wrapped.setMaxSqlCacheSize(cacheSize);
}
}

View File

@@ -8,7 +8,6 @@ import androidx.annotation.NonNull;
import com.annimon.stream.Stream;
import net.sqlcipher.Cursor;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.tracing.Trace;

View File

@@ -7,8 +7,6 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.RecipientId;

View File

@@ -7,8 +7,6 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.tracing.Trace;

View File

@@ -28,7 +28,6 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import com.google.android.mms.pdu_alt.NotificationInd;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteStatement;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;

View File

@@ -25,7 +25,6 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteStatement;
import org.thoughtcrime.securesms.groups.GroupId;

View File

@@ -9,8 +9,6 @@ import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.sqlcipher.database.SQLiteDatabase;
import org.greenrobot.eventbus.EventBus;
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream;

View File

@@ -7,8 +7,6 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.tracing.Trace;
import org.thoughtcrime.securesms.util.Base64;

View File

@@ -29,8 +29,6 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import com.fasterxml.jackson.annotation.JsonProperty;
import net.sqlcipher.database.SQLiteDatabase;
import org.jsoup.helper.StringUtil;
import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.groups.GroupMasterKey;

View File

@@ -1246,12 +1246,12 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
Log.i(TAG, "Upgrade complete. Took " + (System.currentTimeMillis() - startTime) + " ms.");
}
public SQLiteDatabase getReadableDatabase() {
return getReadableDatabase(databaseSecret.asString());
public org.thoughtcrime.securesms.database.SQLiteDatabase getReadableDatabase() {
return new org.thoughtcrime.securesms.database.SQLiteDatabase(getReadableDatabase(databaseSecret.asString()));
}
public SQLiteDatabase getWritableDatabase() {
return getWritableDatabase(databaseSecret.asString());
public org.thoughtcrime.securesms.database.SQLiteDatabase getWritableDatabase() {
return new org.thoughtcrime.securesms.database.SQLiteDatabase(getWritableDatabase(databaseSecret.asString()));
}
public void markCurrent(SQLiteDatabase db) {