android: DNS chain diagnostics run at most once per 10 min instead of on every reconnect; Home probes every 30 s instead of 10 s; a DoT worker closes its TLS connection when it exits

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
DenozordecandClaude Fable 5.2 committed 2026-11-10 10:07:09 +07:00
1 parent 8c5752cfbe
commit a8f32ed7df
3 files changed
+17 -2

No files matched your search

@@ -1134,6 +1134,7 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
{ {
return; return;
} }
sDnsDiagAt = SystemClock.elapsedRealtime();
mDiagExecutor.execute(() -> { mDiagExecutor.execute(() -> {
try try
{ {
@@ -1248,8 +1249,17 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
} }
} }
/* a flapping tunnel must not repeat the probes (three lookups and a TCP
* connect per DoT address) on every reconnect: the radio pays for each */
private static final long DNS_DIAG_MIN_GAP_MS = 10 * 60 * 1000;
private static volatile long sDnsDiagAt;
private void scheduleDnsDiagnostics() private void scheduleDnsDiagnostics()
{ {
if (sDnsDiagAt != 0 && SystemClock.elapsedRealtime() - sDnsDiagAt < DNS_DIAG_MIN_GAP_MS)
{
return;
}
mHandler.removeCallbacks(mDnsDiagRunnable); mHandler.removeCallbacks(mDnsDiagRunnable);
mHandler.postDelayed(mDnsDiagRunnable, DNS_DIAG_DELAY_MS); mHandler.postDelayed(mDnsDiagRunnable, DNS_DIAG_DELAY_MS);
} }
@@ -291,7 +291,11 @@ object SecureDns
{ {
val socket = DatagramSocket(InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0)) val socket = DatagramSocket(InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0))
val executor = ThreadPoolExecutor(WORKERS, WORKERS, 60, TimeUnit.SECONDS, ArrayBlockingQueue(256), val executor = ThreadPoolExecutor(WORKERS, WORKERS, 60, TimeUnit.SECONDS, ArrayBlockingQueue(256),
{ r -> Thread(r, "SecureDns-worker").apply { isDaemon = true } }, ThreadPoolExecutor.DiscardPolicy()) { r ->
/* a worker that times out or is shut down closes its DoT connection,
* otherwise the TLS socket lingers until the garbage collector finds it */
Thread({ try { r.run() } finally { dot.get()?.close(); dot.remove() } }, "SecureDns-worker").apply { isDaemon = true }
}, ThreadPoolExecutor.DiscardPolicy())
executor.allowCoreThreadTimeOut(true) executor.allowCoreThreadTimeOut(true)
server = socket server = socket
serverConfig = config serverConfig = config
@@ -857,7 +857,8 @@ class HomeViewModel(app: Application) : AndroidViewModel(app), VpnStateService.V
companion object companion object
{ {
private const val TRAFFIC_POLL_MS = 1000L private const val TRAFFIC_POLL_MS = 1000L
private const val PROBE_INTERVAL_MS = 10_000L /* 10 s kept the cellular radio out of its idle state for as long as Home was open */
private const val PROBE_INTERVAL_MS = 30_000L
private const val EXIT_REFRESH_MS = 60_000L private const val EXIT_REFRESH_MS = 60_000L
private const val EXIT_TIMEOUT_MS = 5000 private const val EXIT_TIMEOUT_MS = 5000
private const val FASTEST_TIMEOUT_MS = 1500 private const val FASTEST_TIMEOUT_MS = 1500