Added in API level 14

VpnService


open class VpnService : Service
kotlin.Any
   ↳ android.content.Context
   ↳ android.content.ContextWrapper
   ↳ android.app.Service
   ↳ android.net.VpnService

VpnService is a base class for applications to extend and build their own VPN solutions. In general, it creates a virtual network interface, configures addresses and routing rules, and returns a file descriptor to the application. Each read from the descriptor retrieves an outgoing packet which was routed to the interface. Each write to the descriptor injects an incoming packet just like it was received from the interface. The interface is running on Internet Protocol (IP), so packets are always started with IP headers. The application then completes a VPN connection by processing and exchanging packets with the remote server over a tunnel.

Letting applications intercept packets raises huge security concerns. A VPN application can easily break the network. Besides, two of them may conflict with each other. The system takes several actions to address these issues. Here are some key points:

  • User action is required the first time an application creates a VPN connection.
  • There can be only one VPN connection running at the same time. The existing interface is deactivated when a new one is created.
  • A system-managed notification is shown during the lifetime of a VPN connection.
  • A system-managed dialog gives the information of the current VPN connection. It also provides a button to disconnect.
  • The network is restored automatically when the file descriptor is closed. It also covers the cases when a VPN application is crashed or killed by the system.

There are two primary methods in this class: prepare and Builder.establish. The former deals with user action and stops the VPN connection created by another application. The latter creates a VPN interface using the parameters supplied to the Builder. An application must call prepare to grant the right to use other methods in this class, and the right can be revoked at any time. Here are the general steps to create a VPN connection:

  1. When the user presses the button to connect, call prepare and launch the returned intent, if non-null.
  2. When the application becomes prepared, start the service.
  3. Create a tunnel to the remote server and negotiate the network parameters for the VPN connection.
  4. Supply those parameters to a Builder and create a VPN interface by calling Builder.establish.
  5. Process and exchange packets between the tunnel and the returned file descriptor.
  6. When onRevoke is invoked, close the file descriptor and shut down the tunnel gracefully.

Services extending this class need to be declared with an appropriate permission and intent filter. Their access must be secured by android.Manifest.permission#BIND_VPN_SERVICE permission, and their intent filter must match SERVICE_INTERFACE action. Here is an example of declaring a VPN service in AndroidManifest.xml:

<service android:name=".ExampleVpnService"
          android:permission="android.permission.BIND_VPN_SERVICE">
      <intent-filter>
          <action android:name="android.net.VpnService"/>
      </intent-filter>
  </service>

The Android system starts a VPN in the background by calling startService(). In Android 8.0 (API level 26) and higher, the system places VPN apps on the temporary allowlist for a short period so the app can start in the background. The VPN app must promote itself to the foreground after it's launched or the system will shut down the app.

Developer's guide

To learn more about developing VPN apps, read the VPN developer's guide.

Summary

Nested classes
open

Helper class to create a VPN interface.

Constants
static String

The action must be matched by the intent filter of this service.

static String

Key for boolean meta-data field indicating whether this VpnService supports always-on mode.

Inherited constants
Public constructors

Public methods
Boolean

Returns whether the service is running in always-on VPN mode.

Boolean

Returns whether the service is running in always-on VPN lockdown mode.

open IBinder?
onBind(intent: Intent!)

Return the communication interface to the service.

open Unit

Invoked when the application is revoked.

open static Intent!
prepare(context: Context!)

Prepare to establish a VPN connection.

open Boolean
protect(socket: Int)

Protect a socket from VPN connections.

open Boolean

Convenience method to protect a DatagramSocket from VPN connections.

open Boolean
protect(socket: Socket!)

Convenience method to protect a Socket from VPN connections.

open Boolean

Sets the underlying networks used by the VPN for its upstream connections.

Inherited functions

Constants

SERVICE_INTERFACE

Added in API level 14
static val SERVICE_INTERFACE: String

The action must be matched by the intent filter of this service. It also needs to require android.Manifest.permission#BIND_VPN_SERVICE permission so that other applications cannot abuse it.

Value: "android.net.VpnService"

SERVICE_META_DATA_SUPPORTS_ALWAYS_ON

Added in API level 27
static val SERVICE_META_DATA_SUPPORTS_ALWAYS_ON: String

Key for boolean meta-data field indicating whether this VpnService supports always-on mode.

For a VPN app targeting API 24 or above, Android provides users with the ability to set it as always-on, so that VPN connection is persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device owner and profile owner apps through android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage.

VPN apps not supporting this feature should opt out by adding this meta-data field to the VpnService component of AndroidManifest.xml. In case there is more than one VpnService component defined in AndroidManifest.xml, opting out any one of them will opt out the entire app. For example,

<code>&lt;service android:name=".ExampleVpnService"
          android:permission="android.permission.BIND_VPN_SERVICE"&gt;
      &lt;intent-filter&gt;
          &lt;action android:name="android.net.VpnService"/&gt;
      &lt;/intent-filter&gt;
      &lt;meta-data android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
              android:value=false/&gt;
  &lt;/service&gt;
  </code>

This meta-data field defaults to true if absent. It will only have effect on android.os.Build.VERSION_CODES#O_MR1 or higher.

Value: "android.net.VpnService.SUPPORTS_ALWAYS_ON"

Public constructors

VpnService

VpnService()

Public methods

isAlwaysOn

Added in API level 29
fun isAlwaysOn(): Boolean

Returns whether the service is running in always-on VPN mode. In this mode the system ensures that the service is always running by restarting it when necessary, e.g. after reboot.

isLockdownEnabled

Added in API level 29
fun isLockdownEnabled(): Boolean

Returns whether the service is running in always-on VPN lockdown mode. In this mode the system ensures that the service is always running and that the apps aren't allowed to bypass the VPN.

onBind

Added in API level 14
open fun onBind(intent: Intent!): IBinder?

Return the communication interface to the service. This method returns null on Intents other than SERVICE_INTERFACE action. Applications overriding this method must identify the intent and return the corresponding interface accordingly.

Parameters
intent Intent!: The Intent that was used to bind to this service, as given to android.content.Context#bindService. Note that any extras that were included with the Intent at that point will not be seen here.
Return
IBinder? Return an IBinder through which clients can call on to the service.

onRevoke

Added in API level 14
open fun onRevoke(): Unit

Invoked when the application is revoked. At this moment, the VPN interface is already deactivated by the system. The application should close the file descriptor and shut down gracefully. The default implementation of this method is calling Service.stopSelf().

Calls to this method may not happen on the main thread of the process.

See Also

prepare

Added in API level 14
open static fun prepare(context: Context!): Intent!

Prepare to establish a VPN connection. This method returns null if the VPN application is already prepared or if the user has previously consented to the VPN application. Otherwise, it returns an Intent to a system activity. The application should launch the activity using android.app.Activity#startActivityForResult to get itself prepared. The activity may pop up a dialog to require user action, and the result will come back via its android.app.Activity#onActivityResult. If the result is Activity.RESULT_OK, the application becomes prepared and is granted to use other methods in this class.

Only one application can be granted at the same time. The right is revoked when another application is granted. The application losing the right will be notified via its onRevoke. Unless it becomes prepared again, subsequent calls to other methods in this class will fail.

The user may disable the VPN at any time while it is activated, in which case this method will return an intent the next time it is executed to obtain the user's consent again.

See Also

protect

Added in API level 14
open fun protect(socket: Int): Boolean

Protect a socket from VPN connections. After protecting, data sent through this socket will go directly to the underlying network, so its traffic will not be forwarded through the VPN. This method is useful if some connections need to be kept outside of VPN. For example, a VPN tunnel should protect itself if its destination is covered by VPN routes. Otherwise its outgoing packets will be sent back to the VPN interface and cause an infinite loop. This method will fail if the application is not prepared or is revoked.

The socket is NOT closed by this method.

Return
Boolean true on success.

protect

Added in API level 14
open fun protect(socket: DatagramSocket!): Boolean

Convenience method to protect a DatagramSocket from VPN connections.

Return
Boolean true on success.

See Also

protect

Added in API level 14
open fun protect(socket: Socket!): Boolean

Convenience method to protect a Socket from VPN connections.

Return
Boolean true on success.

See Also

setUnderlyingNetworks

Added in API level 22
open fun setUnderlyingNetworks(networks: Array<Network!>!): Boolean

Sets the underlying networks used by the VPN for its upstream connections.

Used by the system to know the actual networks that carry traffic for apps affected by this VPN in order to present this information to the user (e.g., via status bar icons).

This method only needs to be called if the VPN has explicitly bound its underlying communications channels — such as the socket(s) passed to protect(int) — to a Network using APIs such as Network.bindSocket(Socket) or Network.bindSocket(DatagramSocket). The VPN should call this method every time the set of Networks it is using changes.

networks is one of the following:

  • a non-empty array: an array of one or more Networks, in decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular) networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear first in the array.
  • an empty array: a zero-element array, meaning that the VPN has no underlying network connection, and thus, app traffic will not be sent or received.
  • null: (default) signifies that the VPN uses whatever is the system's default network. I.e., it doesn't use the bindSocket or bindDatagramSocket APIs mentioned above to send traffic over specific channels.

This call will succeed only if the VPN is currently established. For setting this value when the VPN has not yet been established, see Builder.setUnderlyingNetworks.

Parameters
networks Array<Network!>!: An array of networks the VPN uses to tunnel traffic to/from its servers.
Return
Boolean true on success.