diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index 740bdecbc6..e2974ea3a5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -16,12 +16,12 @@ */ package org.thoughtcrime.securesms; -import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.WorkerThread; import androidx.appcompat.app.AppCompatDelegate; import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; @@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.dependencies.ApplicationDependencyProvider; import org.thoughtcrime.securesms.gcm.FcmJobService; +import org.thoughtcrime.securesms.jobmanager.JobManager; import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob; import org.thoughtcrime.securesms.jobs.FcmRefreshJob; import org.thoughtcrime.securesms.jobs.GroupV1MigrationJob; @@ -69,6 +70,7 @@ import org.thoughtcrime.securesms.service.RotateSenderCertificateListener; import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener; import org.thoughtcrime.securesms.service.UpdateApkRefreshListener; import org.thoughtcrime.securesms.storage.StorageSyncHelper; +import org.thoughtcrime.securesms.util.AppStartup; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.SignalUncaughtExceptionHandler; @@ -118,40 +120,42 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi super.onCreate(); - initializeSecurityProvider(); - initializeLogging(); - Log.i(TAG, "onCreate()"); - initializeCrashHandling(); - initializeAppDependencies(); - initializeFirstEverAppLaunch(); - initializeApplicationMigrations(); - initializeMessageRetrieval(); - initializeExpiringMessageManager(); - initializeRevealableMessageManager(); - initializeGcmCheck(); - initializeSignedPreKeyCheck(); - initializePeriodicTasks(); - initializeCircumvention(); - initializeRingRtc(); - initializePendingMessages(); - initializeBlobProvider(); - initializeCleanup(); - initializeGlideCodecs(); - - FeatureFlags.init(); - NotificationChannels.create(this); - RefreshPreKeysJob.scheduleIfNecessary(); - StorageSyncHelper.scheduleRoutineSync(); - RegistrationUtil.maybeMarkRegistrationComplete(this); - ProcessLifecycleOwner.get().getLifecycle().addObserver(this); - - if (Build.VERSION.SDK_INT < 21) { - AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); - } - - ApplicationDependencies.getJobManager().beginJobLoop(); - - DynamicTheme.setDefaultDayNightMode(this); + new AppStartup().addBlocking("security-provider", this::initializeSecurityProvider) + .addBlocking("logging", () -> { + initializeLogging(); + Log.i(TAG, "onCreate()"); + }) + .addBlocking("crash-handling", this::initializeCrashHandling) + .addBlocking("eat-db", () -> DatabaseFactory.getInstance(this)) + .addBlocking("app-dependencies", this::initializeAppDependencies) + .addBlocking("first-launch", this::initializeFirstEverAppLaunch) + .addBlocking("app-migrations", this::initializeApplicationMigrations) + .addBlocking("ring-rtc", this::initializeRingRtc) + .addBlocking("mark-registration", () -> RegistrationUtil.maybeMarkRegistrationComplete(this)) + .addBlocking("lifecycle-observer", () -> ProcessLifecycleOwner.get().getLifecycle().addObserver(this)) + .addBlocking("dynamic-theme", () -> DynamicTheme.setDefaultDayNightMode(this)) + .addBlocking("vector-compat", () -> { + if (Build.VERSION.SDK_INT < 21) { + AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); + } + }) + .addDeferred(this::initializeMessageRetrieval) + .addDeferred(this::initializeExpiringMessageManager) + .addDeferred(this::initializeRevealableMessageManager) + .addDeferred(this::initializeGcmCheck) + .addDeferred(this::initializeSignedPreKeyCheck) + .addDeferred(this::initializePeriodicTasks) + .addDeferred(this::initializeCircumvention) + .addDeferred(this::initializePendingMessages) + .addDeferred(this::initializeBlobProvider) + .addDeferred(this::initializeCleanup) + .addDeferred(this::initializeGlideCodecs) + .addDeferred(FeatureFlags::init) + .addDeferred(() -> NotificationChannels.create(this)) + .addDeferred(RefreshPreKeysJob::scheduleIfNecessary) + .addDeferred(StorageSyncHelper::scheduleRoutineSync) + .addDeferred(() -> ApplicationDependencies.getJobManager().beginJobLoop()) + .execute(); Log.d(TAG, "onCreate() took " + (System.currentTimeMillis() - startTime) + " ms"); Tracer.getInstance().end("Application#onCreate()"); @@ -159,17 +163,24 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi @Override public void onStart(@NonNull LifecycleOwner owner) { + long startTime = System.currentTimeMillis(); isAppVisible = true; Log.i(TAG, "App is now visible."); - FeatureFlags.refreshIfNecessary(); - ApplicationDependencies.getRecipientCache().warmUp(); - RetrieveProfileJob.enqueueRoutineFetchIfNecessary(this); - GroupV1MigrationJob.enqueueRoutineMigrationsIfNecessary(this); - executePendingContactSync(); - KeyCachingService.onAppForegrounded(this); + ApplicationDependencies.getFrameRateTracker().begin(); - ApplicationDependencies.getMegaphoneRepository().onAppForegrounded(); - checkBuildExpiration(); + + SignalExecutors.BOUNDED.execute(() -> { + FeatureFlags.refreshIfNecessary(); + ApplicationDependencies.getRecipientCache().warmUp(); + RetrieveProfileJob.enqueueRoutineFetchIfNecessary(this); + GroupV1MigrationJob.enqueueRoutineMigrationsIfNecessary(this); + executePendingContactSync(); + KeyCachingService.onAppForegrounded(this); + ApplicationDependencies.getMegaphoneRepository().onAppForegrounded(); + checkBuildExpiration(); + }); + + Log.d(TAG, "onStart() took " + (System.currentTimeMillis() - startTime) + " ms"); } @Override @@ -335,17 +346,15 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi } } - @SuppressLint("StaticFieldLeak") + @WorkerThread private void initializeCircumvention() { - SignalExecutors.BOUNDED.execute(() -> { - if (new SignalServiceNetworkAccess(ApplicationContext.this).isCensored(ApplicationContext.this)) { - try { - ProviderInstaller.installIfNeeded(ApplicationContext.this); - } catch (Throwable t) { - Log.w(TAG, t); - } + if (new SignalServiceNetworkAccess(ApplicationContext.this).isCensored(ApplicationContext.this)) { + try { + ProviderInstaller.installIfNeeded(ApplicationContext.this); + } catch (Throwable t) { + Log.w(TAG, t); } - }); + } } private void executePendingContactSync() { @@ -366,17 +375,15 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi } } + @WorkerThread private void initializeBlobProvider() { - SignalExecutors.BOUNDED.execute(() -> { - BlobProvider.getInstance().onSessionStart(this); - }); + BlobProvider.getInstance().onSessionStart(this); } + @WorkerThread private void initializeCleanup() { - SignalExecutors.BOUNDED.execute(() -> { - int deleted = DatabaseFactory.getAttachmentDatabase(this).deleteAbandonedPreuploadedAttachments(); - Log.i(TAG, "Deleted " + deleted + " abandoned attachments."); - }); + int deleted = DatabaseFactory.getAttachmentDatabase(this).deleteAbandonedPreuploadedAttachments(); + Log.i(TAG, "Deleted " + deleted + " abandoned attachments."); } private void initializeGlideCodecs() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/TypingStatusSender.java b/app/src/main/java/org/thoughtcrime/securesms/components/TypingStatusSender.java index f749948fa8..5dab5b8ec3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/TypingStatusSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/TypingStatusSender.java @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.components; import android.annotation.SuppressLint; +import android.app.Application; import android.content.Context; import androidx.annotation.NonNull; @@ -21,11 +22,9 @@ public class TypingStatusSender { private static final long REFRESH_TYPING_TIMEOUT = TimeUnit.SECONDS.toMillis(10); private static final long PAUSE_TYPING_TIMEOUT = TimeUnit.SECONDS.toMillis(3); - private final Context context; private final Map selfTypingTimers; - public TypingStatusSender(@NonNull Context context) { - this.context = context; + public TypingStatusSender() { this.selfTypingTimers = new HashMap<>(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java index 2972706918..c54e0a7789 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -38,7 +38,7 @@ public class DatabaseFactory { private static final Object lock = new Object(); - private static DatabaseFactory instance; + private static volatile DatabaseFactory instance; private final SQLCipherOpenHelper databaseHelper; private final SmsDatabase sms; @@ -67,12 +67,14 @@ public class DatabaseFactory { private final MentionDatabase mentionDatabase; public static DatabaseFactory getInstance(Context context) { - synchronized (lock) { - if (instance == null) - instance = new DatabaseFactory(context.getApplicationContext()); - - return instance; + if (instance == null) { + synchronized (lock) { + if (instance == null) { + instance = new DatabaseFactory(context.getApplicationContext()); + } + } } + return instance; } public static MmsSmsDatabase getMmsSmsDatabase(Context context) { @@ -193,8 +195,8 @@ public class DatabaseFactory { private DatabaseFactory(@NonNull Context context) { SQLiteDatabase.loadLibs(context); - DatabaseSecret databaseSecret = new DatabaseSecretProvider(context).getOrCreateDatabaseSecret(); - AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(); + DatabaseSecret databaseSecret = new DatabaseSecretProvider(context).getOrCreateDatabaseSecret(); + AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(); this.databaseHelper = new SQLCipherOpenHelper(context, databaseSecret); this.sms = new SmsDatabase(context, databaseHelper); diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencies.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencies.java index ff92b7a74f..2ee8306bba 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencies.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencies.java @@ -5,7 +5,6 @@ import android.app.Application; import androidx.annotation.MainThread; import androidx.annotation.NonNull; -import org.signal.core.util.tracing.Tracer; import org.thoughtcrime.securesms.KbsEnclave; import org.thoughtcrime.securesms.components.TypingStatusRepository; import org.thoughtcrime.securesms.components.TypingStatusSender; @@ -24,7 +23,6 @@ import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess; import org.thoughtcrime.securesms.recipients.LiveRecipientCache; import org.thoughtcrime.securesms.service.TrimThreadsByDateManager; import org.thoughtcrime.securesms.util.EarlyMessageCache; -import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.FrameRateTracker; import org.thoughtcrime.securesms.util.Hex; import org.thoughtcrime.securesms.util.IasKeyStore; @@ -47,11 +45,11 @@ public class ApplicationDependencies { private static final Object LOCK = new Object(); private static final Object FRAME_RATE_TRACKER_LOCK = new Object(); + private static final Object JOB_MANAGER_LOCK = new Object(); - private static Application application; - private static Provider provider; - private static MessageNotifier messageNotifier; - private static TrimThreadsByDateManager trimThreadsByDateManager; + private static Application application; + private static Provider provider; + private static MessageNotifier messageNotifier; private static volatile SignalServiceAccountManager accountManager; private static volatile SignalServiceMessageSender messageSender; @@ -70,7 +68,7 @@ public class ApplicationDependencies { private static volatile TypingStatusRepository typingStatusRepository; private static volatile TypingStatusSender typingStatusSender; private static volatile DatabaseObserver databaseObserver; - private static volatile Tracer tracer; + private static volatile TrimThreadsByDateManager trimThreadsByDateManager; @MainThread public static void init(@NonNull Application application, @NonNull Provider provider) { @@ -82,7 +80,6 @@ public class ApplicationDependencies { ApplicationDependencies.application = application; ApplicationDependencies.provider = provider; ApplicationDependencies.messageNotifier = provider.provideMessageNotifier(); - ApplicationDependencies.trimThreadsByDateManager = provider.provideTrimThreadsByDateManager(); } } @@ -222,7 +219,7 @@ public class ApplicationDependencies { public static @NonNull JobManager getJobManager() { if (jobManager == null) { - synchronized (LOCK) { + synchronized (JOB_MANAGER_LOCK) { if (jobManager == null) { jobManager = provider.provideJobManager(); } @@ -285,7 +282,15 @@ public class ApplicationDependencies { } public static @NonNull TrimThreadsByDateManager getTrimThreadsByDateManager() { - return trimThreadsByDateManager; + if (trimThreadsByDateManager == null) { + synchronized (LOCK) { + if (trimThreadsByDateManager == null) { + trimThreadsByDateManager = provider.provideTrimThreadsByDateManager(); + } + } + } + + return trimThreadsByDateManager; } public static TypingStatusRepository getTypingStatusRepository() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java index 3e43bf7de3..f489b3b719 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java @@ -15,10 +15,14 @@ import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseObserver; 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; @@ -140,16 +144,17 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr @Override public @NonNull JobManager provideJobManager() { - return new JobManager(context, new JobManager.Configuration.Builder() - .setDataSerializer(new JsonDataSerializer()) - .setJobFactories(JobManagerFactories.getJobFactories(context)) - .setConstraintFactories(JobManagerFactories.getConstraintFactories(context)) - .setConstraintObservers(JobManagerFactories.getConstraintObservers(context)) - .setJobStorage(new FastJobStorage(DatabaseFactory.getJobDatabase(context))) - .setJobMigrator(new JobMigrator(TextSecurePreferences.getJobManagerVersion(context), JobManager.CURRENT_VERSION, JobManagerFactories.getJobMigrations(context))) - .addReservedJobRunner(new FactoryJobPredicate(PushDecryptMessageJob.KEY, PushProcessMessageJob.KEY, MarkerJob.KEY)) - .addReservedJobRunner(new FactoryJobPredicate(PushTextSendJob.KEY, PushMediaSendJob.KEY, PushGroupSendJob.KEY, ReactionSendJob.KEY, TypingSendJob.KEY, GroupCallUpdateSendJob.KEY)) - .build()); + JobManager.Configuration config = new JobManager.Configuration.Builder() + .setDataSerializer(new JsonDataSerializer()) + .setJobFactories(JobManagerFactories.getJobFactories(context)) + .setConstraintFactories(JobManagerFactories.getConstraintFactories(context)) + .setConstraintObservers(JobManagerFactories.getConstraintObservers(context)) + .setJobStorage(new FastJobStorage(DatabaseFactory.getJobDatabase(context))) + .setJobMigrator(new JobMigrator(TextSecurePreferences.getJobManagerVersion(context), JobManager.CURRENT_VERSION, JobManagerFactories.getJobMigrations(context))) + .addReservedJobRunner(new FactoryJobPredicate(PushDecryptMessageJob.KEY, PushProcessMessageJob.KEY, MarkerJob.KEY)) + .addReservedJobRunner(new FactoryJobPredicate(PushTextSendJob.KEY, PushMediaSendJob.KEY, PushGroupSendJob.KEY, ReactionSendJob.KEY, TypingSendJob.KEY, GroupCallUpdateSendJob.KEY)) + .build(); + return new JobManager(context, config); } @Override @@ -188,7 +193,7 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr @Override public @NonNull TypingStatusSender provideTypingStatusSender() { - return new TypingStatusSender(context); + return new TypingStatusSender(); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java index 0af95b05cb..f2a4180526 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java @@ -8,6 +8,7 @@ import android.telephony.TelephonyManager; import androidx.annotation.NonNull; +import org.signal.core.util.concurrent.SignalExecutors; import org.thoughtcrime.securesms.jobmanager.ConstraintObserver; public class CellServiceConstraintObserver implements ConstraintObserver { @@ -17,11 +18,15 @@ public class CellServiceConstraintObserver implements ConstraintObserver { private volatile Notifier notifier; private volatile ServiceState lastKnownState; - private static CellServiceConstraintObserver instance; + private static volatile CellServiceConstraintObserver instance; - public static synchronized CellServiceConstraintObserver getInstance(@NonNull Application application) { + public static CellServiceConstraintObserver getInstance(@NonNull Application application) { if (instance == null) { - instance = new CellServiceConstraintObserver(application); + synchronized (CellServiceConstraintObserver.class) { + if (instance == null) { + instance = new CellServiceConstraintObserver(application); + } + } } return instance; } @@ -30,7 +35,9 @@ public class CellServiceConstraintObserver implements ConstraintObserver { TelephonyManager telephonyManager = (TelephonyManager) application.getSystemService(Context.TELEPHONY_SERVICE); ServiceStateListener serviceStateListener = new ServiceStateListener(); - telephonyManager.listen(serviceStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); + SignalExecutors.BOUNDED.execute(() -> { + telephonyManager.listen(serviceStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); + }); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/DecryptionsDrainedConstraintObserver.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/DecryptionsDrainedConstraintObserver.java index ebb5ef46a9..4bf7ec54f3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/DecryptionsDrainedConstraintObserver.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/DecryptionsDrainedConstraintObserver.java @@ -13,18 +13,10 @@ public class DecryptionsDrainedConstraintObserver implements ConstraintObserver private static final String REASON = DecryptionsDrainedConstraintObserver.class.getSimpleName(); - private volatile Notifier notifier; - - public DecryptionsDrainedConstraintObserver() { - ApplicationDependencies.getIncomingMessageObserver().addDecryptionDrainedListener(() -> { - if (notifier != null) { - notifier.onConstraintMet(REASON); - } - }); - } - @Override public void register(@NonNull Notifier notifier) { - this.notifier = notifier; + ApplicationDependencies.getIncomingMessageObserver().addDecryptionDrainedListener(() -> { + notifier.onConstraintMet(REASON); + }); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java index 0577e6bb6e..dc3689a4d3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java @@ -173,8 +173,7 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob { public static class Factory implements Job.Factory { @Override - public @NonNull - PushGroupSilentUpdateSendJob create(@NonNull Parameters parameters, @NonNull Data data) { + public @NonNull PushGroupSilentUpdateSendJob create(@NonNull Parameters parameters, @NonNull Data data) { List recipients = RecipientId.fromSerializedList(data.getString(KEY_RECIPIENTS)); int initialRecipientCount = data.getInt(KEY_INITIAL_RECIPIENT_COUNT); long timestamp = data.getLong(KEY_TIMESTAMP); diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java index 67c905597a..89398d5381 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.megaphone; +import android.app.Application; import android.content.Context; import androidx.annotation.AnyThread; @@ -28,14 +29,14 @@ import java.util.concurrent.Executor; */ public class MegaphoneRepository { - private final Context context; + private final Application context; private final Executor executor; private final MegaphoneDatabase database; private final Map databaseCache; private boolean enabled; - public MegaphoneRepository(@NonNull Context context) { + public MegaphoneRepository(@NonNull Application context) { this.context = context; this.executor = SignalExecutors.SERIAL; this.database = DatabaseFactory.getMegaphoneDatabase(context); diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.java b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.java index ca06602c7a..1a9e596a0f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.java @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.messages; +import android.app.Application; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; @@ -47,7 +48,7 @@ public class IncomingMessageObserver { private static SignalServiceMessagePipe pipe = null; private static SignalServiceMessagePipe unidentifiedPipe = null; - private final Context context; + private final Application context; private final SignalServiceNetworkAccess networkAccess; private final List decryptionDrainedListeners; @@ -56,7 +57,7 @@ public class IncomingMessageObserver { private volatile boolean networkDrained; private volatile boolean decryptionDrained; - public IncomingMessageObserver(@NonNull Context context) { + public IncomingMessageObserver(@NonNull Application context) { this.context = context; this.networkAccess = ApplicationDependencies.getSignalServiceNetworkAccess(); this.decryptionDrainedListeners = new CopyOnWriteArrayList<>(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java index 452e78b3ee..f334825161 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.messages; +import android.app.Application; import android.content.Context; import androidx.annotation.NonNull; @@ -27,10 +28,10 @@ public class IncomingMessageProcessor { private static final String TAG = Log.tag(IncomingMessageProcessor.class); - private final Context context; + private final Application context; private final ReentrantLock lock; - public IncomingMessageProcessor(@NonNull Context context) { + public IncomingMessageProcessor(@NonNull Application context) { this.context = context; this.lock = new ReentrantLock(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/AppStartup.java b/app/src/main/java/org/thoughtcrime/securesms/util/AppStartup.java new file mode 100644 index 0000000000..1d5ac649bd --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/util/AppStartup.java @@ -0,0 +1,68 @@ +package org.thoughtcrime.securesms.util; + +import androidx.annotation.NonNull; + +import org.signal.core.util.concurrent.SignalExecutors; +import org.signal.core.util.logging.Log; + +import java.util.LinkedList; +import java.util.List; + +public final class AppStartup { + + private static final String TAG = Log.tag(AppStartup.class); + + private final List blocking; + private final List deferred; + + public AppStartup() { + this.blocking = new LinkedList<>(); + this.deferred = new LinkedList<>(); + } + + public @NonNull + AppStartup addBlocking(@NonNull String name, @NonNull Runnable task) { + blocking.add(new Task(name, task)); + return this; + } + + public @NonNull + AppStartup addDeferred(@NonNull Runnable task) { + deferred.add(new Task("", task)); + return this; + } + + public void execute() { + Stopwatch stopwatch = new Stopwatch("init"); + + for (Task task : blocking) { + task.getRunnable().run(); + stopwatch.split(task.getName()); + } + + for (Task task : deferred) { + SignalExecutors.BOUNDED.execute(task.getRunnable()); + } + + stopwatch.split("schedule-deferred"); + stopwatch.stop(TAG); + } + + private class Task { + private final String name; + private final Runnable runnable; + + protected Task(@NonNull String name, @NonNull Runnable runnable) { + this.name = name; + this.runnable = runnable; + } + + @NonNull String getName() { + return name; + } + + public @NonNull Runnable getRunnable() { + return runnable; + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FrameRateTracker.java b/app/src/main/java/org/thoughtcrime/securesms/util/FrameRateTracker.java index 1ce56e8963..df2e29ae3c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/FrameRateTracker.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FrameRateTracker.java @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.util; +import android.app.Application; import android.content.Context; import android.view.Choreographer; import android.view.Display; @@ -23,7 +24,7 @@ public class FrameRateTracker { private static final int MAX_CONSECUTIVE_FRAME_LOGS = 10; - private final Context context; + private final Application context; private double refreshRate; private long idealTimePerFrameNanos; @@ -33,8 +34,8 @@ public class FrameRateTracker { private long consecutiveFrameWarnings; - public FrameRateTracker(@NonNull Context context) { - this.context = context; + public FrameRateTracker(@NonNull Application application) { + this.context = application; updateRefreshRate(); }