diff --git a/android/app/src/main/kotlin/org/getlantern/lantern/LanternApp.kt b/android/app/src/main/kotlin/org/getlantern/lantern/LanternApp.kt index 795a1a6834..140b96164b 100644 --- a/android/app/src/main/kotlin/org/getlantern/lantern/LanternApp.kt +++ b/android/app/src/main/kotlin/org/getlantern/lantern/LanternApp.kt @@ -1,12 +1,15 @@ package org.getlantern.lantern +import android.annotation.SuppressLint import android.app.Application import android.content.ClipboardManager import android.content.Context import android.net.ConnectivityManager import android.net.wifi.WifiManager import android.os.PowerManager +import android.util.Log import androidx.core.content.getSystemService +import lantern.io.mobile.Mobile class LanternApp : Application() { @@ -26,5 +29,36 @@ class LanternApp : Application() { } + override fun onCreate() { + super.onCreate() + applyQAEnvOverrides() + } + + private fun applyQAEnvOverrides() { + if (!BuildConfig.DEVELOPMENT_MODE) return + + try { + val outboundSocks = systemProp("debug.lantern.outbound_socks").trim() + val tz = systemProp("debug.lantern.tz").trim() + if (outboundSocks.isEmpty() && tz.isEmpty()) return + + Mobile.setQAEnvOverrides(outboundSocks, tz) + Log.i(TAG, "QA env overrides applied: outbound_socks=$outboundSocks tz=$tz") + } catch (e: Throwable) { + Log.e(TAG, "Failed to apply QA env overrides", e) + } + } + + @SuppressLint("PrivateApi") + private fun systemProp(key: String): String { + return try { + val cls = Class.forName("android.os.SystemProperties") + val m = cls.getMethod("get", String::class.java, String::class.java) + (m.invoke(null, key, "") as? String) ?: "" + } catch (e: Throwable) { + "" + } + } +} -} \ No newline at end of file +private const val TAG = "LanternApp" diff --git a/lantern-core/mobile/mobile.go b/lantern-core/mobile/mobile.go index 99f96df79c..a4216dca7b 100644 --- a/lantern-core/mobile/mobile.go +++ b/lantern-core/mobile/mobile.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "log/slog" + "os" "sync" "sync/atomic" "time" @@ -88,6 +89,23 @@ func getClient() (*ipc.Client, error) { return core.Client(), nil } +// SetQAEnvOverrides applies QA-only environment overrides before Radiance starts. +func SetQAEnvOverrides(outboundSocks, tz string) error { + if outboundSocks != "" { + if err := os.Setenv("RADIANCE_OUTBOUND_SOCKS_ADDRESS", outboundSocks); err != nil { + return fmt.Errorf("set RADIANCE_OUTBOUND_SOCKS_ADDRESS: %w", err) + } + slog.Info("QA env override set", "name", "RADIANCE_OUTBOUND_SOCKS_ADDRESS", "value", outboundSocks) + } + if tz != "" { + if err := os.Setenv("TZ", tz); err != nil { + return fmt.Errorf("set TZ: %w", err) + } + slog.Info("QA env override set", "name", "TZ", "value", tz) + } + return nil +} + // InitLogging wires the global slog handler (file + stdout) before any other // Mobile.* call. On Android the entire app runs in a single process, so once // common.Init runs `slog.SetDefault` covers all Go code — but it normally