Skip to content

Onboarding warns about VPN lockdown when lockdown is disabled #712

Description

@kasnder

Onboarding's "VPN Lockdown Setting" slide tells users to change a setting that is already correct.

Observed

On a Pixel 8 (Android 17) with lockdown off:

$ adb shell settings get secure always_on_vpn_lockdown
0

the slide still shows the action button "Open VPN Settings", and tapping Next raises the
onboarding_lockdown_sure confirmation ("Proceeding with lockdown enabled may cause connectivity
issues. Are you sure?"). The user is warned about, and asked to confirm past, a state they are not in.

Expected, per refreshSlides(): on Q+ with lockdown disabled the button should read
onboarding_action_disabled ("Disabled") and warningResId should be 0, i.e. no confirmation.

Reproduced twice on release build 2026080501, on a freshly cleared install.

Candidate causes

Two suspects; I could not separate them without instrumenting a build, so both are listed rather than
one asserted.

1. refreshSlides() never runs its update loop on first display.

private void refreshSlides() {
    if (!slidesInitialized) {
        setupSlides();
        return;          // <-- the per-slide update loop below never runs
    }

    for (Slide slide : slides) { ... }   // dynamic state checks live here
}

It is called from onResume(). On the first resume it builds the slides and returns, so the loop
that adapts each slide to device state never executes for the initial display, and every
state-dependent slide keeps the pessimistic defaults setupSlides() constructed it with — for
lockdown, actionButtonText = onboarding_lockdown_action and warningResId = onboarding_lockdown_sure, which is what is observed.

This explains a run with no second resume. It does not explain a run where the VPN consent dialog
came and went (that resumes the activity, so the loop does run) yet the slide still showed
"Open VPN Settings" and still warned — which is what happened here.

2. isLockdownEnabled() returns true when lockdown is off.

int lockdown = Settings.Secure.getInt(getContentResolver(), "always_on_vpn_lockdown", 0);
return lockdown != 0;

always_on_vpn_lockdown is a hidden Settings.Secure key. Worth checking what it actually returns
from the app's own UID on current Android — the observed behaviour is consistent with this returning
non-zero, and would also explain the post-consent run that suspect 1 does not.

Whichever it is, the first-display ordering above is a defect in its own right and affects every
state-dependent slide, not just this one.

Notes

Both this and #711's Private DNS slide push a user through a scary confirmation on a healthy device
during first-run, which is a poor first impression for the default (Minimal-mode) user.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingjavaPull requests that update java code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions