From 6246fea83bcb499b9200931ea9d743ebdbe9e1df Mon Sep 17 00:00:00 2001 From: gmbnt Date: Tue, 24 Mar 2020 11:31:01 +1100 Subject: [PATCH 1/2] Further improve threading --- AndroidManifest.xml | 2 +- .../securesms/ApplicationContext.java | 4 +- ...er.kt => BackgroundOpenGroupPollWorker.kt} | 14 ++--- .../messaging/BackgroundPollWorker.kt | 4 +- .../messaging/LokiPublicChatPoller.kt | 51 +++++++++++-------- .../redesign/messaging/LokiRSSFeedPoller.kt | 3 +- .../securesms/util/TextSecurePreferences.java | 4 +- 7 files changed, 46 insertions(+), 36 deletions(-) rename src/org/thoughtcrime/securesms/loki/redesign/messaging/{BackgroundPublicChatPollWorker.kt => BackgroundOpenGroupPollWorker.kt} (62%) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7709ebc715..bfa2c456dc 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -666,7 +666,7 @@ - + diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 3bf81018ac..d4ee2c93c6 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -64,7 +64,7 @@ import org.thoughtcrime.securesms.loki.LokiPublicChatManager; import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity; import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPollWorker; -import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPublicChatPollWorker; +import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundOpenGroupPollWorker; import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIDatabase; import org.thoughtcrime.securesms.loki.redesign.messaging.LokiRSSFeedPoller; import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase; @@ -355,7 +355,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc LocalBackupListener.schedule(this); RotateSenderCertificateListener.schedule(this); BackgroundPollWorker.schedule(this); // Session - BackgroundPublicChatPollWorker.schedule(this); // Session + BackgroundOpenGroupPollWorker.schedule(this); // Session if (BuildConfig.PLAY_STORE_DISABLED) { UpdateApkRefreshListener.schedule(this); diff --git a/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPublicChatPollWorker.kt b/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundOpenGroupPollWorker.kt similarity index 62% rename from src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPublicChatPollWorker.kt rename to src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundOpenGroupPollWorker.kt index 130122c492..197a9812a8 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPublicChatPollWorker.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundOpenGroupPollWorker.kt @@ -7,32 +7,32 @@ import org.thoughtcrime.securesms.service.PersistentAlarmManagerListener import org.thoughtcrime.securesms.util.TextSecurePreferences import java.util.concurrent.TimeUnit -class BackgroundPublicChatPollWorker : PersistentAlarmManagerListener() { +class BackgroundOpenGroupPollWorker : PersistentAlarmManagerListener() { companion object { private val pollInterval = TimeUnit.MINUTES.toMillis(4) @JvmStatic fun schedule(context: Context) { - BackgroundPublicChatPollWorker().onReceive(context, Intent()) + BackgroundOpenGroupPollWorker().onReceive(context, Intent()) } } override fun getNextScheduledExecutionTime(context: Context): Long { - return TextSecurePreferences.getPublicChatBackgroundPollTime(context) + return TextSecurePreferences.getOpenGroupBackgroundPollTime(context) } override fun onAlarm(context: Context, scheduledTime: Long): Long { if (scheduledTime != 0L) { - val publicChats = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats().map { it.value } - for (publicChat in publicChats) { - val poller = LokiPublicChatPoller(context, publicChat) + val openGroups = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats().map { it.value } + for (openGroup in openGroups) { + val poller = LokiPublicChatPoller(context, openGroup) poller.stop() poller.pollForNewMessages() } } val nextTime = System.currentTimeMillis() + pollInterval - TextSecurePreferences.setPublicChatBackgroundPollTime(context, nextTime) + TextSecurePreferences.setOpenGroupBackgroundPollTime(context, nextTime) return nextTime } } diff --git a/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt b/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt index 184e11d585..4b8fdc9037 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt @@ -32,7 +32,9 @@ class BackgroundPollWorker : PersistentAlarmManagerListener() { val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context) try { - LokiAPI(userHexEncodedPublicKey, lokiAPIDatabase, (context.applicationContext as ApplicationContext).broadcaster).getMessages().map { messages -> + val applicationContext = context.applicationContext as ApplicationContext + val broadcaster = applicationContext.broadcaster + LokiAPI(userHexEncodedPublicKey, lokiAPIDatabase, broadcaster).getMessages().map { messages -> messages.forEach { PushContentReceiveJob(context).processEnvelope(SignalServiceEnvelope(it)) } diff --git a/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiPublicChatPoller.kt b/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiPublicChatPoller.kt index 71b0e766e1..1d98b3e761 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiPublicChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiPublicChatPoller.kt @@ -23,7 +23,6 @@ import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptM import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.loki.api.* import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus -import org.whispersystems.signalservice.loki.utilities.successBackground import java.security.MessageDigest import java.util.* @@ -70,6 +69,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki } private val pollForDisplayNamesTask = object : Runnable { + override fun run() { pollForDisplayNames() handler.postDelayed(this, pollForDisplayNamesInterval) @@ -217,6 +217,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() val database = DatabaseFactory.getLokiAPIDatabase(context) LokiFileServerAPI.configure(false, userHexEncodedPublicKey, userPrivateKey, database) + // Kovenant propagates a context to chained promises, so LokiPublicChatAPI.sharedContext should be used for all of the below LokiDeviceLinkUtilities.getAllLinkedDeviceHexEncodedPublicKeys(userHexEncodedPublicKey).bind(LokiPublicChatAPI.sharedContext) { devices -> userDevices = devices api.getMessages(group.channel, group.server) @@ -235,22 +236,24 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki } } Promise.of(messages) - }.successBackground { + }.success { val newDisplayNameUpdatees = uniqueDevices.mapNotNull { // This will return null if the current device is a master device LokiDeviceLinkUtilities.getMasterHexEncodedPublicKey(it).get() }.toSet() // Fetch the display names of the master devices displayNameUpdatees = displayNameUpdatees.union(newDisplayNameUpdatees) - }.successBackground { messages -> + }.success { messages -> // Process messages in the background - messages.forEach { message -> - if (userDevices.contains(message.hexEncodedPublicKey)) { - processOutgoingMessage(message) - } else { - processIncomingMessage(message) + Thread { + messages.forEach { message -> + if (userDevices.contains(message.hexEncodedPublicKey)) { + processOutgoingMessage(message) + } else { + processIncomingMessage(message) + } } - } + }.start() }.fail { Log.d("Loki", "Failed to get messages for group chat with ID: ${group.channel} on server: ${group.server}.") } @@ -260,11 +263,13 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki if (displayNameUpdatees.isEmpty()) { return } val hexEncodedPublicKeys = displayNameUpdatees displayNameUpdatees = setOf() - api.getDisplayNames(hexEncodedPublicKeys, group.server).successBackground { mapping -> - for (pair in mapping.entries) { - val senderDisplayName = "${pair.value} (...${pair.key.takeLast(8)})" - DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, pair.key, senderDisplayName) - } + api.getDisplayNames(hexEncodedPublicKeys, group.server).success { mapping -> + Thread { + for (pair in mapping.entries) { + val senderDisplayName = "${pair.value} (...${pair.key.takeLast(8)})" + DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, pair.key, senderDisplayName) + } + }.start() }.fail { displayNameUpdatees = displayNameUpdatees.union(hexEncodedPublicKeys) } @@ -272,14 +277,16 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki private fun pollForDeletedMessages() { api.getDeletedMessageServerIDs(group.channel, group.server).success { deletedMessageServerIDs -> - val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) - val deletedMessageIDs = deletedMessageServerIDs.mapNotNull { lokiMessageDatabase.getMessageID(it) } - val smsMessageDatabase = DatabaseFactory.getSmsDatabase(context) - val mmsMessageDatabase = DatabaseFactory.getMmsDatabase(context) - deletedMessageIDs.forEach { - smsMessageDatabase.deleteMessage(it) - mmsMessageDatabase.delete(it) - } + Thread { + val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) + val deletedMessageIDs = deletedMessageServerIDs.mapNotNull { lokiMessageDatabase.getMessageID(it) } + val smsMessageDatabase = DatabaseFactory.getSmsDatabase(context) + val mmsMessageDatabase = DatabaseFactory.getMmsDatabase(context) + deletedMessageIDs.forEach { + smsMessageDatabase.deleteMessage(it) + mmsMessageDatabase.delete(it) + } + }.start() }.fail { Log.d("Loki", "Failed to get deleted messages for group chat with ID: ${group.channel} on server: ${group.server}.") } diff --git a/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiRSSFeedPoller.kt b/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiRSSFeedPoller.kt index b45ce47ade..c8ac9bb5fb 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiRSSFeedPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiRSSFeedPoller.kt @@ -25,6 +25,7 @@ class LokiRSSFeedPoller(private val context: Context, private val feed: LokiRSSF private var hasStarted = false private val task = object : Runnable { + override fun run() { poll() handler.postDelayed(this, interval) @@ -69,7 +70,7 @@ class LokiRSSFeedPoller(private val context: Context, private val feed: LokiRSSF PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.absent()) } }.fail { exception -> - Log.d("Loki", "Couldn't update RSS feed with ID: $feed.id. $exception") + Log.d("Loki", "Couldn't update RSS feed with ID: $feed.id due to exception: $exception.") } } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 7229a8ef0f..42c204dfbb 100644 --- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -1185,11 +1185,11 @@ public class TextSecurePreferences { setLongPreference(context, "background_poll_time", backgroundPollTime); } - public static long getPublicChatBackgroundPollTime(Context context) { + public static long getOpenGroupBackgroundPollTime(Context context) { return getLongPreference(context, "public_chat_background_poll_time", 0L); } - public static void setPublicChatBackgroundPollTime(Context context, long backgroundPollTime) { + public static void setOpenGroupBackgroundPollTime(Context context, long backgroundPollTime) { setLongPreference(context, "public_chat_background_poll_time", backgroundPollTime); } From 16f207b7856aba179fd05d174b18f147123bc0a0 Mon Sep 17 00:00:00 2001 From: gmbnt Date: Tue, 24 Mar 2020 13:48:23 +1100 Subject: [PATCH 2/2] Ditch long polling --- .../securesms/ApplicationContext.java | 26 +++++++++---------- .../loki/redesign/activities/HomeActivity.kt | 2 +- .../redesign/activities/LandingActivity.kt | 3 +-- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index d4ee2c93c6..0687981f55 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -63,8 +63,8 @@ import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger; import org.thoughtcrime.securesms.loki.LokiPublicChatManager; import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity; -import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPollWorker; import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundOpenGroupPollWorker; +import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPollWorker; import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIDatabase; import org.thoughtcrime.securesms.loki.redesign.messaging.LokiRSSFeedPoller; import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase; @@ -94,9 +94,9 @@ import org.whispersystems.signalservice.api.util.StreamDetails; import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol; import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; -import org.whispersystems.signalservice.loki.api.LokiLongPoller; import org.whispersystems.signalservice.loki.api.LokiP2PAPI; import org.whispersystems.signalservice.loki.api.LokiP2PAPIDelegate; +import org.whispersystems.signalservice.loki.api.LokiPoller; import org.whispersystems.signalservice.loki.api.LokiPublicChat; import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI; import org.whispersystems.signalservice.loki.api.LokiRSSFeed; @@ -140,7 +140,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc private PersistentLogger persistentLogger; // Loki - private LokiLongPoller lokiLongPoller = null; + private LokiPoller lokiPoller = null; private LokiRSSFeedPoller lokiNewsFeedPoller = null; private LokiRSSFeedPoller lokiMessengerUpdatesFeedPoller = null; private LokiPublicChatManager lokiPublicChatManager = null; @@ -205,8 +205,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc Log.i(TAG, "App is now visible."); executePendingContactSync(); KeyCachingService.onAppForegrounded(this); - // Loki - Start long polling if needed - startLongPollingIfNeeded(); + // Loki - Start polling if needed + startPollingIfNeeded(); // Loki - Start open group polling if needed lokiPublicChatManager.startPollersIfNeeded(); } @@ -217,8 +217,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc Log.i(TAG, "App is no longer visible."); KeyCachingService.onAppBackgrounded(this); MessageNotifier.setVisibleThread(-1); - // Loki - Stop long polling if needed - if (lokiLongPoller != null) { lokiLongPoller.stopIfNeeded(); } + // Loki - Stop polling if needed + if (lokiPoller != null) { lokiPoller.stopIfNeeded(); } if (lokiPublicChatManager != null) { lokiPublicChatManager.stopPollers(); } } @@ -458,13 +458,13 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc // TODO: Implement } - private void setUpLongPollingIfNeeded() { - if (lokiLongPoller != null) return; + private void setUpPollingIfNeeded() { + if (lokiPoller != null) return; String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this); if (userHexEncodedPublicKey == null) return; LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(this); Context context = this; - lokiLongPoller = new LokiLongPoller(userHexEncodedPublicKey, lokiAPIDatabase, broadcaster, protos -> { + lokiPoller = new LokiPoller(userHexEncodedPublicKey, lokiAPIDatabase, broadcaster, protos -> { for (SignalServiceProtos.Envelope proto : protos) { new PushContentReceiveJob(context).processEnvelope(new SignalServiceEnvelope(proto)); } @@ -472,9 +472,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc }); } - public void startLongPollingIfNeeded() { - setUpLongPollingIfNeeded(); - if (lokiLongPoller != null) { lokiLongPoller.startIfNeeded(); } + public void startPollingIfNeeded() { + setUpPollingIfNeeded(); + if (lokiPoller != null) { lokiPoller.startIfNeeded(); } } private LokiRSSFeed lokiNewsFeed() { diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/HomeActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/HomeActivity.kt index cb1841060c..7e99a11ac7 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/HomeActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/HomeActivity.kt @@ -78,7 +78,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe } } // Double check that the long poller is up - (applicationContext as ApplicationContext).startLongPollingIfNeeded() + (applicationContext as ApplicationContext).startPollingIfNeeded() // Set content view setContentView(R.layout.activity_home) // Set custom toolbar diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt index 130646d4fa..8744131638 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt @@ -27,7 +27,6 @@ import org.whispersystems.libsignal.ecc.Curve import org.whispersystems.libsignal.ecc.ECKeyPair import org.whispersystems.libsignal.util.KeyHelper import org.whispersystems.signalservice.loki.api.DeviceLink -import org.whispersystems.signalservice.loki.api.LokiFileServerAPI import org.whispersystems.signalservice.loki.utilities.hexEncodedPublicKey import org.whispersystems.signalservice.loki.utilities.retryIfNeeded @@ -100,7 +99,7 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega return Toast.makeText(application, "Couldn't link device.", Toast.LENGTH_LONG).show() } val application = ApplicationContext.getInstance(this) - application.startLongPollingIfNeeded() + application.startPollingIfNeeded() application.setUpP2PAPI() application.setUpStorageAPIIfNeeded() val linkDeviceDialog = LinkDeviceSlaveModeDialog()