Loading core/java/android/net/NetworkPolicyManager.java +7 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.net; import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; import static android.app.ActivityManager.procStateToString; import static android.content.pm.PackageManager.GET_SIGNATURES; Loading Loading @@ -805,6 +806,9 @@ public class NetworkPolicyManager { /** @hide */ public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode( int procState, @ProcessCapability int capability) { if (procState == PROCESS_STATE_UNKNOWN) { return false; } return procState <= FOREGROUND_THRESHOLD_STATE || (capability & ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0; } Loading Loading @@ -832,6 +836,9 @@ public class NetworkPolicyManager { /** @hide */ public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState, @ProcessCapability int capabilities) { if (procState == PROCESS_STATE_UNKNOWN) { return false; } return procState <= FOREGROUND_THRESHOLD_STATE // This is meant to be a user-initiated job, and therefore gets similar network // access to FGS. Loading services/core/java/com/android/server/net/NetworkPolicyManagerService.java +61 −24 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_STATE_UNKNOWN; import static android.app.ActivityManager.isProcStateConsideredInteraction; import static android.app.ActivityManager.printCapabilitiesSummary; import static android.app.ActivityManager.procStateToString; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; Loading Loading @@ -1133,6 +1134,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (!callbackInfo.isPending) { mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo) .sendToTarget(); callbackInfo.isPending = true; } } } Loading @@ -1156,6 +1158,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { this.procStateSeq = procStateSeq; this.capability = capability; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("{"); sb.append("uid=").append(uid).append(","); sb.append("proc_state=").append(procStateToString(procState)).append(","); sb.append("seq=").append(procStateSeq).append(","); sb.append("cap="); printCapabilitiesSummary(sb, capability); sb.append(","); sb.append("pending=").append(isPending); sb.append("}"); return sb.toString(); } } final private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() { Loading Loading @@ -3982,31 +3997,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { synchronized (mUidBlockedState) { collectKeys(mUidBlockedState, knownUids); } synchronized (mUidStateCallbackInfos) { collectKeys(mUidStateCallbackInfos, knownUids); } fout.println("Status for all known UIDs:"); fout.increaseIndent(); size = knownUids.size(); for (int i = 0; i < size; i++) { final int uid = knownUids.keyAt(i); fout.print("UID="); fout.print(uid); fout.print("UID", uid); final UidState uidState = mUidState.get(uid); if (uidState == null) { fout.print(" state={null}"); } else { fout.print(" state="); fout.print(uidState.toString()); } fout.print("state", uidState); synchronized (mUidBlockedState) { final UidBlockedState uidBlockedState = mUidBlockedState.get(uid); if (uidBlockedState == null) { fout.print(" blocked_state={null}"); } else { fout.print(" blocked_state="); fout.print(uidBlockedState); fout.print("blocked_state", uidBlockedState); } synchronized (mUidStateCallbackInfos) { final UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid); fout.println(); fout.increaseIndent(); fout.print("callback_info", callbackInfo); fout.decreaseIndent(); } fout.println(); } Loading Loading @@ -4052,27 +4067,49 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @VisibleForTesting boolean isUidForeground(int uid) { synchronized (mUidRulesFirstLock) { return isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid)); } } @GuardedBy("mUidRulesFirstLock") private boolean isUidForegroundOnRestrictBackgroundUL(int uid) { boolean isUidForegroundOnRestrictBackgroundUL(int uid) { final UidState uidState = mUidState.get(uid); return isProcStateAllowedWhileOnRestrictBackground(uidState); if (isProcStateAllowedWhileOnRestrictBackground(uidState)) { return true; } // Check if there is any pending state change. synchronized (mUidStateCallbackInfos) { final UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid); final long prevProcStateSeq = uidState != null ? uidState.procStateSeq : -1; if (callbackInfo != null && callbackInfo.isPending && callbackInfo.procStateSeq >= prevProcStateSeq) { return isProcStateAllowedWhileOnRestrictBackground(callbackInfo.procState, callbackInfo.capability); } } return false; } @VisibleForTesting @GuardedBy("mUidRulesFirstLock") private boolean isUidForegroundOnRestrictPowerUL(int uid) { boolean isUidForegroundOnRestrictPowerUL(int uid) { final UidState uidState = mUidState.get(uid); return isProcStateAllowedWhileIdleOrPowerSaveMode(uidState); if (isProcStateAllowedWhileIdleOrPowerSaveMode(uidState)) { return true; } // Check if there is any pending state change. synchronized (mUidStateCallbackInfos) { final UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid); final long prevProcStateSeq = uidState != null ? uidState.procStateSeq : -1; if (callbackInfo != null && callbackInfo.isPending && callbackInfo.procStateSeq >= prevProcStateSeq) { return isProcStateAllowedWhileIdleOrPowerSaveMode(callbackInfo.procState, callbackInfo.capability); } } return false; } @GuardedBy("mUidRulesFirstLock") private boolean isUidTop(int uid) { final UidState uidState = mUidState.get(uid); // TODO: Consider taking pending uid state change into account. return isProcStateAllowedWhileInLowPowerStandby(uidState); } Loading services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +146 −18 Original line number Diff line number Diff line Loading @@ -18,6 +18,12 @@ 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.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_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER; import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED; import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY; Loading Loading @@ -396,6 +402,26 @@ public class NetworkPolicyManagerServiceTest { } } // TODO: Use TestLooperManager instead. /** * Helper that leverages try-with-resources to pause dispatch of * {@link #mHandlerThread} until released. */ static class SyncBarrier implements AutoCloseable { private final int mToken; private Handler mHandler; SyncBarrier(Handler handler) { mHandler = handler; mToken = mHandler.getLooper().getQueue().postSyncBarrier(); } @Override public void close() throws Exception { mHandler.getLooper().getQueue().removeSyncBarrier(mToken); } } @Before public void callSystemReady() throws Exception { MockitoAnnotations.initMocks(this); Loading Loading @@ -1018,25 +1044,113 @@ public class NetworkPolicyManagerServiceTest { // don't check for side-effects (like calls to NetworkManagementService) neither cover all // different modes (Data Saver, Battery Saver, Doze, App idle, etc...). // These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests. @SuppressWarnings("GuardedBy") @Test public void testUidForeground() throws Exception { // push all uids into background long procStateSeq = 0; callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++); callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++); assertFalse(mService.isUidForeground(UID_A)); assertFalse(mService.isUidForeground(UID_B)); callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++); callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); // push one of the uids into foreground callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, procStateSeq++); assertTrue(mService.isUidForeground(UID_A)); assertFalse(mService.isUidForeground(UID_B)); callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, procStateSeq++); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); // and swap another uid into foreground callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++); callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP, procStateSeq++); assertFalse(mService.isUidForeground(UID_A)); assertTrue(mService.isUidForeground(UID_B)); callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++); callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_TOP, procStateSeq++); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); // change capability of an uid to allow access to power restricted network callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK); callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_NONE); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); // change capability of an uid to allow access to user restricted network callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_IMPORTANT_FOREGROUND, procStateSeq++, PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK); callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_NONE); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); } @SuppressWarnings("GuardedBy") @Test public void testUidForeground_withPendingState() throws Exception { long procStateSeq = 0; callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_NONE); callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_NONE); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) { // Verify that a callback with an old procStateSeq is ignored. callOnUidStatechanged(UID_A, PROCESS_STATE_TOP, 0, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); callOnUidStatechanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); callOnUidStatechanged(UID_A, PROCESS_STATE_IMPORTANT_FOREGROUND, procStateSeq++, PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); callOnUidStatechanged(UID_A, PROCESS_STATE_TOP, procStateSeq++, PROCESS_CAPABILITY_NONE); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); } waitForUidEventHandlerIdle(); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) { callOnUidStatechanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_NONE); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); } waitForUidEventHandlerIdle(); } @Test Loading Loading @@ -1417,14 +1531,28 @@ public class NetworkPolicyManagerServiceTest { @Test public void testOnUidStateChanged_notifyAMS() throws Exception { final long procStateSeq = 222; callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq); callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq); verify(mActivityManagerInternal).notifyNetworkPolicyRulesUpdated(UID_A, procStateSeq); } private void callOnUidStateChanged(int uid, int procState, long procStateSeq) private void callAndWaitOnUidStateChanged(int uid, int procState, long procStateSeq) throws Exception { mUidObserver.onUidStateChanged(uid, procState, procStateSeq, ActivityManager.PROCESS_CAPABILITY_NONE); callAndWaitOnUidStateChanged(uid, procState, procStateSeq, PROCESS_CAPABILITY_NONE); } private void callAndWaitOnUidStateChanged(int uid, int procState, long procStateSeq, int capability) throws Exception { callOnUidStatechanged(uid, procState, procStateSeq, capability); waitForUidEventHandlerIdle(); } private void callOnUidStatechanged(int uid, int procState, long procStateSeq, int capability) throws Exception { mUidObserver.onUidStateChanged(uid, procState, procStateSeq, capability); } private void waitForUidEventHandlerIdle() throws Exception { final CountDownLatch latch = new CountDownLatch(1); mService.mUidEventHandler.post(() -> { latch.countDown(); Loading Loading @@ -1927,9 +2055,9 @@ 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); callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, 0); callAndWaitOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0); callAndWaitOnUidStateChanged(UID_C, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0); expectHasInternetPermission(UID_A, true); expectHasInternetPermission(UID_B, true); expectHasInternetPermission(UID_C, true); Loading Loading
core/java/android/net/NetworkPolicyManager.java +7 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.net; import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; import static android.app.ActivityManager.procStateToString; import static android.content.pm.PackageManager.GET_SIGNATURES; Loading Loading @@ -805,6 +806,9 @@ public class NetworkPolicyManager { /** @hide */ public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode( int procState, @ProcessCapability int capability) { if (procState == PROCESS_STATE_UNKNOWN) { return false; } return procState <= FOREGROUND_THRESHOLD_STATE || (capability & ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0; } Loading Loading @@ -832,6 +836,9 @@ public class NetworkPolicyManager { /** @hide */ public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState, @ProcessCapability int capabilities) { if (procState == PROCESS_STATE_UNKNOWN) { return false; } return procState <= FOREGROUND_THRESHOLD_STATE // This is meant to be a user-initiated job, and therefore gets similar network // access to FGS. Loading
services/core/java/com/android/server/net/NetworkPolicyManagerService.java +61 −24 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_STATE_UNKNOWN; import static android.app.ActivityManager.isProcStateConsideredInteraction; import static android.app.ActivityManager.printCapabilitiesSummary; import static android.app.ActivityManager.procStateToString; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; Loading Loading @@ -1133,6 +1134,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (!callbackInfo.isPending) { mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo) .sendToTarget(); callbackInfo.isPending = true; } } } Loading @@ -1156,6 +1158,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { this.procStateSeq = procStateSeq; this.capability = capability; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("{"); sb.append("uid=").append(uid).append(","); sb.append("proc_state=").append(procStateToString(procState)).append(","); sb.append("seq=").append(procStateSeq).append(","); sb.append("cap="); printCapabilitiesSummary(sb, capability); sb.append(","); sb.append("pending=").append(isPending); sb.append("}"); return sb.toString(); } } final private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() { Loading Loading @@ -3982,31 +3997,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { synchronized (mUidBlockedState) { collectKeys(mUidBlockedState, knownUids); } synchronized (mUidStateCallbackInfos) { collectKeys(mUidStateCallbackInfos, knownUids); } fout.println("Status for all known UIDs:"); fout.increaseIndent(); size = knownUids.size(); for (int i = 0; i < size; i++) { final int uid = knownUids.keyAt(i); fout.print("UID="); fout.print(uid); fout.print("UID", uid); final UidState uidState = mUidState.get(uid); if (uidState == null) { fout.print(" state={null}"); } else { fout.print(" state="); fout.print(uidState.toString()); } fout.print("state", uidState); synchronized (mUidBlockedState) { final UidBlockedState uidBlockedState = mUidBlockedState.get(uid); if (uidBlockedState == null) { fout.print(" blocked_state={null}"); } else { fout.print(" blocked_state="); fout.print(uidBlockedState); fout.print("blocked_state", uidBlockedState); } synchronized (mUidStateCallbackInfos) { final UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid); fout.println(); fout.increaseIndent(); fout.print("callback_info", callbackInfo); fout.decreaseIndent(); } fout.println(); } Loading Loading @@ -4052,27 +4067,49 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @VisibleForTesting boolean isUidForeground(int uid) { synchronized (mUidRulesFirstLock) { return isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid)); } } @GuardedBy("mUidRulesFirstLock") private boolean isUidForegroundOnRestrictBackgroundUL(int uid) { boolean isUidForegroundOnRestrictBackgroundUL(int uid) { final UidState uidState = mUidState.get(uid); return isProcStateAllowedWhileOnRestrictBackground(uidState); if (isProcStateAllowedWhileOnRestrictBackground(uidState)) { return true; } // Check if there is any pending state change. synchronized (mUidStateCallbackInfos) { final UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid); final long prevProcStateSeq = uidState != null ? uidState.procStateSeq : -1; if (callbackInfo != null && callbackInfo.isPending && callbackInfo.procStateSeq >= prevProcStateSeq) { return isProcStateAllowedWhileOnRestrictBackground(callbackInfo.procState, callbackInfo.capability); } } return false; } @VisibleForTesting @GuardedBy("mUidRulesFirstLock") private boolean isUidForegroundOnRestrictPowerUL(int uid) { boolean isUidForegroundOnRestrictPowerUL(int uid) { final UidState uidState = mUidState.get(uid); return isProcStateAllowedWhileIdleOrPowerSaveMode(uidState); if (isProcStateAllowedWhileIdleOrPowerSaveMode(uidState)) { return true; } // Check if there is any pending state change. synchronized (mUidStateCallbackInfos) { final UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid); final long prevProcStateSeq = uidState != null ? uidState.procStateSeq : -1; if (callbackInfo != null && callbackInfo.isPending && callbackInfo.procStateSeq >= prevProcStateSeq) { return isProcStateAllowedWhileIdleOrPowerSaveMode(callbackInfo.procState, callbackInfo.capability); } } return false; } @GuardedBy("mUidRulesFirstLock") private boolean isUidTop(int uid) { final UidState uidState = mUidState.get(uid); // TODO: Consider taking pending uid state change into account. return isProcStateAllowedWhileInLowPowerStandby(uidState); } Loading
services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +146 −18 Original line number Diff line number Diff line Loading @@ -18,6 +18,12 @@ 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.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_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER; import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED; import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY; Loading Loading @@ -396,6 +402,26 @@ public class NetworkPolicyManagerServiceTest { } } // TODO: Use TestLooperManager instead. /** * Helper that leverages try-with-resources to pause dispatch of * {@link #mHandlerThread} until released. */ static class SyncBarrier implements AutoCloseable { private final int mToken; private Handler mHandler; SyncBarrier(Handler handler) { mHandler = handler; mToken = mHandler.getLooper().getQueue().postSyncBarrier(); } @Override public void close() throws Exception { mHandler.getLooper().getQueue().removeSyncBarrier(mToken); } } @Before public void callSystemReady() throws Exception { MockitoAnnotations.initMocks(this); Loading Loading @@ -1018,25 +1044,113 @@ public class NetworkPolicyManagerServiceTest { // don't check for side-effects (like calls to NetworkManagementService) neither cover all // different modes (Data Saver, Battery Saver, Doze, App idle, etc...). // These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests. @SuppressWarnings("GuardedBy") @Test public void testUidForeground() throws Exception { // push all uids into background long procStateSeq = 0; callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++); callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++); assertFalse(mService.isUidForeground(UID_A)); assertFalse(mService.isUidForeground(UID_B)); callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++); callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); // push one of the uids into foreground callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, procStateSeq++); assertTrue(mService.isUidForeground(UID_A)); assertFalse(mService.isUidForeground(UID_B)); callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, procStateSeq++); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); // and swap another uid into foreground callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++); callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP, procStateSeq++); assertFalse(mService.isUidForeground(UID_A)); assertTrue(mService.isUidForeground(UID_B)); callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++); callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_TOP, procStateSeq++); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); // change capability of an uid to allow access to power restricted network callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK); callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_NONE); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); // change capability of an uid to allow access to user restricted network callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_IMPORTANT_FOREGROUND, procStateSeq++, PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK); callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_NONE); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); } @SuppressWarnings("GuardedBy") @Test public void testUidForeground_withPendingState() throws Exception { long procStateSeq = 0; callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_NONE); callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_NONE); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) { // Verify that a callback with an old procStateSeq is ignored. callOnUidStatechanged(UID_A, PROCESS_STATE_TOP, 0, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); callOnUidStatechanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); callOnUidStatechanged(UID_A, PROCESS_STATE_IMPORTANT_FOREGROUND, procStateSeq++, PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); callOnUidStatechanged(UID_A, PROCESS_STATE_TOP, procStateSeq++, PROCESS_CAPABILITY_NONE); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); } waitForUidEventHandlerIdle(); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) { callOnUidStatechanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++, PROCESS_CAPABILITY_NONE); assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A)); assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A)); assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B)); assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B)); } waitForUidEventHandlerIdle(); } @Test Loading Loading @@ -1417,14 +1531,28 @@ public class NetworkPolicyManagerServiceTest { @Test public void testOnUidStateChanged_notifyAMS() throws Exception { final long procStateSeq = 222; callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq); callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq); verify(mActivityManagerInternal).notifyNetworkPolicyRulesUpdated(UID_A, procStateSeq); } private void callOnUidStateChanged(int uid, int procState, long procStateSeq) private void callAndWaitOnUidStateChanged(int uid, int procState, long procStateSeq) throws Exception { mUidObserver.onUidStateChanged(uid, procState, procStateSeq, ActivityManager.PROCESS_CAPABILITY_NONE); callAndWaitOnUidStateChanged(uid, procState, procStateSeq, PROCESS_CAPABILITY_NONE); } private void callAndWaitOnUidStateChanged(int uid, int procState, long procStateSeq, int capability) throws Exception { callOnUidStatechanged(uid, procState, procStateSeq, capability); waitForUidEventHandlerIdle(); } private void callOnUidStatechanged(int uid, int procState, long procStateSeq, int capability) throws Exception { mUidObserver.onUidStateChanged(uid, procState, procStateSeq, capability); } private void waitForUidEventHandlerIdle() throws Exception { final CountDownLatch latch = new CountDownLatch(1); mService.mUidEventHandler.post(() -> { latch.countDown(); Loading Loading @@ -1927,9 +2055,9 @@ 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); callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, 0); callAndWaitOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0); callAndWaitOnUidStateChanged(UID_C, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0); expectHasInternetPermission(UID_A, true); expectHasInternetPermission(UID_B, true); expectHasInternetPermission(UID_C, true); Loading