Loading services/core/java/com/android/server/net/NetworkPolicyManagerService.java +128 −29 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.Manifest.permission.READ_PHONE_STATE; import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; import static android.app.ActivityManager.isProcStateConsideredInteraction; import static android.app.ActivityManager.printCapabilitiesSummary; Loading Loading @@ -523,6 +524,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { */ private boolean mUseMeteredFirewallChains; /** * Whether or not sensitive process states and non-sensitive process-states have different * delays before network is blocked after transitioning to background. */ private boolean mUseDifferentDelaysForBackgroundChain; // See main javadoc for instructions on how to use these locks. final Object mUidRulesFirstLock = new Object(); final Object mNetworkPoliciesSecondLock = new Object(); Loading Loading @@ -552,10 +559,43 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} will lose network access. * The delay is meant to prevent churn due to quick process-state changes. * Note that there is no delay while granting network access. * * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is disabled. */ @VisibleForTesting long mBackgroundRestrictionDelayMs = TimeUnit.SECONDS.toMillis(5); /** * Short delay after which a uid going into a process state having priority equal to * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} or lower will lose network access. * * This will apply to apps that should be fine with losing network access immediately. * It is only meant as a debounce to prevent churn due to quick process-state changes. * Note that there is no delay while granting network access. * * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is enabled. */ @VisibleForTesting long mBackgroundRestrictionShortDelayMs = TimeUnit.SECONDS.toMillis(2); /** * Long delay after which a uid going into a process state having priority equal to * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} or lower will lose network access. * * Unlike {@link #mBackgroundRestrictionShortDelayMs}, this is meant to be applied to apps * in sensitive proc-states like {@link ActivityManager#PROCESS_STATE_TOP_SLEEPING} and * {@link ActivityManager#PROCESS_STATE_LAST_ACTIVITY}, where the user may switch to this app * before this period and any latency in granting network access before resuming app activities * may degrade experience. * * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is enabled. */ @VisibleForTesting long mBackgroundRestrictionLongDelayMs = TimeUnit.SECONDS.toMillis(20); @GuardedBy("mUidRulesFirstLock") private long mNextProcessBackgroundUidsTime = Long.MAX_VALUE; /** Defined network policies. */ @GuardedBy("mNetworkPoliciesSecondLock") final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>(); Loading Loading @@ -1007,6 +1047,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mUseMeteredFirewallChains = Flags.useMeteredFirewallChains(); mUseDifferentDelaysForBackgroundChain = Flags.useDifferentDelaysForBackgroundChain(); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { Loading Loading @@ -1241,12 +1282,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // different chains may change. return true; } if (mBackgroundNetworkRestricted && (previousProcState >= BACKGROUND_THRESHOLD_STATE) if (mBackgroundNetworkRestricted) { if ((previousProcState >= BACKGROUND_THRESHOLD_STATE) != (newProcState >= BACKGROUND_THRESHOLD_STATE)) { // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: Network rules for the // BACKGROUND chain may change. // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: The network rules will // need to be re-evaluated for the background chain. return true; } if (mUseDifferentDelaysForBackgroundChain && newProcState >= BACKGROUND_THRESHOLD_STATE && getBackgroundTransitioningDelay(newProcState) < getBackgroundTransitioningDelay(previousProcState)) { // The old and new proc-state both are in the blocked state but the background // transition delay is reduced, so we may have to update the rules sooner. return true; } } final int networkCapabilities = PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; if ((previousInfo.capability & networkCapabilities) Loading Loading @@ -4045,6 +4096,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { + mBackgroundNetworkRestricted); fout.println(Flags.FLAG_USE_METERED_FIREWALL_CHAINS + ": " + mUseMeteredFirewallChains); fout.println(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN + ": " + mUseDifferentDelaysForBackgroundChain); fout.println(); fout.println("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode); Loading Loading @@ -4188,6 +4241,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.decreaseIndent(); } if (mBackgroundNetworkRestricted) { fout.println(); if (mUseDifferentDelaysForBackgroundChain) { fout.print("Background restrictions short delay: "); TimeUtils.formatDuration(mBackgroundRestrictionShortDelayMs, fout); fout.println(); fout.print("Background restrictions long delay: "); TimeUtils.formatDuration(mBackgroundRestrictionLongDelayMs, fout); fout.println(); } size = mBackgroundTransitioningUids.size(); if (size > 0) { final long nowUptime = SystemClock.uptimeMillis(); Loading @@ -4197,12 +4262,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print("UID="); fout.print(mBackgroundTransitioningUids.keyAt(i)); fout.print(", "); TimeUtils.formatDuration(mBackgroundTransitioningUids.valueAt(i), nowUptime, fout); TimeUtils.formatDuration(mBackgroundTransitioningUids.valueAt(i), nowUptime, fout); fout.println(); } fout.decreaseIndent(); } fout.println(); } final SparseBooleanArray knownUids = new SparseBooleanArray(); collectKeys(mUidState, knownUids); Loading Loading @@ -4337,6 +4404,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { || isProcStateAllowedNetworkWhileBackground(mUidState.get(uid)); } private long getBackgroundTransitioningDelay(int procState) { if (mUseDifferentDelaysForBackgroundChain) { return procState <= PROCESS_STATE_LAST_ACTIVITY ? mBackgroundRestrictionLongDelayMs : mBackgroundRestrictionShortDelayMs; } else { return mBackgroundRestrictionDelayMs; } } /** * Process state of UID changed; if needed, will trigger * {@link #updateRulesForDataUsageRestrictionsUL(int)} and Loading Loading @@ -4387,19 +4463,41 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mBackgroundTransitioningUids.delete(uid); updateRuleForBackgroundUL(uid); updatePowerRestrictionRules = true; } else if (wasAllowed && !isAllowed) { } else if (!isAllowed) { final int transitionIdx = mBackgroundTransitioningUids.indexOfKey(uid); final long completionTimeMs = SystemClock.uptimeMillis() + mBackgroundRestrictionDelayMs; if (mBackgroundTransitioningUids.indexOfKey(uid) < 0) { // This is just a defensive check in case the upstream code ever makes // multiple calls for the same process state change. + getBackgroundTransitioningDelay(procState); boolean completionTimeUpdated = false; if (wasAllowed) { // Rules need to transition from allowed to blocked after the respective // delay. if (transitionIdx < 0) { // This is just a defensive check in case the upstream code ever // makes multiple calls for the same process state change. mBackgroundTransitioningUids.put(uid, completionTimeMs); } if (!mHandler.hasMessages(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS)) { // Many uids may be in this "transitioning" state at the same time, so // using one message at a time to avoid congestion in the MessageQueue. completionTimeUpdated = true; } } else if (mUseDifferentDelaysForBackgroundChain) { // wasAllowed was false, but the transition delay may have reduced. // Currently, this can happen when the uid transitions from // LAST_ACTIVITY to CACHED_ACTIVITY, for example. if (transitionIdx >= 0 && completionTimeMs < mBackgroundTransitioningUids.valueAt( transitionIdx)) { mBackgroundTransitioningUids.setValueAt(transitionIdx, completionTimeMs); completionTimeUpdated = true; } } if (completionTimeUpdated && completionTimeMs < mNextProcessBackgroundUidsTime) { // Many uids may be in this "transitioning" state at the same time, // so we always keep one message to process transition completion at // the earliest time. mHandler.removeMessages(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS); mHandler.sendEmptyMessageAtTime( MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, completionTimeMs); mNextProcessBackgroundUidsTime = completionTimeMs; } } } Loading Loading @@ -5750,10 +5848,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateRuleForBackgroundUL(uid); updateRulesForPowerRestrictionsUL(uid, false); } } mNextProcessBackgroundUidsTime = nextCheckTime; if (nextCheckTime < Long.MAX_VALUE) { mHandler.sendEmptyMessageAtTime(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, nextCheckTime); mHandler.sendEmptyMessageAtTime( MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, nextCheckTime); } } return true; } Loading services/core/java/com/android/server/net/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -17,3 +17,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "use_different_delays_for_background_chain" namespace: "backstage_power" description: "Grant longer grace periods for sensitive process-states before blocking network using the background chain" bug: "323963467" metadata { purpose: PURPOSE_BUGFIX } } services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +64 −1 Original line number Diff line number Diff line Loading @@ -18,11 +18,13 @@ package com.android.server.net; import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.Manifest.permission.NETWORK_STACK; import static android.app.ActivityManager.MAX_PROCESS_STATE; import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL; import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER; Loading Loading @@ -165,9 +167,11 @@ import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.RemoteException; import android.os.SimpleClock; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; Loading Loading @@ -2158,7 +2162,8 @@ public class NetworkPolicyManagerServiceTest { @Test @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testBackgroundChainOnProcStateChange() throws Exception { @RequiresFlagsDisabled(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN) public void testBackgroundChainOnProcStateChangeSameDelay() throws Exception { // initialization calls setFirewallChainEnabled, so we want to reset the invocations. clearInvocations(mNetworkManager); Loading @@ -2185,6 +2190,59 @@ public class NetworkPolicyManagerServiceTest { assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); } @Test @RequiresFlagsEnabled({ Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE, Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN }) public void testBackgroundChainOnProcStateChangeDifferentDelays() throws Exception { // The app will be blocked when there is no prior proc-state. assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); // Tweak delays to avoid waiting too long in tests. mService.mBackgroundRestrictionShortDelayMs = 50; mService.mBackgroundRestrictionLongDelayMs = 1000; int procStateSeq = 231; // Any arbitrary starting sequence. for (int ps = BACKGROUND_THRESHOLD_STATE; ps <= MAX_PROCESS_STATE; ps++) { clearInvocations(mNetworkManager); // Make sure app is in correct process-state to access network. callAndWaitOnUidStateChanged(UID_A, BACKGROUND_THRESHOLD_STATE - 1, procStateSeq++); verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A, FIREWALL_RULE_ALLOW); assertFalse(mService.isUidNetworkingBlocked(UID_A, false)); // Now put the app into the background and test that it eventually loses network. callAndWaitOnUidStateChanged(UID_A, ps, procStateSeq++); final long uidStateChangeTime = SystemClock.uptimeMillis(); if (ps <= PROCESS_STATE_LAST_ACTIVITY) { // Verify that the app is blocked after long delay but not after short delay. waitForDelayedMessageOnHandler(mService.mBackgroundRestrictionShortDelayMs + 1); verify(mNetworkManager, never()).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A, FIREWALL_RULE_DEFAULT); assertFalse(mService.isUidNetworkingBlocked(UID_A, false)); final long timeUntilLongDelay = uidStateChangeTime + mService.mBackgroundRestrictionLongDelayMs - SystemClock.uptimeMillis(); assertTrue("No time left to verify long delay in background transition", timeUntilLongDelay >= 0); waitForDelayedMessageOnHandler(timeUntilLongDelay + 1); verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A, FIREWALL_RULE_DEFAULT); assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); } else { // Verify that the app is blocked after short delay. waitForDelayedMessageOnHandler(mService.mBackgroundRestrictionShortDelayMs + 1); verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A, FIREWALL_RULE_DEFAULT); assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); } } } @Test @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testBackgroundChainOnAllowlistChange() throws Exception { Loading Loading @@ -2881,6 +2939,11 @@ public class NetworkPolicyManagerServiceTest { } } /** * This posts a blocking message to the service handler with the given delayMs and waits for it * to complete. This ensures that all messages posted before the given delayMs will also * have been executed before this method returns and can be verified in subsequent code. */ private void waitForDelayedMessageOnHandler(long delayMs) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); mService.getHandlerForTesting().postDelayed(latch::countDown, delayMs); Loading Loading
services/core/java/com/android/server/net/NetworkPolicyManagerService.java +128 −29 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.Manifest.permission.READ_PHONE_STATE; import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; import static android.app.ActivityManager.isProcStateConsideredInteraction; import static android.app.ActivityManager.printCapabilitiesSummary; Loading Loading @@ -523,6 +524,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { */ private boolean mUseMeteredFirewallChains; /** * Whether or not sensitive process states and non-sensitive process-states have different * delays before network is blocked after transitioning to background. */ private boolean mUseDifferentDelaysForBackgroundChain; // See main javadoc for instructions on how to use these locks. final Object mUidRulesFirstLock = new Object(); final Object mNetworkPoliciesSecondLock = new Object(); Loading Loading @@ -552,10 +559,43 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} will lose network access. * The delay is meant to prevent churn due to quick process-state changes. * Note that there is no delay while granting network access. * * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is disabled. */ @VisibleForTesting long mBackgroundRestrictionDelayMs = TimeUnit.SECONDS.toMillis(5); /** * Short delay after which a uid going into a process state having priority equal to * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} or lower will lose network access. * * This will apply to apps that should be fine with losing network access immediately. * It is only meant as a debounce to prevent churn due to quick process-state changes. * Note that there is no delay while granting network access. * * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is enabled. */ @VisibleForTesting long mBackgroundRestrictionShortDelayMs = TimeUnit.SECONDS.toMillis(2); /** * Long delay after which a uid going into a process state having priority equal to * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} or lower will lose network access. * * Unlike {@link #mBackgroundRestrictionShortDelayMs}, this is meant to be applied to apps * in sensitive proc-states like {@link ActivityManager#PROCESS_STATE_TOP_SLEEPING} and * {@link ActivityManager#PROCESS_STATE_LAST_ACTIVITY}, where the user may switch to this app * before this period and any latency in granting network access before resuming app activities * may degrade experience. * * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is enabled. */ @VisibleForTesting long mBackgroundRestrictionLongDelayMs = TimeUnit.SECONDS.toMillis(20); @GuardedBy("mUidRulesFirstLock") private long mNextProcessBackgroundUidsTime = Long.MAX_VALUE; /** Defined network policies. */ @GuardedBy("mNetworkPoliciesSecondLock") final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>(); Loading Loading @@ -1007,6 +1047,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mUseMeteredFirewallChains = Flags.useMeteredFirewallChains(); mUseDifferentDelaysForBackgroundChain = Flags.useDifferentDelaysForBackgroundChain(); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { Loading Loading @@ -1241,12 +1282,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // different chains may change. return true; } if (mBackgroundNetworkRestricted && (previousProcState >= BACKGROUND_THRESHOLD_STATE) if (mBackgroundNetworkRestricted) { if ((previousProcState >= BACKGROUND_THRESHOLD_STATE) != (newProcState >= BACKGROUND_THRESHOLD_STATE)) { // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: Network rules for the // BACKGROUND chain may change. // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: The network rules will // need to be re-evaluated for the background chain. return true; } if (mUseDifferentDelaysForBackgroundChain && newProcState >= BACKGROUND_THRESHOLD_STATE && getBackgroundTransitioningDelay(newProcState) < getBackgroundTransitioningDelay(previousProcState)) { // The old and new proc-state both are in the blocked state but the background // transition delay is reduced, so we may have to update the rules sooner. return true; } } final int networkCapabilities = PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; if ((previousInfo.capability & networkCapabilities) Loading Loading @@ -4045,6 +4096,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { + mBackgroundNetworkRestricted); fout.println(Flags.FLAG_USE_METERED_FIREWALL_CHAINS + ": " + mUseMeteredFirewallChains); fout.println(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN + ": " + mUseDifferentDelaysForBackgroundChain); fout.println(); fout.println("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode); Loading Loading @@ -4188,6 +4241,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.decreaseIndent(); } if (mBackgroundNetworkRestricted) { fout.println(); if (mUseDifferentDelaysForBackgroundChain) { fout.print("Background restrictions short delay: "); TimeUtils.formatDuration(mBackgroundRestrictionShortDelayMs, fout); fout.println(); fout.print("Background restrictions long delay: "); TimeUtils.formatDuration(mBackgroundRestrictionLongDelayMs, fout); fout.println(); } size = mBackgroundTransitioningUids.size(); if (size > 0) { final long nowUptime = SystemClock.uptimeMillis(); Loading @@ -4197,12 +4262,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print("UID="); fout.print(mBackgroundTransitioningUids.keyAt(i)); fout.print(", "); TimeUtils.formatDuration(mBackgroundTransitioningUids.valueAt(i), nowUptime, fout); TimeUtils.formatDuration(mBackgroundTransitioningUids.valueAt(i), nowUptime, fout); fout.println(); } fout.decreaseIndent(); } fout.println(); } final SparseBooleanArray knownUids = new SparseBooleanArray(); collectKeys(mUidState, knownUids); Loading Loading @@ -4337,6 +4404,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { || isProcStateAllowedNetworkWhileBackground(mUidState.get(uid)); } private long getBackgroundTransitioningDelay(int procState) { if (mUseDifferentDelaysForBackgroundChain) { return procState <= PROCESS_STATE_LAST_ACTIVITY ? mBackgroundRestrictionLongDelayMs : mBackgroundRestrictionShortDelayMs; } else { return mBackgroundRestrictionDelayMs; } } /** * Process state of UID changed; if needed, will trigger * {@link #updateRulesForDataUsageRestrictionsUL(int)} and Loading Loading @@ -4387,19 +4463,41 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mBackgroundTransitioningUids.delete(uid); updateRuleForBackgroundUL(uid); updatePowerRestrictionRules = true; } else if (wasAllowed && !isAllowed) { } else if (!isAllowed) { final int transitionIdx = mBackgroundTransitioningUids.indexOfKey(uid); final long completionTimeMs = SystemClock.uptimeMillis() + mBackgroundRestrictionDelayMs; if (mBackgroundTransitioningUids.indexOfKey(uid) < 0) { // This is just a defensive check in case the upstream code ever makes // multiple calls for the same process state change. + getBackgroundTransitioningDelay(procState); boolean completionTimeUpdated = false; if (wasAllowed) { // Rules need to transition from allowed to blocked after the respective // delay. if (transitionIdx < 0) { // This is just a defensive check in case the upstream code ever // makes multiple calls for the same process state change. mBackgroundTransitioningUids.put(uid, completionTimeMs); } if (!mHandler.hasMessages(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS)) { // Many uids may be in this "transitioning" state at the same time, so // using one message at a time to avoid congestion in the MessageQueue. completionTimeUpdated = true; } } else if (mUseDifferentDelaysForBackgroundChain) { // wasAllowed was false, but the transition delay may have reduced. // Currently, this can happen when the uid transitions from // LAST_ACTIVITY to CACHED_ACTIVITY, for example. if (transitionIdx >= 0 && completionTimeMs < mBackgroundTransitioningUids.valueAt( transitionIdx)) { mBackgroundTransitioningUids.setValueAt(transitionIdx, completionTimeMs); completionTimeUpdated = true; } } if (completionTimeUpdated && completionTimeMs < mNextProcessBackgroundUidsTime) { // Many uids may be in this "transitioning" state at the same time, // so we always keep one message to process transition completion at // the earliest time. mHandler.removeMessages(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS); mHandler.sendEmptyMessageAtTime( MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, completionTimeMs); mNextProcessBackgroundUidsTime = completionTimeMs; } } } Loading Loading @@ -5750,10 +5848,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateRuleForBackgroundUL(uid); updateRulesForPowerRestrictionsUL(uid, false); } } mNextProcessBackgroundUidsTime = nextCheckTime; if (nextCheckTime < Long.MAX_VALUE) { mHandler.sendEmptyMessageAtTime(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, nextCheckTime); mHandler.sendEmptyMessageAtTime( MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, nextCheckTime); } } return true; } Loading
services/core/java/com/android/server/net/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -17,3 +17,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "use_different_delays_for_background_chain" namespace: "backstage_power" description: "Grant longer grace periods for sensitive process-states before blocking network using the background chain" bug: "323963467" metadata { purpose: PURPOSE_BUGFIX } }
services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +64 −1 Original line number Diff line number Diff line Loading @@ -18,11 +18,13 @@ package com.android.server.net; import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.Manifest.permission.NETWORK_STACK; import static android.app.ActivityManager.MAX_PROCESS_STATE; import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL; import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER; Loading Loading @@ -165,9 +167,11 @@ import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.RemoteException; import android.os.SimpleClock; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; Loading Loading @@ -2158,7 +2162,8 @@ public class NetworkPolicyManagerServiceTest { @Test @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testBackgroundChainOnProcStateChange() throws Exception { @RequiresFlagsDisabled(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN) public void testBackgroundChainOnProcStateChangeSameDelay() throws Exception { // initialization calls setFirewallChainEnabled, so we want to reset the invocations. clearInvocations(mNetworkManager); Loading @@ -2185,6 +2190,59 @@ public class NetworkPolicyManagerServiceTest { assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); } @Test @RequiresFlagsEnabled({ Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE, Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN }) public void testBackgroundChainOnProcStateChangeDifferentDelays() throws Exception { // The app will be blocked when there is no prior proc-state. assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); // Tweak delays to avoid waiting too long in tests. mService.mBackgroundRestrictionShortDelayMs = 50; mService.mBackgroundRestrictionLongDelayMs = 1000; int procStateSeq = 231; // Any arbitrary starting sequence. for (int ps = BACKGROUND_THRESHOLD_STATE; ps <= MAX_PROCESS_STATE; ps++) { clearInvocations(mNetworkManager); // Make sure app is in correct process-state to access network. callAndWaitOnUidStateChanged(UID_A, BACKGROUND_THRESHOLD_STATE - 1, procStateSeq++); verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A, FIREWALL_RULE_ALLOW); assertFalse(mService.isUidNetworkingBlocked(UID_A, false)); // Now put the app into the background and test that it eventually loses network. callAndWaitOnUidStateChanged(UID_A, ps, procStateSeq++); final long uidStateChangeTime = SystemClock.uptimeMillis(); if (ps <= PROCESS_STATE_LAST_ACTIVITY) { // Verify that the app is blocked after long delay but not after short delay. waitForDelayedMessageOnHandler(mService.mBackgroundRestrictionShortDelayMs + 1); verify(mNetworkManager, never()).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A, FIREWALL_RULE_DEFAULT); assertFalse(mService.isUidNetworkingBlocked(UID_A, false)); final long timeUntilLongDelay = uidStateChangeTime + mService.mBackgroundRestrictionLongDelayMs - SystemClock.uptimeMillis(); assertTrue("No time left to verify long delay in background transition", timeUntilLongDelay >= 0); waitForDelayedMessageOnHandler(timeUntilLongDelay + 1); verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A, FIREWALL_RULE_DEFAULT); assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); } else { // Verify that the app is blocked after short delay. waitForDelayedMessageOnHandler(mService.mBackgroundRestrictionShortDelayMs + 1); verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A, FIREWALL_RULE_DEFAULT); assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); } } } @Test @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testBackgroundChainOnAllowlistChange() throws Exception { Loading Loading @@ -2881,6 +2939,11 @@ public class NetworkPolicyManagerServiceTest { } } /** * This posts a blocking message to the service handler with the given delayMs and waits for it * to complete. This ensures that all messages posted before the given delayMs will also * have been executed before this method returns and can be verified in subsequent code. */ private void waitForDelayedMessageOnHandler(long delayMs) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); mService.getHandlerForTesting().postDelayed(latch::countDown, delayMs); Loading