From 393857be9cc0dd9438cb9c00cf1b05855bef39c1 Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Fri, 4 Nov 2016 14:48:02 +0000 Subject: [PATCH] VpnSettings: show connected VPN even if deleted So there's a way to disconnect from it, if someone deletes all the keystore entries and the VPN doesn't actually exist any more (but is still sitting around in memory somewhere keeping the connection alive). Bug: 29093779 Fix: 32880676 Test: runtest -x tests/app/src/com/android/settings/vpn2/VpnTests.java Change-Id: I97671a74af746e5baaa5be0b5cff24e2b1766f53 --- .../android/settings/vpn2/VpnSettings.java | 51 +++++++++++++------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java index c2ed1c0da3f..37bed6d2c14 100644 --- a/src/com/android/settings/vpn2/VpnSettings.java +++ b/src/com/android/settings/vpn2/VpnSettings.java @@ -49,6 +49,7 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; @@ -96,8 +97,9 @@ public class VpnSettings extends RestrictedSettingsFragment implements private Map mLegacyVpnPreferences = new ArrayMap<>(); private Map mAppPreferences = new ArrayMap<>(); - private HandlerThread mUpdaterThread; + @GuardedBy("this") private Handler mUpdater; + private HandlerThread mUpdaterThread; private LegacyVpnInfo mConnectedLegacyVpn; private boolean mUnavailable; @@ -181,11 +183,9 @@ public class VpnSettings extends RestrictedSettingsFragment implements mConnectivityManager.registerNetworkCallback(VPN_REQUEST, mNetworkCallback); // Trigger a refresh - if (mUpdater == null) { - mUpdaterThread = new HandlerThread("Refresh VPN list in background"); - mUpdaterThread.start(); - mUpdater = new Handler(mUpdaterThread.getLooper(), this); - } + mUpdaterThread = new HandlerThread("Refresh VPN list in background"); + mUpdaterThread.start(); + mUpdater = new Handler(mUpdaterThread.getLooper(), this); mUpdater.sendEmptyMessage(RESCAN_MESSAGE); } @@ -199,7 +199,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements // Stop monitoring mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); - if (mUpdater != null) { + synchronized (this) { mUpdater.removeCallbacksAndMessages(null); mUpdater = null; mUpdaterThread.quit(); @@ -211,8 +211,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements @Override @WorkerThread public boolean handleMessage(Message message) { - mUpdater.removeMessages(RESCAN_MESSAGE); - // Run heavy RPCs before switching to UI thread final List vpnProfiles = loadVpnProfiles(mKeyStore); final List vpnApps = getVpnApps(getActivity(), /* includeProfiles */ true); @@ -223,6 +221,13 @@ public class VpnSettings extends RestrictedSettingsFragment implements final Set alwaysOnAppVpnInfos = getAlwaysOnAppVpnInfos(); final String lockdownVpnKey = VpnUtils.getLockdownVpn(); + synchronized (this) { + if (mUpdater != null) { + mUpdater.removeMessages(RESCAN_MESSAGE); + mUpdater.sendEmptyMessageDelayed(RESCAN_MESSAGE, RESCAN_INTERVAL_MS); + } + } + // Refresh list of VPNs getActivity().runOnUiThread(new Runnable() { @Override @@ -235,8 +240,9 @@ public class VpnSettings extends RestrictedSettingsFragment implements // Find new VPNs by subtracting existing ones from the full set final Set updates = new ArraySet<>(); + // Add legacy VPNs for (VpnProfile profile : vpnProfiles) { - LegacyVpnPreference p = findOrCreatePreference(profile); + LegacyVpnPreference p = findOrCreatePreference(profile, true); if (connectedLegacyVpns.containsKey(profile.key)) { p.setState(connectedLegacyVpns.get(profile.key).state); } else { @@ -245,6 +251,17 @@ public class VpnSettings extends RestrictedSettingsFragment implements p.setAlwaysOn(lockdownVpnKey != null && lockdownVpnKey.equals(profile.key)); updates.add(p); } + + // Show connected VPNs even if the original entry in keystore is gone + for (LegacyVpnInfo vpn : connectedLegacyVpns.values()) { + final VpnProfile stubProfile = new VpnProfile(vpn.key); + LegacyVpnPreference p = findOrCreatePreference(stubProfile, false); + p.setState(vpn.state); + p.setAlwaysOn(lockdownVpnKey != null && lockdownVpnKey.equals(vpn.key)); + updates.add(p); + } + + // Add VpnService VPNs for (AppVpnInfo app : vpnApps) { AppPreference p = findOrCreatePreference(app); if (connectedAppVpns.contains(app)) { @@ -276,8 +293,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements } } }); - - mUpdater.sendEmptyMessageDelayed(RESCAN_MESSAGE, RESCAN_INTERVAL_MS); return true; } @@ -361,16 +376,20 @@ public class VpnSettings extends RestrictedSettingsFragment implements }; @UiThread - private LegacyVpnPreference findOrCreatePreference(VpnProfile profile) { + private LegacyVpnPreference findOrCreatePreference(VpnProfile profile, boolean update) { LegacyVpnPreference pref = mLegacyVpnPreferences.get(profile.key); - if (pref == null) { + boolean created = false; + if (pref == null ) { pref = new LegacyVpnPreference(getPrefContext()); pref.setOnGearClickListener(mGearListener); pref.setOnPreferenceClickListener(this); mLegacyVpnPreferences.put(profile.key, pref); + created = true; + } + if (created || update) { + // This can change call-to-call because the profile can update and keep the same key. + pref.setProfile(profile); } - // This may change as the profile can update and keep the same key. - pref.setProfile(profile); return pref; }