Device Owner, a special kind of device admin

A Device Owner cannot be uninstalled and is available to all users. It must
be registered before the device_provisioned flag is set.

Device admins can be disabled until used, but visible to device policy
manager, so that users wont be bothered with update requests.

Opened up a few related APIs for use by a system-installed Device Owner.

Change-Id: I847b5fe68c0f724863f778a67602b5bddc79d8e5
diff --git a/api/current.txt b/api/current.txt
index 2e28d7b..d3f1afd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4333,6 +4333,7 @@
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
+    method public boolean isDeviceOwner(java.lang.String);
     method public void lockNow();
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
@@ -16784,9 +16785,20 @@
     method public int getUserCount();
     method public android.os.UserHandle getUserForSerialNumber(long);
     method public java.lang.String getUserName();
+    method public android.os.Bundle getUserRestrictions();
+    method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
     method public boolean isUserAGoat();
+    method public boolean isUserRestricted();
     method public boolean isUserRunning(android.os.UserHandle);
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
+    method public void setUserRestriction(java.lang.String, boolean);
+    method public void setUserRestrictions(android.os.Bundle);
+    method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
+    field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
+    field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
+    field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
+    field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
+    field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
   }
 
   public abstract class Vibrator {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4c0eba0..8284b2c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1513,4 +1513,57 @@
             }
         }
     }
+
+    /**
+     * @hide
+     * Sets the given package as the device owner. The package must already be installed and there
+     * shouldn't be an existing device owner registered, for this call to succeed. Also, this
+     * method must be called before the device is provisioned.
+     * @param packageName the package name of the application to be registered as the device owner.
+     * @return whether the package was successfully registered as the device owner.
+     * @throws IllegalArgumentException if the package name is null or invalid
+     * @throws IllegalStateException if a device owner is already registered or the device has
+     *         already been provisioned.
+     */
+    public boolean setDeviceOwner(String packageName) throws IllegalArgumentException,
+            IllegalStateException {
+        if (mService != null) {
+            try {
+                return mService.setDeviceOwner(packageName);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to set device owner");
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Used to determine if a particular package has been registered as a Device Owner admin.
+     * Device Owner admins cannot be deactivated by the user unless the Device Owner itself allows
+     * it. And Device Owner packages cannot be uninstalled, once registered.
+     * @param packageName the package name to check against the registered device owner.
+     * @return whether or not the package is registered as the Device Owner.
+     */
+    public boolean isDeviceOwner(String packageName) {
+        if (mService != null) {
+            try {
+                return mService.isDeviceOwner(packageName);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to check device owner");
+            }
+        }
+        return false;
+    }
+
+    /** @hide */
+    public String getDeviceOwner() {
+        if (mService != null) {
+            try {
+                return mService.getDeviceOwner();
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to get device owner");
+            }
+        }
+        return null;
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e061ab3..b2a65bf 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -97,4 +97,8 @@
         int numbers, int symbols, int nonletter, int userHandle);
     void reportFailedPasswordAttempt(int userHandle);
     void reportSuccessfulPasswordAttempt(int userHandle);
+
+    boolean setDeviceOwner(String packageName);
+    boolean isDeviceOwner(String packageName);
+    String getDeviceOwner();
 }
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 4c2d7a6..2e8092a 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -34,6 +34,7 @@
     Bitmap getUserIcon(int userHandle);
     List<UserInfo> getUsers(boolean excludeDying);
     UserInfo getUserInfo(int userHandle);
+    boolean isRestricted();
     void setGuestEnabled(boolean enable);
     boolean isGuestEnabled();
     void wipeUser(int userHandle);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7c05528..3f666c1 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -37,48 +37,56 @@
     private final Context mContext;
 
     /**
-     * @hide
-     * Key for user restrictions. Specifies if a user is allowed to add or remove accounts.
+     * Key for user restrictions. Specifies if a user is disallowed from adding and removing
+     * accounts.
+     * The default value is <code>false</code>.
+     * <p/>
      * Type: Boolean
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-    public static final String ALLOW_MODIFY_ACCOUNTS = "modify_accounts";
+    public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
 
     /**
-     * @hide
-     * Key for user restrictions. Specifies if a user is allowed to change Wi-Fi access points.
+     * Key for user restrictions. Specifies if a user is disallowed from changing Wi-Fi
+     * access points.
+     * The default value is <code>false</code>.
+     * <p/>
      * Type: Boolean
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-    public static final String ALLOW_CONFIG_WIFI = "config_wifi";
+    public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";
 
     /**
-     * @hide
-     * Key for user restrictions. Specifies if a user is allowed to install applications.
+     * Key for user restrictions. Specifies if a user is disallowed from installing applications.
+     * The default value is <code>false</code>.
+     * <p/>
      * Type: Boolean
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-    public static final String ALLOW_INSTALL_APPS = "install_apps";
+    public static final String DISALLOW_INSTALL_APPS = "no_install_apps";
 
     /**
-     * @hide
-     * Key for user restrictions. Specifies if a user is allowed to uninstall applications.
+     * Key for user restrictions. Specifies if a user is disallowed from uninstalling applications.
+     * The default value is <code>false</code>.
+     * <p/>
      * Type: Boolean
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-    public static final String ALLOW_UNINSTALL_APPS = "uninstall_apps";
+    public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
 
-    /** @hide *
-     * Key for user restrictions. Specifies if a user is allowed to toggle location sharing.
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from toggling location sharing.
+     * The default value is <code>false</code>.
+     * <p/>
      * Type: Boolean
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-    public static final String ALLOW_CONFIG_LOCATION_ACCESS = "config_location_access";
+    public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
 
     /** @hide */
     public UserManager(Context context, IUserManager service) {
@@ -129,11 +137,14 @@
     }
 
     /**
-     * @hide
+     * Used to check if the user making this call is a restricted user. Restricted users may have
+     * application restrictions imposed on them. All apps should default to the most restrictive
+     * version, unless they have specific restrictions available through a call to
+     * {@link Context#getApplicationRestrictions()}.
      */
     public boolean isUserRestricted() {
         try {
-            return mService.getUserInfo(getUserHandle()).isRestricted();
+            return mService.isRestricted();
         } catch (RemoteException re) {
             Log.w(TAG, "Could not check if user restricted ", re);
             return false;
@@ -189,12 +200,19 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Returns the user-wide restrictions imposed on this user.
+     * @return a Bundle containing all the restrictions.
+     */
     public Bundle getUserRestrictions() {
         return getUserRestrictions(Process.myUserHandle());
     }
 
-    /** @hide */
+    /**
+     * Returns the user-wide restrictions imposed on the user specified by <code>userHandle</code>.
+     * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
+     * @return a Bundle containing all the restrictions.
+     */
     public Bundle getUserRestrictions(UserHandle userHandle) {
         try {
             return mService.getUserRestrictions(userHandle.getIdentifier());
@@ -204,12 +222,21 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Sets all the user-wide restrictions for this user.
+     * Requires the {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @param restrictions the Bundle containing all the restrictions.
+     */
     public void setUserRestrictions(Bundle restrictions) {
         setUserRestrictions(restrictions, Process.myUserHandle());
     }
 
-    /** @hide */
+    /**
+     * Sets all the user-wide restrictions for the specified user.
+     * Requires the {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @param restrictions the Bundle containing all the restrictions.
+     * @param userHandle the UserHandle of the user for whom to set the restrictions.
+     */
     public void setUserRestrictions(Bundle restrictions, UserHandle userHandle) {
         try {
             mService.setUserRestrictions(restrictions, userHandle.getIdentifier());
@@ -218,7 +245,27 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Sets the value of a specific restriction.
+     * Requires the {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @param key the key of the restriction
+     * @param value the value for the restriction
+     * @param userHandle the user whose restriction is to be changed.
+     */
+    public void setUserRestriction(String key, boolean value) {
+        Bundle bundle = getUserRestrictions();
+        bundle.putBoolean(key, value);
+        setUserRestrictions(bundle);
+    }
+
+    /**
+     * @hide
+     * Sets the value of a specific restriction on a specific user.
+     * Requires the {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @param key the key of the restriction
+     * @param value the value for the restriction
+     * @param userHandle the user whose restriction is to be changed.
+     */
     public void setUserRestriction(String key, boolean value, UserHandle userHandle) {
         Bundle bundle = getUserRestrictions(userHandle);
         bundle.putBoolean(key, value);
@@ -467,7 +514,7 @@
      * @hide
      */
     public boolean isLocationSharingToggleAllowed() {
-        return getUserRestrictions().getBoolean(ALLOW_CONFIG_LOCATION_ACCESS);
+        return !getUserRestrictions().getBoolean(DISALLOW_SHARE_LOCATION, false);
     }
 
     /**
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 18b4ec1..d3e7c24 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -41,10 +41,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.Signature;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -62,6 +66,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.util.AtomicFile;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.Slog;
@@ -88,10 +93,11 @@
  * 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 String DEVICE_POLICIES_XML = "device_policies.xml";
+
     private static final int REQUEST_EXPIRE_PASSWORD = 5571;
 
     private static final long MS_PER_DAY = 86400 * 1000;
@@ -109,6 +115,8 @@
     IPowerManager mIPowerManager;
     IWindowManager mIWindowManager;
 
+    private DeviceOwner mDeviceOwner;
+
     public static class DevicePolicyData {
         int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
         int mActivePasswordLength = 0;
@@ -507,6 +515,7 @@
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
         filter.addDataScheme("package");
         context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
     }
@@ -545,6 +554,14 @@
         }
     }
 
+    void loadDeviceOwner() {
+        synchronized (this) {
+            if (DeviceOwner.isRegistered()) {
+                mDeviceOwner = new DeviceOwner();
+            }
+        }
+    }
+
     /**
      * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
      * reminders.  Clears alarm if no expirations are configured.
@@ -709,7 +726,9 @@
         Intent resolveIntent = new Intent();
         resolveIntent.setComponent(adminName);
         List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
-                resolveIntent, PackageManager.GET_META_DATA, userHandle);
+                resolveIntent,
+                PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
+                userHandle);
         if (infos == null || infos.size() <= 0) {
             throw new IllegalArgumentException("Unknown admin: " + adminName);
         }
@@ -994,6 +1013,7 @@
     public void systemReady() {
         synchronized (this) {
             loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
+            loadDeviceOwner();
         }
     }
 
@@ -1052,6 +1072,7 @@
                 }
                 if (replaceIndex == -1) {
                     policy.mAdminList.add(newAdmin);
+                    enableIfNecessary(info.getPackageName(), userHandle);
                 } else {
                     policy.mAdminList.set(replaceIndex, newAdmin);
                 }
@@ -1119,6 +1140,11 @@
                 return;
             }
             if (admin.getUid() != Binder.getCallingUid()) {
+                // If trying to remove device owner, refuse when the caller is not the owner.
+                if (mDeviceOwner != null
+                        && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
+                    return;
+                }
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.BIND_DEVICE_ADMIN, null);
             }
@@ -2351,6 +2377,49 @@
         }
     }
 
+    @Override
+    public boolean setDeviceOwner(String packageName) {
+        if (packageName == null
+                || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
+            throw new IllegalArgumentException("Invalid package name " + packageName
+                    + " for device owner");
+        }
+        synchronized (this) {
+            if (mDeviceOwner == null && !isDeviceProvisioned()) {
+                mDeviceOwner = new DeviceOwner(packageName);
+                mDeviceOwner.writeOwnerFile();
+                return true;
+            } else {
+                throw new IllegalStateException("Trying to set device owner to " + packageName
+                        + ", owner=" + mDeviceOwner.getPackageName()
+                        + ", device_provisioned=" + isDeviceProvisioned());
+            }
+        }
+    }
+
+    @Override
+    public boolean isDeviceOwner(String packageName) {
+        synchronized (this) {
+            return mDeviceOwner != null
+                    && mDeviceOwner.getPackageName().equals(packageName);
+        }
+    }
+
+    @Override
+    public String getDeviceOwner() {
+        synchronized (this) {
+            if (mDeviceOwner != null) {
+                return mDeviceOwner.getPackageName();
+            }
+        }
+        return null;
+    }
+
+    private boolean isDeviceProvisioned() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 0) > 0;
+    }
+
     private void enforceCrossUserPermission(int userHandle) {
         if (userHandle < 0) {
             throw new IllegalArgumentException("Invalid userId " + userHandle);
@@ -2364,6 +2433,22 @@
         }
     }
 
+    private void enableIfNecessary(String packageName, int userId) {
+        try {
+            IPackageManager ipm = AppGlobals.getPackageManager();
+            ApplicationInfo ai = ipm.getApplicationInfo(packageName,
+                    PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
+                    userId);
+            if (ai.enabledSetting
+                    == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+                ipm.setApplicationEnabledSetting(packageName,
+                        PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+                        PackageManager.DONT_KILL_APP, userId);
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -2399,4 +2484,92 @@
             }
         }
     }
+
+    static class DeviceOwner {
+        private static final String DEVICE_OWNER_XML = "device_owner.xml";
+        private static final String TAG_DEVICE_OWNER = "device-owner";
+        private static final String ATTR_PACKAGE = "package";
+        private String mPackageName;
+
+        DeviceOwner() {
+            readOwnerFile();
+        }
+
+        DeviceOwner(String packageName) {
+            this.mPackageName = packageName;
+        }
+
+        static boolean isRegistered() {
+            return new File(Environment.getSystemSecureDirectory(),
+                    DEVICE_OWNER_XML).exists();
+        }
+
+        String getPackageName() {
+            return mPackageName;
+        }
+
+        static boolean isInstalled(String packageName, PackageManager pm) {
+            try {
+                PackageInfo pi;
+                if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
+                    if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        return true;
+                    }
+                }
+            } catch (NameNotFoundException nnfe) {
+                Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
+            }
+            return false;
+        }
+
+        void readOwnerFile() {
+            AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
+                    DEVICE_OWNER_XML));
+            try {
+                FileInputStream input = file.openRead();
+                XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(input, null);
+                int type;
+                while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                        && type != XmlPullParser.START_TAG) {
+                }
+                String tag = parser.getName();
+                if (!TAG_DEVICE_OWNER.equals(tag)) {
+                    throw new XmlPullParserException(
+                            "Device Owner file does not start with device-owner tag: found " + tag);
+                }
+                mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                input.close();
+            } catch (XmlPullParserException xppe) {
+                Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
+            } catch (IOException ioe) {
+                Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
+            }
+        }
+
+        void writeOwnerFile() {
+            synchronized (this) {
+                writeOwnerFileLocked();
+            }
+        }
+
+        private void writeOwnerFileLocked() {
+            AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
+                    DEVICE_OWNER_XML));
+            try {
+                FileOutputStream output = file.startWrite();
+                XmlSerializer out = new FastXmlSerializer();
+                out.setOutput(output, "utf-8");
+                out.startDocument(null, true);
+                out.startTag(null, TAG_DEVICE_OWNER);
+                out.attribute(null, ATTR_PACKAGE, mPackageName);
+                out.endTag(null, TAG_DEVICE_OWNER);
+                out.endDocument();
+                out.flush();
+                file.finishWrite(output);
+            } catch (IOException ioe) {
+                Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index 09daf56..c4b98ad 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -1425,9 +1425,9 @@
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
         checkManageAccountsPermission();
 
-        // Is user allowed to modify accounts?
-        if (!getUserManager().getUserRestrictions(Binder.getCallingUserHandle())
-                .getBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS)) {
+        // Is user disallowed from modifying accounts?
+        if (getUserManager().getUserRestrictions(Binder.getCallingUserHandle())
+                .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
                         "User is not allowed to add an account!");
@@ -2572,7 +2572,7 @@
         if (callingUid != android.os.Process.myUid()) {
             Bundle restrictions = getUserManager().getUserRestrictions(
                     new UserHandle(UserHandle.getUserId(callingUid)));
-            if (!restrictions.getBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS)) {
+            if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
                 return false;
             }
         }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index f1af634..f7ed9d7 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -5933,7 +5933,7 @@
                 null);
 
         final int uid = Binder.getCallingUid();
-        if (!isUserAllowed(UserHandle.getUserId(uid), UserManager.ALLOW_INSTALL_APPS)) {
+        if (isUserRestricted(UserHandle.getUserId(uid), UserManager.DISALLOW_INSTALL_APPS)) {
             try {
                 observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED);
             } catch (RemoteException re) {
@@ -5981,7 +5981,7 @@
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                     "installExistingPackage for user " + userId);
         }
-        if (!isUserAllowed(userId, UserManager.ALLOW_INSTALL_APPS)) {
+        if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
             return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
         }
 
@@ -6015,13 +6015,13 @@
         return PackageManager.INSTALL_SUCCEEDED;
     }
 
-    private boolean isUserAllowed(int userId, String restrictionKey) {
+    private boolean isUserRestricted(int userId, String restrictionKey) {
         Bundle restrictions = sUserManager.getUserRestrictions(userId);
-        if (!restrictions.getBoolean(UserManager.ALLOW_INSTALL_APPS)) {
-            Log.w(TAG, "User does not have permission to: " + restrictionKey);
-            return false;
+        if (restrictions.getBoolean(restrictionKey, false)) {
+            Log.w(TAG, "User is restricted: " + restrictionKey);
+            return true;
         }
-        return true;
+        return false;
     }
 
     @Override
@@ -8418,7 +8418,7 @@
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                     "deletePackage for user " + userId);
         }
-        if (!isUserAllowed(userId, UserManager.ALLOW_UNINSTALL_APPS)) {
+        if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
             try {
                 observer.packageDeleted(packageName, PackageManager.DELETE_FAILED_USER_RESTRICTED);
             } catch (RemoteException re) {
@@ -8464,7 +8464,8 @@
         IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
         try {
-            if (dpm != null && dpm.packageHasActiveAdmins(packageName, userId)) {
+            if (dpm != null && (dpm.packageHasActiveAdmins(packageName, userId)
+                    || dpm.isDeviceOwner(packageName))) {
                 Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
                 return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
             }
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 636b0e5..fecc2df 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -226,6 +226,13 @@
         }
     }
 
+    @Override
+    public boolean isRestricted() {
+        synchronized (mPackagesLock) {
+            return getUserInfoLocked(UserHandle.getCallingUserId()).isRestricted();
+        }
+    }
+
     /*
      * Should be locked on mUsers before calling this.
      */
@@ -558,7 +565,6 @@
         mNextSerialNumber = MIN_USER_ID;
 
         Bundle restrictions = new Bundle();
-        initRestrictionsToDefaults(restrictions);
         mUserRestrictions.append(UserHandle.USER_OWNER, restrictions);
 
         updateUserIdsLocked();
@@ -608,11 +614,11 @@
             Bundle restrictions = mUserRestrictions.get(userInfo.id);
             if (restrictions != null) {
                 serializer.startTag(null, TAG_RESTRICTIONS);
-                writeBoolean(serializer, restrictions, UserManager.ALLOW_CONFIG_WIFI);
-                writeBoolean(serializer, restrictions, UserManager.ALLOW_MODIFY_ACCOUNTS);
-                writeBoolean(serializer, restrictions, UserManager.ALLOW_INSTALL_APPS);
-                writeBoolean(serializer, restrictions, UserManager.ALLOW_UNINSTALL_APPS);
-                writeBoolean(serializer, restrictions, UserManager.ALLOW_CONFIG_LOCATION_ACCESS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_WIFI);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_MODIFY_ACCOUNTS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_INSTALL_APPS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNINSTALL_APPS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_SHARE_LOCATION);
                 serializer.endTag(null, TAG_RESTRICTIONS);
             }
             serializer.endTag(null, TAG_USER);
@@ -676,7 +682,6 @@
         long lastLoggedInTime = 0L;
         boolean partial = false;
         Bundle restrictions = new Bundle();
-        initRestrictionsToDefaults(restrictions);
 
         FileInputStream fis = null;
         try {
@@ -725,11 +730,11 @@
                             name = parser.getText();
                         }
                     } else if (TAG_RESTRICTIONS.equals(tag)) {
-                        readBoolean(parser, restrictions, UserManager.ALLOW_CONFIG_WIFI);
-                        readBoolean(parser, restrictions, UserManager.ALLOW_MODIFY_ACCOUNTS);
-                        readBoolean(parser, restrictions, UserManager.ALLOW_INSTALL_APPS);
-                        readBoolean(parser, restrictions, UserManager.ALLOW_UNINSTALL_APPS);
-                        readBoolean(parser, restrictions, UserManager.ALLOW_CONFIG_LOCATION_ACCESS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_WIFI);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_MODIFY_ACCOUNTS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_INSTALL_APPS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_UNINSTALL_APPS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_SHARE_LOCATION);
                     }
                 }
             }
@@ -758,7 +763,9 @@
     private void readBoolean(XmlPullParser parser, Bundle restrictions,
             String restrictionKey) {
         String value = parser.getAttributeValue(null, restrictionKey);
-        restrictions.putBoolean(restrictionKey, value == null ? true : Boolean.parseBoolean(value));
+        if (value != null) {
+            restrictions.putBoolean(restrictionKey, Boolean.parseBoolean(value));
+        }
     }
 
     private void writeBoolean(XmlSerializer xml, Bundle restrictions, String restrictionKey)
@@ -769,14 +776,6 @@
         }
     }
 
-    private void initRestrictionsToDefaults(Bundle restrictions) {
-        restrictions.putBoolean(UserManager.ALLOW_CONFIG_WIFI, true);
-        restrictions.putBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS, true);
-        restrictions.putBoolean(UserManager.ALLOW_INSTALL_APPS, true);
-        restrictions.putBoolean(UserManager.ALLOW_UNINSTALL_APPS, true);
-        restrictions.putBoolean(UserManager.ALLOW_CONFIG_LOCATION_ACCESS, true);
-    }
-
     private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) {
         String valueString = parser.getAttributeValue(null, attr);
         if (valueString == null) return defaultValue;
@@ -823,7 +822,6 @@
                     writeUserLocked(userInfo);
                     updateUserIdsLocked();
                     Bundle restrictions = new Bundle();
-                    initRestrictionsToDefaults(restrictions);
                     mUserRestrictions.append(userId, restrictions);
                 }
             }