Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 575f04c6 authored by Sudheer Shanka's avatar Sudheer Shanka
Browse files

Use pending uid state when calculating network blocked state.

Since uid state callbacks are handled asynchronously, it is
possible that the network gets restricted before the uid
state callback is handled. So, when checking if the uid is in
the foreground, also consider any pending uid callback info.

Fixes: 278453942
Fixes: 278661002
Test: atest tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
Test: atest tests/cts/hostside/src/com/android/cts/net/HostsideConnOnActivityStartTest.java
Test: atest services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
Change-Id: Id5b6bd025731dc57952fef5e311d6efef310ff94
parent 150c188a
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package android.net;
package android.net;


import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManager.procStateToString;
import static android.app.ActivityManager.procStateToString;
import static android.content.pm.PackageManager.GET_SIGNATURES;
import static android.content.pm.PackageManager.GET_SIGNATURES;


@@ -805,6 +806,9 @@ public class NetworkPolicyManager {
    /** @hide */
    /** @hide */
    public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(
    public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(
            int procState, @ProcessCapability int capability) {
            int procState, @ProcessCapability int capability) {
        if (procState == PROCESS_STATE_UNKNOWN) {
            return false;
        }
        return procState <= FOREGROUND_THRESHOLD_STATE
        return procState <= FOREGROUND_THRESHOLD_STATE
                || (capability & ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0;
                || (capability & ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0;
    }
    }
@@ -832,6 +836,9 @@ public class NetworkPolicyManager {
    /** @hide */
    /** @hide */
    public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState,
    public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState,
            @ProcessCapability int capabilities) {
            @ProcessCapability int capabilities) {
        if (procState == PROCESS_STATE_UNKNOWN) {
            return false;
        }
        return procState <= FOREGROUND_THRESHOLD_STATE
        return procState <= FOREGROUND_THRESHOLD_STATE
                // This is meant to be a user-initiated job, and therefore gets similar network
                // This is meant to be a user-initiated job, and therefore gets similar network
                // access to FGS.
                // access to FGS.
+61 −24
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManager.isProcStateConsideredInteraction;
import static android.app.ActivityManager.isProcStateConsideredInteraction;
import static android.app.ActivityManager.printCapabilitiesSummary;
import static android.app.ActivityManager.procStateToString;
import static android.app.ActivityManager.procStateToString;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
@@ -1133,6 +1134,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                if (!callbackInfo.isPending) {
                if (!callbackInfo.isPending) {
                    mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
                    mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
                            .sendToTarget();
                            .sendToTarget();
                    callbackInfo.isPending = true;
                }
                }
            }
            }
        }
        }
@@ -1156,6 +1158,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            this.procStateSeq = procStateSeq;
            this.procStateSeq = procStateSeq;
            this.capability = capability;
            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() {
    final private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() {
@@ -3982,31 +3997,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                synchronized (mUidBlockedState) {
                synchronized (mUidBlockedState) {
                    collectKeys(mUidBlockedState, knownUids);
                    collectKeys(mUidBlockedState, knownUids);
                }
                }
                synchronized (mUidStateCallbackInfos) {
                    collectKeys(mUidStateCallbackInfos, knownUids);
                }


                fout.println("Status for all known UIDs:");
                fout.println("Status for all known UIDs:");
                fout.increaseIndent();
                fout.increaseIndent();
                size = knownUids.size();
                size = knownUids.size();
                for (int i = 0; i < size; i++) {
                for (int i = 0; i < size; i++) {
                    final int uid = knownUids.keyAt(i);
                    final int uid = knownUids.keyAt(i);
                    fout.print("UID=");
                    fout.print("UID", uid);
                    fout.print(uid);


                    final UidState uidState = mUidState.get(uid);
                    final UidState uidState = mUidState.get(uid);
                    if (uidState == null) {
                    fout.print("state", uidState);
                        fout.print(" state={null}");
                    } else {
                        fout.print(" state=");
                        fout.print(uidState.toString());
                    }


                    synchronized (mUidBlockedState) {
                    synchronized (mUidBlockedState) {
                        final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
                        final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
                        if (uidBlockedState == null) {
                        fout.print("blocked_state", uidBlockedState);
                            fout.print(" blocked_state={null}");
                        } else {
                            fout.print(" blocked_state=");
                            fout.print(uidBlockedState);
                    }
                    }

                    synchronized (mUidStateCallbackInfos) {
                        final UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid);
                        fout.println();
                        fout.increaseIndent();
                        fout.print("callback_info", callbackInfo);
                        fout.decreaseIndent();
                    }
                    }
                    fout.println();
                    fout.println();
                }
                }
@@ -4052,27 +4067,49 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    }
    }


    @VisibleForTesting
    @VisibleForTesting
    boolean isUidForeground(int uid) {
        synchronized (mUidRulesFirstLock) {
            return isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid));
        }
    }

    @GuardedBy("mUidRulesFirstLock")
    @GuardedBy("mUidRulesFirstLock")
    private boolean isUidForegroundOnRestrictBackgroundUL(int uid) {
    boolean isUidForegroundOnRestrictBackgroundUL(int uid) {
        final UidState uidState = mUidState.get(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")
    @GuardedBy("mUidRulesFirstLock")
    private boolean isUidForegroundOnRestrictPowerUL(int uid) {
    boolean isUidForegroundOnRestrictPowerUL(int uid) {
        final UidState uidState = mUidState.get(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")
    @GuardedBy("mUidRulesFirstLock")
    private boolean isUidTop(int uid) {
    private boolean isUidTop(int uid) {
        final UidState uidState = mUidState.get(uid);
        final UidState uidState = mUidState.get(uid);
        // TODO: Consider taking pending uid state change into account.
        return isProcStateAllowedWhileInLowPowerStandby(uidState);
        return isProcStateAllowedWhileInLowPowerStandby(uidState);
    }
    }


+146 −18
Original line number Original line Diff line number Diff line
@@ -18,6 +18,12 @@ package com.android.server.net;


import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.NETWORK_STACK;
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_DATA_SAVER;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
@@ -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
    @Before
    public void callSystemReady() throws Exception {
    public void callSystemReady() throws Exception {
        MockitoAnnotations.initMocks(this);
        MockitoAnnotations.initMocks(this);
@@ -1018,25 +1044,113 @@ public class NetworkPolicyManagerServiceTest {
    // don't check for side-effects (like calls to NetworkManagementService) neither cover all
    // don't check for side-effects (like calls to NetworkManagementService) neither cover all
    // different modes (Data Saver, Battery Saver, Doze, App idle, etc...).
    // different modes (Data Saver, Battery Saver, Doze, App idle, etc...).
    // These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests.
    // These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests.
    @SuppressWarnings("GuardedBy")
    @Test
    @Test
    public void testUidForeground() throws Exception {
    public void testUidForeground() throws Exception {
        // push all uids into background
        // push all uids into background
        long procStateSeq = 0;
        long procStateSeq = 0;
        callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
        callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++);
        callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
        callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++);
        assertFalse(mService.isUidForeground(UID_A));
        assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A));
        assertFalse(mService.isUidForeground(UID_B));
        assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
        assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
        assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));


        // push one of the uids into foreground
        // push one of the uids into foreground
        callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, procStateSeq++);
        callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, procStateSeq++);
        assertTrue(mService.isUidForeground(UID_A));
        assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A));
        assertFalse(mService.isUidForeground(UID_B));
        assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
        assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
        assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));


        // and swap another uid into foreground
        // and swap another uid into foreground
        callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
        callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++);
        callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP, procStateSeq++);
        callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_TOP, procStateSeq++);
        assertFalse(mService.isUidForeground(UID_A));
        assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A));
        assertTrue(mService.isUidForeground(UID_B));
        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
    @Test
@@ -1417,14 +1531,28 @@ public class NetworkPolicyManagerServiceTest {
    @Test
    @Test
    public void testOnUidStateChanged_notifyAMS() throws Exception {
    public void testOnUidStateChanged_notifyAMS() throws Exception {
        final long procStateSeq = 222;
        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);
        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 {
            throws Exception {
        mUidObserver.onUidStateChanged(uid, procState, procStateSeq,
        callAndWaitOnUidStateChanged(uid, procState, procStateSeq,
                ActivityManager.PROCESS_CAPABILITY_NONE);
                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);
        final CountDownLatch latch = new CountDownLatch(1);
        mService.mUidEventHandler.post(() -> {
        mService.mUidEventHandler.post(() -> {
            latch.countDown();
            latch.countDown();
@@ -1927,9 +2055,9 @@ public class NetworkPolicyManagerServiceTest {


    @Test
    @Test
    public void testLowPowerStandbyAllowlist() throws Exception {
    public void testLowPowerStandbyAllowlist() throws Exception {
        callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, 0);
        callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, 0);
        callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
        callAndWaitOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
        callOnUidStateChanged(UID_C, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
        callAndWaitOnUidStateChanged(UID_C, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
        expectHasInternetPermission(UID_A, true);
        expectHasInternetPermission(UID_A, true);
        expectHasInternetPermission(UID_B, true);
        expectHasInternetPermission(UID_B, true);
        expectHasInternetPermission(UID_C, true);
        expectHasInternetPermission(UID_C, true);