2019-07-29 23:02:40 +00:00
package org.thoughtcrime.securesms.migrations ;
import android.content.Context ;
import androidx.annotation.NonNull ;
import androidx.lifecycle.LiveData ;
import androidx.lifecycle.MutableLiveData ;
import org.greenrobot.eventbus.EventBus ;
import org.greenrobot.eventbus.Subscribe ;
import org.greenrobot.eventbus.ThreadMode ;
2020-12-04 23:31:58 +00:00
import org.signal.core.util.logging.Log ;
2019-07-29 23:02:40 +00:00
import org.thoughtcrime.securesms.jobmanager.JobManager ;
2020-12-13 19:44:19 +00:00
import org.thoughtcrime.securesms.keyvalue.SignalStore ;
2020-02-10 20:29:15 +00:00
import org.thoughtcrime.securesms.stickers.BlessedPacks ;
2019-09-05 18:39:18 +00:00
import org.thoughtcrime.securesms.util.TextSecurePreferences ;
2019-07-29 23:02:40 +00:00
import org.thoughtcrime.securesms.util.Util ;
import org.thoughtcrime.securesms.util.VersionTracker ;
2019-09-05 18:39:18 +00:00
import java.util.LinkedHashMap ;
import java.util.Map ;
2019-07-29 23:02:40 +00:00
/ * *
* Manages application - level migrations .
*
* Migrations can be slotted to occur based on changes in the canonical version code
* ( see { @link Util # getCanonicalVersionCode ( ) } ) .
*
* Migrations are performed via { @link MigrationJob } s . These jobs are durable and are run before any
* other job , allowing you to schedule safe migrations . Furthermore , you may specify that a
* migration is UI - blocking , at which point we will show a spinner via
* { @link ApplicationMigrationActivity } if the user opens the app while the migration is in
* progress .
* /
public class ApplicationMigrations {
private static final String TAG = Log . tag ( ApplicationMigrations . class ) ;
private static final MutableLiveData < Boolean > UI_BLOCKING_MIGRATION_RUNNING = new MutableLiveData < > ( ) ;
2019-09-05 18:39:18 +00:00
private static final int LEGACY_CANONICAL_VERSION = 455 ;
2019-07-29 23:02:40 +00:00
private static final class Version {
2021-07-23 20:22:08 +00:00
static final int LEGACY = 1 ;
static final int RECIPIENT_ID = 2 ;
static final int RECIPIENT_SEARCH = 3 ;
static final int RECIPIENT_CLEANUP = 4 ;
static final int AVATAR_MIGRATION = 5 ;
static final int UUIDS = 6 ;
static final int CACHED_ATTACHMENTS = 7 ;
static final int STICKERS_LAUNCH = 8 ;
2021-04-23 18:42:51 +00:00
//static final int TEST_ARGON2 = 9;
2021-07-23 20:22:08 +00:00
static final int SWOON_STICKERS = 10 ;
static final int STORAGE_SERVICE = 11 ;
2021-04-23 18:42:51 +00:00
//static final int STORAGE_KEY_ROTATE = 12;
2021-07-23 20:22:08 +00:00
static final int REMOVE_AVATAR_ID = 13 ;
static final int STORAGE_CAPABILITY = 14 ;
static final int PIN_REMINDER = 15 ;
static final int VERSIONED_PROFILE = 16 ;
static final int PIN_OPT_OUT = 17 ;
static final int TRIM_SETTINGS = 18 ;
static final int THUMBNAIL_CLEANUP = 19 ;
static final int GV2 = 20 ;
static final int GV2_2 = 21 ;
static final int CDS = 22 ;
static final int BACKUP_NOTIFICATION = 23 ;
static final int GV1_MIGRATION = 24 ;
static final int USER_NOTIFICATION = 25 ;
static final int DAY_BY_DAY_STICKERS = 26 ;
static final int BLOB_LOCATION = 27 ;
static final int SYSTEM_NAME_SPLIT = 28 ;
2021-04-08 17:50:50 +00:00
// Versions 29, 30 accidentally skipped
2021-07-23 20:22:08 +00:00
static final int MUTE_SYNC = 31 ;
static final int PROFILE_SHARING_UPDATE = 32 ;
static final int SMS_STORAGE_SYNC = 33 ;
static final int APPLY_UNIVERSAL_EXPIRE = 34 ;
static final int SENDER_KEY = 35 ;
static final int SENDER_KEY_2 = 36 ;
static final int DB_AUTOINCREMENT = 37 ;
static final int ATTACHMENT_CLEANUP = 38 ;
static final int LOG_CLEANUP = 39 ;
static final int ATTACHMENT_CLEANUP_2 = 40 ;
static final int ANNOUNCEMENT_GROUP_CAPABILITY = 41 ;
2021-08-05 15:06:06 +00:00
static final int STICKER_MY_DAILY_LIFE = 42 ;
2021-08-25 20:11:49 +00:00
static final int SENDER_KEY_3 = 43 ;
2021-09-03 21:07:05 +00:00
static final int CHANGE_NUMBER_SYNC = 44 ;
2019-07-29 23:02:40 +00:00
}
2021-08-25 20:11:49 +00:00
public static final int CURRENT_VERSION = 43 ;
2021-07-15 17:17:53 +00:00
2019-07-29 23:02:40 +00:00
/ * *
* This * must * be called after the { @link JobManager } has been instantiated , but * before * the call
* to { @link JobManager # beginJobLoop ( ) } . Otherwise , other non - migration jobs may have started
* executing before we add the migration jobs .
* /
public static void onApplicationCreate ( @NonNull Context context , @NonNull JobManager jobManager ) {
2019-09-05 18:39:18 +00:00
if ( isLegacyUpdate ( context ) ) {
Log . i ( TAG , "Detected the need for a legacy update. Last seen canonical version: " + VersionTracker . getLastSeenVersion ( context ) ) ;
TextSecurePreferences . setAppMigrationVersion ( context , 0 ) ;
}
2019-07-29 23:02:40 +00:00
if ( ! isUpdate ( context ) ) {
Log . d ( TAG , "Not an update. Skipping." ) ;
2020-09-09 14:22:22 +00:00
VersionTracker . updateLastSeenVersion ( context ) ;
2019-07-29 23:02:40 +00:00
return ;
2020-12-13 19:44:19 +00:00
} else {
Log . d ( TAG , "About to update. Clearing deprecation flag." ) ;
SignalStore . misc ( ) . clearClientDeprecated ( ) ;
2019-07-29 23:02:40 +00:00
}
2019-09-05 18:39:18 +00:00
final int lastSeenVersion = TextSecurePreferences . getAppMigrationVersion ( context ) ;
Log . d ( TAG , "currentVersion: " + CURRENT_VERSION + ", lastSeenVersion: " + lastSeenVersion ) ;
2019-07-29 23:02:40 +00:00
2019-09-05 18:39:18 +00:00
LinkedHashMap < Integer , MigrationJob > migrationJobs = getMigrationJobs ( context , lastSeenVersion ) ;
2019-07-29 23:02:40 +00:00
if ( migrationJobs . size ( ) > 0 ) {
Log . i ( TAG , "About to enqueue " + migrationJobs . size ( ) + " migration(s)." ) ;
2019-09-05 18:39:18 +00:00
boolean uiBlocking = true ;
int uiBlockingVersion = lastSeenVersion ;
2019-07-29 23:02:40 +00:00
2019-09-05 18:39:18 +00:00
for ( Map . Entry < Integer , MigrationJob > entry : migrationJobs . entrySet ( ) ) {
int version = entry . getKey ( ) ;
MigrationJob job = entry . getValue ( ) ;
uiBlocking & = job . isUiBlocking ( ) ;
if ( uiBlocking ) {
uiBlockingVersion = version ;
}
2019-07-29 23:02:40 +00:00
jobManager . add ( job ) ;
2019-09-05 18:39:18 +00:00
jobManager . add ( new MigrationCompleteJob ( version ) ) ;
2019-07-29 23:02:40 +00:00
}
2019-09-05 18:39:18 +00:00
if ( uiBlockingVersion > lastSeenVersion ) {
Log . i ( TAG , "Migration set is UI-blocking through version " + uiBlockingVersion + "." ) ;
UI_BLOCKING_MIGRATION_RUNNING . setValue ( true ) ;
} else {
Log . i ( TAG , "Migration set is non-UI-blocking." ) ;
UI_BLOCKING_MIGRATION_RUNNING . setValue ( false ) ;
}
2019-07-29 23:02:40 +00:00
final long startTime = System . currentTimeMillis ( ) ;
2019-09-05 18:39:18 +00:00
final int uiVersion = uiBlockingVersion ;
2019-07-29 23:02:40 +00:00
EventBus . getDefault ( ) . register ( new Object ( ) {
@Subscribe ( sticky = true , threadMode = ThreadMode . MAIN )
public void onMigrationComplete ( MigrationCompleteEvent event ) {
2019-09-05 18:39:18 +00:00
Log . i ( TAG , "Received MigrationCompleteEvent for version " + event . getVersion ( ) + ". (Current: " + CURRENT_VERSION + ")" ) ;
if ( event . getVersion ( ) > CURRENT_VERSION ) {
throw new AssertionError ( "Received a higher version than the current version? App downgrades are not supported. (received: " + event . getVersion ( ) + ", current: " + CURRENT_VERSION + ")" ) ;
}
Log . i ( TAG , "Updating last migration version to " + event . getVersion ( ) ) ;
TextSecurePreferences . setAppMigrationVersion ( context , event . getVersion ( ) ) ;
2019-07-29 23:02:40 +00:00
2019-09-05 18:39:18 +00:00
if ( event . getVersion ( ) = = CURRENT_VERSION ) {
2019-07-29 23:02:40 +00:00
Log . i ( TAG , "Migration complete. Took " + ( System . currentTimeMillis ( ) - startTime ) + " ms." ) ;
EventBus . getDefault ( ) . unregister ( this ) ;
VersionTracker . updateLastSeenVersion ( context ) ;
2019-09-05 18:39:18 +00:00
UI_BLOCKING_MIGRATION_RUNNING . setValue ( false ) ;
} else if ( event . getVersion ( ) > = uiVersion ) {
Log . i ( TAG , "Version is >= the UI-blocking version. Posting 'false'." ) ;
UI_BLOCKING_MIGRATION_RUNNING . setValue ( false ) ;
2019-07-29 23:02:40 +00:00
}
}
} ) ;
} else {
Log . d ( TAG , "No migrations." ) ;
2019-09-05 18:39:18 +00:00
TextSecurePreferences . setAppMigrationVersion ( context , CURRENT_VERSION ) ;
2019-07-29 23:02:40 +00:00
VersionTracker . updateLastSeenVersion ( context ) ;
2019-09-05 18:39:18 +00:00
UI_BLOCKING_MIGRATION_RUNNING . setValue ( false ) ;
2019-07-29 23:02:40 +00:00
}
}
/ * *
* @return A { @link LiveData } object that will update with whether or not a UI blocking migration
* is in progress .
* /
2019-09-05 18:39:18 +00:00
public static LiveData < Boolean > getUiBlockingMigrationStatus ( ) {
2019-07-29 23:02:40 +00:00
return UI_BLOCKING_MIGRATION_RUNNING ;
}
2019-09-05 18:39:18 +00:00
/ * *
* @return True if a UI blocking migration is running .
* /
public static boolean isUiBlockingMigrationRunning ( ) {
Boolean value = UI_BLOCKING_MIGRATION_RUNNING . getValue ( ) ;
return value ! = null & & value ;
}
2019-07-29 23:02:40 +00:00
/ * *
* @return Whether or not we ' re in the middle of an update , as determined by the last seen and
* current version .
* /
2019-09-05 18:39:18 +00:00
public static boolean isUpdate ( @NonNull Context context ) {
return isLegacyUpdate ( context ) | | TextSecurePreferences . getAppMigrationVersion ( context ) < CURRENT_VERSION ;
2019-07-29 23:02:40 +00:00
}
2019-09-05 18:39:18 +00:00
private static LinkedHashMap < Integer , MigrationJob > getMigrationJobs ( @NonNull Context context , int lastSeenVersion ) {
LinkedHashMap < Integer , MigrationJob > jobs = new LinkedHashMap < > ( ) ;
2019-07-29 23:02:40 +00:00
if ( lastSeenVersion < Version . LEGACY ) {
2019-09-05 18:39:18 +00:00
jobs . put ( Version . LEGACY , new LegacyMigrationJob ( ) ) ;
2019-07-29 23:02:40 +00:00
}
2019-08-07 18:22:51 +00:00
if ( lastSeenVersion < Version . RECIPIENT_ID ) {
2019-09-05 18:39:18 +00:00
jobs . put ( Version . RECIPIENT_ID , new DatabaseMigrationJob ( ) ) ;
2019-08-07 18:22:51 +00:00
}
2019-08-26 22:09:01 +00:00
if ( lastSeenVersion < Version . RECIPIENT_SEARCH ) {
2019-09-05 18:39:18 +00:00
jobs . put ( Version . RECIPIENT_SEARCH , new RecipientSearchMigrationJob ( ) ) ;
2019-08-26 22:09:01 +00:00
}
2019-10-02 15:23:21 +00:00
if ( lastSeenVersion < Version . RECIPIENT_CLEANUP ) {
jobs . put ( Version . RECIPIENT_CLEANUP , new DatabaseMigrationJob ( ) ) ;
}
2019-09-23 15:37:01 +00:00
if ( lastSeenVersion < Version . AVATAR_MIGRATION ) {
jobs . put ( Version . AVATAR_MIGRATION , new AvatarMigrationJob ( ) ) ;
}
2019-09-07 03:40:06 +00:00
if ( lastSeenVersion < Version . UUIDS ) {
jobs . put ( Version . UUIDS , new UuidMigrationJob ( ) ) ;
}
2019-11-01 14:03:39 +00:00
if ( lastSeenVersion < Version . CACHED_ATTACHMENTS ) {
jobs . put ( Version . CACHED_ATTACHMENTS , new CachedAttachmentsMigrationJob ( ) ) ;
}
2019-12-13 06:23:32 +00:00
if ( lastSeenVersion < Version . STICKERS_LAUNCH ) {
jobs . put ( Version . STICKERS_LAUNCH , new StickerLaunchMigrationJob ( ) ) ;
}
2020-03-02 15:22:37 +00:00
// This migration only triggered a test we aren't interested in any more.
// if (lastSeenVersion < Version.TEST_ARGON2) {
// jobs.put(Version.TEST_ARGON2, new Argon2TestMigrationJob());
// }
2020-01-15 21:11:41 +00:00
2020-02-10 20:29:15 +00:00
if ( lastSeenVersion < Version . SWOON_STICKERS ) {
jobs . put ( Version . SWOON_STICKERS , new StickerAdditionMigrationJob ( BlessedPacks . SWOON_HANDS , BlessedPacks . SWOON_FACES ) ) ;
}
2020-02-10 18:42:43 +00:00
if ( lastSeenVersion < Version . STORAGE_SERVICE ) {
jobs . put ( Version . STORAGE_SERVICE , new StorageServiceMigrationJob ( ) ) ;
}
2020-04-02 21:09:25 +00:00
// Superceded by StorageCapabilityMigrationJob
// if (lastSeenVersion < Version.STORAGE_KEY_ROTATE) {
// jobs.put(Version.STORAGE_KEY_ROTATE, new StorageKeyRotationMigrationJob());
// }
2020-02-28 18:21:36 +00:00
2020-03-25 22:43:02 +00:00
if ( lastSeenVersion < Version . REMOVE_AVATAR_ID ) {
jobs . put ( Version . REMOVE_AVATAR_ID , new AvatarIdRemovalMigrationJob ( ) ) ;
}
2020-04-02 21:09:25 +00:00
if ( lastSeenVersion < Version . STORAGE_CAPABILITY ) {
jobs . put ( Version . STORAGE_CAPABILITY , new StorageCapabilityMigrationJob ( ) ) ;
}
2020-05-29 22:16:38 +00:00
if ( lastSeenVersion < Version . PIN_REMINDER ) {
jobs . put ( Version . PIN_REMINDER , new PinReminderMigrationJob ( ) ) ;
}
2020-07-07 15:00:29 +00:00
if ( lastSeenVersion < Version . VERSIONED_PROFILE ) {
jobs . put ( Version . VERSIONED_PROFILE , new ProfileMigrationJob ( ) ) ;
}
2020-07-13 12:46:03 +00:00
if ( lastSeenVersion < Version . PIN_OPT_OUT ) {
jobs . put ( Version . PIN_OPT_OUT , new PinOptOutMigration ( ) ) ;
}
2020-09-03 21:52:44 +00:00
if ( lastSeenVersion < Version . TRIM_SETTINGS ) {
jobs . put ( Version . TRIM_SETTINGS , new TrimByLengthSettingsMigrationJob ( ) ) ;
}
2020-09-15 13:27:34 +00:00
if ( lastSeenVersion < Version . THUMBNAIL_CLEANUP ) {
jobs . put ( Version . THUMBNAIL_CLEANUP , new DatabaseMigrationJob ( ) ) ;
}
2020-09-22 20:31:07 +00:00
if ( lastSeenVersion < Version . GV2 ) {
jobs . put ( Version . GV2 , new AttributesMigrationJob ( ) ) ;
}
2020-10-08 00:29:40 +00:00
if ( lastSeenVersion < Version . GV2_2 ) {
jobs . put ( Version . GV2_2 , new AttributesMigrationJob ( ) ) ;
}
2020-10-14 17:43:49 +00:00
if ( lastSeenVersion < Version . CDS ) {
jobs . put ( Version . CDS , new DirectoryRefreshMigrationJob ( ) ) ;
}
2020-10-29 17:32:55 +00:00
if ( lastSeenVersion < Version . BACKUP_NOTIFICATION ) {
jobs . put ( Version . BACKUP_NOTIFICATION , new BackupNotificationMigrationJob ( ) ) ;
}
2020-12-17 22:46:52 +00:00
if ( lastSeenVersion < Version . GV1_MIGRATION ) {
jobs . put ( Version . GV1_MIGRATION , new AttributesMigrationJob ( ) ) ;
}
2021-01-12 03:33:11 +00:00
if ( lastSeenVersion < Version . USER_NOTIFICATION ) {
jobs . put ( Version . USER_NOTIFICATION , new UserNotificationMigrationJob ( ) ) ;
}
2021-01-21 05:11:50 +00:00
if ( lastSeenVersion < Version . DAY_BY_DAY_STICKERS ) {
jobs . put ( Version . DAY_BY_DAY_STICKERS , new StickerDayByDayMigrationJob ( ) ) ;
}
2021-02-11 18:26:12 +00:00
if ( lastSeenVersion < Version . BLOB_LOCATION ) {
jobs . put ( Version . BLOB_LOCATION , new BlobStorageLocationMigrationJob ( ) ) ;
}
2021-03-03 13:37:30 +00:00
if ( lastSeenVersion < Version . SYSTEM_NAME_SPLIT ) {
jobs . put ( Version . SYSTEM_NAME_SPLIT , new DirectoryRefreshMigrationJob ( ) ) ;
}
2021-04-08 17:50:50 +00:00
if ( lastSeenVersion < Version . MUTE_SYNC ) {
jobs . put ( Version . MUTE_SYNC , new StorageServiceMigrationJob ( ) ) ;
}
2021-04-23 18:42:51 +00:00
if ( lastSeenVersion < Version . PROFILE_SHARING_UPDATE ) {
jobs . put ( Version . PROFILE_SHARING_UPDATE , new ProfileSharingUpdateMigrationJob ( ) ) ;
}
2021-05-12 18:58:19 +00:00
if ( lastSeenVersion < Version . SMS_STORAGE_SYNC ) {
jobs . put ( Version . SMS_STORAGE_SYNC , new AccountRecordMigrationJob ( ) ) ;
}
2021-05-18 19:19:33 +00:00
if ( lastSeenVersion < Version . APPLY_UNIVERSAL_EXPIRE ) {
2021-07-15 17:32:29 +00:00
jobs . put ( Version . APPLY_UNIVERSAL_EXPIRE , new ApplyUnknownFieldsToSelfMigrationJob ( ) ) ;
2021-05-18 19:19:33 +00:00
}
2021-05-14 18:03:35 +00:00
if ( lastSeenVersion < Version . SENDER_KEY ) {
jobs . put ( Version . SENDER_KEY , new AttributesMigrationJob ( ) ) ;
}
2021-06-09 13:56:21 +00:00
if ( lastSeenVersion < Version . SENDER_KEY_2 ) {
jobs . put ( Version . SENDER_KEY_2 , new AttributesMigrationJob ( ) ) ;
}
2021-07-15 17:17:53 +00:00
if ( lastSeenVersion < Version . DB_AUTOINCREMENT ) {
jobs . put ( Version . DB_AUTOINCREMENT , new DatabaseMigrationJob ( ) ) ;
}
2021-07-15 17:32:29 +00:00
if ( lastSeenVersion < Version . ATTACHMENT_CLEANUP ) {
jobs . put ( Version . ATTACHMENT_CLEANUP , new AttachmentCleanupMigrationJob ( ) ) ;
}
2021-07-19 22:30:04 +00:00
if ( lastSeenVersion < Version . LOG_CLEANUP ) {
jobs . put ( Version . LOG_CLEANUP , new DeleteDeprecatedLogsMigrationJob ( ) ) ;
}
2021-07-27 17:52:49 +00:00
if ( lastSeenVersion < Version . ATTACHMENT_CLEANUP_2 ) {
jobs . put ( Version . ATTACHMENT_CLEANUP_2 , new AttachmentCleanupMigrationJob ( ) ) ;
}
2021-07-23 20:22:08 +00:00
if ( lastSeenVersion < Version . ANNOUNCEMENT_GROUP_CAPABILITY ) {
jobs . put ( Version . ANNOUNCEMENT_GROUP_CAPABILITY , new AttributesMigrationJob ( ) ) ;
}
2021-08-05 15:06:06 +00:00
if ( lastSeenVersion < Version . STICKER_MY_DAILY_LIFE ) {
jobs . put ( Version . STICKER_MY_DAILY_LIFE , new StickerMyDailyLifeMigrationJob ( ) ) ;
}
2021-08-25 20:11:49 +00:00
if ( lastSeenVersion < Version . SENDER_KEY_3 ) {
jobs . put ( Version . SENDER_KEY_3 , new AttributesMigrationJob ( ) ) ;
}
2021-09-03 21:07:05 +00:00
if ( lastSeenVersion < Version . CHANGE_NUMBER_SYNC ) {
jobs . put ( Version . CHANGE_NUMBER_SYNC , new AccountRecordMigrationJob ( ) ) ;
}
2019-07-29 23:02:40 +00:00
return jobs ;
}
2019-09-05 18:39:18 +00:00
private static boolean isLegacyUpdate ( @NonNull Context context ) {
return VersionTracker . getLastSeenVersion ( context ) < LEGACY_CANONICAL_VERSION ;
}
2019-07-29 23:02:40 +00:00
}