From 68d4eafeddbf7e3a4d333b9ca390ac41a3f5f06e Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Tue, 17 Dec 2024 13:44:17 -0500 Subject: [PATCH] Fix dangling call ringers. --- .../securesms/database/CallLinkTable.kt | 6 +- .../securesms/database/CallTable.kt | 9 ++- .../helpers/SignalDatabaseMigrations.kt | 6 +- .../migration/V261_RemapCallRingers.kt | 62 +++++++++++++++++++ 4 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V261_RemapCallRingers.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/CallLinkTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/CallLinkTable.kt index c09263081d..fb23cd3810 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/CallLinkTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/CallLinkTable.kt @@ -527,11 +527,7 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database override fun remapRecipient(fromId: RecipientId, toId: RecipientId) { val count = writableDatabase.update(TABLE_NAME) - .values( - contentValuesOf( - RECIPIENT_ID to toId.toLong() - ) - ) + .values(RECIPIENT_ID to toId.toLong()) .where("$RECIPIENT_ID = ?", fromId.toLong()) .run() diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt index 1a20396ff9..79ac9ae5fc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt @@ -1489,13 +1489,18 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl } override fun remapRecipient(fromId: RecipientId, toId: RecipientId) { - val count = writableDatabase + val peerCount = writableDatabase .update(TABLE_NAME) .values(PEER to toId.serialize()) .where("$PEER = ?", fromId) .run() - Log.d(TAG, "Remapped $fromId to $toId. count: $count") + val ringerCount = writableDatabase.update(CallLinkTable.TABLE_NAME) + .values(RINGER to toId.toLong()) + .where("$RINGER = ?", fromId.toLong()) + .run() + + Log.d(TAG, "Remapped $fromId to $toId. peerCount: $peerCount, ringerCount: $ringerCount") } /** diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index 13119aa027..df3bf1de81 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -117,6 +117,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V257_CreateBackupMe import org.thoughtcrime.securesms.database.helpers.migration.V258_FixGroupRevokedInviteeUpdate import org.thoughtcrime.securesms.database.helpers.migration.V259_AdjustNotificationProfileMidnightEndTimes import org.thoughtcrime.securesms.database.helpers.migration.V260_RemapQuoteAuthors +import org.thoughtcrime.securesms.database.helpers.migration.V261_RemapCallRingers /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -236,10 +237,11 @@ object SignalDatabaseMigrations { 257 to V257_CreateBackupMediaSyncTable, 258 to V258_FixGroupRevokedInviteeUpdate, 259 to V259_AdjustNotificationProfileMidnightEndTimes, - 260 to V260_RemapQuoteAuthors + 260 to V260_RemapQuoteAuthors, + 261 to V261_RemapCallRingers ) - const val DATABASE_VERSION = 260 + const val DATABASE_VERSION = 261 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V261_RemapCallRingers.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V261_RemapCallRingers.kt new file mode 100644 index 0000000000..428b56eb87 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V261_RemapCallRingers.kt @@ -0,0 +1,62 @@ +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase +import org.signal.core.util.logging.Log +import org.signal.core.util.readToSingleLong +import org.signal.core.util.select + +/** + * Previously, we weren't properly remapping call ringers when recipients were remapped. This repairs those scenarios the best we can. + */ +@Suppress("ClassName") +object V261_RemapCallRingers : SignalDatabaseMigration { + + private val TAG = Log.tag(V261_RemapCallRingers::class) + private const val TEMP_INDEX = "tmp_call_ringer" + + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + // The following queries are really expensive without an index. So we create a temporary one. + db.execSQL("CREATE INDEX $TEMP_INDEX ON call (ringer)") + try { + doMigration(db) + } finally { + db.execSQL("DROP INDEX IF EXISTS $TEMP_INDEX") + } + } + + private fun doMigration(db: SQLiteDatabase) { + // Even with an index, the updates can be a little expensive, so we try to figure out if we need them at all by using a quick check. + val invalidRingerCount = db + .select("count(*)") + .from("call INDEXED BY $TEMP_INDEX") + .where("ringer != 0 AND ringer NOT IN (SELECT _id FROM recipient)") + .run() + .readToSingleLong() + + if (invalidRingerCount == 0L) { + Log.i(TAG, "No invalid call ringers, can skip migration.") + return + } + + // Remap all call ringers using a remapped recipient + db.execSQL( + """ + UPDATE + call INDEXED BY $TEMP_INDEX + SET + ringer = (SELECT new_id FROM remapped_recipients WHERE old_id = call.ringer) + WHERE + ringer IN (SELECT old_id FROM remapped_recipients) + """ + ) + + // If there are any remaining call ringers that don't reference a real recipient, we have no choice but to delete the call + db.execSQL( + """ + DELETE FROM call INDEXED BY $TEMP_INDEX + WHERE ringer != 0 AND ringer NOT IN (SELECT _id FROM recipient) + """ + ) + } +}