Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 77c94a9c authored by Benjamin Franz's avatar Benjamin Franz
Browse files

Create a flag to allow starting managed user in background

Currently DPM.createAndManageUser does not start the user in the
background, leading to a potential race between user having access to
the secondary user and admin having time to push policies. To mitigate
this we're adding a flag that allows secondary users to be started in
background as part of the API. The admin can then apply policies before
switching to that user.

Bug: 64382185
Test: cts-tradefed run singleCommand cts -m DevicePolicyManager --test
com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_StartUserInBackground
--abi arm64-v8a
Change-Id: Id6f6ab7584a249680c8554c21977cbb69a220332
parent b1671e0e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6538,6 +6538,7 @@ package android.app.admin {
    field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
    field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
    field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
    field public static final int START_USER_IN_BACKGROUND = 8; // 0x8
    field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
    field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
  }
+1 −0
Original line number Diff line number Diff line
@@ -6780,6 +6780,7 @@ package android.app.admin {
    field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
    field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
    field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
    field public static final int START_USER_IN_BACKGROUND = 8; // 0x8
    field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
    field public static final int STATE_USER_SETUP_COMPLETE = 2; // 0x2
    field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
+1 −0
Original line number Diff line number Diff line
@@ -6569,6 +6569,7 @@ package android.app.admin {
    field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
    field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
    field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
    field public static final int START_USER_IN_BACKGROUND = 8; // 0x8
    field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
    field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
  }
+21 −1
Original line number Diff line number Diff line
@@ -5979,6 +5979,26 @@ public class DevicePolicyManager {
     */
    public static final int MAKE_USER_DEMO = 0x0004;

    /**
     * Flag used by {@link #createAndManageUser} to specificy that the newly created user should be
     * started in the background as part of the user creation.
     */
    // TODO: Investigate solutions for the case where reboot happens before setup is completed.
    public static final int START_USER_IN_BACKGROUND = 0x0008;

    /**
     * @hide
     */
    @IntDef(
            flag = true,
            prefix = {"SKIP_", "MAKE_USER_", "START_"},
            value = {SKIP_SETUP_WIZARD, MAKE_USER_EPHEMERAL, MAKE_USER_DEMO,
                    START_USER_IN_BACKGROUND}
    )
    @Retention(RetentionPolicy.SOURCE)
    public @interface CreateAndManageUserFlags {}


    /**
     * Called by a device owner to create a user with the specified name and a given component of
     * the calling package as profile owner. The UserHandle returned by this method should not be
@@ -6010,7 +6030,7 @@ public class DevicePolicyManager {
    public @Nullable UserHandle createAndManageUser(@NonNull ComponentName admin,
            @NonNull String name,
            @NonNull ComponentName profileOwner, @Nullable PersistableBundle adminExtras,
            int flags) {
            @CreateAndManageUserFlags int flags) {
        throwIfParentInstance("createAndManageUser");
        try {
            return mService.createAndManageUser(admin, name, profileOwner, adminExtras, flags);
+18 −10
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
import static android.app.admin.DevicePolicyManager.START_USER_IN_BACKGROUND;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
@@ -8157,7 +8158,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        if (user == null) {
            return null;
        }
        // Set admin.
        final long id = mInjector.binderClearCallingIdentity();
        try {
            final String adminPkg = admin.getPackageName();
@@ -8170,30 +8170,38 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                            0 /*installFlags*/, PackageManager.INSTALL_REASON_POLICY);
                }
            } catch (RemoteException e) {
                Slog.e(LOG_TAG, "Failed to make remote calls for createAndManageUser, "
                        + "removing created user", e);
                mUserManager.removeUser(user.getIdentifier());
                return null;
                // Does not happen, same process
            }

            // Set admin.
            setActiveAdmin(profileOwner, true, userHandle);
            // User is not started yet, the broadcast by setActiveAdmin will not be received.
            // So we store adminExtras for broadcasting when the user starts for first time.
            final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
            setProfileOwner(profileOwner, ownerName, userHandle);

            synchronized (this) {
                DevicePolicyData policyData = getUserData(userHandle);
                policyData.mInitBundle = adminExtras;
                policyData.mAdminBroadcastPending = true;
                saveSettingsLocked(userHandle);
            }
            final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
            setProfileOwner(profileOwner, ownerName, userHandle);

            if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
                Settings.Secure.putIntForUser(mContext.getContentResolver(),
                        Settings.Secure.USER_SETUP_COMPLETE, 1, userHandle);
            }

            if ((flags & START_USER_IN_BACKGROUND) != 0) {
                try {
                    mInjector.getIActivityManager().startUserInBackground(user.getIdentifier());
                } catch (RemoteException re) {
                    // Does not happen, same process
                }
            }

            return user;
        } catch (Throwable re) {
            mUserManager.removeUser(user.getIdentifier());
            return null;
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }