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

Commit 361b825c authored by Christine Franks's avatar Christine Franks
Browse files

Support demo mode and demo users

Bug: 62712426
Test: run cts -m CtsDevicePolicyManagerTestCases -t \
com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageEphemeralUser
and
run cts -m CtsDevicePolicyManagerTestCases -t \
com.android.cts.devicepolicy.DeviceOwnerTest# \
testCreateAndManageEphemeralUserFailsWithoutSplitSystemUser
and
runtest -c com.android.server.devicepolicy.DevicePolicyManagerTest \
frameworks-services
Change-Id: I77a71a994fe0f4f1f8c5df7c4ccf493aafa8fefe
parent 037503df
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -5981,6 +5981,13 @@ public class DevicePolicyManager {
     */
    public static final int MAKE_USER_EPHEMERAL = 0x0002;

    /**
     * Flag used by {@link #createAndManageUser} to specify that the user should be created as a
     * demo user.
     * @hide
     */
    public static final int MAKE_USER_DEMO = 0x0004;

    /**
     * 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
+29 −7
Original line number Diff line number Diff line
@@ -526,7 +526,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead.
        Set<String> mOwnerInstalledCaCerts = new ArraySet<>();

        // Used for initialization of users created by createAndManageUsers.
        // Used for initialization of users created by createAndManageUser.
        boolean mAdminBroadcastPending = false;
        PersistableBundle mInitBundle = null;

@@ -4255,6 +4255,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            mInjector.binderRestoreCallingIdentity(token);
        }
    }

    @Override
    public boolean resetPassword(String passwordOrNull, int flags) throws RemoteException {
        final int callingUid = mInjector.binderGetCallingUid();
@@ -7375,9 +7376,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {

    private void enableIfNecessary(String packageName, int userId) {
        try {
            ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName,
                    PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                    userId);
            final ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName,
                    PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, userId);
            if (ai.enabledSetting
                    == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
                mIPackageManager.setApplicationEnabledSetting(packageName,
@@ -8131,8 +8131,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        if (!mInjector.binderGetCallingUserHandle().isSystem()) {
            throw new SecurityException("createAndManageUser was called from non-system user");
        }
        if (!mInjector.userManagerIsSplitSystemUser()
                && (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0) {
        final boolean ephemeral = (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0;
        final boolean demo = (flags & DevicePolicyManager.MAKE_USER_DEMO) != 0
                && UserManager.isDeviceInDemoMode(mContext);
        if (ephemeral && !mInjector.userManagerIsSplitSystemUser() && !demo) {
            throw new IllegalArgumentException(
                    "Ephemeral users are only supported on systems with a split system user.");
        }
@@ -8144,9 +8146,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            final long id = mInjector.binderClearCallingIdentity();
            try {
                int userInfoFlags = 0;
                if ((flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0) {
                if (ephemeral) {
                    userInfoFlags |= UserInfo.FLAG_EPHEMERAL;
                }
                if (demo) {
                    userInfoFlags |= UserInfo.FLAG_DEMO;
                }
                UserInfo userInfo = mUserManagerInternal.createUserEvenWhenDisallowed(name,
                        userInfoFlags);
                if (userInfo != null) {
@@ -8178,6 +8183,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                return null;
            }

            final UserInfo userInfo = getUserInfo(userHandle);
            if (userInfo != null && userInfo.isDemo()) {
                try {
                    final ApplicationInfo ai = mIPackageManager.getApplicationInfo(adminPkg,
                            PackageManager.MATCH_DISABLED_COMPONENTS, userHandle);
                    final boolean isSystemApp =
                            ai != null && (ai.flags & (ApplicationInfo.FLAG_SYSTEM
                                    | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0;
                    if (isSystemApp) {
                        mIPackageManager.setApplicationEnabledSetting(adminPkg,
                                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                                PackageManager.DONT_KILL_APP, userHandle, "DevicePolicyManager");
                    }
                } catch (RemoteException e) {
                }
            }

            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.
+71 −1
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.nullable;
import static org.mockito.Mockito.reset;
@@ -53,6 +54,7 @@ import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.PasswordMetrics;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -338,7 +340,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        // Next, add one more admin.
        // Before doing so, update the application info, now it's enabled.
        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
                PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);

        dpm.setActiveAdmin(admin2, /* replace =*/ false);

@@ -380,6 +382,74 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
    }

    public void testCreateAndManageUser_demoUserSystemApp() throws Exception {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        setDeviceOwner();

        final int id = UserHandle.getUserId(DpmMockContext.CALLER_UID);

        final UserInfo demoUserInfo = mock(UserInfo.class);
        demoUserInfo.id = id;
        doReturn(UserHandle.of(id)).when(demoUserInfo).getUserHandle();
        doReturn(true).when(demoUserInfo).isDemo();
        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        doReturn(demoUserInfo).when(um).getUserInfo(id);
        doReturn(demoUserInfo).when(mContext.getUserManagerInternal())
                .createUserEvenWhenDisallowed(anyString(), anyInt());

        final ApplicationInfo applicationInfo = getServices().ipackageManager.getApplicationInfo(
                admin2.getPackageName(), PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, id);
        applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
        doReturn(applicationInfo).when(getServices().ipackageManager).getApplicationInfo(
                anyString(), anyInt(), anyInt());

        final UserHandle userHandle = dpm.createAndManageUser(admin1, "", admin2, null, 0);

        verify(getServices().ipackageManager, times(1)).setApplicationEnabledSetting(
                eq(admin2.getPackageName()),
                eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
                eq(PackageManager.DONT_KILL_APP),
                eq(id),
                anyString());

        assertNotNull(userHandle);
    }

    public void testCreateAndManageUser_demoUserSystemUpdatedApp() throws Exception {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        setDeviceOwner();

        final int id = UserHandle.getUserId(DpmMockContext.CALLER_UID);

        final UserInfo demoUserInfo = mock(UserInfo.class);
        demoUserInfo.id = id;
        doReturn(UserHandle.of(id)).when(demoUserInfo).getUserHandle();
        doReturn(true).when(demoUserInfo).isDemo();
        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        doReturn(demoUserInfo).when(um).getUserInfo(id);
        doReturn(demoUserInfo).when(mContext.getUserManagerInternal())
                .createUserEvenWhenDisallowed(anyString(), anyInt());

        final ApplicationInfo applicationInfo = getServices().ipackageManager.getApplicationInfo(
                admin2.getPackageName(), PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, id);
        applicationInfo.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
        doReturn(applicationInfo).when(getServices().ipackageManager).getApplicationInfo(
                anyString(), anyInt(), anyInt());

        final UserHandle userHandle = dpm.createAndManageUser(admin1, "", admin2, null, 0);

        verify(getServices().ipackageManager, times(1)).setApplicationEnabledSetting(
                eq(admin2.getPackageName()),
                eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
                eq(PackageManager.DONT_KILL_APP),
                eq(id),
                anyString());

        assertNotNull(userHandle);
    }

    public void testSetActiveAdmin_multiUsers() throws Exception {

        final int ANOTHER_USER_ID = 100;
+5 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.test.mock.MockContext;
import android.util.ArrayMap;

@@ -196,6 +197,10 @@ public class DpmMockContext extends MockContext {
        return mMockSystemServices.packageManager;
    }

    public UserManagerInternal getUserManagerInternal() {
        return mMockSystemServices.userManagerInternal;
    }

    @Override
    public void enforceCallingOrSelfPermission(String permission, String message) {
        if (UserHandle.isSameApp(binder.getCallingUid(), SYSTEM_UID)) {