From 998a02f226a75c9e68e34455bc53f09cfbce5b7e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 2 Mar 2021 23:28:49 +0900 Subject: [PATCH] Isolate an ad-hoc legacy API codepath. The legacy API getNetworkInfo(int type) is expected to return NetworkInfo objects for all network types supported by the device even when those network types are not connected. This requires a lot of fabrication because all the data structures in ConnectivityService store information about connected networks, not networks that don't exist. Worse, the current behaviour is to return BLOCKED instead of DISCONNECTED if background data is restricted. This obviously makes no sense, because a disconnected network cannot be blocked, and because if that network type did connect and was unmetered (e.g., Wi-Fi), it would no longer be BLOCKED. This complicates the code, forcing several methods to deal with a special case of null NetworkCapabilities, no NetworkAgentInfo, etc. Fix this by isolating this outlandish behaviour to its own method. This allows the main codepaths not to have to support this unusual and not very useful edge case. Bug: 174123988 Test: pure refactoring, passes existing tests Change-Id: Ia52b24c59024c8f6e63e584b864e0225cb572090 --- .../android/server/ConnectivityService.java | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 542d527177..ebd483c25e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1551,24 +1551,33 @@ public class ConnectivityService extends IConnectivityManager.Stub return state.networkInfo; } + /** Returns a NetworkInfo object for a network that doesn't exist. */ + private NetworkInfo makeFakeNetworkInfo(int networkType, int uid) { + final NetworkInfo info = new NetworkInfo(networkType, 0 /* subtype */, + getNetworkTypeName(networkType), "" /* subtypeName */); + info.setIsAvailable(true); + // For compatibility with legacy code, return BLOCKED instead of DISCONNECTED when + // background data is restricted. + final NetworkCapabilities nc = new NetworkCapabilities(); // Metered. + final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, false) + ? DetailedState.BLOCKED + : DetailedState.DISCONNECTED; + info.setDetailedState(getLegacyLockdownState(state), + "" /* reason */, null /* extraInfo */); + return info; + } + private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) { if (!mLegacyTypeTracker.isTypeSupported(networkType)) { return null; } final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); - final NetworkInfo info; - final NetworkCapabilities nc; - if (nai != null) { - info = new NetworkInfo(nai.networkInfo); - info.setType(networkType); - nc = nai.networkCapabilities; - } else { - info = new NetworkInfo(networkType, 0, getNetworkTypeName(networkType), ""); - info.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); - info.setIsAvailable(true); - nc = new NetworkCapabilities(); + if (nai == null) { + return makeFakeNetworkInfo(networkType, uid); } - filterNetworkInfo(info, nc, uid, false); + final NetworkInfo info = new NetworkInfo(nai.networkInfo); + info.setType(networkType); + filterNetworkInfo(info, nai.networkCapabilities, uid, false); return info; }