diff options
| author | 2021-12-09 10:07:20 +0100 | |
|---|---|---|
| committer | 2022-02-10 13:53:05 +0100 | |
| commit | 452ab99df938aa5336611babb856da63491d52fc (patch) | |
| tree | 0954402690c2d8d9f1e9d89bc324034f0f833cfc | |
| parent | 4be1391e968e80be176d46c014e903cdecb4954a (diff) | |
Block network access in Low Power Standby
Bug: 190822356
Test: atest NetworkPolicyManagerServiceTest LowPowerStandbyControllerTest
Change-Id: I6c554df71b12bcf06f1c98ef70c35242bc90a689
6 files changed, 347 insertions, 51 deletions
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index df12d2c61ce0..18ec8f57ad3a 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. * @@ -752,6 +769,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 bb229022ac0b..240ed7767212 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; @@ -70,11 +72,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; @@ -88,6 +92,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; @@ -478,6 +483,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { volatile boolean mRestrictBackgroundChangedInBsm; @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictedNetworkingMode; + @GuardedBy("mUidRulesFirstLock") + volatile boolean mLowPowerStandbyActive; private final boolean mSuppressDefaultPolicy; @@ -517,6 +524,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") @@ -545,6 +554,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. @@ -3763,6 +3775,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); @@ -3898,6 +3911,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); @@ -3979,6 +4004,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 @@ -3995,8 +4026,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); @@ -4006,6 +4039,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 { @@ -4029,6 +4073,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateRuleForRestrictPowerUL(uid); } updateRulesForPowerRestrictionsUL(uid); + if (mLowPowerStandbyActive) { + updateRuleForLowPowerStandbyUL(uid); + } return true; } } @@ -4232,6 +4279,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); + setUidFirewallRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_ALLOW); + } else { + mUidFirewallLowPowerStandbyModeRules.delete(uid); + setUidFirewallRule(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). @@ -4261,6 +4352,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") @@ -4598,6 +4697,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mPowerSaveTempWhitelistAppIds.delete(uid); mAppIdleTempWhitelistAppIds.delete(uid); mUidFirewallRestrictedModeRules.delete(uid); + mUidFirewallLowPowerStandbyModeRules.delete(uid); synchronized (mUidStateCallbackInfos) { mUidStateCallbackInfos.remove(uid); } @@ -4823,6 +4923,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid); + final boolean isTop = isUidTop(uid); final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode); @@ -4836,17 +4937,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; @@ -4868,6 +4973,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { + ", mRestrictPower: " + mRestrictPower + ", mDeviceIdleMode: " + mDeviceIdleMode + ", isForeground=" + isForeground + + ", isTop=" + isTop + ", isWhitelisted=" + isWhitelisted + ", oldUidBlockedState=" + previousUidBlockedState.toString() + ", newUidBlockedState=" + uidBlockedState.toString()); @@ -5398,6 +5504,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 { @@ -5445,6 +5553,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) { @@ -5720,6 +5831,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) { @@ -5888,6 +6060,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; @@ -5903,6 +6078,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; } @@ -5927,6 +6106,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, @@ -5935,9 +6115,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, @@ -5955,6 +6137,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: @@ -5975,12 +6159,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: @@ -6047,7 +6235,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/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java index cea84b57377c..2d2bad27ecd3 100644 --- a/services/core/java/com/android/server/power/LowPowerStandbyController.java +++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java @@ -42,6 +42,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; +import com.android.server.net.NetworkPolicyManagerInternal; import java.io.PrintWriter; import java.util.Arrays; @@ -394,7 +395,11 @@ public final class LowPowerStandbyController { /** Notify other system components about the updated Low Power Standby active state */ private void notifyActiveChanged(boolean active) { final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class); + final NetworkPolicyManagerInternal npmi = LocalServices.getService( + NetworkPolicyManagerInternal.class); + pmi.setLowPowerStandbyActive(active); + npmi.setLowPowerStandbyActive(active); } @VisibleForTesting @@ -580,7 +585,10 @@ public final class LowPowerStandbyController { private void notifyAllowlistChanged(int[] allowlistUids) { final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class); + final NetworkPolicyManagerInternal npmi = LocalServices.getService( + NetworkPolicyManagerInternal.class); pmi.setLowPowerStandbyAllowlist(allowlistUids); + npmi.setLowPowerStandbyAllowlist(allowlistUids); } private final class LocalService extends LowPowerStandbyControllerInternal { 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) diff --git a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java index 4ae9613a36d3..00a794446742 100644 --- a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java @@ -47,6 +47,7 @@ import androidx.test.InstrumentationRegistry; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.LocalServices; +import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.testutils.OffsettableClock; import org.junit.After; @@ -80,6 +81,8 @@ public class LowPowerStandbyControllerTest { private IPowerManager mIPowerManagerMock; @Mock private PowerManagerInternal mPowerManagerInternalMock; + @Mock + private NetworkPolicyManagerInternal mNetworkPolicyManagerInternal; @Before public void setUp() throws Exception { @@ -90,6 +93,7 @@ public class LowPowerStandbyControllerTest { PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock, null, null); when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock); + addLocalServiceMock(NetworkPolicyManagerInternal.class, mNetworkPolicyManagerInternal); when(mIPowerManagerMock.isInteractive()).thenReturn(true); @@ -121,6 +125,7 @@ public class LowPowerStandbyControllerTest { public void tearDown() throws Exception { LocalServices.removeServiceForTest(PowerManagerInternal.class); LocalServices.removeServiceForTest(LowPowerStandbyControllerInternal.class); + LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); } @Test @@ -130,6 +135,7 @@ public class LowPowerStandbyControllerTest { assertThat(mController.isActive()).isFalse(); verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean()); + verify(mNetworkPolicyManagerInternal, never()).setLowPowerStandbyActive(anyBoolean()); } @Test @@ -142,6 +148,7 @@ public class LowPowerStandbyControllerTest { awaitStandbyTimeoutAlarm(); assertThat(mController.isActive()).isTrue(); verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(true); + verify(mNetworkPolicyManagerInternal, times(1)).setLowPowerStandbyActive(true); } private void awaitStandbyTimeoutAlarm() { @@ -169,6 +176,7 @@ public class LowPowerStandbyControllerTest { assertThat(mController.isActive()).isFalse(); verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean()); + verify(mNetworkPolicyManagerInternal, never()).setLowPowerStandbyActive(anyBoolean()); } @Test @@ -182,6 +190,7 @@ public class LowPowerStandbyControllerTest { assertThat(mController.isActive()).isTrue(); verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(true); + verify(mNetworkPolicyManagerInternal, times(1)).setLowPowerStandbyActive(true); } @Test @@ -197,6 +206,7 @@ public class LowPowerStandbyControllerTest { assertThat(mController.isActive()).isFalse(); verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean()); + verify(mNetworkPolicyManagerInternal, never()).setLowPowerStandbyActive(anyBoolean()); } private void verifyStandbyAlarmCancelled() { @@ -221,6 +231,7 @@ public class LowPowerStandbyControllerTest { assertThat(mController.isActive()).isFalse(); verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(false); + verify(mNetworkPolicyManagerInternal, times(1)).setLowPowerStandbyActive(false); } @Test @@ -238,6 +249,7 @@ public class LowPowerStandbyControllerTest { assertThat(mController.isActive()).isFalse(); verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(false); + verify(mNetworkPolicyManagerInternal, times(1)).setLowPowerStandbyActive(false); } @Test @@ -255,6 +267,7 @@ public class LowPowerStandbyControllerTest { assertThat(mController.isActive()).isTrue(); verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(false); + verify(mNetworkPolicyManagerInternal, never()).setLowPowerStandbyActive(false); } @Test @@ -273,6 +286,7 @@ public class LowPowerStandbyControllerTest { assertThat(mController.isActive()).isTrue(); verify(mPowerManagerInternalMock, times(2)).setLowPowerStandbyActive(true); + verify(mNetworkPolicyManagerInternal, times(2)).setLowPowerStandbyActive(true); } @Test @@ -285,6 +299,7 @@ public class LowPowerStandbyControllerTest { assertThat(mController.isActive()).isFalse(); verify(mAlarmManagerMock, never()).setExact(anyInt(), anyLong(), anyString(), any(), any()); verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean()); + verify(mNetworkPolicyManagerInternal, never()).setLowPowerStandbyActive(anyBoolean()); } @Test @@ -350,10 +365,12 @@ public class LowPowerStandbyControllerTest { service.addToAllowlist(10); mTestLooper.dispatchAll(); verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[] {10}); + verify(mNetworkPolicyManagerInternal).setLowPowerStandbyAllowlist(new int[] {10}); service.removeFromAllowlist(10); mTestLooper.dispatchAll(); verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[] {}); + verify(mNetworkPolicyManagerInternal).setLowPowerStandbyAllowlist(new int[] {}); } @Test @@ -366,12 +383,14 @@ public class LowPowerStandbyControllerTest { assertThat(mController.isActive()).isTrue(); verify(mPowerManagerInternalMock).setLowPowerStandbyActive(true); + verify(mNetworkPolicyManagerInternal).setLowPowerStandbyActive(true); mController.forceActive(false); mTestLooper.dispatchAll(); assertThat(mController.isActive()).isFalse(); verify(mPowerManagerInternalMock).setLowPowerStandbyActive(false); + verify(mNetworkPolicyManagerInternal).setLowPowerStandbyActive(false); } private void setLowPowerStandbySupportedConfig(boolean supported) { |