VPN: move away from the VPN permission.

VpnBuilder will be replaced by VpnService in the next change.

Change-Id: I2dea67a1616b74d17b372f7b214d207f1617198e
diff --git a/core/java/android/net/VpnBuilder.java b/core/java/android/net/VpnBuilder.java
deleted file mode 100644
index 4582523..0000000
--- a/core/java/android/net/VpnBuilder.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-
-import com.android.internal.net.VpnConfig;
-
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.DatagramSocket;
-import java.net.Socket;
-import java.util.ArrayList;
-
-/**
- * VpnBuilder is a framework which enables applications to 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 framework 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 a remote server
- * over a secured tunnel.
- *
- * <p>Letting applications intercept packets raises huge security concerns.
- * Besides, a VPN application can easily break the network, and two of them
- * may conflict with each other. The framework takes several actions to
- * address these issues. Here are some key points:
- * <ul>
- *   <li>User action is required to create a VPN connection.</li>
- *   <li>There can be only one VPN connection running at the same time. The
- *       existing interface is deactivated when a new one is created.</li>
- *   <li>A system-managed notification is shown during the lifetime of a
- *       VPN connection.</li>
- *   <li>A system-managed dialog gives the information of the current VPN
- *       connection. It also provides a button to disconnect.</li>
- *   <li>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.</li>
- * </ul>
- *
- * <p>There are two primary methods in this class: {@link #prepare} and
- * {@link #establish}. The former deals with the user action and stops
- * the existing VPN connection created by another application. The latter
- * creates a VPN interface using the parameters supplied to this builder.
- * An application must call {@link #prepare} to grant the right to create
- * an interface, and it can be revoked at any time by another application.
- * The application got revoked is notified by an {@link #ACTION_VPN_REVOKED}
- * broadcast. Here are the general steps to create a VPN connection:
- * <ol>
- *   <li>When the user press the button to connect, call {@link #prepare}
- *       and launch the intent if necessary.</li>
- *   <li>Register a receiver for {@link #ACTION_VPN_REVOKED} broadcasts.
- *   <li>Connect to the remote server and negotiate the network parameters
- *       of the VPN connection.</li>
- *   <li>Use those parameters to configure a VpnBuilder and create a VPN
- *       interface by calling {@link #establish}.</li>
- *   <li>Start processing packets between the returned file descriptor and
- *       the VPN tunnel.</li>
- *   <li>When an {@link #ACTION_VPN_REVOKED} broadcast is received, the
- *       interface is already deactivated by the framework. Close the file
- *       descriptor and shut down the VPN tunnel gracefully.
- * </ol>
- * Methods in this class can be used in activities and services. However,
- * the intent returned from {@link #prepare} must be launched from an
- * activity. The broadcast receiver can be registered at any time, but doing
- * it before calling {@link #establish} effectively avoids race conditions.
- *
- * <p class="note">Using this class requires
- * {@link android.Manifest.permission#VPN} permission.
- * @hide
- */
-public class VpnBuilder {
-
-    /**
-     * Broadcast intent action indicating that the VPN application has been
-     * revoked. This can be only received by the target application on the
-     * receiver explicitly registered using {@link Context#registerReceiver}.
-     *
-     * <p>This is a protected intent that can only be sent by the system.
-     */
-    public static final String ACTION_VPN_REVOKED = VpnConfig.ACTION_VPN_REVOKED;
-
-    /**
-     * Use IConnectivityManager instead since those methods are hidden and
-     * not available in ConnectivityManager.
-     */
-    private static IConnectivityManager getService() {
-        return IConnectivityManager.Stub.asInterface(
-                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
-    }
-
-    /**
-     * Prepare to establish a VPN connection. This method returns {@code null}
-     * if the VPN application is already prepared. 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 to the application through its
-     * {@link Activity#onActivityResult}. The application becomes prepared if
-     * the result is {@link Activity#RESULT_OK}, and it is granted to create a
-     * VPN interface by calling {@link #establish}.
-     *
-     * <p>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 by an {@link #ACTION_VPN_REVOKED}
-     * broadcast, and its VPN interface will be deactivated by the system.
-     * The application should then notify the remote server and disconnect
-     * gracefully. Unless the application becomes prepared again, subsequent
-     * calls to {@link #establish} will return {@code null}.
-     *
-     * @see #establish
-     * @see #ACTION_VPN_REVOKED
-     */
-    public static Intent prepare(Context context) {
-        try {
-            if (getService().prepareVpn(context.getPackageName(), null)) {
-                return null;
-            }
-        } catch (RemoteException e) {
-            // ignore
-        }
-        return VpnConfig.getIntentForConfirmation();
-    }
-
-    private VpnConfig mConfig = new VpnConfig();
-    private StringBuilder mAddresses = new StringBuilder();
-    private StringBuilder mRoutes = new StringBuilder();
-
-    /**
-     * Set the name of this session. It will be displayed in system-managed
-     * dialogs and notifications. This is recommended not required.
-     */
-    public VpnBuilder setSession(String session) {
-        mConfig.session = session;
-        return this;
-    }
-
-    /**
-     * Set the {@link PendingIntent} to an activity for users to configure
-     * the VPN connection. If it is not set, the button to configure will
-     * not be shown in system-managed dialogs.
-     */
-    public VpnBuilder setConfigureIntent(PendingIntent intent) {
-        mConfig.configureIntent = intent;
-        return this;
-    }
-
-    /**
-     * Set the maximum transmission unit (MTU) of the VPN interface. If it
-     * is not set, the default value in the operating system will be used.
-     *
-     * @throws IllegalArgumentException if the value is not positive.
-     */
-    public VpnBuilder setMtu(int mtu) {
-        if (mtu <= 0) {
-            throw new IllegalArgumentException("Bad mtu");
-        }
-        mConfig.mtu = mtu;
-        return this;
-    }
-
-    /**
-     * Private method to validate address and prefixLength.
-     */
-    private static void check(InetAddress address, int 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");
-        }
-    }
-
-    /**
-     * Convenience method to add a network address to the VPN interface
-     * using a numeric address string. See {@link InetAddress} for the
-     * definitions of numeric address formats.
-     *
-     * @throws IllegalArgumentException if the address is invalid.
-     * @see #addAddress(InetAddress, int)
-     */
-    public VpnBuilder addAddress(String address, int prefixLength) {
-        return addAddress(InetAddress.parseNumericAddress(address), prefixLength);
-    }
-
-    /**
-     * Add a network address to the VPN interface. Both IPv4 and IPv6
-     * addresses are supported. At least one address must be set before
-     * calling {@link #establish}.
-     *
-     * @throws IllegalArgumentException if the address is invalid.
-     */
-    public VpnBuilder addAddress(InetAddress address, int prefixLength) {
-        check(address, prefixLength);
-
-        if (address.isAnyLocalAddress()) {
-            throw new IllegalArgumentException("Bad address");
-        }
-
-        mAddresses.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
-        return this;
-    }
-
-    /**
-     * Convenience method to add a network route to the VPN interface
-     * using a numeric address string. See {@link InetAddress} for the
-     * definitions of numeric address formats.
-     *
-     * @see #addRoute(InetAddress, int)
-     * @throws IllegalArgumentException if the route is invalid.
-     */
-    public VpnBuilder addRoute(String address, int prefixLength) {
-        return addRoute(InetAddress.parseNumericAddress(address), prefixLength);
-    }
-
-    /**
-     * Add a network route to the VPN interface. Both IPv4 and IPv6
-     * routes are supported.
-     *
-     * @throws IllegalArgumentException if the route is invalid.
-     */
-    public VpnBuilder addRoute(InetAddress address, int prefixLength) {
-        check(address, prefixLength);
-
-        int offset = prefixLength / 8;
-        byte[] bytes = address.getAddress();
-        if (offset < bytes.length) {
-            if ((byte)(bytes[offset] << (prefixLength % 8)) != 0) {
-                throw new IllegalArgumentException("Bad address");
-            }
-            while (++offset < bytes.length) {
-                if (bytes[offset] != 0) {
-                    throw new IllegalArgumentException("Bad address");
-                }
-            }
-        }
-
-        mRoutes.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
-        return this;
-    }
-
-    /**
-     * Convenience method to add a DNS server to the VPN connection
-     * using a numeric address string. See {@link InetAddress} for the
-     * definitions of numeric address formats.
-     *
-     * @throws IllegalArgumentException if the address is invalid.
-     * @see #addDnsServer(InetAddress)
-     */
-    public VpnBuilder addDnsServer(String address) {
-        return addDnsServer(InetAddress.parseNumericAddress(address));
-    }
-
-    /**
-     * Add a DNS server to the VPN connection. Both IPv4 and IPv6
-     * addresses are supported. If none is set, the DNS servers of
-     * the default network will be used.
-     *
-     * @throws IllegalArgumentException if the address is invalid.
-     */
-    public VpnBuilder addDnsServer(InetAddress address) {
-        if (address.isLoopbackAddress() || address.isAnyLocalAddress()) {
-            throw new IllegalArgumentException("Bad address");
-        }
-        if (mConfig.dnsServers == null) {
-            mConfig.dnsServers = new ArrayList<String>();
-        }
-        mConfig.dnsServers.add(address.getHostAddress());
-        return this;
-    }
-
-    /**
-     * Add a search domain to the DNS resolver.
-     */
-    public VpnBuilder addSearchDomain(String domain) {
-        if (mConfig.searchDomains == null) {
-            mConfig.searchDomains = new ArrayList<String>();
-        }
-        mConfig.searchDomains.add(domain);
-        return this;
-    }
-
-    /**
-     * Create a VPN interface using the parameters supplied to this builder.
-     * The interface works on IP packets, and a file descriptor is returned
-     * for the application to access them. Each read retrieves an outgoing
-     * packet which was routed to the interface. Each write injects an
-     * incoming packet just like it was received from the interface. The file
-     * descriptor is put into non-blocking mode by default to avoid blocking
-     * Java threads. To use the file descriptor completely in native space,
-     * see {@link ParcelFileDescriptor#detachFd()}. The application MUST
-     * close the file descriptor when the VPN connection is terminated. The
-     * VPN interface will be removed and the network will be restored by the
-     * framework automatically.
-     *
-     * <p>To avoid conflicts, there can be only one active VPN interface at
-     * the same time. Usually network parameters are never changed during the
-     * lifetime of a VPN connection. It is also common for an application to
-     * create a new file descriptor after closing the previous one. However,
-     * it is rare but not impossible to have two interfaces while performing a
-     * seamless handover. In this case, the old interface will be deactivated
-     * when the new one is configured successfully. Both file descriptors are
-     * valid but now outgoing packets will be routed to the new interface.
-     * Therefore, after draining the old file descriptor, the application MUST
-     * close it and start using the new file descriptor. If the new interface
-     * cannot be created, the existing interface and its file descriptor remain
-     * untouched.
-     *
-     * <p>An exception will be thrown if the interface cannot be created for
-     * any reason. However, this method returns {@code null} if the application
-     * is not prepared or is revoked by another application. This helps solve
-     * possible race conditions while handling {@link #ACTION_VPN_REVOKED}
-     * broadcasts.
-     *
-     * @return {@link ParcelFileDescriptor} of the VPN interface, or
-     *         {@code null} if the application is not prepared.
-     * @throws IllegalArgumentException if a parameter is not accepted by the
-     *         operating system.
-     * @throws IllegalStateException if a parameter cannot be applied by the
-     *         operating system.
-     * @see #prepare
-     */
-    public ParcelFileDescriptor establish() {
-        mConfig.addresses = mAddresses.toString();
-        mConfig.routes = mRoutes.toString();
-
-        try {
-            return getService().establishVpn(mConfig);
-        } catch (RemoteException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    /**
-     * Protect a socket from VPN connections. The socket will be bound to the
-     * current default network interface, so its traffic will not be forwarded
-     * through 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.
-     *
-     * <p>The socket is NOT closed by this method.
-     *
-     * @return {@code true} on success.
-     */
-    public static boolean protect(int socket) {
-        ParcelFileDescriptor dup = null;
-        try {
-            dup = ParcelFileDescriptor.fromFd(socket);
-            return getService().protectVpn(dup);
-        } catch (Exception e) {
-            return false;
-        } finally {
-            try {
-                dup.close();
-            } catch (Exception e) {
-                // ignore
-            }
-        }
-    }
-
-    /**
-     * Protect a {@link Socket} from VPN connections.
-     *
-     * @return {@code true} on success.
-     * @see #protect(int)
-     */
-    public static boolean protect(Socket socket) {
-        return protect(socket.getFileDescriptor$().getInt$());
-    }
-
-    /**
-     * Protect a {@link DatagramSocket} from VPN connections.
-     *
-     * @return {@code true} on success.
-     * @see #protect(int)
-     */
-    public static boolean protect(DatagramSocket socket) {
-        return protect(socket.getFileDescriptor$().getInt$());
-    }
-}
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index d36be10..d61a579 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -32,7 +32,7 @@
  */
 public class VpnConfig implements Parcelable {
 
-    public static final String ACTION_VPN_REVOKED = "android.net.vpn.action.REVOKED";
+    public static final String SERVICE_INTERFACE = "android.net.VpnService";
 
     public static final String LEGACY_VPN = "[Legacy VPN]";
 
@@ -52,7 +52,7 @@
                 PendingIntent.FLAG_NO_CREATE : PendingIntent.FLAG_CANCEL_CURRENT);
     }
 
-    public String packagz;
+    public String user;
     public String interfaze;
     public String session;
     public int mtu = -1;
@@ -70,7 +70,7 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeString(packagz);
+        out.writeString(user);
         out.writeString(interfaze);
         out.writeString(session);
         out.writeInt(mtu);
@@ -87,7 +87,7 @@
         @Override
         public VpnConfig createFromParcel(Parcel in) {
             VpnConfig config = new VpnConfig();
-            config.packagz = in.readString();
+            config.user = in.readString();
             config.interfaze = in.readString();
             config.session = in.readString();
             config.mtu = in.readInt();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f99a94c..19a25cc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -393,14 +393,6 @@
         android:description="@string/permdesc_nfc"
         android:label="@string/permlab_nfc" />
 
-    <!-- Allows applications to provide VPN functionality.
-         @hide Pending API council approval -->
-    <permission android:name="android.permission.VPN"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="dangerous"
-        android:description="@string/permdesc_vpn"
-        android:label="@string/permlab_vpn" />
-
     <!-- Allows an application to use SIP service -->
     <permission android:name="android.permission.USE_SIP"
         android:permissionGroup="android.permission-group.NETWORK"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c5aa4b2..ae14dc8 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1358,14 +1358,6 @@
       with Near Field Communication (NFC) tags, cards, and readers.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_vpn">intercept and modify all network traffic</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_vpn">Allows an application to intercept and
-      inspect all network traffic to establish a VPN connection.
-      Malicious applications may monitor, redirect, or modify network packets
-      without your knowledge.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_disableKeyguard">disable keylock</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_disableKeyguard">Allows an application to disable
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index bd5f739..8e062b7 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -5,7 +5,6 @@
     <application android:label="VpnDialogs"
             android:allowBackup="false" >
         <activity android:name=".ConfirmDialog"
-                android:permission="android.permission.VPN"
                 android:theme="@style/transparent">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 40c0a02..d668e98 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -79,7 +79,7 @@
             mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted);
             mDataReceived = (TextView) view.findViewById(R.id.data_received);
 
-            if (mConfig.packagz.equals(VpnConfig.LEGACY_VPN)) {
+            if (mConfig.user.equals(VpnConfig.LEGACY_VPN)) {
                 mDialog = new AlertDialog.Builder(this)
                         .setIcon(android.R.drawable.ic_dialog_info)
                         .setTitle(R.string.legacy_title)
@@ -89,7 +89,7 @@
                         .create();
             } else {
                 PackageManager pm = getPackageManager();
-                ApplicationInfo app = pm.getApplicationInfo(mConfig.packagz, 0);
+                ApplicationInfo app = pm.getApplicationInfo(mConfig.user, 0);
                 mDialog = new AlertDialog.Builder(this)
                         .setIcon(app.loadIcon(pm))
                         .setTitle(app.loadLabel(pm))
@@ -131,7 +131,7 @@
             if (which == AlertDialog.BUTTON_POSITIVE) {
                 mConfig.configureIntent.send();
             } else if (which == AlertDialog.BUTTON_NEUTRAL) {
-                mService.prepareVpn(mConfig.packagz, VpnConfig.LEGACY_VPN);
+                mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
             }
         } catch (Exception e) {
             Log.e(TAG, "onClick", e);
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index ecbad09..b69cc31 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -54,7 +54,6 @@
 public class Vpn extends INetworkManagementEventObserver.Stub {
 
     private final static String TAG = "Vpn";
-    private final static String VPN = android.Manifest.permission.VPN;
 
     private final Context mContext;
     private final VpnCallback mCallback;
@@ -69,18 +68,6 @@
     }
 
     /**
-     * Protect a socket from routing changes by binding it to the given
-     * interface. The socket is NOT closed by this method.
-     *
-     * @param socket The socket to be bound.
-     * @param name The name of the interface.
-     */
-    public void protect(ParcelFileDescriptor socket, String interfaze) {
-        mContext.enforceCallingPermission(VPN, "protect");
-        jniProtect(socket.getFd(), interfaze);
-    }
-
-    /**
      * Prepare for a VPN application. This method is designed to solve
      * race conditions. It first compares the current prepared package
      * with {@code oldPackage}. If they are the same, the prepared
@@ -115,13 +102,6 @@
             throw new SecurityException("Unauthorized Caller");
         }
 
-        // Check the permission of the given package.
-        PackageManager pm = mContext.getPackageManager();
-        if (!newPackage.equals(VpnConfig.LEGACY_VPN) &&
-                pm.checkPermission(VPN, newPackage) != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException(newPackage + " does not have " + VPN);
-        }
-
         // Reset the interface and hide the notification.
         if (mInterface != null) {
             jniReset(mInterface);
@@ -130,12 +110,9 @@
             mInterface = null;
         }
 
-        // Send out the broadcast or stop LegacyVpnRunner.
+        // Revoke the connection or stop LegacyVpnRunner.
         if (!mPackage.equals(VpnConfig.LEGACY_VPN)) {
-            Intent intent = new Intent(VpnConfig.ACTION_VPN_REVOKED);
-            intent.setPackage(mPackage);
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            mContext.sendBroadcast(intent);
+            // TODO
         } else if (mLegacyVpnRunner != null) {
             mLegacyVpnRunner.exit();
             mLegacyVpnRunner = null;
@@ -147,6 +124,22 @@
     }
 
     /**
+     * Protect a socket from routing changes by binding it to the given
+     * interface. The socket is NOT closed by this method.
+     *
+     * @param socket The socket to be bound.
+     * @param name The name of the interface.
+     */
+    public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
+        PackageManager pm = mContext.getPackageManager();
+        ApplicationInfo app = pm.getApplicationInfo(mPackage, 0);
+        if (Binder.getCallingUid() != app.uid) {
+            throw new SecurityException("Unauthorized Caller");
+        }
+        jniProtect(socket.getFd(), interfaze);
+    }
+
+    /**
      * Establish a VPN network and return the file descriptor of the VPN
      * interface. This methods returns {@code null} if the application is
      * revoked or not prepared.
@@ -155,9 +148,6 @@
      * @return The file descriptor of the VPN interface.
      */
     public synchronized ParcelFileDescriptor establish(VpnConfig config) {
-        // Check the permission of the caller.
-        mContext.enforceCallingPermission(VPN, "establish");
-
         // Check if the caller is already prepared.
         PackageManager pm = mContext.getPackageManager();
         ApplicationInfo app = null;
@@ -170,6 +160,9 @@
             return null;
         }
 
+        // Check if the service is properly declared.
+        // TODO
+
         // Load the label.
         String label = app.loadLabel(pm).toString();
 
@@ -198,6 +191,7 @@
             if (config.routes != null) {
                 jniSetRoutes(interfaze, config.routes);
             }
+            // TODO: bind the service
             if (mInterface != null && !mInterface.equals(interfaze)) {
                 jniReset(mInterface);
             }
@@ -211,23 +205,25 @@
             throw e;
         }
 
-        // Override DNS servers and search domains.
-        mCallback.override(config.dnsServers, config.searchDomains);
-
         // Fill more values.
-        config.packagz = mPackage;
+        config.user = mPackage;
         config.interfaze = mInterface;
 
-        // Show the notification!
+        // Override DNS servers and show the notification.
+        long identity = Binder.clearCallingIdentity();
+        mCallback.override(config.dnsServers, config.searchDomains);
         showNotification(config, label, bitmap);
+        Binder.restoreCallingIdentity(identity);
         return tun;
     }
 
     // INetworkManagementEventObserver.Stub
+    @Override
     public void interfaceAdded(String interfaze) {
     }
 
     // INetworkManagementEventObserver.Stub
+    @Override
     public synchronized void interfaceStatusChanged(String interfaze, boolean up) {
         if (!up && mLegacyVpnRunner != null) {
             mLegacyVpnRunner.check(interfaze);
@@ -235,23 +231,29 @@
     }
 
     // INetworkManagementEventObserver.Stub
-    public synchronized void interfaceLinkStateChanged(String interfaze, boolean up) {
-        if (!up && mLegacyVpnRunner != null) {
-            mLegacyVpnRunner.check(interfaze);
+    @Override
+    public void interfaceLinkStateChanged(String interfaze, boolean up) {
+        interfaceStatusChanged(interfaze, up);
+    }
+
+    // INetworkManagementEventObserver.Stub
+    @Override
+    public synchronized void interfaceRemoved(String interfaze) {
+        if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
+            long identity = Binder.clearCallingIdentity();
+            mCallback.restore();
+            hideNotification();
+            Binder.restoreCallingIdentity(identity);
+            mInterface = null;
+            // TODO: unbind the service
         }
     }
 
     // INetworkManagementEventObserver.Stub
-    public synchronized void interfaceRemoved(String interfaze) {
-        if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
-            mCallback.restore();
-            hideNotification();
-            mInterface = null;
-        }
+    @Override
+    public void limitReached(String limit, String interfaze) {
     }
 
-    public void limitReached(String limitName, String iface) {}
-
     private void showNotification(VpnConfig config, String label, Bitmap icon) {
         NotificationManager nm = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -263,7 +265,6 @@
                     mContext.getString(R.string.vpn_text_long, config.session);
             config.startTime = SystemClock.elapsedRealtime();
 
-            long identity = Binder.clearCallingIdentity();
             Notification notification = new Notification.Builder(mContext)
                     .setSmallIcon(R.drawable.vpn_connected)
                     .setLargeIcon(icon)
@@ -274,7 +275,6 @@
                     .setOngoing(true)
                     .getNotification();
             nm.notify(R.drawable.vpn_connected, notification);
-            Binder.restoreCallingIdentity(identity);
         }
     }
 
@@ -283,9 +283,7 @@
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 
         if (nm != null) {
-            long identity = Binder.clearCallingIdentity();
             nm.cancel(R.drawable.vpn_connected);
-            Binder.restoreCallingIdentity(identity);
         }
     }
 
@@ -355,8 +353,8 @@
             mOuterInterface = mConfig.interfaze;
 
             // Legacy VPN is not a real package, so we use it to carry the key.
-            mInfo.key = mConfig.packagz;
-            mConfig.packagz = VpnConfig.LEGACY_VPN;
+            mInfo.key = mConfig.user;
+            mConfig.user = VpnConfig.LEGACY_VPN;
         }
 
         public void check(String interfaze) {