DevicePolicyManager per user

Bug: 7136483

Store device policy information for each user and apply them when user switches.

Global proxy can only be controlled by owner.
Camera restriction applies to all users, if any one has an admin that disables it.
Storage encryption can only be controlled by owner, although other users can query the state.
Wipe data will only remove the user if non-zero, wipe the device, if zero.

Change-Id: I359be46c1bc3828fd13d4be3228f11495081c8f2
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index e7cea57..8fb6948 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -413,6 +413,13 @@
      */
     public static PendingIntent getBroadcast(Context context, int requestCode,
             Intent intent, int flags) {
+        return getBroadcastAsUser(context, requestCode, intent, flags,
+                new UserHandle(UserHandle.myUserId()));
+    }
+
+    /** @hide */
+    public static PendingIntent getBroadcastAsUser(Context context, int requestCode,
+            Intent intent, int flags, UserHandle userHandle) {
         String packageName = context.getPackageName();
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
@@ -423,7 +430,7 @@
                     ActivityManager.INTENT_SENDER_BROADCAST, packageName,
                     null, null, requestCode, new Intent[] { intent },
                     resolvedType != null ? new String[] { resolvedType } : null,
-                    flags, null, UserHandle.myUserId());
+                    flags, null, userHandle.getIdentifier());
             return target != null ? new PendingIntent(target) : null;
         } catch (RemoteException e) {
         }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4c55bb3..600d02a 100755
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -29,6 +29,7 @@
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.Log;
 
 import java.io.IOException;
@@ -131,7 +132,7 @@
     public boolean isAdminActive(ComponentName who) {
         if (mService != null) {
             try {
-                return mService.isAdminActive(who);
+                return mService.isAdminActive(who, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -147,7 +148,7 @@
     public List<ComponentName> getActiveAdmins() {
         if (mService != null) {
             try {
-                return mService.getActiveAdmins();
+                return mService.getActiveAdmins(UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -156,12 +157,14 @@
     }
 
     /**
+     * Used by package administration code to determine if a package can be stopped
+     * or uninstalled.
      * @hide
      */
     public boolean packageHasActiveAdmins(String packageName) {
         if (mService != null) {
             try {
-                return mService.packageHasActiveAdmins(packageName);
+                return mService.packageHasActiveAdmins(packageName, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -178,7 +181,7 @@
     public void removeActiveAdmin(ComponentName who) {
         if (mService != null) {
             try {
-                mService.removeActiveAdmin(who);
+                mService.removeActiveAdmin(who, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -197,7 +200,7 @@
     public boolean hasGrantedPolicy(ComponentName admin, int usesPolicy) {
         if (mService != null) {
             try {
-                return mService.hasGrantedPolicy(admin, usesPolicy);
+                return mService.hasGrantedPolicy(admin, usesPolicy, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -289,7 +292,7 @@
     public void setPasswordQuality(ComponentName admin, int quality) {
         if (mService != null) {
             try {
-                mService.setPasswordQuality(admin, quality);
+                mService.setPasswordQuality(admin, quality, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -303,9 +306,14 @@
      * all admins.
      */
     public int getPasswordQuality(ComponentName admin) {
+        return getPasswordQuality(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getPasswordQuality(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordQuality(admin);
+                return mService.getPasswordQuality(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -337,7 +345,7 @@
     public void setPasswordMinimumLength(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLength(admin, length);
+                mService.setPasswordMinimumLength(admin, length, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -351,9 +359,14 @@
      * all admins.
      */
     public int getPasswordMinimumLength(ComponentName admin) {
+        return getPasswordMinimumLength(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getPasswordMinimumLength(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumLength(admin);
+                return mService.getPasswordMinimumLength(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -386,7 +399,7 @@
     public void setPasswordMinimumUpperCase(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumUpperCase(admin, length);
+                mService.setPasswordMinimumUpperCase(admin, length, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -406,9 +419,14 @@
      *         password.
      */
     public int getPasswordMinimumUpperCase(ComponentName admin) {
+        return getPasswordMinimumUpperCase(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getPasswordMinimumUpperCase(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumUpperCase(admin);
+                return mService.getPasswordMinimumUpperCase(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -441,7 +459,7 @@
     public void setPasswordMinimumLowerCase(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLowerCase(admin, length);
+                mService.setPasswordMinimumLowerCase(admin, length, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -461,9 +479,14 @@
      *         password.
      */
     public int getPasswordMinimumLowerCase(ComponentName admin) {
+        return getPasswordMinimumLowerCase(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getPasswordMinimumLowerCase(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumLowerCase(admin);
+                return mService.getPasswordMinimumLowerCase(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -495,7 +518,7 @@
     public void setPasswordMinimumLetters(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLetters(admin, length);
+                mService.setPasswordMinimumLetters(admin, length, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -514,9 +537,14 @@
      * @return The minimum number of letters required in the password.
      */
     public int getPasswordMinimumLetters(ComponentName admin) {
+        return getPasswordMinimumLetters(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getPasswordMinimumLetters(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumLetters(admin);
+                return mService.getPasswordMinimumLetters(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -548,7 +576,7 @@
     public void setPasswordMinimumNumeric(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumNumeric(admin, length);
+                mService.setPasswordMinimumNumeric(admin, length, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -567,9 +595,14 @@
      * @return The minimum number of numerical digits required in the password.
      */
     public int getPasswordMinimumNumeric(ComponentName admin) {
+        return getPasswordMinimumNumeric(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getPasswordMinimumNumeric(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumNumeric(admin);
+                return mService.getPasswordMinimumNumeric(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -601,7 +634,7 @@
     public void setPasswordMinimumSymbols(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumSymbols(admin, length);
+                mService.setPasswordMinimumSymbols(admin, length, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -620,9 +653,14 @@
      * @return The minimum number of symbols required in the password.
      */
     public int getPasswordMinimumSymbols(ComponentName admin) {
+        return getPasswordMinimumSymbols(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumSymbols(admin);
+                return mService.getPasswordMinimumSymbols(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -654,7 +692,7 @@
     public void setPasswordMinimumNonLetter(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumNonLetter(admin, length);
+                mService.setPasswordMinimumNonLetter(admin, length, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -673,9 +711,14 @@
      * @return The minimum number of letters required in the password.
      */
     public int getPasswordMinimumNonLetter(ComponentName admin) {
+        return getPasswordMinimumNonLetter(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getPasswordMinimumNonLetter(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumNonLetter(admin);
+                return mService.getPasswordMinimumNonLetter(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -708,7 +751,7 @@
     public void setPasswordHistoryLength(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordHistoryLength(admin, length);
+                mService.setPasswordHistoryLength(admin, length, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -737,7 +780,7 @@
     public void setPasswordExpirationTimeout(ComponentName admin, long timeout) {
         if (mService != null) {
             try {
-                mService.setPasswordExpirationTimeout(admin, timeout);
+                mService.setPasswordExpirationTimeout(admin, timeout, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -756,7 +799,7 @@
     public long getPasswordExpirationTimeout(ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getPasswordExpirationTimeout(admin);
+                return mService.getPasswordExpirationTimeout(admin, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -776,7 +819,7 @@
     public long getPasswordExpiration(ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getPasswordExpiration(admin);
+                return mService.getPasswordExpiration(admin, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -792,9 +835,14 @@
      * @return The length of the password history
      */
     public int getPasswordHistoryLength(ComponentName admin) {
+        return getPasswordHistoryLength(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getPasswordHistoryLength(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordHistoryLength(admin);
+                return mService.getPasswordHistoryLength(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -828,7 +876,7 @@
     public boolean isActivePasswordSufficient() {
         if (mService != null) {
             try {
-                return mService.isActivePasswordSufficient();
+                return mService.isActivePasswordSufficient(UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -847,7 +895,7 @@
     public int getCurrentFailedPasswordAttempts() {
         if (mService != null) {
             try {
-                return mService.getCurrentFailedPasswordAttempts();
+                return mService.getCurrentFailedPasswordAttempts(UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -877,7 +925,7 @@
     public void setMaximumFailedPasswordsForWipe(ComponentName admin, int num) {
         if (mService != null) {
             try {
-                mService.setMaximumFailedPasswordsForWipe(admin, num);
+                mService.setMaximumFailedPasswordsForWipe(admin, num, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -892,9 +940,14 @@
      * all admins.
      */
     public int getMaximumFailedPasswordsForWipe(ComponentName admin) {
+        return getMaximumFailedPasswordsForWipe(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getMaximumFailedPasswordsForWipe(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getMaximumFailedPasswordsForWipe(admin);
+                return mService.getMaximumFailedPasswordsForWipe(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -933,7 +986,7 @@
     public boolean resetPassword(String password, int flags) {
         if (mService != null) {
             try {
-                return mService.resetPassword(password, flags);
+                return mService.resetPassword(password, flags, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -957,7 +1010,7 @@
     public void setMaximumTimeToLock(ComponentName admin, long timeMs) {
         if (mService != null) {
             try {
-                mService.setMaximumTimeToLock(admin, timeMs);
+                mService.setMaximumTimeToLock(admin, timeMs, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -971,9 +1024,14 @@
      * all admins.
      */
     public long getMaximumTimeToLock(ComponentName admin) {
+        return getMaximumTimeToLock(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public long getMaximumTimeToLock(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getMaximumTimeToLock(admin);
+                return mService.getMaximumTimeToLock(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1021,7 +1079,7 @@
     public void wipeData(int flags) {
         if (mService != null) {
             try {
-                mService.wipeData(flags);
+                mService.wipeData(flags, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1090,7 +1148,7 @@
                     }
                     android.net.Proxy.validate(hostName, Integer.toString(port), exclSpec);
                 }
-                return mService.setGlobalProxy(admin, hostSpec, exclSpec);
+                return mService.setGlobalProxy(admin, hostSpec, exclSpec, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1107,7 +1165,7 @@
     public ComponentName getGlobalProxyAdmin() {
         if (mService != null) {
             try {
-                return mService.getGlobalProxyAdmin();
+                return mService.getGlobalProxyAdmin(UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1199,7 +1257,7 @@
     public int setStorageEncryption(ComponentName admin, boolean encrypt) {
         if (mService != null) {
             try {
-                return mService.setStorageEncryption(admin, encrypt);
+                return mService.setStorageEncryption(admin, encrypt, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1219,7 +1277,7 @@
     public boolean getStorageEncryption(ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getStorageEncryption(admin);
+                return mService.getStorageEncryption(admin, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1244,9 +1302,14 @@
      * {@link #ENCRYPTION_STATUS_ACTIVATING}, or{@link #ENCRYPTION_STATUS_ACTIVE}.
      */
     public int getStorageEncryptionStatus() {
+        return getStorageEncryptionStatus(UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getStorageEncryptionStatus(int userHandle) {
         if (mService != null) {
             try {
-                return mService.getStorageEncryptionStatus();
+                return mService.getStorageEncryptionStatus(userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1269,7 +1332,7 @@
     public void setCameraDisabled(ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
-                mService.setCameraDisabled(admin, disabled);
+                mService.setCameraDisabled(admin, disabled, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1283,9 +1346,14 @@
      * have disabled the camera
      */
     public boolean getCameraDisabled(ComponentName admin) {
+        return getCameraDisabled(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean getCameraDisabled(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getCameraDisabled(admin);
+                return mService.getCameraDisabled(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1309,7 +1377,7 @@
     public void setKeyguardWidgetsDisabled(ComponentName admin, int which) {
         if (mService != null) {
             try {
-                mService.setKeyguardWidgetsDisabled(admin, which);
+                mService.setKeyguardWidgetsDisabled(admin, which, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1323,9 +1391,14 @@
      * have disabled widgets in keyguard.
      */
     public int getKeyguardWidgetsDisabled(ComponentName admin) {
+        return getKeyguardWidgetsDisabled(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public int getKeyguardWidgetsDisabled(ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getKeyguardWidgetsDisabled(admin);
+                return mService.getKeyguardWidgetsDisabled(admin, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1339,7 +1412,7 @@
     public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) {
         if (mService != null) {
             try {
-                mService.setActiveAdmin(policyReceiver, refreshing);
+                mService.setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1380,7 +1453,7 @@
     public void getRemoveWarning(ComponentName admin, RemoteCallback result) {
         if (mService != null) {
             try {
-                mService.getRemoveWarning(admin, result);
+                mService.getRemoveWarning(admin, result, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1391,11 +1464,11 @@
      * @hide
      */
     public void setActivePasswordState(int quality, int length, int letters, int uppercase,
-            int lowercase, int numbers, int symbols, int nonletter) {
+            int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
         if (mService != null) {
             try {
                 mService.setActivePasswordState(quality, length, letters, uppercase, lowercase,
-                        numbers, symbols, nonletter);
+                        numbers, symbols, nonletter, userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1405,10 +1478,10 @@
     /**
      * @hide
      */
-    public void reportFailedPasswordAttempt() {
+    public void reportFailedPasswordAttempt(int userHandle) {
         if (mService != null) {
             try {
-                mService.reportFailedPasswordAttempt();
+                mService.reportFailedPasswordAttempt(userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1418,14 +1491,13 @@
     /**
      * @hide
      */
-    public void reportSuccessfulPasswordAttempt() {
+    public void reportSuccessfulPasswordAttempt(int userHandle) {
         if (mService != null) {
             try {
-                mService.reportSuccessfulPasswordAttempt();
+                mService.reportSuccessfulPasswordAttempt(userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
         }
     }
-
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 0b7ec12..bdfb177 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -25,76 +25,76 @@
  * {@hide}
  */
 interface IDevicePolicyManager {
-    void setPasswordQuality(in ComponentName who, int quality);
-    int getPasswordQuality(in ComponentName who);
+    void setPasswordQuality(in ComponentName who, int quality, int userHandle);
+    int getPasswordQuality(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumLength(in ComponentName who, int length);
-    int getPasswordMinimumLength(in ComponentName who);
+    void setPasswordMinimumLength(in ComponentName who, int length, int userHandle);
+    int getPasswordMinimumLength(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumUpperCase(in ComponentName who, int length);
-    int getPasswordMinimumUpperCase(in ComponentName who);
+    void setPasswordMinimumUpperCase(in ComponentName who, int length, int userHandle);
+    int getPasswordMinimumUpperCase(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumLowerCase(in ComponentName who, int length);
-    int getPasswordMinimumLowerCase(in ComponentName who);
+    void setPasswordMinimumLowerCase(in ComponentName who, int length, int userHandle);
+    int getPasswordMinimumLowerCase(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumLetters(in ComponentName who, int length);
-    int getPasswordMinimumLetters(in ComponentName who);
+    void setPasswordMinimumLetters(in ComponentName who, int length, int userHandle);
+    int getPasswordMinimumLetters(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumNumeric(in ComponentName who, int length);
-    int getPasswordMinimumNumeric(in ComponentName who);
+    void setPasswordMinimumNumeric(in ComponentName who, int length, int userHandle);
+    int getPasswordMinimumNumeric(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumSymbols(in ComponentName who, int length);
-    int getPasswordMinimumSymbols(in ComponentName who);
+    void setPasswordMinimumSymbols(in ComponentName who, int length, int userHandle);
+    int getPasswordMinimumSymbols(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumNonLetter(in ComponentName who, int length);
-    int getPasswordMinimumNonLetter(in ComponentName who);
+    void setPasswordMinimumNonLetter(in ComponentName who, int length, int userHandle);
+    int getPasswordMinimumNonLetter(in ComponentName who, int userHandle);
 
-    void setPasswordHistoryLength(in ComponentName who, int length);
-    int getPasswordHistoryLength(in ComponentName who);
+    void setPasswordHistoryLength(in ComponentName who, int length, int userHandle);
+    int getPasswordHistoryLength(in ComponentName who, int userHandle);
 
-    void setPasswordExpirationTimeout(in ComponentName who, long expiration);
-    long getPasswordExpirationTimeout(in ComponentName who);
+    void setPasswordExpirationTimeout(in ComponentName who, long expiration, int userHandle);
+    long getPasswordExpirationTimeout(in ComponentName who, int userHandle);
 
-    long getPasswordExpiration(in ComponentName who);
+    long getPasswordExpiration(in ComponentName who, int userHandle);
 
-    boolean isActivePasswordSufficient();
-    int getCurrentFailedPasswordAttempts();
+    boolean isActivePasswordSufficient(int userHandle);
+    int getCurrentFailedPasswordAttempts(int userHandle);
 
-    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num);
-    int getMaximumFailedPasswordsForWipe(in ComponentName admin);
+    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, int userHandle);
+    int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle);
 
-    boolean resetPassword(String password, int flags);
+    boolean resetPassword(String password, int flags, int userHandle);
 
-    void setMaximumTimeToLock(in ComponentName who, long timeMs);
-    long getMaximumTimeToLock(in ComponentName who);
+    void setMaximumTimeToLock(in ComponentName who, long timeMs, int userHandle);
+    long getMaximumTimeToLock(in ComponentName who, int userHandle);
 
     void lockNow();
 
-    void wipeData(int flags);
+    void wipeData(int flags, int userHandle);
 
-    ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList);
-    ComponentName getGlobalProxyAdmin();
+    ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList, int userHandle);
+    ComponentName getGlobalProxyAdmin(int userHandle);
 
-    int setStorageEncryption(in ComponentName who, boolean encrypt);
-    boolean getStorageEncryption(in ComponentName who);
-    int getStorageEncryptionStatus();
+    int setStorageEncryption(in ComponentName who, boolean encrypt, int userHandle);
+    boolean getStorageEncryption(in ComponentName who, int userHandle);
+    int getStorageEncryptionStatus(int userHandle);
 
-    void setCameraDisabled(in ComponentName who, boolean disabled);
-    boolean getCameraDisabled(in ComponentName who);
+    void setCameraDisabled(in ComponentName who, boolean disabled, int userHandle);
+    boolean getCameraDisabled(in ComponentName who, int userHandle);
 
-    void setKeyguardWidgetsDisabled(in ComponentName who, int which);
-    int getKeyguardWidgetsDisabled(in ComponentName who);
+    void setKeyguardWidgetsDisabled(in ComponentName who, int which, int userHandle);
+    int getKeyguardWidgetsDisabled(in ComponentName who, int userHandle);
 
-    void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing);
-    boolean isAdminActive(in ComponentName policyReceiver);
-    List<ComponentName> getActiveAdmins();
-    boolean packageHasActiveAdmins(String packageName);
-    void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result);
-    void removeActiveAdmin(in ComponentName policyReceiver);
-    boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy);
+    void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing, int userHandle);
+    boolean isAdminActive(in ComponentName policyReceiver, int userHandle);
+    List<ComponentName> getActiveAdmins(int userHandle);
+    boolean packageHasActiveAdmins(String packageName, int userHandle);
+    void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result, int userHandle);
+    void removeActiveAdmin(in ComponentName policyReceiver, int userHandle);
+    boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy, int userHandle);
 
     void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase,
-        int numbers, int symbols, int nonletter);
-    void reportFailedPasswordAttempt();
-    void reportSuccessfulPasswordAttempt();
+        int numbers, int symbols, int nonletter, int userHandle);
+    void reportFailedPasswordAttempt(int userHandle);
+    void reportSuccessfulPasswordAttempt(int userHandle);
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 0710d96..3207435 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -165,7 +165,7 @@
     }
 
     public int getRequestedMinimumPasswordLength() {
-        return getDevicePolicyManager().getPasswordMinimumLength(null);
+        return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId());
     }
 
     /**
@@ -173,47 +173,54 @@
      * MODE_PATTERN which allows the user to choose anything.
      */
     public int getRequestedPasswordQuality() {
-        return getDevicePolicyManager().getPasswordQuality(null);
+        return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId());
     }
 
     public int getRequestedPasswordHistoryLength() {
-        return getDevicePolicyManager().getPasswordHistoryLength(null);
+        return getDevicePolicyManager().getPasswordHistoryLength(null, getCurrentOrCallingUserId());
     }
 
     public int getRequestedPasswordMinimumLetters() {
-        return getDevicePolicyManager().getPasswordMinimumLetters(null);
+        return getDevicePolicyManager().getPasswordMinimumLetters(null,
+                getCurrentOrCallingUserId());
     }
 
     public int getRequestedPasswordMinimumUpperCase() {
-        return getDevicePolicyManager().getPasswordMinimumUpperCase(null);
+        return getDevicePolicyManager().getPasswordMinimumUpperCase(null,
+                getCurrentOrCallingUserId());
     }
 
     public int getRequestedPasswordMinimumLowerCase() {
-        return getDevicePolicyManager().getPasswordMinimumLowerCase(null);
+        return getDevicePolicyManager().getPasswordMinimumLowerCase(null,
+                getCurrentOrCallingUserId());
     }
 
     public int getRequestedPasswordMinimumNumeric() {
-        return getDevicePolicyManager().getPasswordMinimumNumeric(null);
+        return getDevicePolicyManager().getPasswordMinimumNumeric(null,
+                getCurrentOrCallingUserId());
     }
 
     public int getRequestedPasswordMinimumSymbols() {
-        return getDevicePolicyManager().getPasswordMinimumSymbols(null);
+        return getDevicePolicyManager().getPasswordMinimumSymbols(null,
+                getCurrentOrCallingUserId());
     }
 
     public int getRequestedPasswordMinimumNonLetter() {
-        return getDevicePolicyManager().getPasswordMinimumNonLetter(null);
+        return getDevicePolicyManager().getPasswordMinimumNonLetter(null,
+                getCurrentOrCallingUserId());
     }
+
     /**
      * Returns the actual password mode, as set by keyguard after updating the password.
      *
      * @return
      */
     public void reportFailedPasswordAttempt() {
-        getDevicePolicyManager().reportFailedPasswordAttempt();
+        getDevicePolicyManager().reportFailedPasswordAttempt(getCurrentOrCallingUserId());
     }
 
     public void reportSuccessfulPasswordAttempt() {
-        getDevicePolicyManager().reportSuccessfulPasswordAttempt();
+        getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
     }
 
     public void setCurrentUser(int userId) {
@@ -249,7 +256,9 @@
     private int getCurrentOrCallingUserId() {
         int callingUid = Binder.getCallingUid();
         if (callingUid == android.os.Process.SYSTEM_UID) {
-            return mCurrentUserId;
+            // TODO: This is a little inefficient. See if all users of this are able to
+            // handle USER_CURRENT and pass that instead.
+            return getCurrentUser();
         } else {
             return UserHandle.getUserId(callingUid);
         }
@@ -481,21 +490,21 @@
                     deleteGallery();
                     setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
-                            pattern.size(), 0, 0, 0, 0, 0, 0);
+                            pattern.size(), 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
                 } else {
                     setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
                     setLong(PASSWORD_TYPE_ALTERNATE_KEY,
                             DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
                     finishBiometricWeak();
                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
-                            0, 0, 0, 0, 0, 0, 0);
+                            0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
                 }
             } else {
                 if (keyStore.isEmpty()) {
                     keyStore.reset();
                 }
                 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
-                        0, 0, 0, 0, 0);
+                        0, 0, 0, 0, 0, getCurrentOrCallingUserId());
             }
         } catch (RemoteException re) {
             Log.e(TAG, "Couldn't save lock pattern " + re);
@@ -532,7 +541,8 @@
     /** Update the encryption password if it is enabled **/
     private void updateEncryptionPassword(String password) {
         DevicePolicyManager dpm = getDevicePolicyManager();
-        if (dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
+        if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId())
+                != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
             return;
         }
 
@@ -558,7 +568,7 @@
      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
      */
     public void saveLockPassword(String password, int quality) {
-        this.saveLockPassword(password, quality, false);
+        this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId());
     }
 
     /**
@@ -570,23 +580,42 @@
      * @param isFallback Specifies if this is a fallback to biometric weak
      */
     public void saveLockPassword(String password, int quality, boolean isFallback) {
+        saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId());
+    }
+
+    /**
+     * Save a lock password.  Does not ensure that the password is as good
+     * as the requested mode, but will adjust the mode to be as good as the
+     * pattern.
+     * @param password The password to save
+     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
+     * @param isFallback Specifies if this is a fallback to biometric weak
+     * @param userHandle The userId of the user to change the password for
+     */
+    public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
         // Compute the hash
         final byte[] hash = passwordToHash(password);
         try {
-            getLockSettings().setLockPassword(hash, getCurrentOrCallingUserId());
+            if (Process.myUid() != Process.SYSTEM_UID && userHandle != UserHandle.myUserId()) {
+                throw new SecurityException(
+                        "Only the system process can save lock password for another user");
+            }
+            getLockSettings().setLockPassword(hash, userHandle);
             DevicePolicyManager dpm = getDevicePolicyManager();
             KeyStore keyStore = KeyStore.getInstance();
             if (password != null) {
-                // Update the encryption password.
-                updateEncryptionPassword(password);
+                if (userHandle == UserHandle.USER_OWNER) {
+                    // Update the encryption password.
+                    updateEncryptionPassword(password);
 
-                // Update the keystore password
-                keyStore.password(password);
+                    // Update the keystore password
+                    keyStore.password(password);
+                }
 
                 int computedQuality = computePasswordQuality(password);
                 if (!isFallback) {
                     deleteGallery();
-                    setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
+                    setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
                     if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
                         int letters = 0;
                         int uppercase = 0;
@@ -612,25 +641,27 @@
                         }
                         dpm.setActivePasswordState(Math.max(quality, computedQuality),
                                 password.length(), letters, uppercase, lowercase,
-                                numbers, symbols, nonletter);
+                                numbers, symbols, nonletter, userHandle);
                     } else {
                         // The password is not anything.
                         dpm.setActivePasswordState(
                                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
-                                0, 0, 0, 0, 0, 0, 0);
+                                0, 0, 0, 0, 0, 0, 0, userHandle);
                     }
                 } else {
                     // Case where it's a fallback for biometric weak
-                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
-                    setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality));
+                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
+                            userHandle);
+                    setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
+                            userHandle);
                     finishBiometricWeak();
                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
-                            0, 0, 0, 0, 0, 0, 0);
+                            0, 0, 0, 0, 0, 0, 0, userHandle);
                 }
                 // Add the password to the password history. We assume all
                 // password
                 // hashes have the same length for simplicity of implementation.
-                String passwordHistory = getString(PASSWORD_HISTORY_KEY);
+                String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
                 if (passwordHistory == null) {
                     passwordHistory = new String();
                 }
@@ -645,7 +676,7 @@
                             * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
                             .length()));
                 }
-                setString(PASSWORD_HISTORY_KEY, passwordHistory);
+                setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
             } else {
                 // Conditionally reset the keystore if empty. If
                 // non-empty, we are just switching key guard type
@@ -653,7 +684,8 @@
                     keyStore.reset();
                 }
                 dpm.setActivePasswordState(
-                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0);
+                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
+                        userHandle);
             }
         } catch (RemoteException re) {
             // Cant do much
@@ -849,7 +881,7 @@
         if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
             return false;
         }
-        if (getDevicePolicyManager().getCameraDisabled(null)) {
+        if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) {
             return false;
         }
 
@@ -1027,6 +1059,10 @@
     }
 
     private void setLong(String secureSettingKey, long value) {
+        setLong(secureSettingKey, value, getCurrentOrCallingUserId());
+    }
+
+    private void setLong(String secureSettingKey, long value, int userHandle) {
         try {
             getLockSettings().setLong(secureSettingKey, value, getCurrentOrCallingUserId());
         } catch (RemoteException re) {
@@ -1036,17 +1072,20 @@
     }
 
     private String getString(String secureSettingKey) {
+        return getString(secureSettingKey, getCurrentOrCallingUserId());
+    }
+
+    private String getString(String secureSettingKey, int userHandle) {
         try {
-            return getLockSettings().getString(secureSettingKey, null,
-                    getCurrentOrCallingUserId());
+            return getLockSettings().getString(secureSettingKey, null, userHandle);
         } catch (RemoteException re) {
             return null;
         }
     }
 
-    private void setString(String secureSettingKey, String value) {
+    private void setString(String secureSettingKey, String value, int userHandle) {
         try {
-            getLockSettings().setString(secureSettingKey, value, getCurrentOrCallingUserId());
+            getLockSettings().setString(secureSettingKey, value, userHandle);
         } catch (RemoteException re) {
             // What can we do?
             Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 47ec243..49c439b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -33,6 +33,7 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.os.Looper;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -344,7 +345,7 @@
         final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern;
 
         final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
-                .getMaximumFailedPasswordsForWipe(null);
+                .getMaximumFailedPasswordsForWipe(null, mLockPatternUtils.getCurrentUser());
 
         final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
                 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
@@ -678,7 +679,7 @@
     private void maybePopulateWidgets() {
         DevicePolicyManager dpm =
                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        if (dpm != null && dpm.getKeyguardWidgetsDisabled(null)
+        if (dpm != null && dpm.getKeyguardWidgetsDisabled(null, mLockPatternUtils.getCurrentUser())
                 != DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_NONE) {
             Log.v(TAG, "Keyguard widgets disabled because of device policy admin");
             return;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
index 7554236..dc20e74 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
@@ -191,8 +191,9 @@
     }
 
     private void updateTargets() {
+        int currentUserHandle = mLockPatternUtils.getCurrentUser();
         boolean disabledByAdmin = mLockPatternUtils.getDevicePolicyManager()
-                .getCameraDisabled(null);
+                .getCameraDisabled(null, currentUserHandle);
         final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext());
         boolean disabledBySimState = monitor.isSimLocked();
         boolean cameraTargetPresent =
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index 372b0fc..035465a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -559,7 +559,7 @@
 
                 // From DevicePolicyAdmin
                 final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
-                        .getMaximumTimeToLock(null);
+                        .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser());
 
                 long timeout;
                 if (policyTimeout > 0) {
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 28a4310..aec5d6e 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -16,7 +16,6 @@
 
 package com.android.server;
 
-import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.storage.ExternalStorageFormatter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
@@ -28,7 +27,9 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import android.app.Activity;
+import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
+import android.app.AppGlobals;
 import android.app.PendingIntent;
 import android.app.admin.DeviceAdminInfo;
 import android.app.admin.DeviceAdminReceiver;
@@ -40,6 +41,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -49,6 +51,7 @@
 import android.os.IBinder;
 import android.os.IPowerManager;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RecoverySystem;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
@@ -56,10 +59,12 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.Xml;
 import android.view.IWindowManager;
 import android.view.WindowManagerPolicy;
@@ -82,56 +87,86 @@
  * Implementation of the device policy APIs.
  */
 public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+    private static final String DEVICE_POLICIES_XML = "device_policies.xml";
+
     private static final String TAG = "DevicePolicyManagerService";
 
     private static final int REQUEST_EXPIRE_PASSWORD = 5571;
 
-    private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms
+    private static final long MS_PER_DAY = 86400 * 1000;
+
+    private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
 
     protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
             = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
 
-    private static final long MS_PER_DAY = 86400 * 1000;
+    private static final boolean DBG = false;
 
     final Context mContext;
-    final MyPackageMonitor mMonitor;
     final PowerManager.WakeLock mWakeLock;
 
     IPowerManager mIPowerManager;
     IWindowManager mIWindowManager;
 
-    int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-    int mActivePasswordLength = 0;
-    int mActivePasswordUpperCase = 0;
-    int mActivePasswordLowerCase = 0;
-    int mActivePasswordLetters = 0;
-    int mActivePasswordNumeric = 0;
-    int mActivePasswordSymbols = 0;
-    int mActivePasswordNonLetter = 0;
-    int mFailedPasswordAttempts = 0;
+    public static class DevicePolicyData {
+        int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+        int mActivePasswordLength = 0;
+        int mActivePasswordUpperCase = 0;
+        int mActivePasswordLowerCase = 0;
+        int mActivePasswordLetters = 0;
+        int mActivePasswordNumeric = 0;
+        int mActivePasswordSymbols = 0;
+        int mActivePasswordNonLetter = 0;
+        int mFailedPasswordAttempts = 0;
 
-    int mPasswordOwner = -1;
+        int mUserHandle;;
+        int mPasswordOwner = -1;
+        long mLastMaximumTimeToLock = -1;
+
+        final HashMap<ComponentName, ActiveAdmin> mAdminMap
+                = new HashMap<ComponentName, ActiveAdmin>();
+        final ArrayList<ActiveAdmin> mAdminList
+                = new ArrayList<ActiveAdmin>();
+
+        public DevicePolicyData(int userHandle) {
+            mUserHandle = userHandle;
+        }
+    }
+
+    final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
+
     Handler mHandler = new Handler();
 
-    long mLastMaximumTimeToLock = -1;
-
-    final HashMap<ComponentName, ActiveAdmin> mAdminMap
-            = new HashMap<ComponentName, ActiveAdmin>();
-    final ArrayList<ActiveAdmin> mAdminList
-            = new ArrayList<ActiveAdmin>();
-
     BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
+            final String action = intent.getAction();
+            final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                    getSendingUserId());
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                     || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
-                Slog.v(TAG, "Sending password expiration notifications for action " + action);
+                Slog.v(TAG, "Sending password expiration notifications for action " + action
+                        + " for user " + userHandle);
                 mHandler.post(new Runnable() {
                     public void run() {
-                        handlePasswordExpirationNotification();
+                        handlePasswordExpirationNotification(getUserData(userHandle));
                     }
                 });
+            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                removeUserData(userHandle);
+            } else if (Intent.ACTION_USER_STARTED.equals(action)
+                    || Intent.ACTION_PACKAGE_CHANGED.equals(action)
+                    || Intent.ACTION_PACKAGE_REMOVED.equals(action)
+                    || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+
+                if (Intent.ACTION_USER_STARTED.equals(action)) {
+                    // Reset the policy data
+                    synchronized (DevicePolicyManagerService.this) {
+                        mUserData.remove(userHandle);
+                    }
+                }
+
+                handlePackagesChanged(userHandle);
             }
         }
     };
@@ -194,6 +229,10 @@
 
         int getUid() { return info.getActivityInfo().applicationInfo.uid; }
 
+        public UserHandle getUserHandle() {
+            return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
+        }
+
         void writeToXml(XmlSerializer out)
                 throws IllegalArgumentException, IllegalStateException, IOException {
             out.startTag(null, "policies");
@@ -421,39 +460,28 @@
         }
     }
 
-    class MyPackageMonitor extends PackageMonitor {
-        @Override
-        public void onSomePackagesChanged() {
-            synchronized (DevicePolicyManagerService.this) {
-                boolean removed = false;
-                for (int i=mAdminList.size()-1; i>=0; i--) {
-                    ActiveAdmin aa = mAdminList.get(i);
-                    int change = isPackageDisappearing(aa.info.getPackageName());
-                    if (change == PACKAGE_PERMANENT_CHANGE
-                            || change == PACKAGE_TEMPORARY_CHANGE) {
-                        Slog.w(TAG, "Admin unexpectedly uninstalled: "
-                                + aa.info.getComponent());
-                        removed = true;
-                        mAdminList.remove(i);
-                    } else if (isPackageModified(aa.info.getPackageName())) {
-                        try {
-                            mContext.getPackageManager().getReceiverInfo(
-                                    aa.info.getComponent(), 0);
-                        } catch (NameNotFoundException e) {
-                            Slog.w(TAG, "Admin package change removed component: "
-                                    + aa.info.getComponent());
-                            removed = true;
-                            mAdminList.remove(i);
-                        }
-                    }
+    private void handlePackagesChanged(int userHandle) {
+        boolean removed = false;
+        Slog.d(TAG, "Handling package changes for user " + userHandle);
+        DevicePolicyData policy = getUserData(userHandle);
+        IPackageManager pm = AppGlobals.getPackageManager();
+        for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
+            ActiveAdmin aa = policy.mAdminList.get(i);
+            try {
+                if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
+                        || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
+                    removed = true;
+                    policy.mAdminList.remove(i);
                 }
-                if (removed) {
-                    validatePasswordOwnerLocked();
-                    syncDeviceCapabilitiesLocked();
-                    saveSettingsLocked();
-                }
+            } catch (RemoteException re) {
+                // Shouldn't happen
             }
         }
+        if (removed) {
+            validatePasswordOwnerLocked(policy);
+            syncDeviceCapabilitiesLocked(policy);
+            saveSettingsLocked(policy.mUserHandle);
+        }
     }
 
     /**
@@ -461,22 +489,62 @@
      */
     public DevicePolicyManagerService(Context context) {
         mContext = context;
-        mMonitor = new MyPackageMonitor();
-        mMonitor.register(context, null, true);
         mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
                 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_BOOT_COMPLETED);
         filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
-        context.registerReceiver(mReceiver, filter);
+        filter.addAction(Intent.ACTION_USER_REMOVED);
+        filter.addAction(Intent.ACTION_USER_STARTED);
+        context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+        filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+        filter.addDataScheme("package");
+        context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+    }
+
+    /**
+     * Creates and loads the policy data from xml.
+     * @param userHandle the user for whom to load the policy data
+     * @return
+     */
+    DevicePolicyData getUserData(int userHandle) {
+        synchronized (this) {
+            DevicePolicyData policy = mUserData.get(userHandle);
+            if (policy == null) {
+                policy = new DevicePolicyData(userHandle);
+                mUserData.append(userHandle, policy);
+                loadSettingsLocked(policy, userHandle);
+            }
+            return policy;
+        }
+    }
+
+    void removeUserData(int userHandle) {
+        synchronized (this) {
+            if (userHandle == UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
+                return;
+            }
+            DevicePolicyData policy = mUserData.get(userHandle);
+            if (policy != null) {
+                mUserData.remove(userHandle);
+            }
+            File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
+                    DEVICE_POLICIES_XML);
+            policyFile.delete();
+            Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
+        }
     }
 
     /**
      * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
      * reminders.  Clears alarm if no expirations are configured.
      */
-    protected void setExpirationAlarmCheckLocked(Context context) {
-        final long expiration = getPasswordExpirationLocked(null);
+    protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
+        final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
         final long now = System.currentTimeMillis();
         final long timeToExpire = expiration - now;
         final long alarmTime;
@@ -499,9 +567,10 @@
         long token = Binder.clearCallingIdentity();
         try {
             AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-            PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
+            PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
                     new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
-                    PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+                    PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
+                    new UserHandle(policy.mUserHandle));
             am.cancel(pi);
             if (alarmTime != 0) {
                 am.set(AlarmManager.RTC, alarmTime, pi);
@@ -527,8 +596,8 @@
         return mIWindowManager;
     }
 
-    ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
-        ActiveAdmin admin = mAdminMap.get(who);
+    ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
+        ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
         if (admin != null
                 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
                 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
@@ -540,8 +609,10 @@
     ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
             throws SecurityException {
         final int callingUid = Binder.getCallingUid();
+        final int userHandle = UserHandle.getUserId(callingUid);
+        final DevicePolicyData policy = getUserData(userHandle);
         if (who != null) {
-            ActiveAdmin admin = mAdminMap.get(who);
+            ActiveAdmin admin = policy.mAdminMap.get(who);
             if (admin == null) {
                 throw new SecurityException("No active admin " + who);
             }
@@ -556,9 +627,9 @@
             }
             return admin;
         } else {
-            final int N = mAdminList.size();
+            final int N = policy.mAdminList.size();
             for (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
                     return admin;
                 }
@@ -579,18 +650,19 @@
             intent.putExtra("expiration", admin.passwordExpirationDate);
         }
         if (result != null) {
-            mContext.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
+            mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
                     null, result, mHandler, Activity.RESULT_OK, null, null);
         } else {
             mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
         }
     }
 
-    void sendAdminCommandLocked(String action, int reqPolicy) {
-        final int N = mAdminList.size();
-        if (N > 0) {
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+    void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
+        final DevicePolicyData policy = getUserData(userHandle);
+        final int count = policy.mAdminList.size();
+        if (count > 0) {
+            for (int i = 0; i < count; i++) {
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (admin.info.usesPolicy(reqPolicy)) {
                     sendAdminCommandLocked(admin, action);
                 }
@@ -598,8 +670,8 @@
         }
     }
 
-    void removeActiveAdminLocked(final ComponentName adminReceiver) {
-        final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
+    void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
+        final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
         if (admin != null) {
             sendAdminCommandLocked(admin,
                     DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
@@ -607,28 +679,31 @@
                         @Override
                         public void onReceive(Context context, Intent intent) {
                             synchronized (DevicePolicyManagerService.this) {
+                                int userHandle = admin.getUserHandle().getIdentifier();
+                                DevicePolicyData policy = getUserData(userHandle);
                                 boolean doProxyCleanup = admin.info.usesPolicy(
                                         DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
-                                mAdminList.remove(admin);
-                                mAdminMap.remove(adminReceiver);
-                                validatePasswordOwnerLocked();
-                                syncDeviceCapabilitiesLocked();
+                                policy.mAdminList.remove(admin);
+                                policy.mAdminMap.remove(adminReceiver);
+                                validatePasswordOwnerLocked(policy);
+                                syncDeviceCapabilitiesLocked(policy);
                                 if (doProxyCleanup) {
-                                    resetGlobalProxyLocked();
+                                    resetGlobalProxyLocked(getUserData(userHandle));
                                 }
-                                saveSettingsLocked();
-                                updateMaximumTimeToLockLocked();
+                                saveSettingsLocked(userHandle);
+                                updateMaximumTimeToLockLocked(policy);
                             }
                         }
             });
         }
     }
 
-    public DeviceAdminInfo findAdmin(ComponentName adminName) {
+    public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         Intent resolveIntent = new Intent();
         resolveIntent.setComponent(adminName);
         List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
-                resolveIntent, PackageManager.GET_META_DATA);
+                resolveIntent, PackageManager.GET_META_DATA, userHandle);
         if (infos == null || infos.size() <= 0) {
             throw new IllegalArgumentException("Unknown admin: " + adminName);
         }
@@ -636,21 +711,25 @@
         try {
             return new DeviceAdminInfo(mContext, infos.get(0));
         } catch (XmlPullParserException e) {
-            Slog.w(TAG, "Bad device admin requested: " + adminName, e);
+            Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
             return null;
         } catch (IOException e) {
-            Slog.w(TAG, "Bad device admin requested: " + adminName, e);
+            Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
             return null;
         }
     }
 
-    private static JournaledFile makeJournaledFile() {
-        final String base = "/data/system/device_policies.xml";
+    private static JournaledFile makeJournaledFile(int userHandle) {
+        final String base = userHandle == 0
+                ? "/data/system/" + DEVICE_POLICIES_XML
+                : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
+                        .getAbsolutePath();
         return new JournaledFile(new File(base), new File(base + ".tmp"));
     }
 
-    private void saveSettingsLocked() {
-        JournaledFile journal = makeJournaledFile();
+    private void saveSettingsLocked(int userHandle) {
+        DevicePolicyData policy = getUserData(userHandle);
+        JournaledFile journal = makeJournaledFile(userHandle);
         FileOutputStream stream = null;
         try {
             stream = new FileOutputStream(journal.chooseForWrite(), false);
@@ -660,9 +739,9 @@
 
             out.startTag(null, "policies");
 
-            final int N = mAdminList.size();
+            final int N = policy.mAdminList.size();
             for (int i=0; i<N; i++) {
-                ActiveAdmin ap = mAdminList.get(i);
+                ActiveAdmin ap = policy.mAdminList.get(i);
                 if (ap != null) {
                     out.startTag(null, "admin");
                     out.attribute(null, "name", ap.info.getComponent().flattenToString());
@@ -671,32 +750,32 @@
                 }
             }
 
-            if (mPasswordOwner >= 0) {
+            if (policy.mPasswordOwner >= 0) {
                 out.startTag(null, "password-owner");
-                out.attribute(null, "value", Integer.toString(mPasswordOwner));
+                out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
                 out.endTag(null, "password-owner");
             }
 
-            if (mFailedPasswordAttempts != 0) {
+            if (policy.mFailedPasswordAttempts != 0) {
                 out.startTag(null, "failed-password-attempts");
-                out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
+                out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
                 out.endTag(null, "failed-password-attempts");
             }
 
-            if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
-                    || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
-                    || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
-                    || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
+            if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
+                    || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
+                    || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
+                    || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
                 out.startTag(null, "active-password");
-                out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
-                out.attribute(null, "length", Integer.toString(mActivePasswordLength));
-                out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
-                out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
-                out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
+                out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
+                out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
+                out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
+                out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
+                out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
                 out.attribute(null, "numeric", Integer
-                        .toString(mActivePasswordNumeric));
-                out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
-                out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
+                        .toString(policy.mActivePasswordNumeric));
+                out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
+                out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
                 out.endTag(null, "active-password");
             }
 
@@ -705,7 +784,7 @@
             out.endDocument();
             stream.close();
             journal.commit();
-            sendChangedNotification();
+            sendChangedNotification(userHandle);
         } catch (IOException e) {
             try {
                 if (stream != null) {
@@ -718,20 +797,19 @@
         }
     }
 
-    private void sendChangedNotification() {
+    private void sendChangedNotification(int userHandle) {
         Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         long ident = Binder.clearCallingIdentity();
         try {
-            // TODO: This shouldn't be sent to all users, if DPM is per user.
-            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+            mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
-    private void loadSettingsLocked() {
-        JournaledFile journal = makeJournaledFile();
+    private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
+        JournaledFile journal = makeJournaledFile(userHandle);
         FileInputStream stream = null;
         File file = journal.chooseForRead();
         try {
@@ -760,40 +838,46 @@
                     String name = parser.getAttributeValue(null, "name");
                     try {
                         DeviceAdminInfo dai = findAdmin(
-                                ComponentName.unflattenFromString(name));
+                                ComponentName.unflattenFromString(name), userHandle);
+                        if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
+                                != userHandle)) {
+                            Slog.w(TAG, "findAdmin returned an incorrect uid "
+                                    + dai.getActivityInfo().applicationInfo.uid + " for user "
+                                    + userHandle);
+                        }
                         if (dai != null) {
                             ActiveAdmin ap = new ActiveAdmin(dai);
                             ap.readFromXml(parser);
-                            mAdminMap.put(ap.info.getComponent(), ap);
-                            mAdminList.add(ap);
+                            policy.mAdminMap.put(ap.info.getComponent(), ap);
+                            policy.mAdminList.add(ap);
                         }
                     } catch (RuntimeException e) {
                         Slog.w(TAG, "Failed loading admin " + name, e);
                     }
                 } else if ("failed-password-attempts".equals(tag)) {
-                    mFailedPasswordAttempts = Integer.parseInt(
+                    policy.mFailedPasswordAttempts = Integer.parseInt(
                             parser.getAttributeValue(null, "value"));
                     XmlUtils.skipCurrentTag(parser);
                 } else if ("password-owner".equals(tag)) {
-                    mPasswordOwner = Integer.parseInt(
+                    policy.mPasswordOwner = Integer.parseInt(
                             parser.getAttributeValue(null, "value"));
                     XmlUtils.skipCurrentTag(parser);
                 } else if ("active-password".equals(tag)) {
-                    mActivePasswordQuality = Integer.parseInt(
+                    policy.mActivePasswordQuality = Integer.parseInt(
                             parser.getAttributeValue(null, "quality"));
-                    mActivePasswordLength = Integer.parseInt(
+                    policy.mActivePasswordLength = Integer.parseInt(
                             parser.getAttributeValue(null, "length"));
-                    mActivePasswordUpperCase = Integer.parseInt(
+                    policy.mActivePasswordUpperCase = Integer.parseInt(
                             parser.getAttributeValue(null, "uppercase"));
-                    mActivePasswordLowerCase = Integer.parseInt(
+                    policy.mActivePasswordLowerCase = Integer.parseInt(
                             parser.getAttributeValue(null, "lowercase"));
-                    mActivePasswordLetters = Integer.parseInt(
+                    policy.mActivePasswordLetters = Integer.parseInt(
                             parser.getAttributeValue(null, "letters"));
-                    mActivePasswordNumeric = Integer.parseInt(
+                    policy.mActivePasswordNumeric = Integer.parseInt(
                             parser.getAttributeValue(null, "numeric"));
-                    mActivePasswordSymbols = Integer.parseInt(
+                    policy.mActivePasswordSymbols = Integer.parseInt(
                             parser.getAttributeValue(null, "symbols"));
-                    mActivePasswordNonLetter = Integer.parseInt(
+                    policy.mActivePasswordNonLetter = Integer.parseInt(
                             parser.getAttributeValue(null, "nonletter"));
                     XmlUtils.skipCurrentTag(parser);
                 } else {
@@ -827,24 +911,24 @@
         // a sanity check in case the two get out of sync; this should
         // never normally happen.
         LockPatternUtils utils = new LockPatternUtils(mContext);
-        if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
+        if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
             Slog.w(TAG, "Active password quality 0x"
-                    + Integer.toHexString(mActivePasswordQuality)
+                    + Integer.toHexString(policy.mActivePasswordQuality)
                     + " does not match actual quality 0x"
                     + Integer.toHexString(utils.getActivePasswordQuality()));
-            mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-            mActivePasswordLength = 0;
-            mActivePasswordUpperCase = 0;
-            mActivePasswordLowerCase = 0;
-            mActivePasswordLetters = 0;
-            mActivePasswordNumeric = 0;
-            mActivePasswordSymbols = 0;
-            mActivePasswordNonLetter = 0;
+            policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+            policy.mActivePasswordLength = 0;
+            policy.mActivePasswordUpperCase = 0;
+            policy.mActivePasswordLowerCase = 0;
+            policy.mActivePasswordLetters = 0;
+            policy.mActivePasswordNumeric = 0;
+            policy.mActivePasswordSymbols = 0;
+            policy.mActivePasswordNonLetter = 0;
         }
 
-        validatePasswordOwnerLocked();
-        syncDeviceCapabilitiesLocked();
-        updateMaximumTimeToLockLocked();
+        validatePasswordOwnerLocked(policy);
+        syncDeviceCapabilitiesLocked(policy);
+        updateMaximumTimeToLockLocked(policy);
     }
 
     static void validateQualityConstant(int quality) {
@@ -862,19 +946,19 @@
                 + Integer.toHexString(quality));
     }
 
-    void validatePasswordOwnerLocked() {
-        if (mPasswordOwner >= 0) {
+    void validatePasswordOwnerLocked(DevicePolicyData policy) {
+        if (policy.mPasswordOwner >= 0) {
             boolean haveOwner = false;
-            for (int i=mAdminList.size()-1; i>=0; i--) {
-                if (mAdminList.get(i).getUid() == mPasswordOwner) {
+            for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
+                if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
                     haveOwner = true;
                     break;
                 }
             }
             if (!haveOwner) {
-                Slog.w(TAG, "Previous password owner " + mPasswordOwner
+                Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
                         + " no longer active; disabling");
-                mPasswordOwner = -1;
+                policy.mPasswordOwner = -1;
             }
         }
     }
@@ -883,11 +967,11 @@
      * Pushes down policy information to the system for any policies related to general device
      * capabilities that need to be enforced by lower level services (e.g. Camera services).
      */
-    void syncDeviceCapabilitiesLocked() {
+    void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
         // Ensure the status of the camera is synced down to the system. Interested native services
         // should monitor this value and act accordingly.
         boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
-        boolean cameraDisabled = getCameraDisabled(null);
+        boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
         if (cameraDisabled != systemState) {
             long token = Binder.clearCallingIdentity();
             try {
@@ -903,19 +987,19 @@
 
     public void systemReady() {
         synchronized (this) {
-            loadSettingsLocked();
+            loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
         }
     }
 
-    private void handlePasswordExpirationNotification() {
+    private void handlePasswordExpirationNotification(DevicePolicyData policy) {
         synchronized (this) {
             final long now = System.currentTimeMillis();
-            final int N = mAdminList.size();
+            final int N = policy.mAdminList.size();
             if (N <= 0) {
                 return;
             }
             for (int i=0; i < N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
                         && admin.passwordExpirationTimeout > 0L
                         && admin.passwordExpirationDate > 0L
@@ -923,7 +1007,7 @@
                     sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
                 }
             }
-            setExpirationAlarmCheckLocked(mContext);
+            setExpirationAlarmCheckLocked(mContext, policy);
         }
     }
 
@@ -931,27 +1015,29 @@
      * @param adminReceiver The admin to add
      * @param refreshing true = update an active admin, no error
      */
-    public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
+    public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        enforceCrossUserPermission(userHandle);
 
-        DeviceAdminInfo info = findAdmin(adminReceiver);
+        DevicePolicyData policy = getUserData(userHandle);
+        DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
         if (info == null) {
             throw new IllegalArgumentException("Bad admin: " + adminReceiver);
         }
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
+                if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
                     throw new IllegalArgumentException("Admin is already added");
                 }
                 ActiveAdmin newAdmin = new ActiveAdmin(info);
-                mAdminMap.put(adminReceiver, newAdmin);
+                policy.mAdminMap.put(adminReceiver, newAdmin);
                 int replaceIndex = -1;
                 if (refreshing) {
-                    final int N = mAdminList.size();
+                    final int N = policy.mAdminList.size();
                     for (int i=0; i < N; i++) {
-                        ActiveAdmin oldAdmin = mAdminList.get(i);
+                        ActiveAdmin oldAdmin = policy.mAdminList.get(i);
                         if (oldAdmin.info.getComponent().equals(adminReceiver)) {
                             replaceIndex = i;
                             break;
@@ -959,11 +1045,11 @@
                     }
                 }
                 if (replaceIndex == -1) {
-                    mAdminList.add(newAdmin);
+                    policy.mAdminList.add(newAdmin);
                 } else {
-                    mAdminList.set(replaceIndex, newAdmin);
+                    policy.mAdminList.set(replaceIndex, newAdmin);
                 }
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
                 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -971,15 +1057,17 @@
         }
     }
 
-    public boolean isAdminActive(ComponentName adminReceiver) {
+    public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            return getActiveAdminUncheckedLocked(adminReceiver) != null;
+            return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
         }
     }
 
-    public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
+    public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
+            ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
             if (administrator == null) {
                 throw new SecurityException("No active admin " + adminReceiver);
             }
@@ -987,25 +1075,29 @@
         }
     }
 
-    public List<ComponentName> getActiveAdmins() {
+    public List<ComponentName> getActiveAdmins(int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             if (N <= 0) {
                 return null;
             }
             ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
             for (int i=0; i<N; i++) {
-                res.add(mAdminList.get(i).info.getComponent());
+                res.add(policy.mAdminList.get(i).info.getComponent());
             }
             return res;
         }
     }
 
-    public boolean packageHasActiveAdmins(String packageName) {
+    public boolean packageHasActiveAdmins(String packageName, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             for (int i=0; i<N; i++) {
-                if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
+                if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
                     return true;
                 }
             }
@@ -1013,9 +1105,10 @@
         }
     }
 
-    public void removeActiveAdmin(ComponentName adminReceiver) {
+    public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
+            ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
             if (admin == null) {
                 return;
             }
@@ -1025,15 +1118,16 @@
             }
             long ident = Binder.clearCallingIdentity();
             try {
-                removeActiveAdminLocked(adminReceiver);
+                removeActiveAdminLocked(adminReceiver, userHandle);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
         }
     }
 
-    public void setPasswordQuality(ComponentName who, int quality) {
+    public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
         validateQualityConstant(quality);
+        enforceCrossUserPermission(userHandle);
 
         synchronized (this) {
             if (who == null) {
@@ -1043,23 +1137,25 @@
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.passwordQuality != quality) {
                 ap.passwordQuality = quality;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
         }
     }
 
-    public int getPasswordQuality(ComponentName who) {
+    public int getPasswordQuality(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+            DevicePolicyData policy = getUserData(userHandle);
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.passwordQuality : mode;
             }
 
-            final int N = mAdminList.size();
+            final int N = policy.mAdminList.size();
             for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (mode < admin.passwordQuality) {
                     mode = admin.passwordQuality;
                 }
@@ -1068,7 +1164,8 @@
         }
     }
 
-    public void setPasswordMinimumLength(ComponentName who, int length) {
+    public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -1077,23 +1174,25 @@
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLength != length) {
                 ap.minimumPasswordLength = length;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
         }
     }
 
-    public int getPasswordMinimumLength(ComponentName who) {
+    public int getPasswordMinimumLength(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
+            DevicePolicyData policy = getUserData(userHandle);
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.minimumPasswordLength : length;
             }
 
-            final int N = mAdminList.size();
+            final int N = policy.mAdminList.size();
             for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (length < admin.minimumPasswordLength) {
                     length = admin.minimumPasswordLength;
                 }
@@ -1102,7 +1201,8 @@
         }
     }
 
-    public void setPasswordHistoryLength(ComponentName who, int length) {
+    public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -1111,23 +1211,25 @@
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.passwordHistoryLength != length) {
                 ap.passwordHistoryLength = length;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
         }
     }
 
-    public int getPasswordHistoryLength(ComponentName who) {
+    public int getPasswordHistoryLength(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
+            DevicePolicyData policy = getUserData(userHandle);
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.passwordHistoryLength : length;
             }
 
-            final int N = mAdminList.size();
+            final int N = policy.mAdminList.size();
             for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (length < admin.passwordHistoryLength) {
                     length = admin.passwordHistoryLength;
                 }
@@ -1136,7 +1238,8 @@
         }
     }
 
-    public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
+    public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -1155,8 +1258,9 @@
                         + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
                         .format(new Date(expiration)));
             }
-            saveSettingsLocked();
-            setExpirationAlarmCheckLocked(mContext); // in case this is the first one
+            saveSettingsLocked(userHandle);
+            // in case this is the first one
+            setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
         }
     }
 
@@ -1164,17 +1268,19 @@
      * Return a single admin's expiration cycle time, or the min of all cycle times.
      * Returns 0 if not configured.
      */
-    public long getPasswordExpirationTimeout(ComponentName who) {
+    public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.passwordExpirationTimeout : 0L;
             }
 
             long timeout = 0L;
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
                         && timeout > admin.passwordExpirationTimeout)) {
                     timeout = admin.passwordExpirationTimeout;
@@ -1188,16 +1294,17 @@
      * Return a single admin's expiration date/time, or the min (soonest) for all admins.
      * Returns 0 if not configured.
      */
-    private long getPasswordExpirationLocked(ComponentName who) {
+    private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
         if (who != null) {
-            ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+            ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
             return admin != null ? admin.passwordExpirationDate : 0L;
         }
 
         long timeout = 0L;
-        final int N = mAdminList.size();
+        DevicePolicyData policy = getUserData(userHandle);
+        final int N = policy.mAdminList.size();
         for (int i = 0; i < N; i++) {
-            ActiveAdmin admin = mAdminList.get(i);
+            ActiveAdmin admin = policy.mAdminList.get(i);
             if (timeout == 0L || (admin.passwordExpirationDate != 0
                     && timeout > admin.passwordExpirationDate)) {
                 timeout = admin.passwordExpirationDate;
@@ -1206,13 +1313,15 @@
         return timeout;
     }
 
-    public long getPasswordExpiration(ComponentName who) {
+    public long getPasswordExpiration(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            return getPasswordExpirationLocked(who);
+            return getPasswordExpirationLocked(who, userHandle);
         }
     }
 
-    public void setPasswordMinimumUpperCase(ComponentName who, int length) {
+    public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -1221,23 +1330,25 @@
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordUpperCase != length) {
                 ap.minimumPasswordUpperCase = length;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
         }
     }
 
-    public int getPasswordMinimumUpperCase(ComponentName who) {
+    public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.minimumPasswordUpperCase : length;
             }
 
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             for (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (length < admin.minimumPasswordUpperCase) {
                     length = admin.minimumPasswordUpperCase;
                 }
@@ -1246,7 +1357,8 @@
         }
     }
 
-    public void setPasswordMinimumLowerCase(ComponentName who, int length) {
+    public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -1255,23 +1367,25 @@
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLowerCase != length) {
                 ap.minimumPasswordLowerCase = length;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
         }
     }
 
-    public int getPasswordMinimumLowerCase(ComponentName who) {
+    public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.minimumPasswordLowerCase : length;
             }
 
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             for (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (length < admin.minimumPasswordLowerCase) {
                     length = admin.minimumPasswordLowerCase;
                 }
@@ -1280,7 +1394,8 @@
         }
     }
 
-    public void setPasswordMinimumLetters(ComponentName who, int length) {
+    public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -1289,23 +1404,25 @@
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLetters != length) {
                 ap.minimumPasswordLetters = length;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
         }
     }
 
-    public int getPasswordMinimumLetters(ComponentName who) {
+    public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.minimumPasswordLetters : length;
             }
 
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             for (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (length < admin.minimumPasswordLetters) {
                     length = admin.minimumPasswordLetters;
                 }
@@ -1314,7 +1431,8 @@
         }
     }
 
-    public void setPasswordMinimumNumeric(ComponentName who, int length) {
+    public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -1323,23 +1441,25 @@
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordNumeric != length) {
                 ap.minimumPasswordNumeric = length;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
         }
     }
 
-    public int getPasswordMinimumNumeric(ComponentName who) {
+    public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.minimumPasswordNumeric : length;
             }
 
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (length < admin.minimumPasswordNumeric) {
                     length = admin.minimumPasswordNumeric;
                 }
@@ -1348,7 +1468,8 @@
         }
     }
 
-    public void setPasswordMinimumSymbols(ComponentName who, int length) {
+    public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -1357,23 +1478,25 @@
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordSymbols != length) {
                 ap.minimumPasswordSymbols = length;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
         }
     }
 
-    public int getPasswordMinimumSymbols(ComponentName who) {
+    public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.minimumPasswordSymbols : length;
             }
 
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (length < admin.minimumPasswordSymbols) {
                     length = admin.minimumPasswordSymbols;
                 }
@@ -1382,7 +1505,8 @@
         }
     }
 
-    public void setPasswordMinimumNonLetter(ComponentName who, int length) {
+    public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -1391,23 +1515,25 @@
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordNonLetter != length) {
                 ap.minimumPasswordNonLetter = length;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
         }
     }
 
-    public int getPasswordMinimumNonLetter(ComponentName who) {
+    public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.minimumPasswordNonLetter : length;
             }
 
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             for (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (length < admin.minimumPasswordNonLetter) {
                     length = admin.minimumPasswordNonLetter;
                 }
@@ -1416,39 +1542,43 @@
         }
     }
 
-    public boolean isActivePasswordSufficient() {
+    public boolean isActivePasswordSufficient(int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
+            DevicePolicyData policy = getUserData(userHandle);
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
-            if (mActivePasswordQuality < getPasswordQuality(null)
-                    || mActivePasswordLength < getPasswordMinimumLength(null)) {
+            if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
+                    || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
                 return false;
             }
-            if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
+            if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
                 return true;
             }
-            return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
-                    && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
-                    && mActivePasswordLetters >= getPasswordMinimumLetters(null)
-                    && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
-                    && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
-                    && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
+            return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
+                    && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
+                    && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
+                    && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
+                    && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
+                    && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
         }
     }
 
-    public int getCurrentFailedPasswordAttempts() {
+    public int getCurrentFailedPasswordAttempts(int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
-            return mFailedPasswordAttempts;
+            return getUserData(userHandle).mFailedPasswordAttempts;
         }
     }
 
-    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
+    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
@@ -1458,23 +1588,25 @@
                     DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
             if (ap.maximumFailedPasswordsForWipe != num) {
                 ap.maximumFailedPasswordsForWipe = num;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
         }
     }
 
-    public int getMaximumFailedPasswordsForWipe(ComponentName who) {
+    public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
+            DevicePolicyData policy = getUserData(userHandle);
             int count = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
             }
 
-            final int N = mAdminList.size();
+            final int N = policy.mAdminList.size();
             for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (count == 0) {
                     count = admin.maximumFailedPasswordsForWipe;
                 } else if (admin.maximumFailedPasswordsForWipe != 0
@@ -1486,14 +1618,15 @@
         }
     }
 
-    public boolean resetPassword(String password, int flags) {
+    public boolean resetPassword(String password, int flags, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         int quality;
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
-            quality = getPasswordQuality(null);
+            quality = getPasswordQuality(null, userHandle);
             if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
                 int realQuality = LockPatternUtils.computePasswordQuality(password);
                 if (realQuality < quality
@@ -1506,7 +1639,7 @@
                 }
                 quality = Math.max(realQuality, quality);
             }
-            int length = getPasswordMinimumLength(null);
+            int length = getPasswordMinimumLength(null, userHandle);
             if (password.length() < length) {
                 Slog.w(TAG, "resetPassword: password length " + password.length()
                         + " does not meet required length " + length);
@@ -1535,13 +1668,13 @@
                         nonletter++;
                     }
                 }
-                int neededLetters = getPasswordMinimumLetters(null);
+                int neededLetters = getPasswordMinimumLetters(null, userHandle);
                 if(letters < neededLetters) {
                     Slog.w(TAG, "resetPassword: number of letters " + letters
                             + " does not meet required number of letters " + neededLetters);
                     return false;
                 }
-                int neededNumbers = getPasswordMinimumNumeric(null);
+                int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
                 if (numbers < neededNumbers) {
                     Slog
                             .w(TAG, "resetPassword: number of numerical digits " + numbers
@@ -1549,27 +1682,27 @@
                                     + neededNumbers);
                     return false;
                 }
-                int neededLowerCase = getPasswordMinimumLowerCase(null);
+                int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
                 if (lowercase < neededLowerCase) {
                     Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
                             + " does not meet required number of lowercase letters "
                             + neededLowerCase);
                     return false;
                 }
-                int neededUpperCase = getPasswordMinimumUpperCase(null);
+                int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
                 if (uppercase < neededUpperCase) {
                     Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
                             + " does not meet required number of uppercase letters "
                             + neededUpperCase);
                     return false;
                 }
-                int neededSymbols = getPasswordMinimumSymbols(null);
+                int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
                 if (symbols < neededSymbols) {
                     Slog.w(TAG, "resetPassword: number of special symbols " + symbols
                             + " does not meet required number of special symbols " + neededSymbols);
                     return false;
                 }
-                int neededNonLetter = getPasswordMinimumNonLetter(null);
+                int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
                 if (nonletter < neededNonLetter) {
                     Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
                             + " does not meet required number of non-letter characters "
@@ -1580,7 +1713,8 @@
         }
 
         int callingUid = Binder.getCallingUid();
-        if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
+        DevicePolicyData policy = getUserData(userHandle);
+        if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
             Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
             return false;
         }
@@ -1590,13 +1724,13 @@
         long ident = Binder.clearCallingIdentity();
         try {
             LockPatternUtils utils = new LockPatternUtils(mContext);
-            utils.saveLockPassword(password, quality);
+            utils.saveLockPassword(password, quality, false, userHandle);
             synchronized (this) {
                 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
                         != 0 ? callingUid : -1;
-                if (mPasswordOwner != newOwner) {
-                    mPasswordOwner = newOwner;
-                    saveSettingsLocked();
+                if (policy.mPasswordOwner != newOwner) {
+                    policy.mPasswordOwner = newOwner;
+                    saveSettingsLocked(userHandle);
                 }
             }
         } finally {
@@ -1606,7 +1740,8 @@
         return true;
     }
 
-    public void setMaximumTimeToLock(ComponentName who, long timeMs) {
+    public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -1615,15 +1750,15 @@
                     DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
             if (ap.maximumTimeToUnlock != timeMs) {
                 ap.maximumTimeToUnlock = timeMs;
-                saveSettingsLocked();
-                updateMaximumTimeToLockLocked();
+                saveSettingsLocked(userHandle);
+                updateMaximumTimeToLockLocked(getUserData(userHandle));
             }
         }
     }
 
-    void updateMaximumTimeToLockLocked() {
-        long timeMs = getMaximumTimeToLock(null);
-        if (mLastMaximumTimeToLock == timeMs) {
+    void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
+        long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
+        if (policy.mLastMaximumTimeToLock == timeMs) {
             return;
         }
 
@@ -1638,7 +1773,7 @@
                         Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
             }
 
-            mLastMaximumTimeToLock = timeMs;
+            policy.mLastMaximumTimeToLock = timeMs;
 
             try {
                 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
@@ -1650,18 +1785,20 @@
         }
     }
 
-    public long getMaximumTimeToLock(ComponentName who) {
+    public long getMaximumTimeToLock(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             long time = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.maximumTimeToUnlock : time;
             }
 
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (time == 0) {
                     time = admin.maximumTimeToUnlock;
                 } else if (admin.maximumTimeToUnlock != 0
@@ -1679,17 +1816,21 @@
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
-            long ident = Binder.clearCallingIdentity();
-            try {
-                // Power off the display
-                getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
-                        PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
-                // Ensure the device is locked
-                getWindowManager().lockNow();
-            } catch (RemoteException e) {
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+            lockNowUnchecked();
+        }
+    }
+
+    private void lockNowUnchecked() {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            // Power off the display
+            getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
+                    PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
+            // Ensure the device is locked
+            getWindowManager().lockNow();
+        } catch (RemoteException e) {
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -1719,7 +1860,8 @@
         }
     }
 
-    public void wipeData(int flags) {
+    public void wipeData(int flags, final int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
@@ -1727,19 +1869,35 @@
                     DeviceAdminInfo.USES_POLICY_WIPE_DATA);
             long ident = Binder.clearCallingIdentity();
             try {
-                wipeDataLocked(flags);
+                if (userHandle == UserHandle.USER_OWNER) {
+                    wipeDataLocked(flags);
+                } else {
+                    lockNowUnchecked();
+                    mHandler.post(new Runnable() {
+                        public void run() {
+                            try {
+                                ActivityManagerNative.getDefault().switchUser(0);
+                                ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
+                                        .removeUser(userHandle);
+                            } catch (RemoteException re) {
+                                // Shouldn't happen
+                            }
+                        }
+                    });
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
         }
     }
 
-    public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
+    public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
         synchronized (this) {
-            ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
+            ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
             if (admin == null) {
                 try {
                     result.sendResult(null);
@@ -1749,7 +1907,7 @@
             }
             Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
             intent.setComponent(admin.info.getComponent());
-            mContext.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
+            mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
                     null, new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
@@ -1763,34 +1921,36 @@
     }
 
     public void setActivePasswordState(int quality, int length, int letters, int uppercase,
-            int lowercase, int numbers, int symbols, int nonletter) {
+            int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        DevicePolicyData p = getUserData(userHandle);
 
         validateQualityConstant(quality);
 
         synchronized (this) {
-            if (mActivePasswordQuality != quality || mActivePasswordLength != length
-                    || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
-                    || mActivePasswordUpperCase != uppercase
-                    || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
-                    || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
+            if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
+                    || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
+                    || p.mActivePasswordUpperCase != uppercase
+                    || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
+                    || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
                 long ident = Binder.clearCallingIdentity();
                 try {
-                    mActivePasswordQuality = quality;
-                    mActivePasswordLength = length;
-                    mActivePasswordLetters = letters;
-                    mActivePasswordLowerCase = lowercase;
-                    mActivePasswordUpperCase = uppercase;
-                    mActivePasswordNumeric = numbers;
-                    mActivePasswordSymbols = symbols;
-                    mActivePasswordNonLetter = nonletter;
-                    mFailedPasswordAttempts = 0;
-                    saveSettingsLocked();
-                    updatePasswordExpirationsLocked();
-                    setExpirationAlarmCheckLocked(mContext);
+                    p.mActivePasswordQuality = quality;
+                    p.mActivePasswordLength = length;
+                    p.mActivePasswordLetters = letters;
+                    p.mActivePasswordLowerCase = lowercase;
+                    p.mActivePasswordUpperCase = uppercase;
+                    p.mActivePasswordNumeric = numbers;
+                    p.mActivePasswordSymbols = symbols;
+                    p.mActivePasswordNonLetter = nonletter;
+                    p.mFailedPasswordAttempts = 0;
+                    saveSettingsLocked(userHandle);
+                    updatePasswordExpirationsLocked(userHandle);
+                    setExpirationAlarmCheckLocked(mContext, p);
                     sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
-                            DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+                            DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
@@ -1801,55 +1961,60 @@
     /**
      * Called any time the device password is updated.  Resets all password expiration clocks.
      */
-    private void updatePasswordExpirationsLocked() {
-        final int N = mAdminList.size();
+    private void updatePasswordExpirationsLocked(int userHandle) {
+        DevicePolicyData policy = getUserData(userHandle);
+        final int N = policy.mAdminList.size();
         if (N > 0) {
             for (int i=0; i<N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
                     long timeout = admin.passwordExpirationTimeout;
                     long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
                     admin.passwordExpirationDate = expiration;
                 }
             }
-            saveSettingsLocked();
+            saveSettingsLocked(userHandle);
         }
     }
 
-    public void reportFailedPasswordAttempt() {
+    public void reportFailedPasswordAttempt(int userHandle) {
+        enforceCrossUserPermission(userHandle);
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
         synchronized (this) {
+            DevicePolicyData policy = getUserData(userHandle);
             long ident = Binder.clearCallingIdentity();
             try {
-                mFailedPasswordAttempts++;
-                saveSettingsLocked();
-                int max = getMaximumFailedPasswordsForWipe(null);
-                if (max > 0 && mFailedPasswordAttempts >= max) {
+                policy.mFailedPasswordAttempts++;
+                saveSettingsLocked(userHandle);
+                int max = getMaximumFailedPasswordsForWipe(null, userHandle);
+                if (max > 0 && policy.mFailedPasswordAttempts >= max) {
                     wipeDataLocked(0);
                 }
                 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
-                        DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+                        DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
         }
     }
 
-    public void reportSuccessfulPasswordAttempt() {
+    public void reportSuccessfulPasswordAttempt(int userHandle) {
+        enforceCrossUserPermission(userHandle);
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
         synchronized (this) {
-            if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
+            DevicePolicyData policy = getUserData(userHandle);
+            if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
                 long ident = Binder.clearCallingIdentity();
                 try {
-                    mFailedPasswordAttempts = 0;
-                    mPasswordOwner = -1;
-                    saveSettingsLocked();
+                    policy.mFailedPasswordAttempts = 0;
+                    policy.mPasswordOwner = -1;
+                    saveSettingsLocked(userHandle);
                     sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
-                            DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+                            DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
@@ -1858,26 +2023,36 @@
     }
 
     public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
-            String exclusionList) {
+            String exclusionList, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized(this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
             }
 
+            // Only check if owner has set global proxy. We don't allow other users to set it.
+            DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
 
             // Scan through active admins and find if anyone has already
             // set the global proxy.
-            Set<ComponentName> compSet = mAdminMap.keySet();
+            Set<ComponentName> compSet = policy.mAdminMap.keySet();
             for  (ComponentName component : compSet) {
-                ActiveAdmin ap = mAdminMap.get(component);
+                ActiveAdmin ap = policy.mAdminMap.get(component);
                 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
                     // Another admin already sets the global proxy
                     // Return it to the caller.
                     return component;
                 }
             }
+
+            // If the user is not the owner, don't set the global proxy. Fail silently.
+            if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
+                        + userHandle + " is not permitted.");
+                return null;
+            }
             if (proxySpec == null) {
                 admin.specifiesGlobalProxy = false;
                 admin.globalProxySpec = null;
@@ -1892,19 +2067,21 @@
             // Reset the global proxy accordingly
             // Do this using system permissions, as apps cannot write to secure settings
             long origId = Binder.clearCallingIdentity();
-            resetGlobalProxyLocked();
+            resetGlobalProxyLocked(policy);
             Binder.restoreCallingIdentity(origId);
             return null;
         }
     }
 
-    public ComponentName getGlobalProxyAdmin() {
+    public ComponentName getGlobalProxyAdmin(int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized(this) {
+            DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
             // Scan through active admins and find if anyone has already
             // set the global proxy.
-            final int N = mAdminList.size();
+            final int N = policy.mAdminList.size();
             for (int i = 0; i < N; i++) {
-                ActiveAdmin ap = mAdminList.get(i);
+                ActiveAdmin ap = policy.mAdminList.get(i);
                 if (ap.specifiesGlobalProxy) {
                     // Device admin sets the global proxy
                     // Return it to the caller.
@@ -1916,10 +2093,10 @@
         return null;
     }
 
-    private void resetGlobalProxyLocked() {
-        final int N = mAdminList.size();
+    private void resetGlobalProxyLocked(DevicePolicyData policy) {
+        final int N = policy.mAdminList.size();
         for (int i = 0; i < N; i++) {
-            ActiveAdmin ap = mAdminList.get(i);
+            ActiveAdmin ap = policy.mAdminList.get(i);
             if (ap.specifiesGlobalProxy) {
                 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
                 return;
@@ -1957,12 +2134,21 @@
      * Set the storage encryption request for a single admin.  Returns the new total request
      * status (for all admins).
      */
-    public int setStorageEncryption(ComponentName who, boolean encrypt) {
+    public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // Check for permissions
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
             }
+            // Only owner can set storage encryption
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return 0;
+            }
+
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
 
@@ -1974,14 +2160,15 @@
             // (1) Record the value for the admin so it's sticky
             if (ap.encryptionRequested != encrypt) {
                 ap.encryptionRequested = encrypt;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
 
+            DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
             // (2) Compute "max" for all admins
             boolean newRequested = false;
-            final int N = mAdminList.size();
+            final int N = policy.mAdminList.size();
             for (int i = 0; i < N; i++) {
-                newRequested |= mAdminList.get(i).encryptionRequested;
+                newRequested |= policy.mAdminList.get(i).encryptionRequested;
             }
 
             // Notify OS of new request
@@ -1998,20 +2185,22 @@
      * Get the current storage encryption request status for a given admin, or aggregate of all
      * active admins.
      */
-    public boolean getStorageEncryption(ComponentName who) {
+    public boolean getStorageEncryption(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // Check for permissions if a particular caller is specified
             if (who != null) {
                 // When checking for a single caller, status is based on caller's request
-                ActiveAdmin ap = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
                 return ap != null ? ap.encryptionRequested : false;
             }
 
             // If no particular caller is specified, return the aggregate set of requests.
             // This is short circuited by returning true on the first hit.
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             for (int i = 0; i < N; i++) {
-                if (mAdminList.get(i).encryptionRequested) {
+                if (policy.mAdminList.get(i).encryptionRequested) {
                     return true;
                 }
             }
@@ -2022,7 +2211,8 @@
     /**
      * Get the current encryption status of the device.
      */
-    public int getStorageEncryptionStatus() {
+    public int getStorageEncryptionStatus(int userHandle) {
+        enforceCrossUserPermission(userHandle);
         return getEncryptionStatus();
     }
 
@@ -2069,7 +2259,8 @@
     /**
      * Disables all device cameras according to the specified admin.
      */
-    public void setCameraDisabled(ComponentName who, boolean disabled) {
+    public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2078,9 +2269,9 @@
                     DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
             if (ap.disableCamera != disabled) {
                 ap.disableCamera = disabled;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
-            syncDeviceCapabilitiesLocked();
+            syncDeviceCapabilitiesLocked(getUserData(userHandle));
         }
     }
 
@@ -2088,17 +2279,18 @@
      * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
      * active admins.
      */
-    public boolean getCameraDisabled(ComponentName who) {
+    public boolean getCameraDisabled(ComponentName who, int userHandle) {
         synchronized (this) {
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return (admin != null) ? admin.disableCamera : false;
             }
 
+            DevicePolicyData policy = getUserData(userHandle);
             // Determine whether or not the device camera is disabled for any active admins.
-            final int N = mAdminList.size();
+            final int N = policy.mAdminList.size();
             for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 if (admin.disableCamera) {
                     return true;
                 }
@@ -2110,7 +2302,8 @@
     /**
      * Selectively disable keyguard widgets.
      */
-    public void setKeyguardWidgetsDisabled(ComponentName who, int which) {
+    public void setKeyguardWidgetsDisabled(ComponentName who, int which, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2119,9 +2312,9 @@
                     DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_WIDGETS);
             if ((ap.disableKeyguardWidgets & which) != which) {
                 ap.disableKeyguardWidgets |= which;
-                saveSettingsLocked();
+                saveSettingsLocked(userHandle);
             }
-            syncDeviceCapabilitiesLocked();
+            syncDeviceCapabilitiesLocked(getUserData(userHandle));
         }
     }
 
@@ -2129,24 +2322,39 @@
      * Gets the disabled state for widgets in keyguard for the given admin,
      * or the aggregate of all active admins if who is null.
      */
-    public int getKeyguardWidgetsDisabled(ComponentName who) {
+    public int getKeyguardWidgetsDisabled(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return (admin != null) ? admin.disableKeyguardWidgets : 0;
             }
 
             // Determine whether or not keyguard widgets are disabled for any active admins.
-            final int N = mAdminList.size();
+            DevicePolicyData policy = getUserData(userHandle);
+            final int N = policy.mAdminList.size();
             int which = 0;
             for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = mAdminList.get(i);
+                ActiveAdmin admin = policy.mAdminList.get(i);
                 which |= admin.disableKeyguardWidgets;
             }
             return which;
         }
     }
 
+    private void enforceCrossUserPermission(int userHandle) {
+        if (userHandle < 0) {
+            throw new IllegalArgumentException("Invalid userId " + userHandle);
+        }
+        final int callingUid = Binder.getCallingUid();
+        if (userHandle == UserHandle.getUserId(callingUid)) return;
+        if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
+                    + " INTERACT_ACROSS_USERS_FULL permission");
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -2163,19 +2371,23 @@
         synchronized (this) {
             p.println("Current Device Policy Manager state:");
 
-            p.println("  Enabled Device Admins:");
-            final int N = mAdminList.size();
-            for (int i=0; i<N; i++) {
-                ActiveAdmin ap = mAdminList.get(i);
-                if (ap != null) {
-                    pw.print("  "); pw.print(ap.info.getComponent().flattenToShortString());
-                            pw.println(":");
-                    ap.dump("    ", pw);
+            int userCount = mUserData.size();
+            for (int u = 0; u < userCount; u++) {
+                DevicePolicyData policy = getUserData(mUserData.keyAt(u));
+                p.println("  Enabled Device Admins (User " + policy.mUserHandle + "):");
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin ap = policy.mAdminList.get(i);
+                    if (ap != null) {
+                        pw.print("  "); pw.print(ap.info.getComponent().flattenToShortString());
+                                pw.println(":");
+                        ap.dump("    ", pw);
+                    }
                 }
-            }
 
-            pw.println(" ");
-            pw.print("  mPasswordOwner="); pw.println(mPasswordOwner);
+                pw.println(" ");
+                pw.print("  mPasswordOwner="); pw.println(policy.mPasswordOwner);
+            }
         }
     }
 }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 536c612..f0cc083 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -8044,13 +8044,13 @@
         IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
         try {
-            if (dpm != null && dpm.packageHasActiveAdmins(packageName)) {
+            if (dpm != null && dpm.packageHasActiveAdmins(packageName, UserHandle.getUserId(uid))) {
                 Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
                 return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
             }
         } catch (RemoteException e) {
         }
-        
+
         synchronized (mInstallLock) {
             res = deletePackageLI(packageName,
                     (flags & PackageManager.DELETE_ALL_USERS) != 0
diff --git a/services/java/com/android/server/wm/KeyguardDisableHandler.java b/services/java/com/android/server/wm/KeyguardDisableHandler.java
index d935b8b..859df51 100644
--- a/services/java/com/android/server/wm/KeyguardDisableHandler.java
+++ b/services/java/com/android/server/wm/KeyguardDisableHandler.java
@@ -16,12 +16,15 @@
 
 package com.android.server.wm;
 
+import android.app.ActivityManagerNative;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.TokenWatcher;
+import android.os.UserHandle;
 import android.util.Log;
 import android.util.Pair;
 import android.view.WindowManagerPolicy;
@@ -87,9 +90,14 @@
                 DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
                         Context.DEVICE_POLICY_SERVICE);
                 if (dpm != null) {
-                    mAllowDisableKeyguard = dpm.getPasswordQuality(null)
-                            == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
-                                    ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
+                    try {
+                        mAllowDisableKeyguard = dpm.getPasswordQuality(null, 
+                                ActivityManagerNative.getDefault().getCurrentUser().id)
+                                == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
+                                        ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
+                    } catch (RemoteException re) {
+                        // Nothing much we can do
+                    }
                 }
             }
             if (mAllowDisableKeyguard == ALLOW_DISABLE_YES) {