Implement lazy Tor startup and idle shutdown for battery efficiency#10
Merged
Conversation
The in-app diagnostic log reader ran `logcat -v time` with no filter, so it received every log line from every app on the device and scanned each one for the Morganite tag. Started from MainActivity.onStart(), this woke the CPU continuously the whole time the UI was visible. Filter at the logcat level with "Morganite:V *:S" so only relevant lines are ever delivered; the on-screen log panel is unchanged. updateClients() rebuilt OkHttpClient instances on every settings/Tor-status change without releasing the old ones, leaving idle connection pools and dispatcher threads alive (idle sockets keep the radio warm until OkHttp's eviction). Release each distinct replaced client with evictAll() + graceful shutdown(), guarding against the cases where the two clients alias the same instance. https://claude.ai/code/session_01V3TCgA2EBDCaDGAkY6Lzyy
The real background battery drain: CustomHttpServer creates a NostrClient whose RelayPool keeps WebSocket connections alive with an auto-reconnect loop. The downloadFirstEvent accessory used by fetchAuthorServers only closes the REQ subscription, never the socket, so once any cache-miss request carrying an "as=" author hint triggers a lookup, the WebSocket to wss://nostr.land stays open and keeps reconnecting in the background, holding the radio awake indefinitely. Disconnect the client once no author lookup is still in flight (tracked with an AtomicInteger so concurrent lookups share the socket and only the last one tears it down), and also disconnect when the server stops. This keeps the relay connection scoped to actual use instead of leaking it for the process lifetime. https://claude.ai/code/session_01V3TCgA2EBDCaDGAkY6Lzyy
When useTor was enabled, Tor was started at server startup and kept running for the entire lifetime of the foreground service, even with no traffic. The tor daemon keeps the radio awake with circuit and connection padding, periodic directory/consensus fetches and circuit maintenance, so this was the dominant background battery drain whenever the setting was on. Tor here is only used as an outbound SOCKS proxy for fetches (the HTTP server is not exposed as an onion service), so it does not need to run while idle. Bring Tor up lazily via ensureTorReady() only when a request actually routes through it (an .onion URL, useTorForAllUrls, or a nostr author-server lookup), suspending until it bootstraps (STATUS_ON) or a timeout elapses. Track in-flight tor-routed operations with a counter and, once none remain, stop the daemon after a 5 minute idle period. Tor is no longer started eagerly on enable or at server start; it is still torn down immediately when the setting is turned off or the server stops. The only user-visible cost is added latency on the first tor-routed fetch after an idle period while Tor re-bootstraps. https://claude.ai/code/session_01V3TCgA2EBDCaDGAkY6Lzyy
greenart7c3
force-pushed
the
claude/battery-drain-sources-BcWhf
branch
from
June 8, 2026 17:31
d1f2bff to
f2f29e8
Compare
updateClients() is invoked from torStatusReceiver.onReceive, which runs on the main thread. connectionPool.evictAll() closes idle sockets, and closing an SSL socket performs network I/O, so it crashed with NetworkOnMainThreadException — now reliably, because on-demand Tor emits several status broadcasts while it bootstraps. Move the evictAll()/executor shutdown of replaced clients onto the IO scope so no network work happens on the main thread. https://claude.ai/code/session_01V3TCgA2EBDCaDGAkY6Lzyy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR optimizes battery consumption by implementing lazy Tor startup and idle shutdown, along with improved resource cleanup for HTTP clients and Nostr relay connections.
Key Changes
Tor Lifecycle Management
ensureTorReady()method when a tor-routed request is neededscheduleTorIdleStop()torStartMutexto ensure only one caller starts Tor while others wait for the same bootstrapResource Cleanup
evictAll()on connection pools andshutdown()on dispatcher executors, preventing idle socket leaksactiveAuthorLookupsandtorUserscounters to track in-flight operations and coordinate resource cleanupLogcat Filtering
"$TAG:V *:S") at the logcat level to reduce CPU wake-ups by only receiving Morganite-tagged log lines instead of all device logsImplementation Details
ensureTorReady(): Suspends until Tor reaches STATUS_ON or timeout occurs, with mutex-protected startupscheduleTorIdleStop(): Cancels previous idle job and arms a new timer that checks if Tor is still unused before stoppingtryFetchAndSave()andstreamFromServer(): Now suspend functions that manage Tor user counts and ensure Tor is ready before executing blocking operationshttps://claude.ai/code/session_01V3TCgA2EBDCaDGAkY6Lzyy