diff options
4 files changed, 320 insertions, 51 deletions
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 43ae4fc0a41b..2c2a703b16e2 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -176,6 +176,9 @@ public class NetworkPolicyManager { public static final int FOREGROUND_THRESHOLD_STATE = ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + /** @hide */ + public static final int TOP_THRESHOLD_STATE = ActivityManager.PROCESS_STATE_BOUND_TOP; + /** * {@link Intent} extra that indicates which {@link NetworkTemplate} rule it * applies to. @@ -247,6 +250,20 @@ public class NetworkPolicyManager { */ public static final int ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS = 1 << 4; /** + * Flag to indicate that app is exempt from certain network restrictions because of it being + * in the bound top or top procstate. + * + * @hide + */ + public static final int ALLOWED_REASON_TOP = 1 << 5; + /** + * Flag to indicate that app is exempt from low power standby restrictions because of it being + * allowlisted. + * + * @hide + */ + public static final int ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST = 1 << 6; + /** * Flag to indicate that app is exempt from certain metered network restrictions because user * explicitly exempted it. * @@ -770,6 +787,14 @@ public class NetworkPolicyManager { || (capability & ActivityManager.PROCESS_CAPABILITY_NETWORK) != 0; } + /** @hide */ + public static boolean isProcStateAllowedWhileInLowPowerStandby(@Nullable UidState uidState) { + if (uidState == null) { + return false; + } + return uidState.procState <= TOP_THRESHOLD_STATE; + } + /** * Returns true if {@param procState} is considered foreground and as such will be allowed * to access network when the device is in data saver mode. Otherwise, false. diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java index 8ef42ff97aad..3cb587812c2a 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java @@ -91,4 +91,10 @@ public abstract class NetworkPolicyManagerInternal { */ public abstract void setMeteredRestrictedPackagesAsync( Set<String> packageNames, int userId); + + /** Informs that Low Power Standby has become active */ + public abstract void setLowPowerStandbyActive(boolean active); + + /** Informs that the Low Power Standby allowlist has changed */ + public abstract void setLowPowerStandbyAllowlist(int[] uids); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 67b44696d326..ea851ba9669f 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -46,17 +46,19 @@ import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRI import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY; import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER; import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE; +import static android.net.ConnectivityManager.BLOCKED_REASON_LOW_POWER_STANDBY; import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; import static android.net.ConnectivityManager.BLOCKED_REASON_RESTRICTED_MODE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.INetd.FIREWALL_CHAIN_DOZABLE; -import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE; -import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED; -import static android.net.INetd.FIREWALL_CHAIN_STANDBY; import static android.net.INetd.FIREWALL_RULE_ALLOW; import static android.net.INetd.FIREWALL_RULE_DENY; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; @@ -69,11 +71,13 @@ import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_MASK; import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_SYSTEM; import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_USER_EXEMPTED; import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST; import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE; import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_ALLOWLIST; import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST; import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_TOP; import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND; @@ -87,6 +91,7 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_RESTRICTED_MODE; import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode; +import static android.net.NetworkPolicyManager.isProcStateAllowedWhileInLowPowerStandby; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground; import static android.net.NetworkPolicyManager.resolveNetworkId; import static android.net.NetworkPolicyManager.uidPoliciesToString; @@ -477,6 +482,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { volatile boolean mRestrictBackgroundChangedInBsm; @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictedNetworkingMode; + @GuardedBy("mUidRulesFirstLock") + volatile boolean mLowPowerStandbyActive; private final boolean mSuppressDefaultPolicy; @@ -516,6 +523,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray(); @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidFirewallRestrictedModeRules = new SparseIntArray(); + @GuardedBy("mUidRulesFirstLock") + final SparseIntArray mUidFirewallLowPowerStandbyModeRules = new SparseIntArray(); /** Set of states for the child firewall chains. True if the chain is active. */ @GuardedBy("mUidRulesFirstLock") @@ -544,6 +553,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") private final SparseBooleanArray mPowerSaveTempWhitelistAppIds = new SparseBooleanArray(); + @GuardedBy("mUidRulesFirstLock") + private final SparseBooleanArray mLowPowerStandbyAllowlistUids = new SparseBooleanArray(); + /** * UIDs that have been allowlisted temporarily to be able to have network access despite being * idle. Other power saving restrictions still apply. @@ -3785,6 +3797,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print("Restrict power: "); fout.println(mRestrictPower); fout.print("Device idle: "); fout.println(mDeviceIdleMode); fout.print("Restricted networking mode: "); fout.println(mRestrictedNetworkingMode); + fout.print("Low Power Standby mode: "); fout.println(mLowPowerStandbyActive); synchronized (mMeteredIfacesLock) { fout.print("Metered ifaces: "); fout.println(mMeteredIfaces); @@ -3920,6 +3933,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.decreaseIndent(); } + size = mLowPowerStandbyAllowlistUids.size(); + if (size > 0) { + fout.println("Low Power Standby allowlist uids:"); + fout.increaseIndent(); + for (int i = 0; i < size; i++) { + fout.print("UID="); + fout.print(mLowPowerStandbyAllowlistUids.keyAt(i)); + fout.println(); + } + fout.decreaseIndent(); + } + final SparseBooleanArray knownUids = new SparseBooleanArray(); collectKeys(mUidState, knownUids); collectKeys(mUidBlockedState, knownUids); @@ -4001,6 +4026,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return isProcStateAllowedWhileIdleOrPowerSaveMode(uidState); } + @GuardedBy("mUidRulesFirstLock") + private boolean isUidTop(int uid) { + final UidState uidState = mUidState.get(uid); + return isProcStateAllowedWhileInLowPowerStandby(uidState); + } + /** * Process state of UID changed; if needed, will trigger * {@link #updateRulesForDataUsageRestrictionsUL(int)} and @@ -4017,8 +4048,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // state changed, push updated rules mUidState.put(uid, newUidState); updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, newUidState); - if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState) - != isProcStateAllowedWhileIdleOrPowerSaveMode(newUidState)) { + boolean allowedWhileIdleOrPowerSaveModeChanged = + isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState) + != isProcStateAllowedWhileIdleOrPowerSaveMode(newUidState); + if (allowedWhileIdleOrPowerSaveModeChanged) { updateRuleForAppIdleUL(uid); if (mDeviceIdleMode) { updateRuleForDeviceIdleUL(uid); @@ -4028,6 +4061,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } updateRulesForPowerRestrictionsUL(uid); } + if (mLowPowerStandbyActive) { + boolean allowedInLpsChanged = + isProcStateAllowedWhileInLowPowerStandby(oldUidState) + != isProcStateAllowedWhileInLowPowerStandby(newUidState); + if (allowedInLpsChanged) { + if (!allowedWhileIdleOrPowerSaveModeChanged) { + updateRulesForPowerRestrictionsUL(uid); + } + updateRuleForLowPowerStandbyUL(uid); + } + } return true; } } finally { @@ -4051,6 +4095,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateRuleForRestrictPowerUL(uid); } updateRulesForPowerRestrictionsUL(uid); + if (mLowPowerStandbyActive) { + updateRuleForLowPowerStandbyUL(uid); + } return true; } } @@ -4254,6 +4301,50 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + @GuardedBy("mUidRulesFirstLock") + void updateRulesForLowPowerStandbyUL() { + Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForLowPowerStandbyUL"); + try { + if (mLowPowerStandbyActive) { + mUidFirewallLowPowerStandbyModeRules.clear(); + for (int i = mUidState.size() - 1; i >= 0; i--) { + final int uid = mUidState.keyAt(i); + UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + if (hasInternetPermissionUL(uid) && uidBlockedState != null + && (uidBlockedState.effectiveBlockedReasons + & BLOCKED_REASON_LOW_POWER_STANDBY) == 0) { + mUidFirewallLowPowerStandbyModeRules.put(mUidBlockedState.keyAt(i), + FIREWALL_RULE_ALLOW); + } + } + setUidFirewallRulesUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, + mUidFirewallLowPowerStandbyModeRules, CHAIN_TOGGLE_ENABLE); + } else { + setUidFirewallRulesUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, null, CHAIN_TOGGLE_DISABLE); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_NETWORK); + } + } + + @GuardedBy("mUidRulesFirstLock") + void updateRuleForLowPowerStandbyUL(int uid) { + if (!hasInternetPermissionUL(uid)) { + return; + } + + final UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + if (mUidState.contains(uid) && uidBlockedState != null + && (uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY) + == 0) { + mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW); + setUidFirewallRuleUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_ALLOW); + } else { + mUidFirewallLowPowerStandbyModeRules.delete(uid); + setUidFirewallRuleUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_DEFAULT); + } + } + /** * Returns whether a uid is allowlisted from power saving restrictions (eg: Battery Saver, Doze * mode, and app idle). @@ -4283,6 +4374,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return mPowerSaveWhitelistExceptIdleAppIds.get(appId); } + /** + * Returns whether a uid is allowlisted from low power standby restrictions. + */ + @GuardedBy("mUidRulesFirstLock") + private boolean isAllowlistedFromLowPowerStandbyUL(int uid) { + return mLowPowerStandbyAllowlistUids.get(uid); + } + // NOTE: since both fw_dozable and fw_powersave uses the same map // (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method. @GuardedBy("mUidRulesFirstLock") @@ -4620,6 +4719,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mPowerSaveTempWhitelistAppIds.delete(uid); mAppIdleTempWhitelistAppIds.delete(uid); mUidFirewallRestrictedModeRules.delete(uid); + mUidFirewallLowPowerStandbyModeRules.delete(uid); synchronized (mUidStateCallbackInfos) { mUidStateCallbackInfos.remove(uid); } @@ -4845,6 +4945,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid); + final boolean isTop = isUidTop(uid); final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode); @@ -4858,17 +4959,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { int newAllowedReasons = ALLOWED_REASON_NONE; newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0); newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0); + newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0); newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0); newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE); newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0); newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0); + newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0); newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true) ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0); newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid) ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0); newAllowedReasons |= (uidBlockedState.allowedReasons & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS); + newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid)) + ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0; uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK) | newBlockedReasons; @@ -4890,6 +4995,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { + ", mRestrictPower: " + mRestrictPower + ", mDeviceIdleMode: " + mDeviceIdleMode + ", isForeground=" + isForeground + + ", isTop=" + isTop + ", isWhitelisted=" + isWhitelisted + ", oldUidBlockedState=" + previousUidBlockedState.toString() + ", newUidBlockedState=" + uidBlockedState.toString()); @@ -5421,6 +5527,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mUidFirewallPowerSaveRules.put(uid, rule); } else if (chain == FIREWALL_CHAIN_RESTRICTED) { mUidFirewallRestrictedModeRules.put(uid, rule); + } else if (chain == FIREWALL_CHAIN_LOW_POWER_STANDBY) { + mUidFirewallLowPowerStandbyModeRules.put(uid, rule); } try { @@ -5468,6 +5576,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT); mNetworkManager .setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, FIREWALL_RULE_DEFAULT); + mNetworkManager + .setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, + FIREWALL_RULE_DEFAULT); mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false); mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false); } catch (IllegalStateException e) { @@ -5747,6 +5858,67 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mHandler.obtainMessage(MSG_METERED_RESTRICTED_PACKAGES_CHANGED, userId, 0, packageNames).sendToTarget(); } + + @Override + public void setLowPowerStandbyActive(boolean active) { + Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setLowPowerStandbyActive"); + try { + synchronized (mUidRulesFirstLock) { + if (mLowPowerStandbyActive == active) { + return; + } + mLowPowerStandbyActive = active; + synchronized (mNetworkPoliciesSecondLock) { + if (!mSystemReady) return; + } + + forEachUid("updateRulesForRestrictPower", + uid -> updateRulesForPowerRestrictionsUL(uid)); + updateRulesForLowPowerStandbyUL(); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_NETWORK); + } + } + + @Override + public void setLowPowerStandbyAllowlist(int[] uids) { + synchronized (mUidRulesFirstLock) { + final SparseBooleanArray changedUids = new SparseBooleanArray(); + for (int i = 0; i < mLowPowerStandbyAllowlistUids.size(); i++) { + final int oldUid = mLowPowerStandbyAllowlistUids.keyAt(i); + if (!ArrayUtils.contains(uids, oldUid)) { + changedUids.put(oldUid, true); + } + } + + for (int i = 0; i < changedUids.size(); i++) { + final int deletedUid = changedUids.keyAt(i); + mLowPowerStandbyAllowlistUids.delete(deletedUid); + } + + for (int newUid : uids) { + if (mLowPowerStandbyAllowlistUids.indexOfKey(newUid) < 0) { + changedUids.append(newUid, true); + mLowPowerStandbyAllowlistUids.append(newUid, true); + } + } + + if (!mLowPowerStandbyActive) { + return; + } + + synchronized (mNetworkPoliciesSecondLock) { + if (!mSystemReady) return; + } + + for (int i = 0; i < changedUids.size(); i++) { + final int changedUid = changedUids.keyAt(i); + updateRulesForPowerRestrictionsUL(changedUid); + updateRuleForLowPowerStandbyUL(changedUid); + } + } + } } private void setMeteredRestrictedPackagesInternal(Set<String> packageNames, int userId) { @@ -5904,6 +6076,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER; effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_USER_RESTRICTED; } + if ((allowedReasons & ALLOWED_REASON_TOP) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_LOW_POWER_STANDBY; + } if ((allowedReasons & ALLOWED_REASON_POWER_SAVE_ALLOWLIST) != 0) { effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER; effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE; @@ -5919,6 +6094,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) { effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER; } + if ((allowedReasons & ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_LOW_POWER_STANDBY; + } + return effectiveBlockedReasons; } @@ -5943,6 +6122,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { BLOCKED_REASON_DOZE, BLOCKED_REASON_APP_STANDBY, BLOCKED_REASON_RESTRICTED_MODE, + BLOCKED_REASON_LOW_POWER_STANDBY, BLOCKED_METERED_REASON_DATA_SAVER, BLOCKED_METERED_REASON_USER_RESTRICTED, BLOCKED_METERED_REASON_ADMIN_DISABLED, @@ -5951,9 +6131,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int[] ALLOWED_REASONS = { ALLOWED_REASON_SYSTEM, ALLOWED_REASON_FOREGROUND, + ALLOWED_REASON_TOP, ALLOWED_REASON_POWER_SAVE_ALLOWLIST, ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST, ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS, + ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST, ALLOWED_METERED_REASON_USER_EXEMPTED, ALLOWED_METERED_REASON_SYSTEM, ALLOWED_METERED_REASON_FOREGROUND, @@ -5971,6 +6153,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return "APP_STANDBY"; case BLOCKED_REASON_RESTRICTED_MODE: return "RESTRICTED_MODE"; + case BLOCKED_REASON_LOW_POWER_STANDBY: + return "LOW_POWER_STANDBY"; case BLOCKED_METERED_REASON_DATA_SAVER: return "DATA_SAVER"; case BLOCKED_METERED_REASON_USER_RESTRICTED: @@ -5991,12 +6175,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return "SYSTEM"; case ALLOWED_REASON_FOREGROUND: return "FOREGROUND"; + case ALLOWED_REASON_TOP: + return "TOP"; case ALLOWED_REASON_POWER_SAVE_ALLOWLIST: return "POWER_SAVE_ALLOWLIST"; case ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST: return "POWER_SAVE_EXCEPT_IDLE_ALLOWLIST"; case ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS: return "RESTRICTED_MODE_PERMISSIONS"; + case ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST: + return "LOW_POWER_STANDBY_ALLOWLIST"; case ALLOWED_METERED_REASON_USER_EXEMPTED: return "METERED_USER_EXEMPTED"; case ALLOWED_METERED_REASON_SYSTEM: @@ -6063,7 +6251,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { int powerBlockedReasons = BLOCKED_REASON_APP_STANDBY | BLOCKED_REASON_DOZE - | BLOCKED_REASON_BATTERY_SAVER; + | BLOCKED_REASON_BATTERY_SAVER + | BLOCKED_REASON_LOW_POWER_STANDBY; if ((effectiveBlockedReasons & powerBlockedReasons) != 0) { uidRule |= RULE_REJECT_ALL; } else if ((blockedReasons & powerBlockedReasons) != 0) { diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index f865a50978b5..af8ac6f412f5 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -23,11 +23,13 @@ import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRI import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY; import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER; import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE; +import static android.net.ConnectivityManager.BLOCKED_REASON_LOW_POWER_STANDBY; import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED; import static android.net.INetd.FIREWALL_RULE_ALLOW; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -38,8 +40,10 @@ import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_FOREGROUND; import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_SYSTEM; import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST; import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE; import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_TOP; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.POLICY_NONE; @@ -200,6 +204,7 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; @@ -1877,55 +1882,99 @@ public class NetworkPolicyManagerServiceTest { } @Test + public void testLowPowerStandbyAllowlist() throws Exception { + callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, 0); + callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0); + callOnUidStateChanged(UID_C, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0); + expectHasInternetPermission(UID_A, true); + expectHasInternetPermission(UID_B, true); + expectHasInternetPermission(UID_C, true); + + final NetworkPolicyManagerInternal internal = LocalServices + .getService(NetworkPolicyManagerInternal.class); + + Map<Integer, Integer> firewallUidRules = new ArrayMap<>(); + doAnswer(arg -> { + int[] uids = arg.getArgument(1); + int[] rules = arg.getArgument(2); + assertTrue(uids.length == rules.length); + + for (int i = 0; i < uids.length; ++i) { + firewallUidRules.put(uids[i], rules[i]); + } + return null; + }).when(mNetworkManager).setFirewallUidRules(eq(FIREWALL_CHAIN_LOW_POWER_STANDBY), + any(int[].class), any(int[].class)); + + internal.setLowPowerStandbyAllowlist(new int[] { UID_B }); + internal.setLowPowerStandbyActive(true); + assertEquals(FIREWALL_RULE_ALLOW, firewallUidRules.get(UID_A).intValue()); + assertEquals(FIREWALL_RULE_ALLOW, firewallUidRules.get(UID_B).intValue()); + assertFalse(mService.isUidNetworkingBlocked(UID_A, false)); + assertFalse(mService.isUidNetworkingBlocked(UID_B, false)); + assertTrue(mService.isUidNetworkingBlocked(UID_C, false)); + + internal.setLowPowerStandbyActive(false); + assertFalse(mService.isUidNetworkingBlocked(UID_A, false)); + assertFalse(mService.isUidNetworkingBlocked(UID_B, false)); + assertFalse(mService.isUidNetworkingBlocked(UID_C, false)); + } + + @Test public void testUpdateEffectiveBlockedReasons() { - final SparseArray<Pair<Integer, Integer>> effectiveBlockedReasons = new SparseArray<>(); - effectiveBlockedReasons.put(BLOCKED_REASON_NONE, - Pair.create(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE)); - - effectiveBlockedReasons.put(BLOCKED_REASON_NONE, - Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_SYSTEM)); - effectiveBlockedReasons.put(BLOCKED_REASON_NONE, - Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE, - ALLOWED_REASON_SYSTEM)); - effectiveBlockedReasons.put(BLOCKED_REASON_NONE, - Pair.create(BLOCKED_METERED_REASON_DATA_SAVER, - ALLOWED_METERED_REASON_SYSTEM)); - effectiveBlockedReasons.put(BLOCKED_REASON_NONE, - Pair.create(BLOCKED_METERED_REASON_DATA_SAVER - | BLOCKED_METERED_REASON_USER_RESTRICTED, - ALLOWED_METERED_REASON_SYSTEM)); - - effectiveBlockedReasons.put(BLOCKED_METERED_REASON_DATA_SAVER, + final Map<Pair<Integer, Integer>, Integer> effectiveBlockedReasons = new HashMap<>(); + effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE), + BLOCKED_REASON_NONE); + + effectiveBlockedReasons.put( + Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_SYSTEM), + BLOCKED_REASON_NONE); + effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE, + ALLOWED_REASON_SYSTEM), BLOCKED_REASON_NONE); + effectiveBlockedReasons.put( + Pair.create(BLOCKED_METERED_REASON_DATA_SAVER, ALLOWED_METERED_REASON_SYSTEM), + BLOCKED_REASON_NONE); + effectiveBlockedReasons.put(Pair.create(BLOCKED_METERED_REASON_DATA_SAVER + | BLOCKED_METERED_REASON_USER_RESTRICTED, + ALLOWED_METERED_REASON_SYSTEM), BLOCKED_REASON_NONE); + + effectiveBlockedReasons.put( Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_METERED_REASON_DATA_SAVER, - ALLOWED_REASON_SYSTEM)); - effectiveBlockedReasons.put(BLOCKED_REASON_APP_STANDBY, + ALLOWED_REASON_SYSTEM), BLOCKED_METERED_REASON_DATA_SAVER); + effectiveBlockedReasons.put( Pair.create(BLOCKED_REASON_APP_STANDBY | BLOCKED_METERED_REASON_USER_RESTRICTED, - ALLOWED_METERED_REASON_SYSTEM)); - - effectiveBlockedReasons.put(BLOCKED_REASON_NONE, - Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_FOREGROUND)); - effectiveBlockedReasons.put(BLOCKED_REASON_NONE, - Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE, - ALLOWED_REASON_FOREGROUND)); - effectiveBlockedReasons.put(BLOCKED_REASON_NONE, - Pair.create(BLOCKED_METERED_REASON_DATA_SAVER, ALLOWED_METERED_REASON_FOREGROUND)); - effectiveBlockedReasons.put(BLOCKED_REASON_NONE, - Pair.create(BLOCKED_METERED_REASON_DATA_SAVER - | BLOCKED_METERED_REASON_USER_RESTRICTED, - ALLOWED_METERED_REASON_FOREGROUND)); - effectiveBlockedReasons.put(BLOCKED_METERED_REASON_DATA_SAVER, + ALLOWED_METERED_REASON_SYSTEM), BLOCKED_REASON_APP_STANDBY); + + effectiveBlockedReasons.put( + Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_FOREGROUND), + BLOCKED_REASON_NONE); + effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE, + ALLOWED_REASON_FOREGROUND), BLOCKED_REASON_NONE); + effectiveBlockedReasons.put( + Pair.create(BLOCKED_METERED_REASON_DATA_SAVER, ALLOWED_METERED_REASON_FOREGROUND), + BLOCKED_REASON_NONE); + effectiveBlockedReasons.put(Pair.create(BLOCKED_METERED_REASON_DATA_SAVER + | BLOCKED_METERED_REASON_USER_RESTRICTED, + ALLOWED_METERED_REASON_FOREGROUND), BLOCKED_REASON_NONE); + effectiveBlockedReasons.put( Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_METERED_REASON_DATA_SAVER, - ALLOWED_REASON_FOREGROUND)); - effectiveBlockedReasons.put(BLOCKED_REASON_BATTERY_SAVER, - Pair.create(BLOCKED_REASON_BATTERY_SAVER - | BLOCKED_METERED_REASON_USER_RESTRICTED, - ALLOWED_METERED_REASON_FOREGROUND)); + ALLOWED_REASON_FOREGROUND), BLOCKED_METERED_REASON_DATA_SAVER); + effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_BATTERY_SAVER + | BLOCKED_METERED_REASON_USER_RESTRICTED, + ALLOWED_METERED_REASON_FOREGROUND), BLOCKED_REASON_BATTERY_SAVER); + + effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_LOW_POWER_STANDBY, + ALLOWED_REASON_FOREGROUND), BLOCKED_REASON_LOW_POWER_STANDBY); + effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_LOW_POWER_STANDBY, + ALLOWED_REASON_TOP), BLOCKED_REASON_NONE); + effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_LOW_POWER_STANDBY, + ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST), BLOCKED_REASON_NONE); // TODO: test more combinations of blocked reasons. - for (int i = 0; i < effectiveBlockedReasons.size(); ++i) { - final int expectedEffectiveBlockedReasons = effectiveBlockedReasons.keyAt(i); - final int blockedReasons = effectiveBlockedReasons.valueAt(i).first; - final int allowedReasons = effectiveBlockedReasons.valueAt(i).second; + for (Map.Entry<Pair<Integer, Integer>, Integer> test : effectiveBlockedReasons.entrySet()) { + final int expectedEffectiveBlockedReasons = test.getValue(); + final int blockedReasons = test.getKey().first; + final int allowedReasons = test.getKey().second; final String errorMsg = "Expected=" + blockedReasonsToString(expectedEffectiveBlockedReasons) + "; blockedReasons=" + blockedReasonsToString(blockedReasons) |