fix: fcm task was not cancelable and cannot remove listeners

This commit is contained in:
jubb 2021-03-03 15:07:37 +11:00
parent d631897a3a
commit 1b417362ae
2 changed files with 519 additions and 464 deletions

View File

@ -29,65 +29,17 @@ import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner; import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.multidex.MultiDexApplication; import androidx.multidex.MultiDexApplication;
import com.google.firebase.iid.FirebaseInstanceId;
import org.conscrypt.Conscrypt; import org.conscrypt.Conscrypt;
import org.session.libsession.messaging.MessagingConfiguration; import org.session.libsession.messaging.MessagingConfiguration;
import org.session.libsession.messaging.avatars.AvatarHelper; import org.session.libsession.messaging.avatars.AvatarHelper;
import org.session.libsession.utilities.SSKEnvironment;
import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier; import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier;
import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWrapper; import org.session.libsession.messaging.threads.Address;
import org.session.libsession.utilities.SSKEnvironment;
import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.Util; import org.session.libsession.utilities.Util;
import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWrapper;
import org.session.libsession.utilities.dynamiclanguage.LocaleParser; import org.session.libsession.utilities.dynamiclanguage.LocaleParser;
import org.signal.aesgcmprovider.AesGcmProvider;
import org.thoughtcrime.securesms.loki.api.SessionProtocolImpl;
import org.thoughtcrime.securesms.sskenvironment.ProfileManager;
import org.thoughtcrime.securesms.sskenvironment.ReadReceiptManager;
import org.thoughtcrime.securesms.sskenvironment.TypingStatusRepository;
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.session.libsession.utilities.preferences.ProfileKeyUtil; import org.session.libsession.utilities.preferences.ProfileKeyUtil;
import org.session.libsession.messaging.threads.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
import org.thoughtcrime.securesms.jobmanager.DependencyInjector;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
import org.thoughtcrime.securesms.jobs.FastJobStorage;
import org.thoughtcrime.securesms.jobs.JobManagerFactories;
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob;
import org.thoughtcrime.securesms.logging.AndroidLogger;
import org.session.libsignal.utilities.logging.Log;
import org.thoughtcrime.securesms.logging.PersistentLogger;
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
import org.thoughtcrime.securesms.loki.api.BackgroundPollWorker;
import org.thoughtcrime.securesms.loki.api.ClosedGroupPoller;
import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager;
import org.thoughtcrime.securesms.loki.api.PublicChatManager;
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol;
import org.thoughtcrime.securesms.loki.utilities.Broadcaster;
import org.thoughtcrime.securesms.loki.utilities.UiModeUtilities;
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.notifications.OptimizedMessageNotifier;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.LocalBackupListener;
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
import org.thoughtcrime.securesms.util.dynamiclanguage.LocaleParseHelper;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.PeerConnectionFactory.InitializationOptions;
import org.webrtc.voiceengine.WebRtcAudioManager;
import org.webrtc.voiceengine.WebRtcAudioUtils;
import org.session.libsignal.service.api.messages.SignalServiceEnvelope; import org.session.libsignal.service.api.messages.SignalServiceEnvelope;
import org.session.libsignal.service.api.util.StreamDetails; import org.session.libsignal.service.api.util.StreamDetails;
import org.session.libsignal.service.internal.push.SignalServiceProtos; import org.session.libsignal.service.internal.push.SignalServiceProtos;
@ -99,6 +51,52 @@ import org.session.libsignal.service.loki.api.fileserver.FileServerAPI;
import org.session.libsignal.service.loki.api.opengroups.PublicChatAPI; import org.session.libsignal.service.loki.api.opengroups.PublicChatAPI;
import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol; import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol;
import org.session.libsignal.service.loki.utilities.mentions.MentionsManager; import org.session.libsignal.service.loki.utilities.mentions.MentionsManager;
import org.session.libsignal.utilities.logging.Log;
import org.signal.aesgcmprovider.AesGcmProvider;
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
import org.thoughtcrime.securesms.jobmanager.DependencyInjector;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
import org.thoughtcrime.securesms.jobs.FastJobStorage;
import org.thoughtcrime.securesms.jobs.JobManagerFactories;
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob;
import org.thoughtcrime.securesms.logging.AndroidLogger;
import org.thoughtcrime.securesms.logging.PersistentLogger;
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
import org.thoughtcrime.securesms.loki.api.BackgroundPollWorker;
import org.thoughtcrime.securesms.loki.api.ClosedGroupPoller;
import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager;
import org.thoughtcrime.securesms.loki.api.PublicChatManager;
import org.thoughtcrime.securesms.loki.api.SessionProtocolImpl;
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol;
import org.thoughtcrime.securesms.loki.utilities.Broadcaster;
import org.thoughtcrime.securesms.loki.utilities.FcmUtils;
import org.thoughtcrime.securesms.loki.utilities.UiModeUtilities;
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.notifications.OptimizedMessageNotifier;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.LocalBackupListener;
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
import org.thoughtcrime.securesms.sskenvironment.ProfileManager;
import org.thoughtcrime.securesms.sskenvironment.ReadReceiptManager;
import org.thoughtcrime.securesms.sskenvironment.TypingStatusRepository;
import org.thoughtcrime.securesms.util.dynamiclanguage.LocaleParseHelper;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.PeerConnectionFactory.InitializationOptions;
import org.webrtc.voiceengine.WebRtcAudioManager;
import org.webrtc.voiceengine.WebRtcAudioUtils;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -110,6 +108,7 @@ import java.util.Set;
import dagger.ObjectGraph; import dagger.ObjectGraph;
import kotlin.Unit; import kotlin.Unit;
import kotlinx.coroutines.Job;
import network.loki.messenger.BuildConfig; import network.loki.messenger.BuildConfig;
import static nl.komponents.kovenant.android.KovenantAndroid.startKovenant; import static nl.komponents.kovenant.android.KovenantAndroid.startKovenant;
@ -117,7 +116,7 @@ import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant;
/** /**
* Will be called once when the TextSecure process is created. * Will be called once when the TextSecure process is created.
* * <p>
* We're using this as an insertion point to patch up the Android PRNG disaster, * We're using this as an insertion point to patch up the Android PRNG disaster,
* to initialize the job manager, and to check for GCM registration freshness. * to initialize the job manager, and to check for GCM registration freshness.
* *
@ -146,6 +145,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
private PublicChatAPI publicChatAPI = null; private PublicChatAPI publicChatAPI = null;
public Broadcaster broadcaster = null; public Broadcaster broadcaster = null;
public SignalCommunicationModule communicationModule; public SignalCommunicationModule communicationModule;
private Job firebaseInstanceIdJob;
private volatile boolean isAppVisible; private volatile boolean isAppVisible;
@ -210,7 +210,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
Log.i(TAG, "App is now visible."); Log.i(TAG, "App is now visible.");
KeyCachingService.onAppForegrounded(this); KeyCachingService.onAppForegrounded(this);
// Loki // Loki
if (poller != null) { poller.setCaughtUp(false); } if (poller != null) {
poller.setCaughtUp(false);
}
startPollingIfNeeded(); startPollingIfNeeded();
publicChatManager.markAllAsNotCaughtUp(); publicChatManager.markAllAsNotCaughtUp();
publicChatManager.startPollersIfNeeded(); publicChatManager.startPollersIfNeeded();
@ -224,9 +226,15 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
KeyCachingService.onAppBackgrounded(this); KeyCachingService.onAppBackgrounded(this);
messageNotifier.setVisibleThread(-1); messageNotifier.setVisibleThread(-1);
// Loki // Loki
if (poller != null) { poller.stopIfNeeded(); } if (poller != null) {
if (closedGroupPoller != null) { closedGroupPoller.stopIfNeeded(); } poller.stopIfNeeded();
if (publicChatManager != null) { publicChatManager.stopPollers(); } }
if (closedGroupPoller != null) {
closedGroupPoller.stopIfNeeded();
}
if (publicChatManager != null) {
publicChatManager.stopPollers();
}
} }
@Override @Override
@ -262,9 +270,13 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
return typingStatusSender; return typingStatusSender;
} }
public ReadReceiptManager getReadReceiptManager() { return readReceiptManager; } public ReadReceiptManager getReadReceiptManager() {
return readReceiptManager;
}
public ProfileManager getProfileManager() { return profileManager; } public ProfileManager getProfileManager() {
return profileManager;
}
public boolean isAppVisible() { public boolean isAppVisible() {
return isAppVisible; return isAppVisible;
@ -275,10 +287,15 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
} }
// Loki // Loki
public @Nullable PublicChatAPI getPublicChatAPI() { public @Nullable
if (publicChatAPI != null || !IdentityKeyUtil.hasIdentityKey(this)) { return publicChatAPI; } PublicChatAPI getPublicChatAPI() {
if (publicChatAPI != null || !IdentityKeyUtil.hasIdentityKey(this)) {
return publicChatAPI;
}
String userPublicKey = TextSecurePreferences.getLocalNumber(this); String userPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userPublicKey== null) { return publicChatAPI; } if (userPublicKey == null) {
return publicChatAPI;
}
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize(); byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this); LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this); LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
@ -414,33 +431,37 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(base, TextSecurePreferences.getLanguage(base))); super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(base, TextSecurePreferences.getLanguage(base)));
} }
private static class ProviderInitializationException extends RuntimeException { } private static class ProviderInitializationException extends RuntimeException {
}
// region Loki // region Loki
public boolean setUpStorageAPIIfNeeded() { public boolean setUpStorageAPIIfNeeded() {
String userPublicKey = TextSecurePreferences.getLocalNumber(this); String userPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userPublicKey == null || !IdentityKeyUtil.hasIdentityKey(this)) { return false; } if (userPublicKey == null || !IdentityKeyUtil.hasIdentityKey(this)) {
return false;
}
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize(); byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
LokiAPIDatabaseProtocol apiDB = DatabaseFactory.getLokiAPIDatabase(this); LokiAPIDatabaseProtocol apiDB = DatabaseFactory.getLokiAPIDatabase(this);
FileServerAPI.Companion.configure(userPublicKey, userPrivateKey, apiDB); FileServerAPI.Companion.configure(userPublicKey, userPrivateKey, apiDB);
return true; return true;
} }
public void registerForFCMIfNeeded(Boolean force) { public void registerForFCMIfNeeded(final Boolean force) {
Context context = this; if (firebaseInstanceIdJob != null && firebaseInstanceIdJob.isActive()) return;
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(task -> { firebaseInstanceIdJob = FcmUtils.getFcmInstanceId(task->{
if (!task.isSuccessful()) { if (!task.isSuccessful()) {
Log.w("Loki", "FirebaseInstanceId.getInstance().getInstanceId() failed." + task.getException()); Log.w("Loki", "FirebaseInstanceId.getInstance().getInstanceId() failed." + task.getException());
return; return Unit.INSTANCE;
} }
String token = task.getResult().getToken(); String token = task.getResult().getToken();
String userPublicKey = TextSecurePreferences.getLocalNumber(context); String userPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userPublicKey == null) return; if (userPublicKey == null) return Unit.INSTANCE;
if (TextSecurePreferences.isUsingFCM(this)) { if (TextSecurePreferences.isUsingFCM(this)) {
LokiPushNotificationManager.register(token, userPublicKey, context, force); LokiPushNotificationManager.register(token, userPublicKey, this, force);
} else { } else {
LokiPushNotificationManager.unregister(token, context); LokiPushNotificationManager.unregister(token, this);
} }
return Unit.INSTANCE;
}); });
} }
@ -468,14 +489,24 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
public void startPollingIfNeeded() { public void startPollingIfNeeded() {
setUpPollingIfNeeded(); setUpPollingIfNeeded();
if (poller != null) { poller.startIfNeeded(); } if (poller != null) {
if (closedGroupPoller != null) { closedGroupPoller.startIfNeeded(); } poller.startIfNeeded();
}
if (closedGroupPoller != null) {
closedGroupPoller.startIfNeeded();
}
} }
public void stopPolling() { public void stopPolling() {
if (poller != null) { poller.stopIfNeeded(); } if (poller != null) {
if (closedGroupPoller != null) { closedGroupPoller.stopIfNeeded(); } poller.stopIfNeeded();
if (publicChatManager != null) { publicChatManager.stopPollers(); } }
if (closedGroupPoller != null) {
closedGroupPoller.stopIfNeeded();
}
if (publicChatManager != null) {
publicChatManager.stopPollers();
}
} }
private void resubmitProfilePictureIfNeeded() { private void resubmitProfilePictureIfNeeded() {
@ -510,7 +541,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
} catch (Exception e) { } catch (Exception e) {
// Do nothing // Do nothing
} }
if (publicChatAPI == null) { return; } if (publicChatAPI == null) {
return;
}
byte[] profileKey = ProfileKeyUtil.getProfileKey(this); byte[] profileKey = ProfileKeyUtil.getProfileKey(this);
String url = TextSecurePreferences.getProfilePictureURL(this); String url = TextSecurePreferences.getProfilePictureURL(this);
Set<String> servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers(); Set<String> servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers();
@ -527,6 +560,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
if (token != null && !token.isEmpty()) { if (token != null && !token.isEmpty()) {
LokiPushNotificationManager.unregister(token, this); LokiPushNotificationManager.unregister(token, this);
} }
if (firebaseInstanceIdJob != null && firebaseInstanceIdJob.isActive()) {
firebaseInstanceIdJob.cancel(null);
}
String displayName = TextSecurePreferences.getProfileName(this); String displayName = TextSecurePreferences.getProfileName(this);
boolean isUsingFCM = TextSecurePreferences.isUsingFCM(this); boolean isUsingFCM = TextSecurePreferences.isUsingFCM(this);
TextSecurePreferences.clearAll(this); TextSecurePreferences.clearAll(this);

View File

@ -0,0 +1,19 @@
@file:JvmName("FcmUtils")
package org.thoughtcrime.securesms.loki.utilities
import com.google.android.gms.tasks.Task
import com.google.firebase.iid.FirebaseInstanceId
import com.google.firebase.iid.InstanceIdResult
import kotlinx.coroutines.*
fun getFcmInstanceId(body: (Task<InstanceIdResult>)->Unit): Job = MainScope().launch(Dispatchers.IO) {
val task = FirebaseInstanceId.getInstance().instanceId
while (!task.isComplete && isActive) {
// wait for task to complete while we are active
}
if (!isActive) return@launch // don't 'complete' task if we were canceled
withContext(Dispatchers.Main) {
body(task)
}
}