FileDocCategorySizeDatePackage
VpnService.javaAPI DocAndroid 5.1 API33685Thu Mar 12 22:22:10 GMT 2015android.net

VpnService

public class VpnService extends android.app.Service
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: {@link #prepare} and {@link 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 {@link Builder}. An application must call {@link #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 {@link #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 {@link Builder} and create a VPN interface by calling {@link Builder#establish}.
  5. Process and exchange packets between the tunnel and the returned file descriptor.
  6. When {@link #onRevoke} is invoked, close the file descriptor and shut down the tunnel gracefully.

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

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

Fields Summary
public static final String
SERVICE_INTERFACE
The action must be matched by the intent filter of this service. It also needs to require {@link android.Manifest.permission#BIND_VPN_SERVICE} permission so that other applications cannot abuse it.
Constructors Summary
Methods Summary
public booleanaddAddress(java.net.InetAddress address, int prefixLength)
Adds a network address to the VPN interface. Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the address is already in use or cannot be assigned to the interface for any other reason. Adding an address implicitly allows traffic from that address family (i.e., IPv4 or IPv6) to be routed over the VPN. @see Builder#allowFamily

throws
{@link IllegalArgumentException} if the address is invalid.
param
address The IP address (IPv4 or IPv6) to assign to the VPN interface.
param
prefixLength The prefix length of the address.
return
{@code true} on success.
see
Builder#addAddress
hide

        check(address, prefixLength);
        try {
            return getService().addVpnAddress(address.getHostAddress(), prefixLength);
        } catch (RemoteException e) {
            throw new IllegalStateException(e);
        }
    
private static voidcheck(java.net.InetAddress address, int prefixLength)
Private method to validate address and prefixLength.

        if (address.isLoopbackAddress()) {
            throw new IllegalArgumentException("Bad address");
        }
        if (address instanceof Inet4Address) {
            if (prefixLength < 0 || prefixLength > 32) {
                throw new IllegalArgumentException("Bad prefixLength");
            }
        } else if (address instanceof Inet6Address) {
            if (prefixLength < 0 || prefixLength > 128) {
                throw new IllegalArgumentException("Bad prefixLength");
            }
        } else {
            throw new IllegalArgumentException("Unsupported family");
        }
    
private static IConnectivityManagergetService()
Use IConnectivityManager since those methods are hidden and not available in ConnectivityManager.


                     
        
        return IConnectivityManager.Stub.asInterface(
                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
    
public android.os.IBinderonBind(android.content.Intent intent)
Return the communication interface to the service. This method returns {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE} action. Applications overriding this method must identify the intent and return the corresponding interface accordingly.

see
Service#onBind

        if (intent != null && SERVICE_INTERFACE.equals(intent.getAction())) {
            return new Callback();
        }
        return null;
    
public voidonRevoke()
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 {@link Service#stopSelf()}.

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

see
#prepare

        stopSelf();
    
public static android.content.Intentprepare(android.content.Context context)
Prepare to establish a VPN connection. This method returns {@code null} if the VPN application is already prepared or if the user has previously consented to the VPN application. Otherwise, it returns an {@link Intent} to a system activity. The application should launch the activity using {@link 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 {@link Activity#onActivityResult}. If the result is {@link 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 {@link #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
#onRevoke

        try {
            if (getService().prepareVpn(context.getPackageName(), null)) {
                return null;
            }
        } catch (RemoteException e) {
            // ignore
        }
        return VpnConfig.getIntentForConfirmation();
    
public static voidprepareAndAuthorize(android.content.Context context)
Version of {@link #prepare(Context)} which does not require user consent.

Requires {@link android.Manifest.permission#CONTROL_VPN} and should generally not be used. Only acceptable in situations where user consent has been obtained through other means.

Once this is run, future preparations may be done with the standard prepare method as this will authorize the package to prepare the VPN without consent in the future.

hide

        IConnectivityManager cm = getService();
        String packageName = context.getPackageName();
        try {
            // Only prepare if we're not already prepared.
            if (!cm.prepareVpn(packageName, null)) {
                cm.prepareVpn(null, packageName);
            }
            cm.setVpnPackageAuthorization(true);
        } catch (RemoteException e) {
            // ignore
        }
    
public booleanprotect(int socket)
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
{@code true} on success.

        return NetworkUtils.protectFromVpn(socket);
    
public booleanprotect(java.net.Socket socket)
Convenience method to protect a {@link Socket} from VPN connections.

return
{@code true} on success.
see
#protect(int)

        return protect(socket.getFileDescriptor$().getInt$());
    
public booleanprotect(java.net.DatagramSocket socket)
Convenience method to protect a {@link DatagramSocket} from VPN connections.

return
{@code true} on success.
see
#protect(int)

        return protect(socket.getFileDescriptor$().getInt$());
    
public booleanremoveAddress(java.net.InetAddress address, int prefixLength)
Removes a network address from the VPN interface. Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the address is not assigned to the VPN interface, or if it is the only address assigned (thus cannot be removed), or if the address cannot be removed for any other reason. After removing an address, if there are no addresses, routes or DNS servers of a particular address family (i.e., IPv4 or IPv6) configured on the VPN, that DOES NOT block that family from being routed. In other words, once an address family has been allowed, it stays allowed for the rest of the VPN's session. @see Builder#allowFamily

throws
{@link IllegalArgumentException} if the address is invalid.
param
address The IP address (IPv4 or IPv6) to assign to the VPN interface.
param
prefixLength The prefix length of the address.
return
{@code true} on success.
hide

        check(address, prefixLength);
        try {
            return getService().removeVpnAddress(address.getHostAddress(), prefixLength);
        } catch (RemoteException e) {
            throw new IllegalStateException(e);
        }
    
public booleansetUnderlyingNetworks(android.net.Network[] networks)
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 {@link #protect(int)} — to a {@code Network} using APIs such as {@link Network#bindSocket(Socket)} or {@link Network#bindSocket(DatagramSocket)}. The VPN should call this method every time the set of {@code Network}s it is using changes.

{@code networks} is one of the following:

  • a non-empty array: an array of one or more {@link Network}s, 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 {@code bindSocket} or {@code 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 {@link Builder#setUnderlyingNetworks}.

param
networks An array of networks the VPN uses to tunnel traffic to/from its servers.
return
{@code true} on success.

        try {
            return getService().setUnderlyingNetworksForVpn(networks);
        } catch (RemoteException e) {
            throw new IllegalStateException(e);
        }