From fa5da77484fc5e3e19d46b56eb16cd5be85104cb Mon Sep 17 00:00:00 2001 From: Jamil Date: Wed, 28 Aug 2024 19:11:08 -0700 Subject: [PATCH] fix(android): Record crashlytics exception without crashing (#6475) Instead of causing a NullPointerException, we should be more careful and gracefully handle the case where the TunnelService's session pointer has been cleared, but still record the exception in Crashlytics. This patch also increases the robustness of the link properties DNS list not having valid or useful DNS servers in them, and compacts the list before sending to connlib, instead of potentially sending a JSON array of nulls. ``` Fatal Exception: java.lang.NullPointerException: at NetworkMonitor.onLinkPropertiesChanged(NetworkMonitor.kt:31) at android.net.ConnectivityManager$NetworkCallback.onAvailable(ConnectivityManager.java:4018) at android.net.ConnectivityManager$NetworkCallback.onAvailable(ConnectivityManager.java:3992) at android.net.ConnectivityManager$CallbackHandler.handleMessage(ConnectivityManager.java:4338) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.os.HandlerThread.run(HandlerThread.java:67) ``` This fixes an issue seen by customer where the MDM solution is yanking the TunnelService without graceful shutdown. --- .../dev/firezone/android/tunnel/NetworkMonitor.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/kotlin/android/app/src/main/java/dev/firezone/android/tunnel/NetworkMonitor.kt b/kotlin/android/app/src/main/java/dev/firezone/android/tunnel/NetworkMonitor.kt index fa406a860..8278ccdb4 100644 --- a/kotlin/android/app/src/main/java/dev/firezone/android/tunnel/NetworkMonitor.kt +++ b/kotlin/android/app/src/main/java/dev/firezone/android/tunnel/NetworkMonitor.kt @@ -2,6 +2,8 @@ import android.net.ConnectivityManager import android.net.LinkProperties import android.net.Network +import com.google.firebase.crashlytics.ktx.crashlytics +import com.google.firebase.ktx.Firebase import com.google.gson.Gson import dev.firezone.android.tunnel.ConnlibSession import dev.firezone.android.tunnel.TunnelService @@ -27,13 +29,20 @@ class NetworkMonitor(private val tunnelService: TunnelService) : ConnectivityMan lastDns = linkProperties.dnsServers // Strip the scope id from IPv6 addresses. See https://github.com/firezone/firezone/issues/5781 - val dnsList = linkProperties.dnsServers.map { it.hostAddress!!.split("%")[0] } - ConnlibSession.setDns(tunnelService.connlibSessionPtr!!, Gson().toJson(dnsList)) + val dnsList = + linkProperties.dnsServers.mapNotNull { + it.hostAddress?.split("%")?.getOrNull(0) + } + tunnelService.connlibSessionPtr?.let { + ConnlibSession.setDns(it, Gson().toJson(dnsList)) + } ?: Firebase.crashlytics.recordException(NullPointerException("connlibSessionPtr is null")) } if (lastNetwork != network) { lastNetwork = network - ConnlibSession.reset(tunnelService.connlibSessionPtr!!) + tunnelService.connlibSessionPtr?.let { + ConnlibSession.reset(it) + } ?: Firebase.crashlytics.recordException(NullPointerException("connlibSessionPtr is null")) } // Release mutex lock