diff options
6 files changed, 169 insertions, 26 deletions
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 57f5967e61a7..d6f564351e0a 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -23,6 +23,7 @@ import android.net.ProxyProperties; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; /** @@ -105,5 +106,7 @@ interface IConnectivityManager ParcelFileDescriptor establishVpn(in VpnConfig config); - void doLegacyVpn(in VpnConfig config, in String[] racoon, in String[] mtpd); + void startLegacyVpn(in VpnConfig config, in String[] racoon, in String[] mtpd); + + LegacyVpnInfo getLegacyVpnInfo(); } diff --git a/core/java/com/android/internal/net/LegacyVpnInfo.aidl b/core/java/com/android/internal/net/LegacyVpnInfo.aidl new file mode 100644 index 000000000000..0ca26272cca1 --- /dev/null +++ b/core/java/com/android/internal/net/LegacyVpnInfo.aidl @@ -0,0 +1,19 @@ +/* + * 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 com.android.internal.net; + +parcelable LegacyVpnInfo; diff --git a/core/java/com/android/internal/net/LegacyVpnInfo.java b/core/java/com/android/internal/net/LegacyVpnInfo.java new file mode 100644 index 000000000000..b620abac6b9e --- /dev/null +++ b/core/java/com/android/internal/net/LegacyVpnInfo.java @@ -0,0 +1,69 @@ +/* + * 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 com.android.internal.net; + +import android.app.PendingIntent; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A simple container used to carry information of the ongoing legacy VPN. + * Internal use only. + * + * @hide + */ +public class LegacyVpnInfo implements Parcelable { + public static final int STATE_DISCONNECTED = 0; + public static final int STATE_INITIALIZING = 1; + public static final int STATE_CONNECTING = 2; + public static final int STATE_CONNECTED = 3; + public static final int STATE_TIMEOUT = 4; + public static final int STATE_FAILED = 5; + + public String key; + public int state = -1; + public PendingIntent intent; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeString(key); + out.writeInt(state); + out.writeParcelable(intent, flags); + } + + public static final Parcelable.Creator<LegacyVpnInfo> CREATOR = + new Parcelable.Creator<LegacyVpnInfo>() { + @Override + public LegacyVpnInfo createFromParcel(Parcel in) { + LegacyVpnInfo info = new LegacyVpnInfo(); + info.key = in.readString(); + info.state = in.readInt(); + info.intent = in.readParcelable(null); + return info; + } + + @Override + public LegacyVpnInfo[] newArray(int size) { + return new LegacyVpnInfo[size]; + } + }; +} diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java index 003c244b2183..d36be10e0038 100644 --- a/core/java/com/android/internal/net/VpnConfig.java +++ b/core/java/com/android/internal/net/VpnConfig.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.Intent; import android.os.Parcel; import android.os.Parcelable; -import android.os.SystemClock; import java.util.List; @@ -43,14 +42,14 @@ public class VpnConfig implements Parcelable { return intent; } - public static PendingIntent getIntentForNotification(Context context, VpnConfig config) { - config.startTime = SystemClock.elapsedRealtime(); + public static PendingIntent getIntentForStatusPanel(Context context, VpnConfig config) { Intent intent = new Intent(); intent.setClassName("com.android.vpndialogs", "com.android.vpndialogs.ManageDialog"); intent.putExtra("config", config); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + return PendingIntent.getActivity(context, 0, intent, (config == null) ? + PendingIntent.FLAG_NO_CREATE : PendingIntent.FLAG_CANCEL_CURRENT); } public String packagz; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index afc04bb841b3..b98d2a278785 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -64,6 +64,7 @@ import android.util.EventLog; import android.util.Slog; import android.util.SparseIntArray; +import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.telephony.Phone; import com.android.server.connectivity.Tethering; @@ -2469,8 +2470,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * Protect a socket from VPN routing rules. This method is used by - * VpnBuilder and not available in ConnectivityManager. Permission - * checks are done in Vpn class. + * VpnBuilder and not available in ConnectivityManager. Permissions + * are checked in Vpn class. * @hide */ @Override @@ -2480,8 +2481,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * Prepare for a VPN application. This method is used by VpnDialogs - * and not available in ConnectivityManager. Permission checks are - * done in Vpn class. + * and not available in ConnectivityManager. Permissions are checked + * in Vpn class. * @hide */ @Override @@ -2492,8 +2493,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * Configure a TUN interface and return its file descriptor. Parameters * are encoded and opaque to this class. This method is used by VpnBuilder - * and not available in ConnectivityManager. Permission checks are done - * in Vpn class. + * and not available in ConnectivityManager. Permissions are checked in + * Vpn class. * @hide */ @Override @@ -2502,12 +2503,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { } /** - * Handle a legacy VPN request. + * Start legacy VPN and return an intent to VpnDialogs. This method is + * used by VpnSettings and not available in ConnectivityManager. + * Permissions are checked in Vpn class. + * @hide + */ + @Override + public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { + mVpn.startLegacyVpn(config, racoon, mtpd); + } + + /** + * Return the information of the ongoing legacy VPN. This method is used + * by VpnSettings and not available in ConnectivityManager. Permissions + * are checked in Vpn class. * @hide */ @Override - public void doLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { - mVpn.doLegacyVpn(config, racoon, mtpd); + public LegacyVpnInfo getLegacyVpnInfo() { + return mVpn.getLegacyVpnInfo(); } private String getDefaultInterface() { diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java index bb3ce283c4f2..c185012994b9 100644 --- a/services/java/com/android/server/connectivity/Vpn.java +++ b/services/java/com/android/server/connectivity/Vpn.java @@ -37,6 +37,7 @@ import android.os.SystemProperties; import android.util.Log; import com.android.internal.R; +import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.server.ConnectivityService.VpnCallback; @@ -250,6 +251,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { mContext.getString(R.string.vpn_title_long, label); String text = (config.session == null) ? mContext.getString(R.string.vpn_text) : mContext.getString(R.string.vpn_text_long, config.session); + config.startTime = SystemClock.elapsedRealtime(); long identity = Binder.clearCallingIdentity(); Notification notification = new Notification.Builder(mContext) @@ -257,7 +259,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { .setLargeIcon(icon) .setContentTitle(title) .setContentText(text) - .setContentIntent(VpnConfig.getIntentForNotification(mContext, config)) + .setContentIntent(VpnConfig.getIntentForStatusPanel(mContext, config)) .setDefaults(Notification.DEFAULT_ALL) .setOngoing(true) .getNotification(); @@ -284,24 +286,35 @@ public class Vpn extends INetworkManagementEventObserver.Stub { private native void jniProtect(int socket, String interfaze); /** - * Handle a legacy VPN request. This method stops the daemons and restart - * them if arguments are not null. Heavy things are offloaded to another + * Start legacy VPN. 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 doLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { + public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { // Prepare for the new request. This also checks the caller. prepare(null, VpnConfig.LEGACY_VPN); - // Start a new runner and we are done! + // Start a new LegacyVpnRunner and we are done! mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); mLegacyVpnRunner.start(); } /** + * Return the information of the current ongoing legacy VPN. + */ + public synchronized LegacyVpnInfo getLegacyVpnInfo() { + // Only system user can call this method. + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Unauthorized Caller"); + } + return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo(); + } + + /** * Bringing up a VPN connection takes time, and that is all this thread * does. Here we have plenty of time. The only thing we need to take * care of is responding to interruptions as soon as possible. Otherwise @@ -315,6 +328,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub { private final VpnConfig mConfig; private final String[] mDaemons; private final String[][] mArguments; + private final LegacyVpnInfo mInfo; + private long mTimer = -1; public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) { @@ -322,7 +337,10 @@ public class Vpn extends INetworkManagementEventObserver.Stub { mConfig = config; mDaemons = new String[] {"racoon", "mtpd"}; mArguments = new String[][] {racoon, mtpd}; + mInfo = new LegacyVpnInfo(); + // Legacy VPN is not a real package, so we use it to carry the key. + mInfo.key = mConfig.packagz; mConfig.packagz = VpnConfig.LEGACY_VPN; } @@ -334,14 +352,22 @@ public class Vpn extends INetworkManagementEventObserver.Stub { interrupt(); } + public LegacyVpnInfo getInfo() { + // Update the info when VPN is disconnected. + if (mInfo.state == LegacyVpnInfo.STATE_CONNECTED && mInterface == null) { + mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED; + mInfo.intent = null; + } + return mInfo; + } + @Override public void run() { // Wait for the previous thread since it has been interrupted. - Log.v(TAG, "wait"); + Log.v(TAG, "Waiting"); synchronized (TAG) { - Log.v(TAG, "begin"); + Log.v(TAG, "Executing"); execute(); - Log.v(TAG, "end"); } } @@ -353,7 +379,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } else if (now - mTimer <= 30000) { Thread.sleep(yield ? 200 : 1); } else { - throw new InterruptedException("time is up"); + mInfo.state = LegacyVpnInfo.STATE_TIMEOUT; + throw new IllegalStateException("time is up"); } } @@ -362,6 +389,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { try { // Initialize the timer. checkpoint(false); + mInfo.state = LegacyVpnInfo.STATE_INITIALIZING; // First stop the daemons. for (String daemon : mDaemons) { @@ -390,8 +418,10 @@ public class Vpn extends INetworkManagementEventObserver.Stub { restart = restart || (arguments != null); } if (!restart) { + mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED; return; } + mInfo.state = LegacyVpnInfo.STATE_CONNECTING; // Start the daemon with arguments. for (int i = 0; i < mDaemons.length; ++i) { @@ -459,7 +489,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { String daemon = mDaemons[i]; if (mArguments[i] != null && !"running".equals( SystemProperties.get("init.svc." + daemon))) { - throw new IllegalArgumentException(daemon + " is dead"); + throw new IllegalStateException(daemon + " is dead"); } } checkpoint(true); @@ -492,11 +522,20 @@ public class Vpn extends INetworkManagementEventObserver.Stub { mInterface = mConfig.interfaze; mCallback.override(mConfig.dnsServers, mConfig.searchDomains); showNotification(mConfig, null, null); + + Log.i(TAG, "Connected!"); + mInfo.state = LegacyVpnInfo.STATE_CONNECTED; + mInfo.intent = VpnConfig.getIntentForStatusPanel(mContext, null); } - Log.i(TAG, "Connected!"); } catch (Exception e) { - Log.i(TAG, "Abort because " + e.getMessage()); + Log.i(TAG, "Aborting", e); exit(); + } finally { + // Do not leave an unstable state. + if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING || + mInfo.state == LegacyVpnInfo.STATE_CONNECTING) { + mInfo.state = LegacyVpnInfo.STATE_FAILED; + } } } } |