The Android VPN screen shows one row with a name, a key icon and maybe an always-on toggle. It rarely shows the endpoint, the route policy, the DNS servers or the credentials that make the connection work, because for an app-based tunnel those belong to the app. The practical consequence is a runbook question, not a philosophical one: before editing a downloaded file or hunting for a central profile store, find out which component owns the setting you want to change.

Identify the connection type first

There are at least three arrangements on the same settings screen. An app can use VpnService to build a virtual interface and own the protocol and private configuration, including a local filtering app with no remote exit. Android can also provision a platform IKEv2 profile through Ikev2VpnProfile, available from API 30, where the platform holds more of the profile. And a provider app can present its own server list and assemble settings internally.

adb shell dumpsys connectivity | grep -i -A12 "VPN"
adb shell cmd connectivity list-owners 2>/dev/null || true

The first command shows the active VPN network and its link properties, which is the applied state. If the row names a package you recognize, start with that app's own profile view rather than the system screen.

Record the owner and the profile scope

Write down four facts before changing anything: the owning package, whether the connection lives in the personal or work profile, the profile or connection name as the app displays it, and who administers it. A device owner can provision a work-profile VPN that a personal-profile user cannot edit, and the same app installed twice gives you two independent owners.

This step prevents the most common wasted hour, which is editing a profile that is not the one connected. Apps often keep several profiles, and the active one is a property of the app, not of the Android row.

Compare requested, received and applied state

These are three different stages, and a discrepancy between them tells you which component to fix.

StageWhere to lookWhat it proves
RequestedThe app's profile editor or imported fileWhat the owner intends to use
ReceivedSanitized app log of server-supplied optionsWhat the peer actually pushed
AppliedLink properties and routes after connectWhat the device is really using

The applied stage is the one you can observe without trusting anyone's log. Compare the DNS servers and routes in the active link properties with the ones the profile claims; if they differ, the server pushed something or the app applied a policy you did not expect.

adb shell ip addr show tun0
adb shell ip route show table all | head -40

Interface names differ between apps, so list the interfaces first and read the one that appeared when the tunnel connected. A route that is present in the app's editor but absent here was never applied; a route that is here but absent from the editor came from somewhere else.

Edit the artifact the owner actually reads

For an imported OpenVPN profile, the app usually keeps its own copy. Editing the originally downloaded file later does not change the next connection; use the app's documented editor, or re-import and confirm which profile is now active. That is the difference between changing a file and changing a configuration.

Provider apps often assemble settings from a server list instead of writing a user-editable file. The absence of an export button is not evidence that the VPN is fake, and an exported file may omit device-bound keys or enrollment material that another device would need. Treat export and import as separate operations with their own preconditions.

Write the support note without exposing secrets

A useful note names the exact app and profile, the setting that appears wrong, and the evidence from each stage. For example: this profile receives a private DNS address from the server, but the intended work app cannot resolve its service, and the applied link properties show that resolver while the profile editor shows another.

Keep credentials out of the note. Rooting the device to search app-private storage is not required to identify the owner, and a guessed data-directory path is not a supported interface. If the answer needs bytes that only the app can see, ask the owner for a diagnostic export rather than improvising one.

When the work is done, close the loop: confirm the active profile name, re-read the applied state, and disconnect once to verify the change survives a reconnect. A setting that only exists in the editor has not been deployed.

Makomi ya ndenge moko