From 7dbf83df03da96f02157ab0d2d1377c1cdc1d8c7 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 28 Apr 2016 15:33:18 -0600 Subject: [PATCH] Flag to mark foreground jobs, fix data saver. When a job will eventually run in the foreground, the internal scheduling needs to ignore any background network restrictions when satisfying constraints. This also means the job should ignore the current device doze state, since the requesting app could get the same behavior by starting their own foreground service. Always dispatch network policy changes to ConnectivityService first to ensure that it has up-to-date information. Fix bugs around data saver that were causing networks to not be marked as BLOCKED for background apps; before this fix apps would have been spinning in internal connectivity loops, thinking that the network was actually connected when the kernel was actually blocking their traffic. Offer new ConnectivityService method overloads to ignore the blocked state for a specific UID. Print unsatisfied job constraints to aid debugging. Bug: 26571724 Change-Id: Iaaa17933e6dc1bf6d3dff26d0bfc12222e51e241 --- .../java/android/net/ConnectivityManager.java | 21 +++- .../android/net/IConnectivityManager.aidl | 6 +- .../android/server/ConnectivityService.java | 109 ++++++++++++------ 3 files changed, 94 insertions(+), 42 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index faf5c64e5a..933dddf4a9 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -774,8 +774,13 @@ public class ConnectivityManager { * @hide */ public Network getActiveNetworkForUid(int uid) { + return getActiveNetworkForUid(uid, false); + } + + /** {@hide} */ + public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) { try { - return mService.getActiveNetworkForUid(uid); + return mService.getActiveNetworkForUid(uid, ignoreBlocked); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -836,8 +841,13 @@ public class ConnectivityManager { * {@hide} */ public NetworkInfo getActiveNetworkInfoForUid(int uid) { + return getActiveNetworkInfoForUid(uid, false); + } + + /** {@hide} */ + public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) { try { - return mService.getActiveNetworkInfoForUid(uid); + return mService.getActiveNetworkInfoForUid(uid, ignoreBlocked); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -880,8 +890,13 @@ public class ConnectivityManager { * is not valid. */ public NetworkInfo getNetworkInfo(Network network) { + return getNetworkInfoForUid(network, Process.myUid(), false); + } + + /** {@hide} */ + public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) { try { - return mService.getNetworkInfoForNetwork(network); + return mService.getNetworkInfoForUid(network, uid, ignoreBlocked); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index c897c4506c..aec6b3ec23 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -44,11 +44,11 @@ import com.android.internal.net.VpnProfile; interface IConnectivityManager { Network getActiveNetwork(); - Network getActiveNetworkForUid(int uid); + Network getActiveNetworkForUid(int uid, boolean ignoreBlocked); NetworkInfo getActiveNetworkInfo(); - NetworkInfo getActiveNetworkInfoForUid(int uid); + NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked); NetworkInfo getNetworkInfo(int networkType); - NetworkInfo getNetworkInfoForNetwork(in Network network); + NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked); NetworkInfo[] getAllNetworkInfo(); Network getNetworkForType(int networkType); Network[] getAllNetworks(); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d85827e990..f5e9d1968e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -29,8 +29,12 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; +import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; +import static android.net.NetworkPolicyManager.RULE_UNKNOWN; + import android.annotation.Nullable; import android.app.BroadcastOptions; import android.app.Notification; @@ -96,8 +100,10 @@ import android.security.Credentials; import android.security.KeyStore; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.ArraySet; import android.util.LocalLog; import android.util.LocalLog.ReadOnlyLocalLog; +import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -121,9 +127,9 @@ import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.KeepaliveTracker; -import com.android.server.connectivity.NetworkDiagnostics; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.NetworkAgentInfo; +import com.android.server.connectivity.NetworkDiagnostics; import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.PacManager; import com.android.server.connectivity.PermissionMonitor; @@ -131,8 +137,8 @@ import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.LockdownVpnTracker; + import com.google.android.collect.Lists; -import com.google.android.collect.Sets; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -152,11 +158,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.SortedSet; +import java.util.TreeSet; /** * @hide @@ -202,9 +208,14 @@ public class ConnectivityService extends IConnectivityManager.Stub /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */ private Object mRulesLock = new Object(); /** Currently active network rules by UID. */ + @GuardedBy("mRulesLock") private SparseIntArray mUidRules = new SparseIntArray(); /** Set of ifaces that are costly. */ - private HashSet mMeteredIfaces = Sets.newHashSet(); + @GuardedBy("mRulesLock") + private ArraySet mMeteredIfaces = new ArraySet<>(); + /** Flag indicating if background data is restricted. */ + @GuardedBy("mRulesLock") + private boolean mRestrictBackground; final private Context mContext; private int mNetworkPreference; @@ -651,7 +662,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); try { - mPolicyManager.registerListener(mPolicyListener); + mPolicyManager.setConnectivityListener(mPolicyListener); + mRestrictBackground = mPolicyManager.getRestrictBackground(); } catch (RemoteException e) { // ouch, no rules updates means some processes may never get network loge("unable to register INetworkPolicyListener" + e.toString()); @@ -819,7 +831,7 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new IllegalStateException("No free netIds"); } - private NetworkState getFilteredNetworkState(int networkType, int uid) { + private NetworkState getFilteredNetworkState(int networkType, int uid, boolean ignoreBlocked) { if (mLegacyTypeTracker.isTypeSupported(networkType)) { final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); final NetworkState state; @@ -834,7 +846,7 @@ public class ConnectivityService extends IConnectivityManager.Stub state = new NetworkState(info, new LinkProperties(), new NetworkCapabilities(), null, null, null); } - filterNetworkStateForUid(state, uid); + filterNetworkStateForUid(state, uid, ignoreBlocked); return state; } else { return NetworkState.EMPTY; @@ -890,22 +902,36 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Check if UID should be blocked from using the network with the given LinkProperties. */ - private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid) { - final boolean networkCostly; + private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid, + boolean ignoreBlocked) { + // Networks aren't blocked when ignoring blocked status + if (ignoreBlocked) return false; + // Networks are never blocked for system services + if (uid < Process.FIRST_APPLICATION_UID) return false; + + final boolean networkMetered; final int uidRules; final String iface = (lp == null ? "" : lp.getInterfaceName()); synchronized (mRulesLock) { - networkCostly = mMeteredIfaces.contains(iface); - uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); + networkMetered = mMeteredIfaces.contains(iface); + uidRules = mUidRules.get(uid, RULE_UNKNOWN); } - if (uidRules == RULE_REJECT_ALL) { - return true; - } else if ((uidRules == RULE_REJECT_METERED) && networkCostly) { - return true; - } else { - return false; + switch (uidRules) { + case RULE_ALLOW_ALL: + case RULE_ALLOW_METERED: + case RULE_TEMPORARY_ALLOW_METERED: + return false; + case RULE_REJECT_METERED: + return networkMetered; + case RULE_REJECT_ALL: + return true; + case RULE_UNKNOWN: + default: + // When background data is restricted device-wide, the default + // behavior for apps should be like RULE_REJECT_METERED + return mRestrictBackground ? networkMetered : false; } } @@ -930,10 +956,10 @@ public class ConnectivityService extends IConnectivityManager.Stub * on {@link #isNetworkWithLinkPropertiesBlocked}, or * {@link NetworkInfo#isMetered()} based on network policies. */ - private void filterNetworkStateForUid(NetworkState state, int uid) { + private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) { if (state == null || state.networkInfo == null || state.linkProperties == null) return; - if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid)) { + if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, ignoreBlocked)) { state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null); } if (mLockdownTracker != null) { @@ -962,7 +988,7 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceAccessPermission(); final int uid = Binder.getCallingUid(); final NetworkState state = getUnfilteredActiveNetworkState(uid); - filterNetworkStateForUid(state, uid); + filterNetworkStateForUid(state, uid, false); maybeLogBlockedNetworkInfo(state.networkInfo, uid); return state.networkInfo; } @@ -970,16 +996,16 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public Network getActiveNetwork() { enforceAccessPermission(); - return getActiveNetworkForUidInternal(Binder.getCallingUid()); + return getActiveNetworkForUidInternal(Binder.getCallingUid(), false); } @Override - public Network getActiveNetworkForUid(int uid) { + public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) { enforceConnectivityInternalPermission(); - return getActiveNetworkForUidInternal(uid); + return getActiveNetworkForUidInternal(uid, ignoreBlocked); } - private Network getActiveNetworkForUidInternal(final int uid) { + private Network getActiveNetworkForUidInternal(final int uid, boolean ignoreBlocked) { final int user = UserHandle.getUserId(uid); int vpnNetId = NETID_UNSET; synchronized (mVpns) { @@ -994,7 +1020,10 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nai != null) return nai.network; } nai = getDefaultNetwork(); - if (nai != null && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid)) nai = null; + if (nai != null + && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, ignoreBlocked)) { + nai = null; + } return nai != null ? nai.network : null; } @@ -1006,10 +1035,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public NetworkInfo getActiveNetworkInfoForUid(int uid) { + public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) { enforceConnectivityInternalPermission(); final NetworkState state = getUnfilteredActiveNetworkState(uid); - filterNetworkStateForUid(state, uid); + filterNetworkStateForUid(state, uid, ignoreBlocked); return state.networkInfo; } @@ -1023,22 +1052,21 @@ public class ConnectivityService extends IConnectivityManager.Stub // getUnfilteredActiveNetworkState. final NetworkState state = getUnfilteredActiveNetworkState(uid); if (state.networkInfo != null && state.networkInfo.getType() == networkType) { - filterNetworkStateForUid(state, uid); + filterNetworkStateForUid(state, uid, false); return state.networkInfo; } } - final NetworkState state = getFilteredNetworkState(networkType, uid); + final NetworkState state = getFilteredNetworkState(networkType, uid, false); return state.networkInfo; } @Override - public NetworkInfo getNetworkInfoForNetwork(Network network) { + public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) { enforceAccessPermission(); - final int uid = Binder.getCallingUid(); final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); if (nai != null) { final NetworkState state = nai.getNetworkState(); - filterNetworkStateForUid(state, uid); + filterNetworkStateForUid(state, uid, ignoreBlocked); return state.networkInfo; } else { return null; @@ -1063,8 +1091,8 @@ public class ConnectivityService extends IConnectivityManager.Stub public Network getNetworkForType(int networkType) { enforceAccessPermission(); final int uid = Binder.getCallingUid(); - NetworkState state = getFilteredNetworkState(networkType, uid); - if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid)) { + NetworkState state = getFilteredNetworkState(networkType, uid, false); + if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, false)) { return state.network; } return null; @@ -1381,6 +1409,11 @@ public class ConnectivityService extends IConnectivityManager.Stub if (LOGD_RULES) { log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); } + + synchronized (mRulesLock) { + mRestrictBackground = restrictBackground; + } + if (restrictBackground) { log("onRestrictBackgroundChanged(true): disabling tethering"); mTethering.untetherAll(); @@ -1824,6 +1857,10 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.decreaseIndent(); pw.println(); + pw.print("Restrict background: "); + pw.println(mRestrictBackground); + pw.println(); + pw.println("Network Requests:"); pw.increaseIndent(); for (NetworkRequestInfo nri : mNetworkRequests.values()) { @@ -2765,7 +2802,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // which isn't meant to work on uncreated networks. if (!nai.created) return; - if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid)) return; + if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) return; nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid); }