Loading core/java/com/android/internal/net/VpnConfig.java +2 −0 Original line number Diff line number Diff line Loading @@ -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"); Loading packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java +2 −3 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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); Loading services/java/com/android/server/connectivity/Vpn.java +73 −58 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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 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 new VPN application. * @return The name of the current prepared package. * @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; } Loading @@ -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); } Loading @@ -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; } Loading @@ -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. * 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 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. * * @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. Loading Loading @@ -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 { Loading Loading @@ -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; } } Loading Loading @@ -277,24 +278,29 @@ 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! if (config != null) { mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); mLegacyVpnRunner.start(); } } /** * Bringing up a VPN connection takes time, and that is all this thread Loading @@ -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); } Loading Loading @@ -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); Loading Loading @@ -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. // Set the routes as requested. if (mConfig.routes != null) { jniSetRoutes(mConfig.interfaceName, mConfig.routes); } // This is it! Here is the end of our journey! // 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); Loading @@ -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(); } } } Loading Loading
core/java/com/android/internal/net/VpnConfig.java +2 −0 Original line number Diff line number Diff line Loading @@ -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"); Loading
packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java +2 −3 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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); Loading
services/java/com/android/server/connectivity/Vpn.java +73 −58 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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 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 new VPN application. * @return The name of the current prepared package. * @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; } Loading @@ -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); } Loading @@ -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; } Loading @@ -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. * 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 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. * * @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. Loading Loading @@ -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 { Loading Loading @@ -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; } } Loading Loading @@ -277,24 +278,29 @@ 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! if (config != null) { mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); mLegacyVpnRunner.start(); } } /** * Bringing up a VPN connection takes time, and that is all this thread Loading @@ -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); } Loading Loading @@ -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); Loading Loading @@ -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. // Set the routes as requested. if (mConfig.routes != null) { jniSetRoutes(mConfig.interfaceName, mConfig.routes); } // This is it! Here is the end of our journey! // 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); Loading @@ -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(); } } } Loading