summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/net/VpnConfig.java2
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java5
-rw-r--r--services/java/com/android/server/connectivity/Vpn.java131
3 files changed, 77 insertions, 61 deletions
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index 572a1d7..310b2df 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -35,6 +35,8 @@ public class VpnConfig implements Parcelable {
public static final String ACTION_VPN_REVOKED = "android.net.vpn.action.REVOKED";
+ public static final String LEGACY_VPN = "[Legacy VPN]";
+
public static Intent getIntentForConfirmation() {
Intent intent = new Intent();
intent.setClassName("com.android.vpndialogs", "com.android.vpndialogs.ConfirmDialog");
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index c076ba0..206ce23 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -72,8 +72,7 @@ public class ManageDialog extends Activity implements Handler.Callback,
mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted);
mDataReceived = (TextView) view.findViewById(R.id.data_received);
- if (mConfig.packageName == null) {
- // Legacy VPN does not have a package name.
+ if (mConfig.packageName.equals(VpnConfig.LEGACY_VPN)) {
mDialog = new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle(R.string.legacy_title)
@@ -126,7 +125,7 @@ public class ManageDialog extends Activity implements Handler.Callback,
if (which == AlertDialog.BUTTON_POSITIVE) {
mConfig.configureIntent.send();
} else if (which == AlertDialog.BUTTON_NEUTRAL) {
- mService.prepareVpn("");
+ mService.prepareVpn(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 a8be916..760a5b6 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -55,9 +55,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
private final Context mContext;
private final VpnCallback mCallback;
- private String mPackageName;
+ private String mPackageName = VpnConfig.LEGACY_VPN;
private String mInterfaceName;
-
private LegacyVpnRunner mLegacyVpnRunner;
public Vpn(Context context, VpnCallback callback) {
@@ -66,13 +65,37 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
}
/**
- * Prepare for a VPN application.
+ * Protect a socket from routing changes by binding it to the given
+ * interface. The socket IS closed by this method.
*
- * @param packageName The package name of the new VPN application.
- * @return The name of the current prepared package.
+ * @param socket The socket to be bound.
+ * @param name The name of the interface.
+ */
+ public void protect(ParcelFileDescriptor socket, String name) {
+ try {
+ mContext.enforceCallingPermission(VPN, "protect");
+ jniProtectSocket(socket.getFd(), name);
+ } finally {
+ try {
+ socket.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * Prepare for a VPN application. If the new application is valid,
+ * the previous prepared application is revoked. Since legacy VPN
+ * is not a real application, it uses {@link VpnConfig#LEGACY_VPN}
+ * as its package name. Note that this method does not check if
+ * the applications are the same.
+ *
+ * @param packageName The package name of the VPN application.
+ * @return The package name of the current prepared application.
*/
public synchronized String prepare(String packageName) {
- // Return the current prepared package if the new one is null.
+ // Return the current prepared application if the new one is null.
if (packageName == null) {
return mPackageName;
}
@@ -84,9 +107,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
// Check the permission of the given package.
PackageManager pm = mContext.getPackageManager();
- if (packageName.isEmpty()) {
- packageName = null;
- } else if (pm.checkPermission(VPN, packageName) != PackageManager.PERMISSION_GRANTED) {
+ if (!packageName.equals(VpnConfig.LEGACY_VPN) &&
+ pm.checkPermission(VPN, packageName) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException(packageName + " does not have " + VPN);
}
@@ -98,16 +120,13 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
mInterfaceName = null;
}
- // Notify the package being revoked.
- if (mPackageName != null) {
+ // Send out the broadcast or stop LegacyVpnRunner.
+ if (!mPackageName.equals(VpnConfig.LEGACY_VPN)) {
Intent intent = new Intent(VpnConfig.ACTION_VPN_REVOKED);
intent.setPackage(mPackageName);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcast(intent);
- }
-
- // Stop legacy VPN if it has been started.
- if (mLegacyVpnRunner != null) {
+ } else if (mLegacyVpnRunner != null) {
mLegacyVpnRunner.exit();
mLegacyVpnRunner = null;
}
@@ -118,30 +137,12 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
}
/**
- * Protect a socket from routing changes by binding it to the given
- * interface. The socket IS closed by this method.
- *
- * @param socket The socket to be bound.
- * @param name The name of the interface.
- */
- public void protect(ParcelFileDescriptor socket, String name) {
- try {
- mContext.enforceCallingPermission(VPN, "protect");
- jniProtectSocket(socket.getFd(), name);
- } finally {
- try {
- socket.close();
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- /**
- * Configure a TUN interface and return its file descriptor.
+ * Establish a VPN network and return the file descriptor of the VPN
+ * interface. This methods returns {@code null} if the application is
+ * not prepared or revoked.
*
- * @param config The parameters to configure the interface.
- * @return The file descriptor of the interface.
+ * @param config The parameters to configure the network.
+ * @return The file descriptor of the VPN interface.
*/
public synchronized ParcelFileDescriptor establish(VpnConfig config) {
// Check the permission of the caller.
@@ -175,7 +176,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
icon.draw(new Canvas(bitmap));
}
- // Create the interface and abort if any of the following steps fails.
+ // Configure the interface. Abort if any of these steps fails.
ParcelFileDescriptor descriptor =
ParcelFileDescriptor.adoptFd(jniCreateInterface(config.mtu));
try {
@@ -226,8 +227,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
// INetworkManagementEventObserver.Stub
public synchronized void interfaceRemoved(String name) {
if (name.equals(mInterfaceName) && jniCheckInterface(name) == 0) {
- hideNotification();
mCallback.restore();
+ hideNotification();
mInterfaceName = null;
}
}
@@ -277,23 +278,28 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
private native void jniProtectSocket(int fd, String name);
/**
- * Handle legacy VPN requests. This method stops the daemons and restart
- * them if their arguments are not null. Heavy things are offloaded to
- * another thread, so callers will not be blocked too long.
+ * Handle a legacy VPN request. This method stops the daemons and restart
+ * them if arguments are not null. Heavy things are offloaded to another
+ * thread, so callers will not be blocked for a long time.
*
+ * @param config The parameters to configure the network.
* @param raoocn The arguments to be passed to racoon.
* @param mtpd The arguments to be passed to mtpd.
*/
- public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
- // Stop the current VPN just like a normal VPN application.
- prepare("");
+ public synchronized void doLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
+ // There is nothing to stop if another VPN application is prepared.
+ if (config == null && !mPackageName.equals(VpnConfig.LEGACY_VPN)) {
+ return;
+ }
- // Legacy VPN does not have a package name.
- config.packageName = null;
+ // Reset everything. This also checks the caller.
+ prepare(VpnConfig.LEGACY_VPN);
// Start a new runner and we are done!
- mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
- mLegacyVpnRunner.start();
+ if (config != null) {
+ mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
+ mLegacyVpnRunner.start();
+ }
}
/**
@@ -317,9 +323,12 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
mConfig = config;
mDaemons = new String[] {"racoon", "mtpd"};
mArguments = new String[][] {racoon, mtpd};
+
+ mConfig.packageName = VpnConfig.LEGACY_VPN;
}
public void exit() {
+ // We assume that everything is reset after the daemons die.
for (String daemon : mDaemons) {
SystemProperties.set("ctl.stop", daemon);
}
@@ -376,7 +385,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
checkpoint(true);
}
- // Check if we need to restart some daemons.
+ // Check if we need to restart any of the daemons.
boolean restart = false;
for (String[] arguments : mArguments) {
restart = restart || (arguments != null);
@@ -468,16 +477,24 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
}
}
- // TODO: support routes and search domains for IPSec Mode-CFG.
+ // TODO: support routes and search domains from IPSec Mode-CFG.
- // This is it! Here is the end of our journey!
+ // Set the routes as requested.
+ if (mConfig.routes != null) {
+ jniSetRoutes(mConfig.interfaceName, mConfig.routes);
+ }
+
+ // The final step must be synchronized.
synchronized (Vpn.this) {
// Check if the thread is interrupted while we are waiting.
checkpoint(false);
- if (mConfig.routes != null) {
- jniSetRoutes(mConfig.interfaceName, mConfig.routes);
+ // Check if the interface is gone while we are waiting.
+ if (jniCheckInterface(mConfig.interfaceName) == 0) {
+ throw new IllegalStateException(mConfig.interfaceName + " is gone");
}
+
+ // Now INetworkManagementEventObserver is watching our back.
mInterfaceName = mConfig.interfaceName;
mCallback.override(mConfig.dnsServers, mConfig.searchDomains);
showNotification(mConfig, null, null);
@@ -485,9 +502,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
Log.i(TAG, "Connected!");
} catch (Exception e) {
Log.i(TAG, "Abort due to " + e.getMessage());
- for (String daemon : mDaemons) {
- SystemProperties.set("ctl.stop", daemon);
- }
+ exit();
}
}
}