diff --git a/android/src/main/java/com/tailscale/ipn/ui/localapi/Client.kt b/android/src/main/java/com/tailscale/ipn/ui/localapi/Client.kt index 5b12338b35..2a30db4e5c 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/localapi/Client.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/localapi/Client.kt @@ -4,6 +4,7 @@ package com.tailscale.ipn.ui.localapi import android.content.Context +import com.tailscale.ipn.App import com.tailscale.ipn.ui.model.BugReportID import com.tailscale.ipn.ui.model.Errors import com.tailscale.ipn.ui.model.Ipn @@ -13,7 +14,6 @@ import com.tailscale.ipn.ui.model.StableNodeID import com.tailscale.ipn.ui.model.Tailcfg import com.tailscale.ipn.ui.util.InputStreamAdapter import com.tailscale.ipn.util.TSLog -import com.tailscale.ipn.App import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -69,9 +69,7 @@ class Client(private val scope: CoroutineScope) { private val TAG = Client::class.simpleName // Access libtailscale.Application lazily - private val app: libtailscale.Application by lazy { - App.get().getLibtailscaleApp() -} + private val app: libtailscale.Application by lazy { App.get().getLibtailscaleApp() } fun start(options: Ipn.Options, responseHandler: (Result) -> Unit) { val body = Json.encodeToString(options).toByteArray() @@ -102,6 +100,14 @@ class Client(private val scope: CoroutineScope) { } fun editPrefs(prefs: Ipn.MaskedPrefs, responseHandler: (Result) -> Unit) { + // Log the stack trace for debugging purposes for + // https://github.com/tailscale/tailscale/issues/14125 + val stackTrace = + Thread.currentThread().stackTrace.joinToString("\n") { element -> + "at ${element.className}.${element.methodName}(${element.fileName}:${element.lineNumber})" + } + TSLog.v("editPrefs", "Called editPrefs with prefs: $prefs\nStack trace:\n$stackTrace") + val body = Json.encodeToString(prefs).toByteArray() return patch(Endpoint.PREFS, body, responseHandler = responseHandler) } diff --git a/android/src/main/java/com/tailscale/ipn/util/TSLog.kt b/android/src/main/java/com/tailscale/ipn/util/TSLog.kt index 4394574fab..c078b064ca 100644 --- a/android/src/main/java/com/tailscale/ipn/util/TSLog.kt +++ b/android/src/main/java/com/tailscale/ipn/util/TSLog.kt @@ -2,12 +2,18 @@ // SPDX-License-Identifier: BSD-3-Clause package com.tailscale.ipn.util +import android.content.Context import android.util.Log import libtailscale.Libtailscale object TSLog { + private lateinit var appContext: Context var libtailscaleWrapper = LibtailscaleWrapper() + fun init(context: Context) { + appContext = context.applicationContext + } + fun d(tag: String?, message: String) { Log.d(tag, message) libtailscaleWrapper.sendLog(tag, message) @@ -18,6 +24,13 @@ object TSLog { libtailscaleWrapper.sendLog(tag, message) } + fun v(tag: String?, message: String) { + if (isUnstableRelease()) { + Log.v(tag, message) + libtailscaleWrapper.sendLog(tag, message) + } + } + // Overloaded function without Throwable because Java does not support default parameters @JvmStatic fun e(tag: String?, message: String) { @@ -35,6 +48,15 @@ object TSLog { } } + private fun isUnstableRelease(): Boolean { + val versionName = + appContext.packageManager.getPackageInfo(appContext.packageName, 0).versionName + + // Extract the middle number and check if it's odd + val middleNumber = versionName.split(".").getOrNull(1)?.toIntOrNull() + return middleNumber?.let { it % 2 == 1 } ?: false + } + class LibtailscaleWrapper { public fun sendLog(tag: String?, message: String) { val logTag = tag ?: ""