fix: allow devnet url switch from app start intent for qa - #2148
Open
Bilb wants to merge 1 commit into
Open
Conversation
Bilb
force-pushed
the
fix-allow-devnet-switch-no-rebuild
branch
from
August 3, 2026 16:59
7c4d7dc to
539f3ed
Compare
mpretty-cyro
requested changes
Aug 3, 2026
| * them (e.g. `SnodeDirectory.seedNodePool`) are app-scoped singletons that may resolve before or | ||
| * after the first activity is created. Persisting means the value is guaranteed to be in effect on | ||
| * the NEXT launch; callers that need it applied deterministically should force-restart the app after | ||
| * the first launch (which is what the appium harness does). |
Collaborator
There was a problem hiding this comment.
Not sure if this comment relates to some local changes you have but at the moment I don't think Appium does a force-restart - openAndroidApp in open_app.ts it calls await wrappedDevice.createSession(capabilities)
| prefs.setLastSnodePoolRefresh(0L) | ||
| } | ||
|
|
||
| prefs.setSnodePoolSeedMarker(marker) |
Collaborator
There was a problem hiding this comment.
Looks like PathManager persists the onion request paths from previous launches so swapping environments could result in paths from previous launches sticking around (not a huge issue for our use case but might be good to clear it here as well):
private val warmUpJob: Deferred<Unit> = scope.async(start = CoroutineStart.LAZY) {
val persisted = sanitizePaths(storage.getOnionRequestPaths())
_paths.update { current -> if (current.isEmpty()) persisted else current }
}
init {
// persist to DB whenever paths change
scope.launch {
_paths.drop(1).collectLatest { paths ->
try {
if (paths.isEmpty()) storage.clearOnionRequestPaths()
else storage.setOnionRequestPaths(paths)
} catch (e: Exception) {
Log.e("Onion Request", "Failed to persist paths to storage, keeping in-memory only", e)
}
}
}
}
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
Lets QA automation point a build at a different devnet seed / service network via launch
intent extras, instead of requiring an app rebuild per target network.
Android apps can't read the launcher's environment, so this is the Android counterpart of
iOS's
processUnitTestEnvVariablesIfNeeded: the equivalent channel is intent extras on thelaunch activity, which Appium sets with
appium:optionalIntentArguments.Supported extras:
sessionDevnetSeedUrlsessionServiceNetworkmainnet|testnet|devnetHow it works
QaLaunchConfig.apply()runs fromHomeActivity.onCreate, the launcher target via theRoutingActivityalias. It's in the plainonCreateoverload rather thanonCreate(savedInstanceState, ready)because the latter only runs when the base classdidn't route away — so on a fresh install, exactly the automation case, it never fires.
them (
SnodeDirectory.seedNodePool) are app-scoped singletons that may resolve before orafter the first activity. They take effect on the next launch; the harness force-restarts
after the first launch.
SnodeDirectoryrecords a marker identifying the seed configuration each cached snode poolwas fetched from, and discards the pool when that configuration changes. Without this, a
cached pool from the previous network is happily reused and the switch appears to do nothing
until app data is wiped. The marker is also re-checked before persisting a fetched pool, so a
config change racing an in-flight fetch can't leave an old-network pool sitting behind an
already-updated marker.
Security
The launcher alias is
android:exported="true", so any app on the device can start it withextras. Acting on them is gated on
BuildConfig.ALLOW_QA_LAUNCH_CONFIG— a compile-timeconstant, so R8 strips the reader entirely from builds that don't opt in. It defaults to
falseindefaultConfig, isfalseforrelease/releaseWithDebugMenu, andtrueonlyfor
debug/qa/automaticQa. Gating on anything weaker (a runtime pref, a build-type stringcompare) would turn an exported launcher into a way for a third-party app to repoint a release
build's network.
Extras parsing is also hardened against a hostile
Bundle: a caller can reference aParcelable class we don't have, and the unparcel then throws
BadParcelableException, whichuncaught is a remote crash-on-launch for every QA build. A malformed Bundle is logged and
treated as no configuration.
Testing
ALLOW_QA_LAUNCH_CONFIGin the generatedBuildConfigfor all five build types.on the startup path.