First cut of user restriction layering.

- Start persisting restrictions set by DO/PO.

- Also dump user restrictions on dumpsys

- More changes will follow, including migration.

- Now System settings are mockable.

Bug 23902097
Bug 23902477

Change-Id: I0bda22f484e1a8e259a1feb2df83c5f4a29116da
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 31fc24b..341410d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -59,8 +59,6 @@
 import android.util.TimeUtils;
 import android.util.Xml;
 
-import com.google.android.collect.Sets;
-
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.util.FastXmlSerializer;
@@ -82,7 +80,6 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 import libcore.io.IoUtils;
 
@@ -147,10 +144,6 @@
      */
     private static final boolean CONFIG_PROFILES_SHARE_CREDENTIAL = true;
 
-    // Set of user restrictions, which can only be enforced by the system
-    private static final Set<String> SYSTEM_CONTROLLED_RESTRICTIONS = Sets.newArraySet(
-            UserManager.DISALLOW_RECORD_AUDIO);
-
     static final int WRITE_USER_MSG = 1;
     static final int WRITE_USER_DELAY = 2*1000;  // 2 seconds
 
@@ -596,7 +589,7 @@
     public void setUserRestriction(String key, boolean value, int userId) {
         checkManageUsersPermission("setUserRestriction");
         synchronized (mPackagesLock) {
-            if (!SYSTEM_CONTROLLED_RESTRICTIONS.contains(key)) {
+            if (!UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS.contains(key)) {
                 Bundle restrictions = getUserRestrictions(userId);
                 restrictions.putBoolean(key, value);
                 setUserRestrictionsInternalLocked(restrictions, userId);
@@ -622,7 +615,7 @@
         synchronized (mPackagesLock) {
             final Bundle oldUserRestrictions = mUserRestrictions.get(userId);
             // Restore the original state of system controlled restrictions from oldUserRestrictions
-            for (String key : SYSTEM_CONTROLLED_RESTRICTIONS) {
+            for (String key : UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS) {
                 restrictions.remove(key);
                 if (oldUserRestrictions.containsKey(key)) {
                     restrictions.putBoolean(key, oldUserRestrictions.getBoolean(key));
@@ -815,7 +808,8 @@
                                 && type != XmlPullParser.END_TAG) {
                             if (type == XmlPullParser.START_TAG) {
                                 if (parser.getName().equals(TAG_RESTRICTIONS)) {
-                                    readRestrictionsLocked(parser, mGuestRestrictions);
+                                    UserRestrictionsUtils
+                                            .readRestrictions(parser, mGuestRestrictions);
                                 }
                                 break;
                             }
@@ -978,7 +972,7 @@
             serializer.endTag(null, TAG_NAME);
             Bundle restrictions = mUserRestrictions.get(userInfo.id);
             if (restrictions != null) {
-                writeRestrictionsLocked(serializer, restrictions);
+                UserRestrictionsUtils.writeRestrictions(serializer, restrictions, TAG_RESTRICTIONS);
             }
             serializer.endTag(null, TAG_USER);
 
@@ -1016,7 +1010,8 @@
             serializer.attribute(null, ATTR_USER_VERSION, Integer.toString(mUserVersion));
 
             serializer.startTag(null, TAG_GUEST_RESTRICTIONS);
-            writeRestrictionsLocked(serializer, mGuestRestrictions);
+            UserRestrictionsUtils
+                    .writeRestrictions(serializer, mGuestRestrictions, TAG_RESTRICTIONS);
             serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
             final int userSize = mUsers.size();
             for (int i = 0; i < userSize; i++) {
@@ -1036,45 +1031,6 @@
         }
     }
 
-    private void writeRestrictionsLocked(XmlSerializer serializer, Bundle restrictions)
-            throws IOException {
-        serializer.startTag(null, TAG_RESTRICTIONS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_WIFI);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_MODIFY_ACCOUNTS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_INSTALL_APPS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNINSTALL_APPS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_SHARE_LOCATION);
-        writeBoolean(serializer, restrictions,
-                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_BLUETOOTH);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_REMOVE_USER);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_DEBUGGING_FEATURES);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_VPN);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_TETHERING);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_NETWORK_RESET);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_FACTORY_RESET);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADD_USER);
-        writeBoolean(serializer, restrictions, UserManager.ENSURE_VERIFY_APPS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_APPS_CONTROL);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADJUST_VOLUME);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_CALLS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_SMS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_FUN);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_CREATE_WINDOWS);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_BEAM);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_WALLPAPER);
-        writeBoolean(serializer, restrictions, UserManager.DISALLOW_SAFE_BOOT);
-        writeBoolean(serializer, restrictions, UserManager.ALLOW_PARENT_PROFILE_APP_LINKING);
-        serializer.endTag(null, TAG_RESTRICTIONS);
-    }
-
     private UserInfo readUserLocked(int id) {
         int flags = 0;
         int serialNumber = id;
@@ -1143,7 +1099,7 @@
                             name = parser.getText();
                         }
                     } else if (TAG_RESTRICTIONS.equals(tag)) {
-                        readRestrictionsLocked(parser, restrictions);
+                        UserRestrictionsUtils.readRestrictions(parser, restrictions);
                     }
                 }
             }
@@ -1172,60 +1128,6 @@
         return null;
     }
 
-    private void readRestrictionsLocked(XmlPullParser parser, Bundle restrictions)
-            throws IOException {
-        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_WIFI);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_MODIFY_ACCOUNTS);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_INSTALL_APPS);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_UNINSTALL_APPS);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_SHARE_LOCATION);
-        readBoolean(parser, restrictions,
-                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_BLUETOOTH);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_REMOVE_USER);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_DEBUGGING_FEATURES);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_VPN);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_TETHERING);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_NETWORK_RESET);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_FACTORY_RESET);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_ADD_USER);
-        readBoolean(parser, restrictions, UserManager.ENSURE_VERIFY_APPS);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_APPS_CONTROL);
-        readBoolean(parser, restrictions,
-                UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_ADJUST_VOLUME);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_CALLS);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_SMS);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_FUN);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_CREATE_WINDOWS);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_BEAM);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_WALLPAPER);
-        readBoolean(parser, restrictions, UserManager.DISALLOW_SAFE_BOOT);
-        readBoolean(parser, restrictions, UserManager.ALLOW_PARENT_PROFILE_APP_LINKING);
-    }
-
-    private void readBoolean(XmlPullParser parser, Bundle restrictions,
-            String restrictionKey) {
-        String value = parser.getAttributeValue(null, restrictionKey);
-        if (value != null) {
-            restrictions.putBoolean(restrictionKey, Boolean.parseBoolean(value));
-        }
-    }
-
-    private void writeBoolean(XmlSerializer xml, Bundle restrictions, String restrictionKey)
-            throws IOException {
-        if (restrictions.containsKey(restrictionKey)) {
-            xml.attribute(null, restrictionKey,
-                    Boolean.toString(restrictions.getBoolean(restrictionKey)));
-        }
-    }
-
     private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) {
         String valueString = parser.getAttributeValue(null, attr);
         if (valueString == null) return defaultValue;
@@ -2142,7 +2044,13 @@
                     sb.append(" ago");
                     pw.println(sb);
                 }
+                pw.println("    Restrictions:");
+                UserRestrictionsUtils.dumpRestrictions(
+                        pw, "      ", mUserRestrictions.get(user.id));
             }
+            pw.println();
+            pw.println("Guest restrictions:");
+            UserRestrictionsUtils.dumpRestrictions(pw, "  ", mGuestRestrictions);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
new file mode 100644
index 0000000..db1fd2e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import com.google.android.collect.Sets;
+
+import com.android.internal.util.Preconditions;
+
+import android.os.Bundle;
+import android.os.UserManager;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Set;
+
+public class UserRestrictionsUtils {
+    private UserRestrictionsUtils() {
+    }
+
+    public static final String[] USER_RESTRICTIONS = {
+            UserManager.DISALLOW_CONFIG_WIFI,
+            UserManager.DISALLOW_MODIFY_ACCOUNTS,
+            UserManager.DISALLOW_INSTALL_APPS,
+            UserManager.DISALLOW_UNINSTALL_APPS,
+            UserManager.DISALLOW_SHARE_LOCATION,
+            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+            UserManager.DISALLOW_CONFIG_BLUETOOTH,
+            UserManager.DISALLOW_USB_FILE_TRANSFER,
+            UserManager.DISALLOW_CONFIG_CREDENTIALS,
+            UserManager.DISALLOW_REMOVE_USER,
+            UserManager.DISALLOW_DEBUGGING_FEATURES,
+            UserManager.DISALLOW_CONFIG_VPN,
+            UserManager.DISALLOW_CONFIG_TETHERING,
+            UserManager.DISALLOW_NETWORK_RESET,
+            UserManager.DISALLOW_FACTORY_RESET,
+            UserManager.DISALLOW_ADD_USER,
+            UserManager.ENSURE_VERIFY_APPS,
+            UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
+            UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
+            UserManager.DISALLOW_APPS_CONTROL,
+            UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
+            UserManager.DISALLOW_UNMUTE_MICROPHONE,
+            UserManager.DISALLOW_ADJUST_VOLUME,
+            UserManager.DISALLOW_OUTGOING_CALLS,
+            UserManager.DISALLOW_SMS,
+            UserManager.DISALLOW_FUN,
+            UserManager.DISALLOW_CREATE_WINDOWS,
+            UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE,
+            UserManager.DISALLOW_OUTGOING_BEAM,
+            UserManager.DISALLOW_WALLPAPER,
+            UserManager.DISALLOW_SAFE_BOOT,
+            UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
+            UserManager.DISALLOW_RECORD_AUDIO,
+    };
+
+    /**
+     * Set of user restrictions, which can only be enforced by the system.
+     */
+    public static final Set<String> SYSTEM_CONTROLLED_USER_RESTRICTIONS = Sets.newArraySet(
+            UserManager.DISALLOW_RECORD_AUDIO);
+
+    /**
+     * Set of user restriction which we don't want to persist.
+     */
+    public static final Set<String> NON_PERSIST_USER_RESTRICTIONS = Sets.newArraySet(
+            UserManager.DISALLOW_RECORD_AUDIO);
+
+    public static void writeRestrictions(XmlSerializer serializer, Bundle restrictions,
+            String tag) throws IOException {
+        serializer.startTag(null, tag);
+        for (String key : USER_RESTRICTIONS) {
+            //
+            if (restrictions.getBoolean(key)
+                    && !NON_PERSIST_USER_RESTRICTIONS.contains(key)) {
+                serializer.attribute(null, key, "true");
+            }
+        }
+        serializer.endTag(null, tag);
+    }
+
+    public static void readRestrictions(XmlPullParser parser, Bundle restrictions)
+            throws IOException {
+        for (String key : USER_RESTRICTIONS) {
+            final String value = parser.getAttributeValue(null, key);
+            if (value != null) {
+                restrictions.putBoolean(key, Boolean.parseBoolean(value));
+            }
+        }
+    }
+
+    public static void dumpRestrictions(PrintWriter pw, String prefix, Bundle restrictions) {
+        boolean noneSet = true;
+        if (restrictions != null) {
+            for (String key : restrictions.keySet()) {
+                if (restrictions.getBoolean(key, false)) {
+                    pw.println(prefix + key);
+                    noneSet = false;
+                }
+            }
+        }
+        if (noneSet) {
+            pw.println(prefix + "none");
+        }
+    }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e85f01a..cb5ab1b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -124,6 +124,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
+import com.android.server.pm.UserRestrictionsUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -277,7 +278,8 @@
     final LocalService mLocalService;
 
     // Stores and loads state on device and profile owners.
-    private final Owners mOwners;
+    @VisibleForTesting
+    final Owners mOwners;
 
     private final Binder mToken = new Binder();
 
@@ -433,6 +435,8 @@
         private static final String TAG_PROVIDER = "provider";
         private static final String TAG_PACKAGE_LIST_ITEM  = "item";
 
+        private static final String TAG_USER_RESTRICTIONS = "user-restrictions";
+
         final DeviceAdminInfo info;
 
         int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -512,6 +516,8 @@
 
         List<String> crossProfileWidgetProviders;
 
+        Bundle userRestrictions;
+
         ActiveAdmin(DeviceAdminInfo _info) {
             info = _info;
         }
@@ -686,6 +692,10 @@
             writePackageListToXml(out, TAG_PERMITTED_ACCESSIBILITY_SERVICES,
                     permittedAccessiblityServices);
             writePackageListToXml(out, TAG_PERMITTED_IMES, permittedInputMethods);
+            if (hasUserRestrictions()) {
+                UserRestrictionsUtils.writeRestrictions(
+                        out, userRestrictions, TAG_USER_RESTRICTIONS);
+            }
         }
 
         void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -795,6 +805,8 @@
                     permittedAccessiblityServices = readPackageList(parser, tag);
                 } else if (TAG_PERMITTED_IMES.equals(tag)) {
                     permittedInputMethods = readPackageList(parser, tag);
+                } else if (TAG_USER_RESTRICTIONS.equals(tag)) {
+                    UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions());
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -915,6 +927,17 @@
             return result;
         }
 
+        boolean hasUserRestrictions() {
+            return userRestrictions != null && userRestrictions.size() > 0;
+        }
+
+        Bundle ensureUserRestrictions() {
+            if (userRestrictions == null) {
+                userRestrictions = new Bundle();
+            }
+            return userRestrictions;
+        }
+
         void dump(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("uid="); pw.println(getUid());
             pw.print(prefix); pw.println("policies:");
@@ -984,6 +1007,8 @@
                 pw.print(prefix); pw.print("permittedInputMethods=");
                         pw.println(permittedInputMethods.toString());
             }
+            pw.print(prefix); pw.println("userRestrictions:");
+            UserRestrictionsUtils.dumpRestrictions(pw, prefix + "  ", userRestrictions);
         }
     }
 
@@ -1116,6 +1141,10 @@
             return getCallingUid() == Process.myUid();
         }
 
+        final int userHandleGetCallingUserId() {
+            return UserHandle.getUserId(binderGetCallingUid());
+        }
+
         File environmentGetUserSystemDirectory(int userId) {
             return Environment.getUserSystemDirectory(userId);
         }
@@ -1151,6 +1180,42 @@
         String getDevicePolicyFilePathForSystemUser() {
             return "/data/system/";
         }
+
+        int settingsSecureGetIntForUser(String name, int def, int userHandle) {
+            return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    name, def, userHandle);
+        }
+
+        void settingsSecurePutIntForUser(String name, int value, int userHandle) {
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    name, value, userHandle);
+        }
+
+        void settingsSecurePutStringForUser(String name, String value, int userHandle) {
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    name, value, userHandle);
+        }
+
+        void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
+            Settings.Global.putStringForUser(mContext.getContentResolver(),
+                    name, value, userHandle);
+        }
+
+        void settingsSecurePutInt(String name, int value) {
+            Settings.Secure.putInt(mContext.getContentResolver(), name, value);
+        }
+
+        void settingsGlobalPutInt(String name, int value) {
+            Settings.Global.putInt(mContext.getContentResolver(), name, value);
+        }
+
+        void settingsSecurePutString(String name, String value) {
+            Settings.Secure.putString(mContext.getContentResolver(), name, value);
+        }
+
+        void settingsGlobalPutString(String name, String value) {
+            Settings.Global.putString(mContext.getContentResolver(), name, value);
+        }
     }
 
     /**
@@ -3158,8 +3223,7 @@
             } else {
                 // Make sure KEEP_SCREEN_ON is disabled, since that
                 // would allow bypassing of the maximum time to lock.
-                Settings.Global.putInt(mContext.getContentResolver(),
-                        Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+                mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
             }
 
             policy.mLastMaximumTimeToLock = timeMs;
@@ -3378,7 +3442,7 @@
         // If there is a profile owner, redirect to that; otherwise query the device owner.
         ComponentName aliasChooser = getProfileOwner(caller.getIdentifier());
         if (aliasChooser == null && caller.isOwner()) {
-            ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdmin();
+            ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
             if (deviceOwnerAdmin != null) {
                 aliasChooser = deviceOwnerAdmin.info.getComponent();
             }
@@ -3838,16 +3902,15 @@
             } catch (NumberFormatException e) {}
         }
         exclusionList = exclusionList.trim();
-        ContentResolver res = mContext.getContentResolver();
 
         ProxyInfo proxyProperties = new ProxyInfo(data[0], proxyPort, exclusionList);
         if (!proxyProperties.isValid()) {
             Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
             return;
         }
-        Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
-        Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
-        Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+        mInjector.settingsGlobalPutString(Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
+        mInjector.settingsGlobalPutInt(Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
+        mInjector.settingsGlobalPutString(Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
                 exclusionList);
     }
 
@@ -4071,8 +4134,7 @@
         if (required) {
             long ident = mInjector.binderClearCallingIdentity();
             try {
-                Settings.Global.putInt(mContext.getContentResolver(),
-                        Settings.Global.AUTO_TIME, 1 /* AUTO_TIME on */);
+                mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1 /* AUTO_TIME on */);
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
@@ -4088,7 +4150,7 @@
             return false;
         }
         synchronized (this) {
-            ActiveAdmin deviceOwner = getDeviceOwnerAdmin();
+            ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
             return (deviceOwner != null) ? deviceOwner.requireAutoTime : false;
         }
     }
@@ -4309,7 +4371,8 @@
     }
 
     // Returns the active device owner or null if there is no device owner.
-    private ActiveAdmin getDeviceOwnerAdmin() {
+    @VisibleForTesting
+    ActiveAdmin getDeviceOwnerAdminLocked() {
         String deviceOwnerPackageName = getDeviceOwner();
         if (deviceOwnerPackageName == null) {
             return null;
@@ -4502,7 +4565,8 @@
 
     // Returns the active profile owner for this user or null if the current user has no
     // profile owner.
-    private ActiveAdmin getProfileOwnerAdmin(int userHandle) {
+    @VisibleForTesting
+    ActiveAdmin getProfileOwnerAdminLocked(int userHandle) {
         ComponentName profileOwner = mOwners.getProfileOwnerComponent(userHandle);
         if (profileOwner == null) {
             return null;
@@ -5374,7 +5438,7 @@
     @Override
     public void setUserRestriction(ComponentName who, String key, boolean enabled) {
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
+        final int userHandle = mInjector.userHandleGetCallingUserId();
         final UserHandle user = new UserHandle(userHandle);
         synchronized (this) {
             ActiveAdmin activeAdmin =
@@ -5399,37 +5463,40 @@
                         mInjector.getIAudioService()
                                 .setMasterMute(true, 0, mContext.getPackageName(), userHandle);
                     } else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) {
-                        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        mInjector.settingsSecurePutIntForUser(
                                 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0,
                                 userHandle);
                     } else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
-                        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        mInjector.settingsSecurePutIntForUser(
                                 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF,
                                 userHandle);
-                        Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                        mInjector.settingsSecurePutStringForUser(
                                 Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "",
                                 userHandle);
                     } else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) {
                         // Only disable adb if changing for system user, since it is global
                         // TODO: should this be admin user?
                         if (userHandle == UserHandle.USER_SYSTEM) {
-                            Settings.Global.putStringForUser(mContext.getContentResolver(),
+                            mInjector.settingsGlobalPutStringForUser(
                                     Settings.Global.ADB_ENABLED, "0", userHandle);
                         }
                     } else if (UserManager.ENSURE_VERIFY_APPS.equals(key)) {
-                        Settings.Global.putStringForUser(mContext.getContentResolver(),
+                        mInjector.settingsGlobalPutStringForUser(
                                 Settings.Global.PACKAGE_VERIFIER_ENABLE, "1",
                                 userHandle);
-                        Settings.Global.putStringForUser(mContext.getContentResolver(),
+                        mInjector.settingsGlobalPutStringForUser(
                                 Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1",
                                 userHandle);
                     } else if (UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES.equals(key)) {
-                        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        mInjector.settingsSecurePutIntForUser(
                                 Settings.Secure.INSTALL_NON_MARKET_APPS, 0,
                                 userHandle);
                     }
                 }
                 mUserManager.setUserRestriction(key, enabled, user);
+                activeAdmin.ensureUserRestrictions().putBoolean(key, enabled);
+                saveSettingsLocked(userHandle);
+
                 if (enabled != alreadyRestricted) {
                     if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
                         // Send out notifications however as some clients may want to reread the
@@ -5730,7 +5797,7 @@
         // TODO: Should there be a check to make sure this relationship is within a profile group?
         //enforceSystemProcess("getCrossProfileCallerIdDisabled can only be called by system");
         synchronized (this) {
-            ActiveAdmin admin = getProfileOwnerAdmin(userId);
+            ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
             return (admin != null) ? admin.disableCallerId : false;
         }
     }
@@ -5823,7 +5890,7 @@
         // within a profile group?
         // enforceSystemProcess("getCrossProfileCallerIdDisabled can only be called by system");
         synchronized (this) {
-            ActiveAdmin admin = getProfileOwnerAdmin(userId);
+            ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
             return (admin != null) ? admin.disableBluetoothContactSharing : false;
         }
     }
@@ -5926,7 +5993,6 @@
 
     @Override
     public void setGlobalSetting(ComponentName who, String setting, String value) {
-        final ContentResolver contentResolver = mContext.getContentResolver();
         Preconditions.checkNotNull(who, "ComponentName is null");
 
         synchronized (this) {
@@ -5954,7 +6020,7 @@
 
             long id = mInjector.binderClearCallingIdentity();
             try {
-                Settings.Global.putString(contentResolver, setting, value);
+                mInjector.settingsGlobalPutString(setting, value);
             } finally {
                 mInjector.binderRestoreCallingIdentity(id);
             }
@@ -5983,7 +6049,7 @@
 
             long id = mInjector.binderClearCallingIdentity();
             try {
-                Settings.Secure.putStringForUser(contentResolver, setting, value, callingUserId);
+                mInjector.settingsSecurePutStringForUser(setting, value, callingUserId);
             } finally {
                 mInjector.binderRestoreCallingIdentity(id);
             }
@@ -6106,11 +6172,10 @@
      */
     void updateUserSetupComplete() {
         List<UserInfo> users = mUserManager.getUsers(true);
-        ContentResolver resolver = mContext.getContentResolver();
         final int N = users.size();
         for (int i = 0; i < N; i++) {
             int userHandle = users.get(i).id;
-            if (Settings.Secure.getIntForUser(resolver, Settings.Secure.USER_SETUP_COMPLETE, 0,
+            if (mInjector.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
                     userHandle) != 0) {
                 DevicePolicyData policy = getUserData(userHandle);
                 if (!policy.mUserSetupComplete) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 76122e1..f9543c2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -16,16 +16,11 @@
 
 package com.android.server.devicepolicy;
 
-import android.app.AppGlobals;
 import android.app.admin.SystemUpdatePolicy;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.os.Environment;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.ArrayMap;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index f4ffe2e..b109e7b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -225,5 +225,45 @@
         boolean userManagerIsSplitSystemUser() {
             return context.userManagerForMock.isSplitSystemUser();
         }
+
+        @Override
+        int settingsSecureGetIntForUser(String name, int def, int userHandle) {
+            return context.settings.settingsSecureGetIntForUser(name, def, userHandle);
+        }
+
+        @Override
+        void settingsSecurePutIntForUser(String name, int value, int userHandle) {
+            context.settings.settingsSecurePutIntForUser(name, value, userHandle);
+        }
+
+        @Override
+        void settingsSecurePutStringForUser(String name, String value, int userHandle) {
+            context.settings.settingsSecurePutStringForUser(name, value, userHandle);
+        }
+
+        @Override
+        void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
+            context.settings.settingsGlobalPutStringForUser(name, value, userHandle);
+        }
+
+        @Override
+        void settingsSecurePutInt(String name, int value) {
+            context.settings.settingsSecurePutInt(name, value);
+        }
+
+        @Override
+        void settingsGlobalPutInt(String name, int value) {
+            context.settings.settingsGlobalPutInt(name, value);
+        }
+
+        @Override
+        void settingsSecurePutString(String name, String value) {
+            context.settings.settingsSecurePutString(name, value);
+        }
+
+        @Override
+        void settingsGlobalPutString(String name, String value) {
+            context.settings.settingsGlobalPutString(name, value);
+        }
     }
 }
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 5b23798..03b892e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -31,8 +31,8 @@
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.content.pm.PackageInfo;
-import android.content.pm.UserInfo;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Pair;
 
 import org.mockito.ArgumentCaptor;
@@ -65,8 +65,6 @@
  (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
  */
 public class DevicePolicyManagerTest extends DpmTestBase {
-
-
     private DpmMockContext mContext;
     public DevicePolicyManager dpm;
     public DevicePolicyManagerServiceTestable dpms;
@@ -207,9 +205,7 @@
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
-        final UserInfo uh = new UserInfo(DpmMockContext.CALLER_USER_HANDLE, "user", 0);
-
-        // DO needs to be an DA.
+        // PO needs to be an DA.
         dpm.setActiveAdmin(admin, /* replace =*/ false);
 
         // Fire!
@@ -625,4 +621,97 @@
         dpm.setApplicationRestrictions(admin1, "pkg2", new Bundle());
         assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size());
     }
+
+    public void testSetUserRestriction_asDo() 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);
+        setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
+                DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+        // Call.
+        dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
+        assertTrue(dpm.setDeviceOwner(admin1.getPackageName(), "owner-name",
+                UserHandle.USER_SYSTEM));
+
+        assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_SMS));
+        assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_SMS);
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
+
+        assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_SMS));
+        assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+
+        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_SMS);
+
+        assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_SMS));
+        assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+
+        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
+
+        assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_SMS));
+        assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+
+        // TODO Check inner calls.
+        // TODO Make sure restrictions are written to the file.
+    }
+
+    public void testSetUserRestriction_asPo() {
+        setAsProfileOwner(admin1);
+
+        assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                .ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
+        assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                .ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
+
+        assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                .ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
+        assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                .ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+
+        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+
+        assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                .ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
+        assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                .ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+
+        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
+
+        assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                .ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
+        assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                .ensureUserRestrictions()
+                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+
+        // TODO Check inner calls.
+        // TODO Make sure restrictions are written to the file.
+    }
 }
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 7b36e88..73d63ea 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -158,6 +158,33 @@
         }
     }
 
+    public static class SettingsForMock {
+        int settingsSecureGetIntForUser(String name, int def, int userHandle) {
+            return 0;
+        }
+
+        void settingsSecurePutIntForUser(String name, int value, int userHandle) {
+        }
+
+        void settingsSecurePutStringForUser(String name, String value, int userHandle) {
+        }
+
+        void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
+        }
+
+        void settingsSecurePutInt(String name, int value) {
+        }
+
+        void settingsGlobalPutInt(String name, int value) {
+        }
+
+        void settingsSecurePutString(String name, String value) {
+        }
+
+        void settingsGlobalPutString(String name, String value) {
+        }
+    }
+
     public final Context realTestContext;
 
     /**
@@ -184,6 +211,7 @@
     public final IBackupManager ibackupManager;
     public final IAudioService iaudioService;
     public final LockPatternUtils lockPatternUtils;
+    public final SettingsForMock settings;
 
     /** Note this is a partial mock, not a real mock. */
     public final PackageManager packageManager;
@@ -212,6 +240,7 @@
         ibackupManager = mock(IBackupManager.class);
         iaudioService = mock(IAudioService.class);
         lockPatternUtils = mock(LockPatternUtils.class);
+        settings = mock(SettingsForMock.class);
 
         // Package manager is huge, so we use a partial mock instead.
         packageManager = spy(context.getPackageManager());
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 5255628..a210d46 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -21,6 +21,7 @@
 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;
@@ -28,6 +29,8 @@
 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;