Skip to content

K2GO-404 feat(networkpolicy): gate non-REST egress (rootfs, OTA) + fold internet readers - #567

Merged
luisguzman-adfa merged 5 commits into
mainfrom
feat/K2GO-404-metered-gate-non-rest-egress
Sep 17, 2026
Merged

luisguzman-adfa merged 5 commits into
mainfrom
feat/K2GO-404-metered-gate-non-rest-egress

Conversation

@luisguzman-adfa

Copy link
Copy Markdown
Collaborator

What

Extends the K2GO-395 metered cost-consent gate to the non-REST heavy-download egress.

  • Rootfs install (aria2: rootfs image + proot-distro base): gated at the wizard commit
    SetupLibraryActivity.startWizardInstall, wrapping the whole commit (InstallGuard marker
    • service start + navigation) so a decline plants no marker. Covers fresh install and
      reinstall -- both funnel through this commit.
  • OTA APK update (UpdateController): prompt at the DownloadManager enqueue (an Activity is
    present, so a prompt beats a silent setAllowedOverMetered(false)).
  • Portal APK / PDF: NOT gated -- the WebView DownloadListener only serves local box files
    (internal host), never metered internet egress.
  • Fold: AndroidNetworkClassifier is now the single ConnectivityManager reader via
    hasInternet and hasValidatedInternet (the latter keeps NET_CAPABILITY_VALIDATED);
    DashboardRebuild.hasInternet and InstallService.hasValidatedInternet are removed and
    their callers routed.

Why

Follow-up to K2GO-395: the largest transfers (a rootfs image, an OTA APK) must not spend a
metered plan without consent.

Verification

  • Compile and domain unit tests green.
  • Device (OnePlus over a metered Samsung hotspot): the rootfs gate fires at the wizard
    Continue on the reinstall path; "Not now" aborts with no InstallGuard marker and no
    navigation; "Continue on data" proceeds.
  • OTA: the same guardHeavyStart mechanism proven in K2GO-395; the enqueue wrap is verified
    by review.
  • Two code-review passes; findings fixed.

Follow-up (second PR, K2GO-404)

The wizard/system-install maps path needs an orchestrator "waiting for network" state (a
MapsProvisioner.drain refusal is terminal today), so it lands separately.

Note: a null ConnectivityManager now reads as no internet (was "unknown -> true" in
DashboardRebuild) -- an edge effectively never hit; failing closed is safe.

The wizard install downloads the rootfs image and the proot-distro base over aria2
(internet). It started with no cost prompt. Wrap SetupLibraryActivity.startWizardInstall
in NetworkPolicyGate.guardHeavyStart: the gate covers the whole commit -- the
InstallGuard marker, the service start and the navigation -- so a decline plants no
marker and does not navigate to the boot gate (a marker with no install behind it would
send the next launch into recovery). Decline/offline resets the installStarting debounce
so the user can retry after moving to Wi-Fi. In-flight resume on a returning network is
handled headless by InstallService.onValidatedNetworkReturned, not re-prompted; a gate at
the headless aria2 start would have no Activity for the dialog, so the UI commit is the
seam (mirrors startZimDownload / openMapsIndex).
… cost

The OTA APK is an internet download enqueued through DownloadManager with no cost check.
An Activity is present in UpdateController, so prompt via NetworkPolicyGate.guardHeavyStart
at the enqueue (consistent with the other seams) rather than a silent
setAllowedOverMetered(false): on consent (or Wi-Fi) it enqueues, on decline it does not
start and the user keeps the existing build. Portal APK/PDF downloads are NOT gated -- the
WebView DownloadListener only serves local box files (internal host), never metered egress.
…AndroidNetworkClassifier

There were three ConnectivityManager readers for "what is the network". Make
AndroidNetworkClassifier the single reader: add hasInternet (classify != NONE) and
hasValidatedInternet (adds NET_CAPABILITY_VALIDATED, load-bearing for the install
resume's captive-portal avoidance). Remove DashboardRebuild.hasInternet and
InstallService.hasValidatedInternet and route their callers here. One behavior delta:
a null ConnectivityManager now reads as no internet (was "unknown -> true" in
DashboardRebuild), an edge effectively never hit -- failing closed is safe. Removes the
now-unused android.net imports from InstallService.
…-395

Record what K2GO-404's first PR gates (rootfs aria2 at startWizardInstall; OTA at the
enqueue), why portal APK/PDF are exempt (local box files, never metered), and the
hasInternet fold with its null-ConnectivityManager delta. Note the remaining second PR:
the wizard/system-install maps path, which needs an orchestrator "waiting for network"
state because a MapsProvisioner.drain refusal is terminal (mapsStartFailed) today.
The seam comments over-explained. Keep the non-obvious why (the InstallGuard
marker -> recovery reason, the NET_CAPABILITY_VALIDATED reason, the cm==null
delta) and drop the narrative; remove the "moved to ..." markers left where the
folded methods were (the fold is documented on AndroidNetworkClassifier).
@luisguzman-adfa
luisguzman-adfa merged commit 731a7a2 into main Sep 17, 2026
3 checks passed
@luisguzman-adfa
luisguzman-adfa deleted the feat/K2GO-404-metered-gate-non-rest-egress branch September 17, 2026 04:06
@luisguzman-adfa

Copy link
Copy Markdown
Collaborator Author

Wizard-maps seam resolved as covered -- no second PR needed. The wizard only banks the maps selection; the base-maps REST download runs during the install, which starts only via startWizardInstall -- gated in the first PR (session-wide consent covers the maps sub-download; a decline never starts the install). The Wi-Fi-start-then-metered-mid-install residual is in-flight best-effort by design, and the proactive alert warns. A maps-drain hold was considered and rejected (the refusal is terminal and pins the user on the progress screen -- complex and worse UX for a covered case). ADR-395 sec.4/5/10 updated. The metered cost-consent feature is complete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant