Merge "Moar test cases for NetworkPolicyManagerServiceTest."
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index a39d5c8..ed1d777 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -412,7 +412,8 @@
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
             INetworkStatsService networkStats, INetworkManagementService networkManagement) {
         this(context, activityManager, networkStats, networkManagement,
-                NtpTrustedTime.getInstance(context), getSystemDir(), false);
+                AppGlobals.getPackageManager(), NtpTrustedTime.getInstance(context), getSystemDir(),
+                false);
     }
 
     private static File getSystemDir() {
@@ -421,7 +422,7 @@
 
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
             INetworkStatsService networkStats, INetworkManagementService networkManagement,
-            TrustedTime time, File systemDir, boolean suppressDefaultPolicy) {
+            IPackageManager pm, TrustedTime time, File systemDir, boolean suppressDefaultPolicy) {
         mContext = checkNotNull(context, "missing context");
         mActivityManager = checkNotNull(activityManager, "missing activityManager");
         mNetworkStats = checkNotNull(networkStats, "missing networkStats");
@@ -430,7 +431,7 @@
                 Context.DEVICE_IDLE_CONTROLLER));
         mTime = checkNotNull(time, "missing TrustedTime");
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mIPm = AppGlobals.getPackageManager();
+        mIPm = pm;
 
         HandlerThread thread = new HandlerThread(TAG);
         thread.start();
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-on.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-on.xml
new file mode 100644
index 0000000..034411e
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-on.xml
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10" restrictBackground="true" >
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-off.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-off.xml
new file mode 100644
index 0000000..5b1c03c
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-off.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10" restrictBackground="false">
+  <uid-policy uid="10004" policy="1" />
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-on.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-on.xml
new file mode 100644
index 0000000..bec2371
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-on.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10" restrictBackground="true">
+  <uid-policy uid="10004" policy="1" />
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-off.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-off.xml
new file mode 100644
index 0000000..196ca28
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-off.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10" restrictBackground="false">
+  <uid-policy uid="10004" policy="4" />
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-on.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-on.xml
new file mode 100644
index 0000000..4b7724c
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-on.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10" restrictBackground="true">
+  <uid-policy uid="10004" policy="4" />
+</policy-list>
diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
index 13657ab..6b5be580 100644
--- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
+++ b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
@@ -44,7 +44,17 @@
 
     private final List<BroadcastInterceptor> mInterceptors = Lists.newArrayList();
 
-    public class BroadcastInterceptor extends AbstractFuture<Intent> {
+    abstract class FutureIntent extends AbstractFuture<Intent> {
+        public void assertNotReceived()
+                throws InterruptedException, ExecutionException {
+            assertNotReceived(5, TimeUnit.SECONDS);
+        }
+
+        public abstract void assertNotReceived(long timeout, TimeUnit unit)
+                throws InterruptedException, ExecutionException;
+    }
+
+    public class BroadcastInterceptor extends FutureIntent {
         private final BroadcastReceiver mReceiver;
         private final IntentFilter mFilter;
 
@@ -76,17 +86,32 @@
                 throw new RuntimeException(e);
             }
         }
+
+        @Override
+        public void assertNotReceived()
+            throws InterruptedException, ExecutionException {
+            assertNotReceived(5, TimeUnit.SECONDS);
+        }
+
+        public void assertNotReceived(long timeout, TimeUnit unit)
+                throws InterruptedException, ExecutionException {
+            try {
+                final Intent intent = get(timeout, unit);
+                throw new AssertionError("Received intent: " + intent);
+            } catch (TimeoutException e) {
+            }
+        }
     }
 
     public BroadcastInterceptingContext(Context base) {
         super(base);
     }
 
-    public Future<Intent> nextBroadcastIntent(String action) {
+    public FutureIntent nextBroadcastIntent(String action) {
         return nextBroadcastIntent(new IntentFilter(action));
     }
 
-    public Future<Intent> nextBroadcastIntent(IntentFilter filter) {
+    public FutureIntent nextBroadcastIntent(IntentFilter filter) {
         final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter);
         synchronized (mInterceptors) {
             mInterceptors.add(interceptor);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 064b9159..c19ae11 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -52,9 +52,11 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.Manifest;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.app.INotificationManager;
@@ -64,9 +66,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.Signature;
+import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
 import android.net.INetworkPolicyListener;
@@ -84,12 +88,14 @@
 import android.os.PowerManagerInternal;
 import android.os.UserHandle;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 import android.text.format.Time;
 import android.util.Log;
 import android.util.TrustedTime;
 
+import com.android.server.BroadcastInterceptingContext.FutureIntent;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.net.NetworkPolicyManagerService;
 
@@ -136,6 +142,7 @@
  * Tests for {@link NetworkPolicyManagerService}.
  */
 @RunWith(AndroidJUnit4.class)
+@MediumTest
 public class NetworkPolicyManagerServiceTest {
     private static final String TAG = "NetworkPolicyManagerServiceTest";
 
@@ -167,6 +174,7 @@
     private @Mock IConnectivityManager mConnManager;
     private @Mock INotificationManager mNotifManager;
     private @Mock PackageManager mPackageManager;
+    private @Mock IPackageManager mIpm;
 
     private IUidObserver mUidObserver;
     private INetworkManagementEventObserver mNetworkObserver;
@@ -240,7 +248,7 @@
         }).when(mActivityManager).registerUidObserver(any(), anyInt());
 
         mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
-                mNetworkManager, mTime, mPolicyDir, true);
+                mNetworkManager, mIpm, mTime, mPolicyDir, true);
         mService.bindConnectivityManager(mConnManager);
         mService.bindNotificationManager(mNotifManager);
         mPolicyListener = new NetworkPolicyListenerAnswer(mService);
@@ -275,7 +283,7 @@
         mService.systemReady();
 
         // catch INetworkManagementEventObserver during systemReady()
-        ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
+        final ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
               ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
         verify(mNetworkManager).registerObserver(networkObserver.capture());
         mNetworkObserver = networkObserver.getValue();
@@ -295,6 +303,191 @@
     }
 
     @Test
+    public void testTurnRestrictBackgroundOn() throws Exception {
+        assertRestrictBackgroundOff(); // Sanity check.
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        setRestrictBackground(true);
+        assertRestrictBackgroundChangedReceived(futureIntent, null);
+    }
+
+    @Test
+    @NetPolicyXml("restrict-background-on.xml")
+    public void testTurnRestrictBackgroundOff() throws Exception {
+        assertRestrictBackgroundOn(); // Sanity check.
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        setRestrictBackground(false);
+        assertRestrictBackgroundChangedReceived(futureIntent, null);
+    }
+
+    /**
+     * Adds whitelist when restrict background is on - app should receive an intent.
+     */
+    @Test
+    @NetPolicyXml("restrict-background-on.xml")
+    public void testAddRestrictBackgroundWhitelist_restrictBackgroundOn() throws Exception {
+        assertRestrictBackgroundOn(); // Sanity check.
+        addRestrictBackgroundWhitelist(true);
+    }
+
+    /**
+     * Adds whitelist when restrict background is off - app should not receive an intent.
+     */
+    @Test
+    public void testAddRestrictBackgroundWhitelist_restrictBackgroundOff() throws Exception {
+        assertRestrictBackgroundOff(); // Sanity check.
+        addRestrictBackgroundWhitelist(false);
+    }
+
+    private void addRestrictBackgroundWhitelist(boolean expectIntent) throws Exception {
+        assertWhitelistUids(); // Sanity check.
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        mPolicyListener.expect().onRestrictBackgroundWhitelistChanged(anyInt(), anyBoolean());
+
+        mService.addRestrictBackgroundWhitelistedUid(UID_A);
+
+        assertWhitelistUids(UID_A);
+        mPolicyListener.waitAndVerify().onRestrictBackgroundWhitelistChanged(APP_ID_A, true);
+        mPolicyListener.verifyNotCalled().onRestrictBackgroundBlacklistChanged(APP_ID_A, true);
+        if (expectIntent) {
+            assertRestrictBackgroundChangedReceived(futureIntent, PKG_NAME_A);
+        } else {
+            futureIntent.assertNotReceived();
+        }
+    }
+
+    /**
+     * Removes whitelist when restrict background is on - app should receive an intent.
+     */
+    @Test
+    @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml")
+    public void testRemoveRestrictBackgroundWhitelist_restrictBackgroundOn() throws Exception {
+        assertRestrictBackgroundOn(); // Sanity check.
+        removeRestrictBackgroundWhitelist(true);
+    }
+
+    /**
+     * Removes whitelist when restrict background is off - app should not receive an intent.
+     */
+    @Test
+    @NetPolicyXml("uidA-whitelisted-restrict-background-off.xml")
+    public void testRemoveRestrictBackgroundWhitelist_restrictBackgroundOff() throws Exception {
+        assertRestrictBackgroundOff(); // Sanity check.
+        removeRestrictBackgroundWhitelist(false);
+    }
+
+    private void removeRestrictBackgroundWhitelist(boolean expectIntent) throws Exception {
+        assertWhitelistUids(UID_A); // Sanity check.
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        mPolicyListener.expect().onRestrictBackgroundWhitelistChanged(anyInt(), anyBoolean());
+
+        mService.removeRestrictBackgroundWhitelistedUid(UID_A);
+
+        assertWhitelistUids();
+        mPolicyListener.waitAndVerify().onRestrictBackgroundWhitelistChanged(APP_ID_A, false);
+        mPolicyListener.verifyNotCalled().onRestrictBackgroundBlacklistChanged(APP_ID_A, false);
+        if (expectIntent) {
+            assertRestrictBackgroundChangedReceived(futureIntent, PKG_NAME_A);
+        } else {
+            futureIntent.assertNotReceived();
+        }
+    }
+
+    /**
+     * Adds blacklist when restrict background is on - app should receive an intent.
+     */
+    @Test
+    @NetPolicyXml("restrict-background-on.xml")
+    public void testAddRestrictBackgroundBlacklist_restrictBackgroundOn() throws Exception {
+        assertRestrictBackgroundOn(); // Sanity check.
+        addRestrictBackgroundBlacklist(true);
+    }
+
+    /**
+     * Adds blacklist when restrict background is off - app should receive an intent.
+     */
+    @Test
+    public void testAddRestrictBackgroundBlacklist_restrictBackgroundOff() throws Exception {
+        assertRestrictBackgroundOff(); // Sanity check.
+        addRestrictBackgroundBlacklist(true);
+    }
+
+    private void addRestrictBackgroundBlacklist(boolean expectIntent) throws Exception {
+        assertUidPolicy(UID_A, POLICY_NONE); // Sanity check.
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        mPolicyListener.expect().onRestrictBackgroundBlacklistChanged(anyInt(), anyBoolean());
+
+        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+
+        assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+        mPolicyListener.waitAndVerify().onRestrictBackgroundBlacklistChanged(APP_ID_A, true);
+        mPolicyListener.verifyNotCalled().onRestrictBackgroundWhitelistChanged(APP_ID_A, true);
+        if (expectIntent) {
+            assertRestrictBackgroundChangedReceived(futureIntent, PKG_NAME_A);
+        } else {
+            futureIntent.assertNotReceived();
+        }
+    }
+
+    /**
+     * Removes blacklist when restrict background is on - app should receive an intent.
+     */
+    @Test
+    @NetPolicyXml("uidA-blacklisted-restrict-background-on.xml")
+    public void testRemoveRestrictBackgroundBlacklist_restrictBackgroundOn() throws Exception {
+        assertRestrictBackgroundOn(); // Sanity check.
+        removeRestrictBackgroundBlacklist(true);
+    }
+
+    /**
+     * Removes blacklist when restrict background is off - app should receive an intent.
+     */
+    @Test
+    @NetPolicyXml("uidA-blacklisted-restrict-background-off.xml")
+    public void testRemoveRestrictBackgroundBlacklist_restrictBackgroundOff() throws Exception {
+        assertRestrictBackgroundOff(); // Sanity check.
+        removeRestrictBackgroundBlacklist(true);
+    }
+
+    private void removeRestrictBackgroundBlacklist(boolean expectIntent) throws Exception {
+        assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND); // Sanity check.
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        mPolicyListener.expect().onRestrictBackgroundBlacklistChanged(anyInt(), anyBoolean());
+
+        mService.setUidPolicy(UID_A, POLICY_NONE);
+
+        assertUidPolicy(UID_A, POLICY_NONE);
+        mPolicyListener.waitAndVerify().onRestrictBackgroundBlacklistChanged(APP_ID_A, false);
+        mPolicyListener.verifyNotCalled().onRestrictBackgroundWhitelistChanged(APP_ID_A, false);
+        if (expectIntent) {
+            assertRestrictBackgroundChangedReceived(futureIntent, PKG_NAME_A);
+        } else {
+            futureIntent.assertNotReceived();
+        }
+    }
+
+    @NetPolicyXml("uidA-blacklisted-restrict-background-off.xml")
+    public void testBlacklistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception {
+        // Sanity checks.
+        assertRestrictBackgroundOn();
+        assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        setRestrictBackground(true);
+        futureIntent.assertNotReceived();
+    }
+
+    @NetPolicyXml("uidA-whitelisted-restrict-background-off.xml")
+    public void testWhitelistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception {
+        // Sanity checks.
+        assertRestrictBackgroundOff();
+        assertWhitelistUids(UID_A);
+
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        setRestrictBackground(true);
+        futureIntent.assertNotReceived();
+    }
+
+    @Test
     @NetPolicyXml("restrict-background-lists-whitelist-format.xml")
     public void testRestrictBackgroundLists_whitelistFormat() throws Exception {
         restrictBackgroundListsTest();
@@ -771,6 +964,11 @@
         return futureAnswer;
     }
 
+    private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception {
+        when(mIpm.checkUidPermission(Manifest.permission.INTERNET, uid)).thenReturn(
+                hasIt ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);
+    }
+
     private void verifySetInterfaceQuota(String iface, long quotaBytes) throws Exception {
         verify(mNetworkManager, atLeastOnce()).setInterfaceQuota(iface, quotaBytes);
     }
@@ -857,6 +1055,27 @@
         assertContainsInAnyOrder(mService.getRestrictBackgroundWhitelistedUids(), uids);
     }
 
+    private void assertRestrictBackgroundOn() throws Exception {
+        assertTrue("restrictBackground should be set", mService.getRestrictBackground());
+    }
+
+    private void assertRestrictBackgroundOff() throws Exception {
+        assertFalse("restrictBackground should not be set", mService.getRestrictBackground());
+    }
+
+    private FutureIntent newRestrictBackgroundChangedFuture() {
+        return mServiceContext
+                .nextBroadcastIntent(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
+    }
+
+    private void assertRestrictBackgroundChangedReceived(Future<Intent> future,
+            String expectedPackage) throws Exception {
+        final String action = ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
+        final Intent intent = future.get(5, TimeUnit.SECONDS);
+        assertNotNull("Didn't get a " + action + "intent in 5 seconds");
+        assertEquals("Wrong package on " + action + " intent", expectedPackage, intent.getPackage());
+    }
+
     // TODO: replace by Truth, Hamcrest, or a similar tool.
     private void assertContainsInAnyOrder(int[] actual, int...expected) {
         final StringBuilder errors = new StringBuilder();
@@ -896,6 +1115,16 @@
         mElapsedRealtime += duration;
     }
 
+    private FutureIntent mRestrictBackgroundChanged;
+
+    private void setRestrictBackground(boolean flag) throws Exception {
+        // Must set expectation, otherwise NMPS will reset value to previous one.
+        when(mNetworkManager.setDataSaverModeEnabled(flag)).thenReturn(true);
+        mService.setRestrictBackground(flag);
+        // Sanity check.
+        assertEquals("restrictBackground not set", flag, mService.getRestrictBackground());
+    }
+
     /**
      * Creates a mock and registers it to {@link LocalServices}.
      */
@@ -950,6 +1179,11 @@
             }
             return verify(listener, atLeastOnce());
         }
+
+        INetworkPolicyListener verifyNotCalled() {
+            return verify(listener, never());
+        }
+
     }
 
     private void setNetpolicyXml(Context context) throws Exception {