From 581f7630e8761c010809d420ff711317c7cbd565 Mon Sep 17 00:00:00 2001 From: Michelle Tang Date: Fri, 18 Sep 2026 12:26:24 -0400 Subject: [PATCH] Rotate storage service for mentions. --- .../securesms/database/RecipientTable.kt | 15 +++++++ .../securesms/jobs/JobManagerFactories.java | 2 + .../migrations/ApplicationMigrations.java | 7 ++- .../MentionsStorageServiceMigrationJob.kt | 45 +++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/migrations/MentionsStorageServiceMigrationJob.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt index 994ba886f8..2603d0dca8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt @@ -900,6 +900,21 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } } + fun markAllGV2NeedsSync() { + writableDatabase.withinTransaction { db -> + db + .select(ID) + .from(TABLE_NAME) + .where("$TYPE = ? AND $STORAGE_SERVICE_ID NOT NULL", RecipientType.GV2.id) + .run() + .use { cursor -> + while (cursor.moveToNext()) { + rotateStorageId(RecipientId.from(cursor.requireLong(ID))) + } + } + } + } + fun applyStorageIdUpdates(storageIds: Map) { val db = writableDatabase db.beginTransaction() diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java index d0148d639c..e0f473f015 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java @@ -83,6 +83,7 @@ import org.thoughtcrime.securesms.migrations.KeyTransparencyFailureMigrationJob; import org.thoughtcrime.securesms.migrations.KeyTransparencyUsernameMigrationJob; import org.thoughtcrime.securesms.migrations.LegacyMigrationJob; import org.thoughtcrime.securesms.migrations.LocalArchiveReconciliationMigrationJob; +import org.thoughtcrime.securesms.migrations.MentionsStorageServiceMigrationJob; import org.thoughtcrime.securesms.migrations.MigrationCompleteJob; import org.thoughtcrime.securesms.migrations.OptimizeMessageSearchIndexMigrationJob; import org.thoughtcrime.securesms.migrations.PassingMigrationJob; @@ -360,6 +361,7 @@ public final class JobManagerFactories { put(KeyTransparencyUsernameMigrationJob.KEY, new KeyTransparencyUsernameMigrationJob.Factory()); put(LegacyMigrationJob.KEY, new LegacyMigrationJob.Factory()); put(LocalArchiveReconciliationMigrationJob.KEY, new LocalArchiveReconciliationMigrationJob.Factory()); + put(MentionsStorageServiceMigrationJob.KEY, new MentionsStorageServiceMigrationJob.Factory()); put(MigrationCompleteJob.KEY, new MigrationCompleteJob.Factory()); put(OptimizeMessageSearchIndexMigrationJob.KEY, new OptimizeMessageSearchIndexMigrationJob.Factory()); put(PinOptOutMigration.KEY, new PinOptOutMigration.Factory()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java index 7856b3fad9..f59c19fa74 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java @@ -217,9 +217,10 @@ public class ApplicationMigrations { static final int CLEAR_ZK_CREDENTIALS = 172; static final int SVR2_ENCLAVE_UPDATE_7 = 173; static final int DISABLE_UNREAD_REMINDER = 174; + static final int MENTIONS_STORAGE_SERVICE = 175; } - public static final int CURRENT_VERSION = 174; + public static final int CURRENT_VERSION = 175; /** * This *must* be called after the {@link JobManager} has been instantiated, but *before* the call @@ -1006,6 +1007,10 @@ public class ApplicationMigrations { jobs.put(Version.DISABLE_UNREAD_REMINDER, new DisableUnreadReminderMigrationJob()); } + if (lastSeenVersion < Version.MENTIONS_STORAGE_SERVICE) { + jobs.put(Version.MENTIONS_STORAGE_SERVICE, new MentionsStorageServiceMigrationJob()); + } + return jobs; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/MentionsStorageServiceMigrationJob.kt b/app/src/main/java/org/thoughtcrime/securesms/migrations/MentionsStorageServiceMigrationJob.kt new file mode 100644 index 0000000000..a4776b315b --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/MentionsStorageServiceMigrationJob.kt @@ -0,0 +1,45 @@ +package org.thoughtcrime.securesms.migrations + +import org.signal.core.util.logging.Log +import org.signal.core.util.logging.Log.tag +import org.thoughtcrime.securesms.database.SignalDatabase +import org.thoughtcrime.securesms.jobmanager.Job +import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.storage.StorageSyncHelper + +/** + * Rotates the storage service id for every GV2 group to support writing the new mentions setting + */ +internal class MentionsStorageServiceMigrationJob private constructor(parameters: Parameters) : MigrationJob(parameters) { + + companion object { + + const val KEY = "MentionsStorageServiceMigrationJob" + + private val TAG: String = tag(MentionsStorageServiceMigrationJob::class.java) + } + + internal constructor() : this(Parameters.Builder().build()) + + override fun isUiBlocking(): Boolean = false + + override fun getFactoryKey(): String = KEY + + override fun performMigration() { + if (!SignalStore.account.isRegistered || SignalStore.account.aci == null) { + Log.i(TAG, "Unregistered, skipping.") + return + } + + SignalDatabase.recipients.markAllGV2NeedsSync() + StorageSyncHelper.scheduleSyncForDataChange() + } + + override fun shouldRetry(e: Exception): Boolean = false + + class Factory : Job.Factory { + override fun create(parameters: Parameters, serializedData: ByteArray?): MentionsStorageServiceMigrationJob { + return MentionsStorageServiceMigrationJob(parameters) + } + } +}