mirror of
https://github.com/therealaleph/MasterHttpRelayVPN-RUST.git
synced 2026-05-19 08:04:39 +03:00
v1.0.2: stable release signature, idempotent Stop, top-level Settings for CA install (#33)
Three fixes + one behaviour change from v1.0.1 reports. APK signature is now stable (release.jks committed) ---------------------------------------------------- v1.0.0 and v1.0.1 signed release APKs with Gradle's auto-generated debug keystore, which is randomly generated per machine and per CI runner. Result: every upgrade failed with INSTALL_FAILED_UPDATE_INCOMPATIBLE and users had to uninstall first. Unfixable without a stable key. android/app/release.jks now holds that key, committed to the repo with the password in plaintext in build.gradle.kts. This is fine for a FOSS sideload project without a Play Store identity — the trust model is "trust the source tree you pulled from," not "trust the key we hold." Anyone forking and shipping a rebranded build should generate their own key. One-time cost: v1.0.1 → v1.0.2 STILL requires uninstall, because we're switching signature keys. Every upgrade from v1.0.2 onward is clean. Stop no longer (sometimes) closes the app ----------------------------------------- teardown() is reachable from three paths on two threads: 1. ACTION_STOP onStartCommand branch (mhrv-teardown worker) 2. onDestroy after stopSelf (main thread) 3. VpnService revocation out-of-band (main thread) Running the full native cleanup sequence twice races the two threads through Tun2proxy.stop() → fd.close() → Native.stopProxy(handle) on state that's already been nullified — SIGSEGV source, user-visible as "tap Stop, app disappears." New AtomicBoolean `tornDown` gates entry: first caller wins, every subsequent caller logs "teardown: already done" and returns. onDestroy also wraps the call in try/catch — crashing out of onDestroy takes the whole process with it, which is exactly the bug we're trying to fix. Smoke-tested on emulator: teardown now logs teardown: begin caller=mhrv-teardown ... clean sequence ... teardown: done onDestroy entered teardown: already done, skipping (caller=main) onDestroy done with PID unchanged throughout. CA install now routes to the Settings search -------------------------------------------- Old flow: `Settings.ACTION_SECURITY_SETTINGS` deep-link, then walk "Encryption & credentials → Install a certificate → CA certificate". That path varies wildly between OEMs (Samsung buries it under "Biometrics and security → Other security settings"; Xiaomi under "Passwords & Security → Privacy"; Pixel splits it between "More security settings" and "Privacy controls" depending on Android version). Users got lost. New flow: open the top-level Settings app (`Settings.ACTION_SETTINGS`) and instruct the user to use the Settings search bar to find "CA certificate". Search is consistent across OEMs and Android versions; the menu paths are not. Dialog, snackbar, and `docs/android.md` copy all updated to match. Version bump: 1.0.1 → 1.0.2 (versionCode 101 → 102). releases/mhrv-rs-android-universal-v1.0.1.apk replaced with the v1.0.2 build. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
b734f41faa
commit
64409f6b41
@@ -14,8 +14,8 @@ android {
|
||||
applicationId = "com.therealaleph.mhrv"
|
||||
minSdk = 24 // Android 7.0 — covers 99%+ of live devices.
|
||||
targetSdk = 34
|
||||
versionCode = 101
|
||||
versionName = "1.0.1"
|
||||
versionCode = 102
|
||||
versionName = "1.0.2"
|
||||
|
||||
// Ship all four mainstream Android ABIs:
|
||||
// - arm64-v8a — 95%+ of real-world Android phones since 2019
|
||||
@@ -30,6 +30,31 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
// Committed keystore — fixed signature across machines and
|
||||
// across CI runs. Using the auto-generated debug keystore
|
||||
// (as v1.0.0 / v1.0.1 did) makes every release APK fail to
|
||||
// install over the previous one with
|
||||
// INSTALL_FAILED_UPDATE_INCOMPATIBLE, because Android treats
|
||||
// a signature change as "different app": the user has to
|
||||
// uninstall first. That's awful UX.
|
||||
//
|
||||
// The password is in plaintext because this is an
|
||||
// open-source project without Play Store identity. A
|
||||
// forked/rebuilt APK signed with a different key is
|
||||
// fundamentally a different install path anyway — the
|
||||
// protection model here is "trust the source tree you
|
||||
// pulled from," not "trust that we hold a key you can't
|
||||
// see." If you're forking, generate your own key, commit
|
||||
// it, and ship.
|
||||
storeFile = file("release.jks")
|
||||
storePassword = "mhrv-rs-release"
|
||||
keyAlias = "mhrv-rs"
|
||||
keyPassword = "mhrv-rs-release"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
@@ -37,15 +62,7 @@ android {
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro",
|
||||
)
|
||||
// Sign release builds with the debug keystore so users can
|
||||
// sideload the APK without us shipping a proper release key.
|
||||
// The project has no Play Store presence, so signature
|
||||
// identity per-build doesn't matter — installability does.
|
||||
// Gradle auto-creates `~/.android/debug.keystore` on first use;
|
||||
// CI runners inherit that behaviour. Anyone rebuilding from
|
||||
// source gets their own signature, which is what we want for
|
||||
// an open-source project: trust the source, not a key we hold.
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user