Allow some packages to be excluded during during work profile creation.

Bug: 31657192
Test: adb shell am instrument -e class com.android.server.pm.UserManagerTest#testAddManagedProfile_withDisallowedPackages -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
Change-Id: I37eab6084e0f911d0e2407186b789875588194a2
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index ace4e32..ac8ee8d 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -981,7 +981,7 @@
             } else if (userId < 0) {
                 info = mUm.createUser(name, flags);
             } else {
-                info = mUm.createProfileForUser(name, flags, userId);
+                info = mUm.createProfileForUser(name, flags, userId, null);
             }
 
             if (info != null) {
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index eeb641d..3324f6f 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -36,7 +36,8 @@
     int getCredentialOwnerProfile(int userHandle);
 
     UserInfo createUser(in String name, int flags);
-    UserInfo createProfileForUser(in String name, int flags, int userHandle);
+    UserInfo createProfileForUser(in String name, int flags, int userHandle,
+            in String[] disallowedPackages);
     UserInfo createRestrictedProfile(String name, int parentUserHandle);
     void setUserEnabled(int userHandle);
     boolean removeUser(int userHandle);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 5dc18fb..c7e5e63 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1340,15 +1340,34 @@
      *
      * @param name the user's name
      * @param flags flags that identify the type of user and other properties.
-     * @see UserInfo
-     * @param userHandle new user will be a profile of this use.
+     * @param userHandle new user will be a profile of this user.
      *
-     * @return the UserInfo object for the created user, or null if the user could not be created.
+     * @return the {@link UserInfo} object for the created user, or null if the user
+     *         could not be created.
      * @hide
      */
     public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle) {
+        return createProfileForUser(name, flags, userHandle, null);
+    }
+
+    /**
+     * Version of {@link #createProfileForUser(String, int, int)} that allows you to specify
+     * any packages that should not be installed in the new profile by default, these packages can
+     * still be installed later by the user if needed.
+     *
+     * @param name the user's name
+     * @param flags flags that identify the type of user and other properties.
+     * @param userHandle new user will be a profile of this user.
+     * @param disallowedPackages packages that will not be installed in the profile being created.
+     *
+     * @return the {@link UserInfo} object for the created user, or null if the user
+     *         could not be created.
+     * @hide
+     */
+    public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle,
+            String[] disallowedPackages) {
         try {
-            return mService.createProfileForUser(name, flags, userHandle);
+            return mService.createProfileForUser(name, flags, userHandle, disallowedPackages);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index df02b86..6e87558 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -20618,9 +20618,9 @@
     }
 
     /** Called by UserManagerService */
-    void createNewUser(int userId) {
+    void createNewUser(int userId, String[] disallowedPackages) {
         synchronized (mInstallLock) {
-            mSettings.createNewUserLI(this, mInstaller, userId);
+            mSettings.createNewUserLI(this, mInstaller, userId, disallowedPackages);
         }
         synchronized (mPackages) {
             scheduleWritePackageRestrictionsLocked(userId);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 8cab355..ba1dde0 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3956,7 +3956,7 @@
     }
 
     void createNewUserLI(@NonNull PackageManagerService service, @NonNull Installer installer,
-            int userHandle) {
+            int userHandle, String[] disallowedPackages) {
         String[] volumeUuids;
         String[] names;
         int[] appIds;
@@ -3977,8 +3977,10 @@
                 if (ps.pkg == null || ps.pkg.applicationInfo == null) {
                     continue;
                 }
+                final boolean shouldInstall = ps.isSystem() &&
+                        !ArrayUtils.contains(disallowedPackages, ps.name);
                 // Only system apps are initially installed.
-                ps.setInstalled(ps.isSystem(), userHandle);
+                ps.setInstalled(shouldInstall, userHandle);
                 // Need to create a data directory for all apps under this user. Accumulate all
                 // required args and call the installer after mPackages lock has been released
                 volumeUuids[i] = ps.volumeUuid;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 533d9b5..9146bec2 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2182,9 +2182,10 @@
     }
 
     @Override
-    public UserInfo createProfileForUser(String name, int flags, int userId) {
+    public UserInfo createProfileForUser(String name, int flags, int userId,
+            String[] disallowedPackages) {
         checkManageOrCreateUsersPermission(flags);
-        return createUserInternal(name, flags, userId);
+        return createUserInternal(name, flags, userId, disallowedPackages);
     }
 
     @Override
@@ -2194,6 +2195,11 @@
     }
 
     private UserInfo createUserInternal(String name, int flags, int parentId) {
+        return createUserInternal(name, flags, parentId, null);
+    }
+
+    private UserInfo createUserInternal(String name, int flags, int parentId,
+            String[] disallowedPackages) {
         if (hasUserRestriction(UserManager.DISALLOW_ADD_USER, UserHandle.getCallingUserId())) {
             Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
             return null;
@@ -2204,10 +2210,11 @@
             Log.w(LOG_TAG, "Cannot add user. Not enough space on disk.");
             return null;
         }
-        return createUserInternalUnchecked(name, flags, parentId);
+        return createUserInternalUnchecked(name, flags, parentId, disallowedPackages);
     }
 
-    private UserInfo createUserInternalUnchecked(String name, int flags, int parentId) {
+    private UserInfo createUserInternalUnchecked(String name, int flags, int parentId,
+            String[] disallowedPackages) {
         if (ActivityManager.isLowRamDeviceStatic()) {
             return null;
         }
@@ -2321,7 +2328,7 @@
             storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral());
             mPm.prepareUserData(userId, userInfo.serialNumber,
                     StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
-            mPm.createNewUser(userId);
+            mPm.createNewUser(userId, disallowedPackages);
             userInfo.partial = false;
             synchronized (mPackagesLock) {
                 writeUserLP(userData);
@@ -2371,7 +2378,8 @@
     @Override
     public UserInfo createRestrictedProfile(String name, int parentUserId) {
         checkManageOrCreateUsersPermission("setupRestrictedProfile");
-        final UserInfo user = createProfileForUser(name, UserInfo.FLAG_RESTRICTED, parentUserId);
+        final UserInfo user = createProfileForUser(
+                name, UserInfo.FLAG_RESTRICTED, parentUserId, null);
         if (user == null) {
             return null;
         }
@@ -3533,7 +3541,7 @@
 
         @Override
         public UserInfo createUserEvenWhenDisallowed(String name, int flags) {
-            UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL);
+            UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL, null);
             // Keep this in sync with UserManager.createUser
             if (user != null && !user.isAdmin()) {
                 setUserRestriction(UserManager.DISALLOW_SMS, true, user.id);
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 514f095..3548f28 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -44,6 +44,7 @@
     <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
     <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 6a434ca..0fb2c9f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.app.ActivityManager;
 import android.os.Bundle;
@@ -46,16 +47,24 @@
     private static final int REMOVE_TIMEOUT_MILLIS = 60 * 1000; // 60 seconds
     private static final int SWITCH_USER_TIMEOUT_MILLIS = 40 * 1000; // 40 seconds
 
+    // Packages which are used during tests.
+    private static final String[] PACKAGES = new String[] {
+            "com.android.egg",
+            "com.android.retaildemo"
+    };
+
     private final Object mUserRemoveLock = new Object();
     private final Object mUserSwitchLock = new Object();
 
     private UserManager mUserManager = null;
+    private PackageManager mPackageManager;
     private List<Integer> usersToRemove;
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
         mUserManager = UserManager.get(getContext());
+        mPackageManager = getContext().getPackageManager();
 
         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
@@ -185,6 +194,49 @@
         assertFalse(mUserManager.isManagedProfile());
     }
 
+    // Verify that disallowed packages are not installed in the managed profile.
+    @MediumTest
+    public void testAddManagedProfile_withDisallowedPackages() throws Exception {
+        final int primaryUserId = mUserManager.getPrimaryUser().id;
+        UserInfo userInfo1 = createProfileForUser("Managed1",
+                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+        // Verify that the packagesToVerify are installed by default.
+        for (String pkg : PACKAGES) {
+            assertTrue("Package should be installed in managed profile: " + pkg,
+                    isPackageInstalledForUser(pkg, userInfo1.id));
+        }
+        removeUser(userInfo1.id);
+
+        UserInfo userInfo2 = createProfileForUser("Managed2",
+                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId, PACKAGES);
+        // Verify that the packagesToVerify are not installed by default.
+        for (String pkg : PACKAGES) {
+            assertFalse("Package should not be installed in managed profile when disallowed: "
+                    + pkg, isPackageInstalledForUser(pkg, userInfo2.id));
+        }
+    }
+
+    // Verify that if any packages are disallowed to install during creation of managed profile can
+    // still be installed later.
+    @MediumTest
+    public void testAddManagedProfile_disallowedPackagesInstalledLater() throws Exception {
+        final int primaryUserId = mUserManager.getPrimaryUser().id;
+        UserInfo userInfo = createProfileForUser("Managed",
+                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId, PACKAGES);
+        // Verify that the packagesToVerify are not installed by default.
+        for (String pkg : PACKAGES) {
+            assertFalse("Package should not be installed in managed profile when disallowed: "
+                    + pkg, isPackageInstalledForUser(pkg, userInfo.id));
+        }
+
+        // Verify that the disallowed packages during profile creation can be installed now.
+        for (String pkg : PACKAGES) {
+            assertEquals("Package could not be installed: " + pkg,
+                    PackageManager.INSTALL_SUCCEEDED,
+                    mPackageManager.installExistingPackageAsUser(pkg, userInfo.id));
+        }
+    }
+
     @MediumTest
     public void testAddRestrictedProfile() throws Exception {
         UserInfo userInfo = createRestrictedProfile("Profile");
@@ -357,6 +409,14 @@
         switchUser(startUser);
     }
 
+    private boolean isPackageInstalledForUser(String packageName, int userId) {
+        try {
+            return mPackageManager.getPackageInfoAsUser(packageName, 0, userId) != null;
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
     private void switchUser(int userId) {
         synchronized (mUserSwitchLock) {
             ActivityManager am = getContext().getSystemService(ActivityManager.class);
@@ -401,7 +461,13 @@
     }
 
     private UserInfo createProfileForUser(String name, int flags, int userHandle) {
-        UserInfo profile = mUserManager.createProfileForUser(name, flags, userHandle);
+        return createProfileForUser(name, flags, userHandle, null);
+    }
+
+    private UserInfo createProfileForUser(String name, int flags, int userHandle,
+            String[] disallowedPackages) {
+        UserInfo profile = mUserManager.createProfileForUser(
+                name, flags, userHandle, disallowedPackages);
         if (profile != null) {
             usersToRemove.add(profile.id);
         }