More work on layered user restrictions.

- Now when DO/PO sets a user restriction, DPMS pushes it to UMS and
then UMS persists it, in order for UserManager.hasUserRestriction()
to never have to talk with DPMS, which would cause lock inversion.

- Also apply user restrictions when a user start.

- This is an updated version of the abandoned CL -- the difference
is, ActivityManager no longer has to call DPMS.

- Also removed an unnecessary write to userlist.xml in UMS.
upgradeIfNecessaryLP().

Bug 23902097
Bug 25388912
Bug 25354031
Bug 25641040

Change-Id: I0948aea06ad7d0f45fe612a431d765faddfe3c58
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 36980e3..0bd4896 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -25,12 +25,8 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.os.Bundle;
-import android.content.pm.PackageInfo;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Pair;
@@ -50,6 +46,7 @@
 import static org.mockito.Matchers.isNull;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -768,21 +765,42 @@
                 dpm.getUserRestrictions(admin1)
         );
 
-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_SMS);
+        reset(mContext.userManagerInternal);
+
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                MockUtils.checkUserRestrictions(),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
+                );
+        reset(mContext.userManagerInternal);
+
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
+        );
+        reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
                 DpmTestUtils.newRestrictions(
-                        UserManager.DISALLOW_SMS, UserManager.DISALLOW_OUTGOING_CALLS),
+                        UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS),
                 dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
         );
         DpmTestUtils.assertRestrictions(
                 DpmTestUtils.newRestrictions(
-                        UserManager.DISALLOW_SMS, UserManager.DISALLOW_OUTGOING_CALLS),
+                        UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS),
                 dpm.getUserRestrictions(admin1)
         );
 
-        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_SMS);
+        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
+                MockUtils.checkUserRestrictions()
+        );
+        reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
                 DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
@@ -794,6 +812,12 @@
         );
 
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                MockUtils.checkUserRestrictions(),
+                MockUtils.checkUserRestrictions()
+        );
+        reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
                 DpmTestUtils.newRestrictions(),
@@ -804,7 +828,68 @@
                 dpm.getUserRestrictions(admin1)
         );
 
-        // TODO Check inner calls.
+        // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE are PO restrictions, but when
+        // DO sets them, the scope is global.
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
+        reset(mContext.userManagerInternal);
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                MockUtils.checkUserRestrictions(),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
+                        UserManager.DISALLOW_UNMUTE_MICROPHONE)
+        );
+        reset(mContext.userManagerInternal);
+
+        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
+        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+
+
+        // More tests.
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                MockUtils.checkUserRestrictions(),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
+        );
+        reset(mContext.userManagerInternal);
+
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                MockUtils.checkUserRestrictions(),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
+                        UserManager.DISALLOW_ADD_USER)
+        );
+        reset(mContext.userManagerInternal);
+
+        dpm.setCameraDisabled(admin1, true);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                // DISALLOW_CAMERA will be applied to both local and global.
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
+                        UserManager.DISALLOW_CAMERA, UserManager.DISALLOW_ADD_USER)
+        );
+        reset(mContext.userManagerInternal);
+
+        // Set up another DA and let it disable camera.  Now DISALLOW_CAMERA will only be applied
+        // locally.
+        dpm.setCameraDisabled(admin1, false);
+        reset(mContext.userManagerInternal);
+
+        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
+        dpm.setActiveAdmin(admin2, /* replace =*/ false, UserHandle.USER_SYSTEM);
+        dpm.setCameraDisabled(admin2, true);
+
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                // DISALLOW_CAMERA will be applied to both local and global.
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
+                        UserManager.DISALLOW_ADD_USER)
+        );
+        reset(mContext.userManagerInternal);
         // TODO Make sure restrictions are written to the file.
     }
 
@@ -818,7 +903,21 @@
         );
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(DpmMockContext.CALLER_USER_HANDLE),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
+                isNull(Bundle.class)
+        );
+        reset(mContext.userManagerInternal);
+
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(DpmMockContext.CALLER_USER_HANDLE),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+                        UserManager.DISALLOW_OUTGOING_CALLS),
+                isNull(Bundle.class)
+        );
+        reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
                 DpmTestUtils.newRestrictions(
@@ -837,7 +936,12 @@
         );
 
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
-
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(DpmMockContext.CALLER_USER_HANDLE),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
+                isNull(Bundle.class)
+        );
+        reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
                 DpmTestUtils.newRestrictions(
@@ -854,6 +958,12 @@
         );
 
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(DpmMockContext.CALLER_USER_HANDLE),
+                MockUtils.checkUserRestrictions(),
+                isNull(Bundle.class)
+        );
+        reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
                 DpmTestUtils.newRestrictions(),
@@ -865,69 +975,29 @@
                 dpm.getUserRestrictions(admin1)
         );
 
-        // TODO Check inner calls.
+        // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE can be set by PO too, even
+        // though when DO sets them they'll be applied globally.
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
+        reset(mContext.userManagerInternal);
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(DpmMockContext.CALLER_USER_HANDLE),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
+                        UserManager.DISALLOW_UNMUTE_MICROPHONE),
+                isNull(Bundle.class)
+        );
+        reset(mContext.userManagerInternal);
+
+        dpm.setCameraDisabled(admin1, true);
+        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(DpmMockContext.CALLER_USER_HANDLE),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA,
+                        UserManager.DISALLOW_ADJUST_VOLUME,
+                        UserManager.DISALLOW_UNMUTE_MICROPHONE),
+                isNull(Bundle.class)
+        );
+        reset(mContext.userManagerInternal);
+
         // TODO Make sure restrictions are written to the file.
     }
-
-    public void testGetComposedUserRestrictions_noDoNoPo() throws Exception {
-        final Bundle in = DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS);
-
-        Bundle actual = dpms.mLocalService.getComposedUserRestrictions(
-                UserHandle.USER_SYSTEM, in);
-        assertTrue(in == actual);
-
-        actual = dpms.mLocalService.getComposedUserRestrictions(
-                DpmMockContext.CALLER_USER_HANDLE, in);
-        assertTrue(in == actual);
-    }
-
-    public void testGetComposedUserRestrictions() throws Exception {
-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
-
-        // First, set DO.
-
-        // Call from a process on the system user.
-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
-
-        // Make sure admin1 is installed on system user.
-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
-
-        // Call.
-        dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
-        assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
-                UserHandle.USER_SYSTEM));
-
-        dpm.addUserRestriction(admin1, "rest1");
-        dpm.addUserRestriction(admin1, "rest2");
-
-        // Set PO on CALLER_USER_HANDLE.
-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
-
-        setAsProfileOwner(admin2);
-
-        dpm.addUserRestriction(admin2, "restA");
-        dpm.addUserRestriction(admin2, "restB");
-
-        final Bundle in = DpmTestUtils.newRestrictions("abc");
-
-        Bundle actual = dpms.mLocalService.getComposedUserRestrictions(
-                UserHandle.USER_SYSTEM, in);
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions("abc", "rest1", "rest2"),
-                actual);
-
-        actual = dpms.mLocalService.getComposedUserRestrictions(
-                DpmMockContext.CALLER_USER_HANDLE, in);
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions("abc", "rest1", "rest2", "restA", "restB"),
-                actual);
-
-        actual = dpms.mLocalService.getComposedUserRestrictions(
-                DpmMockContext.CALLER_USER_HANDLE + 1, in);
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions("abc", "rest1", "rest2"),
-                actual);
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index cc337b0..f4fdc95 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -260,9 +260,6 @@
 
         // System user is always running.
         setUserRunning(UserHandle.USER_SYSTEM, true);
-
-        // This method must return an object.
-        when(userManagerInternal.getUserRestrictionsLock()).thenReturn(new Object());
     }
 
     public File addUser(int userId, int flags) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index 5008fbf..58db192 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -17,8 +17,12 @@
 
 import com.google.common.base.Objects;
 
+import com.android.internal.util.Preconditions;
+import com.android.server.pm.UserRestrictionsUtils;
+
 import android.content.ComponentName;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.UserHandle;
 
 import org.hamcrest.BaseMatcher;
@@ -77,4 +81,37 @@
         };
         return Mockito.argThat(m);
     }
+
+    public static Bundle checkUserRestrictions(String... keys) {
+        final Bundle expected = DpmTestUtils.newRestrictions(Preconditions.checkNotNull(keys));
+        final Matcher<Bundle> m = new BaseMatcher<Bundle>() {
+            @Override
+            public boolean matches(Object item) {
+                if (item == null) return false;
+                return UserRestrictionsUtils.areEqual((Bundle) item, expected);
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("User restrictions=" + getRestrictionsAsString(expected));
+            }
+        };
+        return Mockito.argThat(m);
+    }
+
+    private static String getRestrictionsAsString(Bundle b) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("[");
+
+        if (b != null) {
+            String sep = "";
+            for (String key : b.keySet()) {
+                sb.append(sep);
+                sep = ",";
+                sb.append(key);
+            }
+        }
+        sb.append("]");
+        return sb.toString();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
index 4e11762..423c4d5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -19,21 +19,7 @@
 import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
 
 import android.content.ComponentName;
-import android.content.pm.UserInfo;
 import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-
-import static org.mockito.Mockito.when;
 
 /**
  * Tests for the DeviceOwner object that saves & loads device and policy owner information.