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
diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java
index c2ed1c0..37bed6d 100644
--- a/src/com/android/settings/vpn2/VpnSettings.java
+++ b/src/com/android/settings/vpn2/VpnSettings.java
@@ -49,6 +49,7 @@
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 @@
private Map<String, LegacyVpnPreference> mLegacyVpnPreferences = new ArrayMap<>();
private Map<AppVpnInfo, AppPreference> mAppPreferences = new ArrayMap<>();
- private HandlerThread mUpdaterThread;
+ @GuardedBy("this")
private Handler mUpdater;
+ private HandlerThread mUpdaterThread;
private LegacyVpnInfo mConnectedLegacyVpn;
private boolean mUnavailable;
@@ -181,11 +183,9 @@
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 @@
// Stop monitoring
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
- if (mUpdater != null) {
+ synchronized (this) {
mUpdater.removeCallbacksAndMessages(null);
mUpdater = null;
mUpdaterThread.quit();
@@ -211,8 +211,6 @@
@Override @WorkerThread
public boolean handleMessage(Message message) {
- mUpdater.removeMessages(RESCAN_MESSAGE);
-
// Run heavy RPCs before switching to UI thread
final List<VpnProfile> vpnProfiles = loadVpnProfiles(mKeyStore);
final List<AppVpnInfo> vpnApps = getVpnApps(getActivity(), /* includeProfiles */ true);
@@ -223,6 +221,13 @@
final Set<AppVpnInfo> 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 @@
// Find new VPNs by subtracting existing ones from the full set
final Set<Preference> 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 @@
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 @@
}
}
});
-
- mUpdater.sendEmptyMessageDelayed(RESCAN_MESSAGE, RESCAN_INTERVAL_MS);
return true;
}
@@ -361,16 +376,20 @@
};
@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;
}
- // This may change as the profile can update and keep the same key.
- pref.setProfile(profile);
+ if (created || update) {
+ // This can change call-to-call because the profile can update and keep the same key.
+ pref.setProfile(profile);
+ }
return pref;
}