Modify getUserProfiles to return only enabled profiles:

Add a new enabled state for a managed profile.
Expose that as a new API on DevicePolicyManager.
Set the new state when enabling the profile.
Return only enabled profiles from the user manager.

Bug: 13755441
Bug: 13755091
Change-Id: I2907b182e19b3562592da688b3f68ef5f4088557
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8fa076b..ed007e9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16369,7 +16369,8 @@
      * background.
      */
     private void updateCurrentProfileIdsLocked() {
-        final List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId);
+        final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+                mCurrentUserId, false /* enabledOnly */);
         int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
         for (int i = 0; i < currentProfileIds.length; i++) {
             currentProfileIds[i] = profiles.get(i).id;
@@ -16379,7 +16380,8 @@
 
     private Set getProfileIdsLocked(int userId) {
         Set userIds = new HashSet<Integer>();
-        final List<UserInfo> profiles = getUserManagerLocked().getProfiles(userId);
+        final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+                userId, false /* enabledOnly */);
         for (UserInfo user : profiles) {
             userIds.add(Integer.valueOf(user.id));
         }
@@ -16678,7 +16680,8 @@
 
     void startProfilesLocked() {
         if (DEBUG_MU) Slog.i(TAG_MU, "startProfilesLocked");
-        List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId);
+        List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+                mCurrentUserId, false /* enabledOnly */);
         List<UserInfo> toStart = new ArrayList<UserInfo>(profiles.size());
         for (UserInfo user : profiles) {
             if ((user.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 53db9ef..210e151b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -24,6 +24,7 @@
 import android.app.ActivityThread;
 import android.app.admin.DevicePolicyManager;
 import android.app.IStopUserCallback;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -258,11 +259,20 @@
     }
 
     @Override
-    public List<UserInfo> getProfiles(int userId) {
+    public List<UserInfo> getProfiles(int userId, boolean enabledOnly) {
         if (userId != UserHandle.getCallingUserId()) {
             checkManageUsersPermission("getting profiles related to user " + userId);
         }
         synchronized (mPackagesLock) {
+            // Getting the service here is not good for testing purposes. However, this service
+            // is not available when UserManagerService starts up so we need a lazy load.
+
+            DevicePolicyManager dpm = null;
+            if (enabledOnly) {
+                dpm = (DevicePolicyManager)
+                        mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+            }
+
             UserInfo user = getUserInfoLocked(userId);
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             for (int i = 0; i < mUsers.size(); i++) {
@@ -270,6 +280,23 @@
                 if (!isProfileOf(user, profile)) {
                     continue;
                 }
+
+                if (enabledOnly && profile.isManagedProfile()) {
+                    if (dpm != null) {
+                        if(!dpm.isProfileEnabled(profile.id)) {
+                            continue;
+                        }
+                    } else {
+                        Log.w(LOG_TAG,
+                                "Attempting to reach DevicePolicyManager before it was started");
+                        // TODO: There might be system apps that need to call this. Make sure that
+                        // DevicePolicyManagerService is ready at that time (otherwise, any default
+                        // value is a bad one).
+                        throw new IllegalArgumentException(String.format(
+                                "Attempting to get enabled profiles for %d before "
+                                + "DevicePolicyManagerService has been started.", userId));
+                    }
+                }
                 users.add(profile);
             }
             return users;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 1b048a1..3186527 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -53,6 +53,7 @@
     private static final String ATTR_NAME = "name";
     private static final String ATTR_PACKAGE = "package";
     private static final String ATTR_USERID = "userId";
+    private static final String ATTR_ENABLED = "profileEnabled";
 
     private AtomicFile fileForWriting;
 
@@ -61,11 +62,10 @@
     private OutputStream mOutputStreamForTest;
 
     // Internal state for the device owner package.
-    private String mDeviceOwnerPackageName;
-    private String mDeviceOwnerName;
+    private OwnerInfo mDeviceOwner;
 
     // Internal state for the profile owner packages.
-    private final HashMap<Integer, String[]> mProfileOwners = new HashMap<Integer, String[]>();
+    private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
 
     // Private default constructor.
     private DeviceOwner() {
@@ -95,8 +95,7 @@
      */
     static DeviceOwner createWithDeviceOwner(String packageName, String ownerName) {
         DeviceOwner owner = new DeviceOwner();
-        owner.mDeviceOwnerPackageName = packageName;
-        owner.mDeviceOwnerName = ownerName;
+        owner.mDeviceOwner = new OwnerInfo(ownerName, packageName);
         return owner;
     }
 
@@ -105,25 +104,25 @@
      */
     static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) {
         DeviceOwner owner = new DeviceOwner();
-        owner.mProfileOwners.put(userId, new String[] { packageName, ownerName });
+        owner.mProfileOwners.put(
+                userId, new OwnerInfo(ownerName, packageName, false /* disabled */));
         return owner;
     }
 
     String getDeviceOwnerPackageName() {
-        return mDeviceOwnerPackageName;
+        return mDeviceOwner.packageName;
     }
 
     String getDeviceOwnerName() {
-        return mDeviceOwnerName;
+        return mDeviceOwner.name;
     }
 
     void setDeviceOwner(String packageName, String ownerName) {
-        mDeviceOwnerPackageName = packageName;
-        mDeviceOwnerName = ownerName;
+        mDeviceOwner = new OwnerInfo(ownerName, packageName);
     }
 
     void setProfileOwner(String packageName, String ownerName, int userId) {
-        mProfileOwners.put(userId, new String[] { packageName, ownerName });
+        mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName, false /* disabled */));
     }
 
     void removeProfileOwner(int userId) {
@@ -131,17 +130,30 @@
     }
 
     String getProfileOwnerPackageName(int userId) {
-        String[] profileOwner = mProfileOwners.get(userId);
-        return profileOwner != null ? profileOwner[0] : null;
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner.packageName : null;
     }
 
     String getProfileOwnerName(int userId) {
-        String[] profileOwner = mProfileOwners.get(userId);
-        return profileOwner != null ? profileOwner[1] : null;
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner.name : null;
+    }
+
+    boolean isProfileEnabled(int userId) {
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner.enabled : true;
+    }
+
+    void setProfileEnabled(int userId) {
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        if (profileOwner == null) {
+            throw new IllegalArgumentException("No profile owner exists.");
+        }
+        profileOwner.enabled = true;
     }
 
     boolean hasDeviceOwner() {
-        return mDeviceOwnerPackageName != null;
+        return mDeviceOwner != null;
     }
 
     static boolean isInstalled(String packageName, PackageManager pm) {
@@ -185,14 +197,18 @@
 
                 String tag = parser.getName();
                 if (tag.equals(TAG_DEVICE_OWNER)) {
-                    mDeviceOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                    mDeviceOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+                    mDeviceOwner = new OwnerInfo(
+                            parser.getAttributeValue(null, ATTR_NAME),
+                            parser.getAttributeValue(null, ATTR_PACKAGE));
                 } else if (tag.equals(TAG_PROFILE_OWNER)) {
                     String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                     String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+                    Boolean profileEnabled = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, ATTR_ENABLED));
                     int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
                     mProfileOwners.put(userId,
-                            new String[] { profileOwnerPackageName, profileOwnerName });
+                            new OwnerInfo(
+                                    profileOwnerPackageName, profileOwnerName, profileEnabled));
                 } else {
                     throw new XmlPullParserException(
                             "Unexpected tag in device owner file: " + tag);
@@ -220,21 +236,22 @@
             out.startDocument(null, true);
 
             // Write device owner tag
-            if (mDeviceOwnerPackageName != null) {
+            if (mDeviceOwner != null) {
                 out.startTag(null, TAG_DEVICE_OWNER);
-                out.attribute(null, ATTR_PACKAGE, mDeviceOwnerPackageName);
-                if (mDeviceOwnerName != null) {
-                    out.attribute(null, ATTR_NAME, mDeviceOwnerName);
+                out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
+                if (mDeviceOwner.packageName != null) {
+                    out.attribute(null, ATTR_NAME, mDeviceOwner.packageName);
                 }
                 out.endTag(null, TAG_DEVICE_OWNER);
             }
 
             // Write profile owner tags
             if (mProfileOwners.size() > 0) {
-                for (HashMap.Entry<Integer, String[]> owner : mProfileOwners.entrySet()) {
+                for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
                     out.startTag(null, TAG_PROFILE_OWNER);
-                    out.attribute(null, ATTR_PACKAGE, owner.getValue()[0]);
-                    out.attribute(null, ATTR_NAME, owner.getValue()[1]);
+                    out.attribute(null, ATTR_PACKAGE, owner.getValue().packageName);
+                    out.attribute(null, ATTR_NAME, owner.getValue().name);
+                    out.attribute(null, ATTR_ENABLED, String.valueOf(owner.getValue().enabled));
                     out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
                     out.endTag(null, TAG_PROFILE_OWNER);
                 }
@@ -271,4 +288,20 @@
             fileForWriting.finishWrite((FileOutputStream) stream);
         }
     }
+
+    static class OwnerInfo {
+        public String name;
+        public String packageName;
+        public boolean enabled = true; // only makes sense for managed profiles
+
+        public OwnerInfo(String name, String packageName, boolean enabled) {
+            this(name, packageName);
+            this.enabled = enabled;
+        }
+
+        public OwnerInfo(String name, String packageName) {
+            this.name = name;
+            this.packageName = packageName;
+        }
+    }
 }
\ No newline at end of file
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d6f9dea..cf45149 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2900,9 +2900,13 @@
             }
             // Check if this is the profile owner who is calling
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            Slog.d(LOG_TAG, "Enabling the profile for: " + UserHandle.getCallingUserId());
-            long id = Binder.clearCallingIdentity();
+            int userId = UserHandle.getCallingUserId();
+            Slog.d(LOG_TAG, "Enabling the profile for: " + userId);
 
+            mDeviceOwner.setProfileEnabled(userId);
+            mDeviceOwner.writeOwnerFile();
+
+            long id = Binder.clearCallingIdentity();
             try {
                 Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED);
                 intent.putExtra(Intent.EXTRA_USER, new UserHandle(UserHandle.getCallingUserId()));
@@ -2944,6 +2948,23 @@
         return null;
     }
 
+    @Override
+    public boolean isProfileEnabled(int userHandle) {
+        if (!mHasFeature) {
+            // If device policy management is not enabled, then the userHandle cannot belong to a
+            // managed profile. All other profiles are considered enabled.
+            return true;
+        }
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+
+        synchronized (this) {
+            if (mDeviceOwner != null) {
+                 return mDeviceOwner.isProfileEnabled(userHandle);
+            }
+        }
+        return true;
+    }
+
     private boolean isDeviceProvisioned() {
         return Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 0) > 0;