Merge "Listen for network disconnect." into jb-mr2-dev
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 9e9b43d..e5d6e51 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -129,4 +129,6 @@
void captivePortalCheckComplete(in NetworkInfo info);
void supplyMessenger(int networkType, in Messenger messenger);
+
+ int findConnectionTypeForIface(in String iface);
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 01625dd..c2f4a2c 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -544,7 +544,7 @@
mTethering.getTetherableBluetoothRegexs().length != 0) &&
mTethering.getUpstreamIfaceTypes().length != 0);
- mVpn = new Vpn(mContext, mVpnCallback, mNetd);
+ mVpn = new Vpn(mContext, mVpnCallback, mNetd, this);
mVpn.startMonitoring(mContext, mTrackerHandler);
mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler);
@@ -3448,4 +3448,19 @@
mNetTrackers[networkType].supplyMessenger(messenger);
}
}
+
+ public int findConnectionTypeForIface(String iface) {
+ enforceConnectivityInternalPermission();
+
+ if (TextUtils.isEmpty(iface)) return ConnectivityManager.TYPE_NONE;
+ for (NetworkStateTracker tracker : mNetTrackers) {
+ if (tracker != null) {
+ LinkProperties lp = tracker.getLinkProperties();
+ if (lp != null && iface.equals(lp.getInterfaceName())) {
+ return tracker.getNetworkInfo().getType();
+ }
+ }
+ }
+ return ConnectivityManager.TYPE_NONE;
+ }
}
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 533db46..10c7e27 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -21,9 +21,11 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -33,6 +35,7 @@
import android.graphics.drawable.Drawable;
import android.net.BaseNetworkStateTracker;
import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.LinkProperties;
import android.net.LocalSocket;
@@ -71,6 +74,7 @@
import java.net.InetAddress;
import java.nio.charset.Charsets;
import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
import libcore.io.IoUtils;
@@ -92,12 +96,15 @@
private LegacyVpnRunner mLegacyVpnRunner;
private PendingIntent mStatusIntent;
private boolean mEnableNotif = true;
+ private final IConnectivityManager mConnService;
- public Vpn(Context context, VpnCallback callback, INetworkManagementService netService) {
+ public Vpn(Context context, VpnCallback callback, INetworkManagementService netService,
+ IConnectivityManager connService) {
// TODO: create dedicated TYPE_VPN network type
super(ConnectivityManager.TYPE_DUMMY);
mContext = context;
mCallback = callback;
+ mConnService = connService;
try {
netService.registerObserver(mObserver);
@@ -562,7 +569,6 @@
if (!profile.searchDomains.isEmpty()) {
config.searchDomains = Arrays.asList(profile.searchDomains.split(" +"));
}
-
startLegacyVpn(config, racoon, mtpd);
}
@@ -630,9 +636,32 @@
private final String[][] mArguments;
private final LocalSocket[] mSockets;
private final String mOuterInterface;
+ private final AtomicInteger mOuterConnection =
+ new AtomicInteger(ConnectivityManager.TYPE_NONE);
private long mTimer = -1;
+ /**
+ * Watch for the outer connection (passing in the constructor) going away.
+ */
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
+ ConnectivityManager.TYPE_NONE) == mOuterConnection.get()) {
+ NetworkInfo info = (NetworkInfo)intent.getExtra(
+ ConnectivityManager.EXTRA_NETWORK_INFO);
+ if (info != null && !info.isConnectedOrConnecting()) {
+ try {
+ mObserver.interfaceStatusChanged(mOuterInterface, false);
+ } catch (RemoteException e) {}
+ }
+ }
+ }
+ }
+ };
+
public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) {
super(TAG);
mConfig = config;
@@ -644,7 +673,22 @@
// This is the interface which VPN is running on,
// mConfig.interfaze will change to point to OUR
// internal interface soon. TODO - add inner/outer to mconfig
+ // TODO - we have a race - if the outer iface goes away/disconnects before we hit this
+ // we will leave the VPN up. We should check that it's still there/connected after
+ // registering
mOuterInterface = mConfig.interfaze;
+
+ try {
+ mOuterConnection.set(
+ mConnService.findConnectionTypeForIface(mOuterInterface));
+ } catch (Exception e) {
+ mOuterConnection.set(ConnectivityManager.TYPE_NONE);
+ }
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+
}
public void check(String interfaze) {
@@ -661,6 +705,9 @@
IoUtils.closeQuietly(socket);
}
updateState(DetailedState.DISCONNECTED, "exit");
+ try {
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ } catch (IllegalArgumentException e) {}
}
@Override