Restart websocket immediately upon network change.

This commit is contained in:
Nicholas
2023-05-22 14:46:59 -04:00
parent 987f9b9dba
commit 92888778c2
3 changed files with 88 additions and 22 deletions

View File

@@ -3,11 +3,8 @@ package org.thoughtcrime.securesms.messages
import android.annotation.SuppressLint
import android.app.Application
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.os.IBinder
import androidx.annotation.VisibleForTesting
import androidx.core.app.NotificationCompat
@@ -87,10 +84,19 @@ class IncomingMessageObserver(private val context: Application) {
private val decryptionDrainedListeners: MutableList<Runnable> = CopyOnWriteArrayList()
private val keepAliveTokens: MutableMap<String, Long> = mutableMapOf()
private val connectionReceiver: BroadcastReceiver
private val lock: ReentrantLock = ReentrantLock()
private val connectionNecessarySemaphore = Semaphore(0)
private val networkConnectionListener = NetworkConnectionListener(context) { isNetworkAvailable ->
lock.withLock {
if (isNetworkAvailable()) {
Log.w(TAG, "Lost network connection. Shutting down our websocket connections and resetting the drained state.")
decryptionDrained = false
disconnect()
}
connectionNecessarySemaphore.release()
}
}
private val messageContentProcessor = MessageContentProcessorV2(context)
@@ -136,20 +142,7 @@ class IncomingMessageObserver(private val context: Application) {
}
})
connectionReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
lock.withLock {
if (!NetworkConstraint.isMet(context)) {
Log.w(TAG, "Lost network connection. Shutting down our websocket connections and resetting the drained state.")
decryptionDrained = false
disconnect()
}
connectionNecessarySemaphore.release()
}
}
}
context.registerReceiver(connectionReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
networkConnectionListener.register()
}
fun notifyRegistrationChanged() {
@@ -250,8 +243,7 @@ class IncomingMessageObserver(private val context: Application) {
fun terminateAsync() {
Log.w(TAG, "Termination Enqueued! ${this.hashCode()}", Throwable())
INSTANCE_COUNT.decrementAndGet()
context.unregisterReceiver(connectionReceiver)
networkConnectionListener.unregister()
SignalExecutors.BOUNDED.execute {
Log.w(TAG, "Beginning termination. ${this.hashCode()}")
terminated = true

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.messages
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.Network
import android.os.Build
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.util.ServiceUtil
/**
* Backcompat listener for determining when the network connection is lost.
* On API 28+, [onNetworkLost] is invoked when the system notifies the app that the network is lost.
* On earlier versions, [onNetworkLost] is invoked on any network change (gained, lost, losing, etc)
* Therefore, [onNetworkLost] is a higher-order function, which takes a function to determine conditionally if it should run.
* API 28+ only runs on lost networks, so it provides a conditional that's always true because that is guaranteed by the call site.
* Earlier versions use [NetworkConstraint.isMet] to query the current network state upon receiving the broadcast.
*/
class NetworkConnectionListener(private val context: Context, private val onNetworkLost: (() -> Boolean) -> Unit) {
companion object {
private val TAG = Log.tag(NetworkConnectionListener::class.java)
}
private val connectivityManager = ServiceUtil.getConnectivityManager(context)
private val networkChangedCallback: ConnectivityManager.NetworkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onUnavailable() {
super.onUnavailable()
Log.d(TAG, "ConnectivityManager.NetworkCallback onUnavailable()")
onNetworkLost { true }
}
override fun onAvailable(network: Network) {
super.onAvailable(network)
Log.d(TAG, "ConnectivityManager.NetworkCallback onAvailable()")
onNetworkLost { false }
}
override fun onLost(network: Network) {
super.onLost(network)
Log.d(TAG, "ConnectivityManager.NetworkCallback onLost()")
onNetworkLost { true }
}
}
private val connectionReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d(TAG, "BroadcastReceiver onReceive().")
onNetworkLost { !NetworkConstraint.isMet(context) }
}
}
fun register() {
if (Build.VERSION.SDK_INT >= 28) {
connectivityManager.registerDefaultNetworkCallback(networkChangedCallback)
} else {
context.registerReceiver(connectionReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
}
}
fun unregister() {
if (Build.VERSION.SDK_INT >= 28) {
connectivityManager.unregisterNetworkCallback(networkChangedCallback)
} else {
context.unregisterReceiver(connectionReceiver)
}
}
}

View File

@@ -5,8 +5,6 @@ import android.app.Application;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalWebSocket;
import org.whispersystems.signalservice.api.util.Preconditions;