VpnService always-on "not supported by this app"

Nathan F.

I'm trying to write a VPN application for android, and no matter what I do it seems that the "Always On" setting for my application is grayed out.

I cannot find any documentation anywhere in the android docs that states WHY a VpnService might not be allowed to use the "Always On" feature.

Just to make sure I'm clear, my VpnService works just fine if i manually enable it. I'm able to connect, use it, etc without any issues. I'm just confused as to why in the Android settings it's showing as "not supported for this device" under the "Always-On" toggle for my Vpn Service.

Note: I am using a custom protocol, and on some forum somewhere I did see once that "Google doesn't allow Always-On for VPNs that don't use protocols that have been whitelisted by google", however no where have I found documentation to support this claim, so I'm doubtful that it is the cause.

What I have found from reading the Android Documentation:

  1. If you explicitly supply the SERVICE_META_DATA_SUPPORTS_ALWAYS_ON flag to the <service> definition in your Android Manafest with a value of false it will tell the system that your application does not support the Always On feature. However, if you leave it out, it defaults to true. So there should be no need to supply this.

  2. According to the Android Souce in AppManagementFragment.java#updateRestrictedViews, it uses a function mConnectivityManager.isAlwaysOnVpnPackageSupportedForUser(mUserId, mPackageName), however I'm having difficulty following the logic of this function. When looking at ConnectivityManager.java#isAlwaysOnVpnPackageSupportedForUser, it seems to end up in ConnectivityService.java#isAlwaysOnVpnPackageSupported and ultimately points to Vpn.java#isAlwaysOnPackageSupported which can result in your VPN being considered to NOT support always on if one of the following is met:

    1. The package name passed to the function is null.
    2. The system is unable to locate the package using PackageManager. getApplicationInfoAsUser().
    3. The target for the application is less than VERSION_CODES.N
    4. The package does not contain any Vpn Services in its AndroidManifest.xml.
    5. The package defines ANY VpnServices with the SERVICE_META_DATA_SUPPORTS_ALWAYS_ON meta data set to false.

Note: My application targets API 29.

And that's about it.

Since my application meets all of the requirements stated in Vpn.java#isAlwaysOnPackageSupported, i'm left very confused as to why it will not work.

I've created an android studio project that demonstrates this happening on my Samsung Galaxy S10. You can find it here on github.

My code for reference:

My service is configured as is documented in the Android Documentation.

<service
    android:name=".provider.VpnProvider"
    android:enabled="true"
    android:permission="android.permission.BIND_VPN_SERVICE"
    android:description="@string/service_description"
    android:exported="false">
    <intent-filter>
        <action android:name="android.net.VpnSerivce" />
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</service>

In my Dashboard activity, I use this to handle the Connect button being tapped.

public static final int REQ_START_VPN = 40;

public boolean connect() {
    Intent intent;

    try {
        intent = VpnProvider.prepare(this.getApplicationContext());
    } catch (IllegalStateException e) {
        return false;
    }

    if (intent != null) {
        try {
            this.startActivityForResult(intent, REQ_START_VPN);
            return true;
        } catch (ActivityNotFoundException e) {
            new BasicDialog(
                this, R.string.not_supported,
                R.string.not_supported_message
            ).show();
        }
    } else {
        this.onActivityResult(REQ_START_VPN, AppCompatActivity.RESULT_OK, null);
        return true;
    }
}

I then handle the result using the following:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == AppCompatActivity.RESULT_OK) {
        if (requestCode == REQ_START_VPN) {
            try {
                this.startService(new Intent(this, VpnProvider.class));
            } catch (IllegalStateException ignored) {}
        }
    }
}

My VpnProvider class extends VpnService and has the following for Building the interface:

VpnService.Builder builder = this.new Builder();
builder.setMtu(mtu);
builder.addAddress("1.2.3.4", 32);
builder.addDnsServer("8.8.8.8");
builder.addDnsServer("8.8.4.4");
builder.addRoute("0.0.0.0", 0);
vpnInterface = builder.establish();
Nathan F.

I've found the problem.

In my AndroidManifest.xml when I declared the intent-filters for my service I had a typo.

<action android:name="android.net.VpnSerivce" />

instead of

<action android:name="android.net.VpnService" />

This made my application not inform the operating system that my application had a VpnService as documented in the android documentation here.

This typo took three days of my life that I will never get back.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Android VpnService - How to check VpnService if it was started?

Android Management API and VpnService

Android firewall with VpnService

Android VpnService 'protect' method not working

Android VpnService with multiple addresses and routes?

Trouble deploying Django app to Heroku "no Cedar-supported app detected"

Getting "Split Screen or picture-in-picture is not supported for this app"

Heroku error message no Cedar-supported app detected

How to stop a VpnService that was called with prepare() and startService()?

Xamarin Android - VpnService is blocking all apps

what is Android VpnService.Builder setBlocking

Issue about Android understanding VpnService code

Not able to install my ARKit supported app in iPhone 6, but demo app by apple is running successfully on same iphone

heroku push rejected no cedar-supported app detected php - index.php present

Android VpnService protect socket that's stored in native code?

A firewall for Android with VpnService. Responses are delivered, but a SocketTimeoutException is thrown

Android VpnService start on Device ACTION_BOOT_COMPLETED not working

Android VpnService to capture packets won't capture packets

VpnService.Builder IPv6 error null object

Is the ";" a must always?

"If" inside an always OR condition in the sensitivity list of the always block?

Why is regex always true or always false

jQuery.ajax - always() not always running

Is IsNullable always trune and IsAutoincrement always false for Npgsql?

display the footer always down the page always

Generator function that always processes, but does not always yield

NODEmcu Always stating connection failed always

the method form.is_valid always returns always

Curl and Laravel, always redirects