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

Commit 9a18f5fa authored by Christine Franks's avatar Christine Franks
Browse files

Add settings and reset operations for demo users

- Allow Global settings to be set in demo mode
- Allow Secure settings to be set by demo users
- Allow fully enabling apps for demo users
- Send enable broadcast as foreground broadcast

Bug: 62712426
Test: runtest -c \
com.android.server.devicepolicy.DevicePolicyManagerTest \
frameworks-services

Change-Id: Icd5d1eda12aa6b97bd4770713710a982bb0fc8e5
parent 0a3684eb
Loading
Loading
Loading
Loading
+30 −28
Original line number Diff line number Diff line
@@ -2384,6 +2384,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            BroadcastReceiver result) {
        Intent intent = new Intent(action);
        intent.setComponent(admin.info.getComponent());
        if (UserManager.isDeviceInDemoMode(mContext)) {
            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        }
        if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
            intent.putExtra("expiration", admin.passwordExpirationDate);
        }
@@ -8183,23 +8186,6 @@ 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.
@@ -8493,6 +8479,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
                    DELEGATION_ENABLE_SYSTEM_APP);

            final boolean isDemo = isCurrentUserDemo();

            int userId = UserHandle.getCallingUserId();
            long id = mInjector.binderClearCallingIdentity();

@@ -8503,14 +8491,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                }

                int parentUserId = getProfileParentId(userId);
                if (!isSystemApp(mIPackageManager, packageName, parentUserId)) {
                if (!isDemo && !isSystemApp(mIPackageManager, packageName, parentUserId)) {
                    throw new IllegalArgumentException("Only system apps can be enabled this way.");
                }

                // Install the app.
                mIPackageManager.installExistingPackageAsUser(packageName, userId,
                        0 /*installFlags*/, PackageManager.INSTALL_REASON_POLICY);

                if (isDemo) {
                    // Ensure the app is also ENABLED for demo users.
                    mIPackageManager.setApplicationEnabledSetting(packageName,
                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                            PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
                }
            } catch (RemoteException re) {
                // shouldn't happen
                Slog.wtf(LOG_TAG, "Failed to install " + packageName, re);
@@ -8955,7 +8948,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                return;
            }

            if (!GLOBAL_SETTINGS_WHITELIST.contains(setting)) {
            if (!GLOBAL_SETTINGS_WHITELIST.contains(setting)
                    && !UserManager.isDeviceInDemoMode(mContext)) {
                throw new SecurityException(String.format(
                        "Permission denial: device owners cannot update %1$s", setting));
            }
@@ -8987,11 +8981,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);

            if (isDeviceOwner(who, callingUserId)) {
                if (!SECURE_SETTINGS_DEVICEOWNER_WHITELIST.contains(setting)) {
                if (!SECURE_SETTINGS_DEVICEOWNER_WHITELIST.contains(setting)
                        && !isCurrentUserDemo()) {
                    throw new SecurityException(String.format(
                            "Permission denial: Device owners cannot update %1$s", setting));
                }
            } else if (!SECURE_SETTINGS_WHITELIST.contains(setting)) {
            } else if (!SECURE_SETTINGS_WHITELIST.contains(setting) && !isCurrentUserDemo()) {
                throw new SecurityException(String.format(
                        "Permission denial: Profile owners cannot update %1$s", setting));
            }
@@ -9442,12 +9437,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {

    @Override
    public SystemUpdatePolicy getSystemUpdatePolicy() {
        if (UserManager.isDeviceInDemoMode(mContext)) {
            // Pretending to have an automatic update policy when the device is in retail demo
            // mode. This will allow the device to download and install an ota without
            // any user interaction.
            return SystemUpdatePolicy.createAutomaticInstallPolicy();
        }
        synchronized (this) {
            SystemUpdatePolicy policy =  mOwners.getSystemUpdatePolicy();
            if (policy != null && !policy.isValid()) {
@@ -10454,6 +10443,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
    }

    private boolean isCurrentUserDemo() {
        if (UserManager.isDeviceInDemoMode(mContext)) {
            final int userId = mInjector.userHandleGetCallingUserId();
            final long callingIdentity = mInjector.binderClearCallingIdentity();
            try {
                return mUserManager.getUserInfo(userId).isDemo();
            } finally {
                mInjector.binderRestoreCallingIdentity(callingIdentity);
            }
        }
        return false;
    }

    private void removePackageIfRequired(final String packageName, final int userId) {
        if (!packageHasActiveAdmins(packageName, userId)) {
            // Will not do anything if uninstall was not requested or was already started.
+0 −68
Original line number Diff line number Diff line
@@ -382,74 +382,6 @@ 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;
+3 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.os.PowerManagerInternal;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
import android.security.KeyChain;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
@@ -53,6 +54,7 @@ import android.util.ArrayMap;
import android.util.Pair;
import android.view.IWindowManager;

import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.widget.LockPatternUtils;

import java.io.File;
@@ -130,6 +132,7 @@ public class MockSystemServices {
        packageManager = spy(realContext.getPackageManager());

        contentResolver = new MockContentResolver();
        contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());

        // Add the system user with a fake profile group already set up (this can happen in the real
        // world if a managed profile is added and then removed).