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

Commit bdcada97 authored by Esteban Talavera's avatar Esteban Talavera
Browse files

Affiliated profile owners can set lock task packages

Mentioned that in the documentation, cleaned up the code
a bit and added unit tests

Bug: 34614754

Test: runtest -c com.android.server.devicepolicy.DevicePolicyManagerTest    frameworks-services
Change-Id: I91232bbe494398015094ab977c6a2adce339811f
parent 8e332cc5
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -6073,20 +6073,24 @@ public class DevicePolicyManager {
    /**
     * Sets which packages may enter lock task mode.
     * <p>
     * Any packages that shares uid with an allowed package will also be allowed to activate lock
     * Any packages that share uid with an allowed package will also be allowed to activate lock
     * task. From {@link android.os.Build.VERSION_CODES#M} removing packages from the lock task
     * package list results in locked tasks belonging to those packages to be finished. This
     * function can only be called by the device owner.
     * package list results in locked tasks belonging to those packages to be finished.
     * <p>
     * This function can only be called by the device owner or by a profile owner of a user/profile
     * that is affiliated with the device owner user. See {@link #setAffiliationIds}. Any packages
     * set via this method will be cleared if the user becomes unaffiliated.
     *
     * @param packages The list of packages allowed to enter lock task mode
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @throws SecurityException if {@code admin} is not a device owner.
     * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of
     * an affiliated user or profile.
     * @see Activity#startLockTask()
     * @see DeviceAdminReceiver#onLockTaskModeEntering(Context, Intent, String)
     * @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent)
     * @see UserManager#DISALLOW_CREATE_WINDOWS
     */
    public void setLockTaskPackages(@NonNull ComponentName admin, String[] packages)
    public void setLockTaskPackages(@NonNull ComponentName admin, @NonNull String[] packages)
            throws SecurityException {
        throwIfParentInstance("setLockTaskPackages");
        if (mService != null) {
@@ -6099,9 +6103,12 @@ public class DevicePolicyManager {
    }

    /**
     * This function returns the list of packages allowed to start the lock task mode.
     * Returns the list of packages allowed to start the lock task mode.
     *
     * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of
     * an affiliated user or profile.
     * @see #setLockTaskPackages
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @hide
     */
    public @NonNull String[] getLockTaskPackages(@NonNull ComponentName admin) {
@@ -6113,7 +6120,7 @@ public class DevicePolicyManager {
                throw e.rethrowFromSystemServer();
            }
        }
        return null;
        return new String[0];
    }

    /**
+32 −35
Original line number Diff line number Diff line
@@ -8564,18 +8564,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
    }

    /**
     * Sets which packages may enter lock task mode.
     *
     * <p>This function can only be called by the device owner or alternatively by the profile owner
     * in case the user is affiliated.
     *
     * @param packages The list of packages allowed to enter lock task mode.
     */
    @Override
    public void setLockTaskPackages(ComponentName who, String[] packages)
            throws SecurityException {
        Preconditions.checkNotNull(who, "ComponentName is null");
        Preconditions.checkNotNull(packages, "packages is null");

        synchronized (this) {
            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8598,49 +8591,52 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        updateLockTaskPackagesLocked(packages, userHandle);
    }

    private void maybeClearLockTaskPackagesLocked() {
        final long ident = mInjector.binderClearCallingIdentity();
        try {
            final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
            for (int i = 0; i < userInfos.size(); i++) {
                int userId = userInfos.get(i).id;
                final List<String> lockTaskPackages = getUserData(userId).mLockTaskPackages;
                if (!lockTaskPackages.isEmpty() &&
                        !isUserAffiliatedWithDeviceLocked(userId)) {
                    Slog.d(LOG_TAG,
                            "User id " + userId + " not affiliated. Clearing lock task packages");
                    setLockTaskPackagesLocked(userId, Collections.<String>emptyList());
                }
            }
        } finally {
            mInjector.binderRestoreCallingIdentity(ident);
        }
    }

    /**
     * This function returns the list of components allowed to start the task lock mode.
     */
    @Override
    public String[] getLockTaskPackages(ComponentName who) {
        Preconditions.checkNotNull(who, "ComponentName is null");

        final int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
        synchronized (this) {
            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
            int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
            final List<String> packages = getLockTaskPackagesLocked(userHandle);
            return packages.toArray(new String[packages.size()]);
        }
            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
            if (!isUserAffiliatedWithDeviceLocked(userHandle)) {
                throw new SecurityException("Admin " + who +
                    " is neither the device owner or affiliated user's profile owner.");
            }

    private List<String> getLockTaskPackagesLocked(int userHandle) {
        final DevicePolicyData policy = getUserData(userHandle);
        return policy.mLockTaskPackages;
            final List<String> packages = getUserData(userHandle).mLockTaskPackages;
            return packages.toArray(new String[packages.size()]);
        }
    }

    /**
     * This function lets the caller know whether the given package is allowed to start the
     * lock task mode.
     * @param pkg The package to check
     */
    @Override
    public boolean isLockTaskPermitted(String pkg) {
        // Get current user's devicepolicy
        int uid = mInjector.binderGetCallingUid();
        int userHandle = UserHandle.getUserId(uid);
        DevicePolicyData policy = getUserData(userHandle);
        final int userHandle = mInjector.userHandleGetCallingUserId();
        synchronized (this) {
            for (int i = 0; i < policy.mLockTaskPackages.size(); i++) {
                String lockTaskPackage = policy.mLockTaskPackages.get(i);

                // If the given package equals one of the packages stored our list,
                // we allow this package to start lock task mode.
                if (lockTaskPackage.equals(pkg)) {
                    return true;
                }
            return getUserData(userHandle).mLockTaskPackages.contains(pkg);
        }
    }
        return false;
    }

    @Override
    public void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userHandle) {
@@ -9848,6 +9844,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            // but as a result of that other users might become affiliated or un-affiliated.
            maybePauseDeviceWideLoggingLocked();
            maybeResumeDeviceWideLoggingLocked();
            maybeClearLockTaskPackagesLocked();
        }
    }

+69 −0
Original line number Diff line number Diff line
@@ -3332,6 +3332,75 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        MoreAsserts.assertEmpty(targetUsers);
    }

    public void testLockTaskPackagesAllowedForAffiliatedUsers() throws Exception {
        // Setup a device owner.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        // Lock task packages are updated when loading user data.
        verify(mContext.iactivityManager)
                .updateLockTaskPackages(eq(UserHandle.USER_SYSTEM), eq(new String[0]));

        // Set up a managed profile managed by different package (package name shouldn't matter)
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
        final ComponentName adminDifferentPackage =
                new ComponentName("another.package", "whatever.class");
        addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2);
        verify(mContext.iactivityManager)
                .updateLockTaskPackages(eq(MANAGED_PROFILE_USER_ID), eq(new String[0]));

        // The DO can still set lock task packages
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        final String[] doPackages = {"doPackage1", "doPackage2"};
        dpm.setLockTaskPackages(admin1, doPackages);
        MoreAsserts.assertEquals(doPackages, dpm.getLockTaskPackages(admin1));
        assertTrue(dpm.isLockTaskPermitted("doPackage1"));
        assertFalse(dpm.isLockTaskPermitted("anotherPackage"));
        verify(mContext.iactivityManager)
                .updateLockTaskPackages(eq(UserHandle.USER_SYSTEM), eq(doPackages));

        // Managed profile is unaffiliated - shouldn't be able to setLockTaskPackages.
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        final String[] poPackages = {"poPackage1", "poPackage2"};
        try {
            dpm.setLockTaskPackages(adminDifferentPackage, poPackages);
            fail("Didn't throw expected security exception.");
        } catch (SecurityException expected) {
        }
        try {
            dpm.getLockTaskPackages(adminDifferentPackage);
            fail("Didn't throw expected security exception.");
        } catch (SecurityException expected) {
        }
        assertFalse(dpm.isLockTaskPermitted("doPackage1"));

        // Setting same affiliation ids
        final List<String> userAffiliationIds = Arrays.asList("some-affiliation-id");
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        dpm.setAffiliationIds(admin1, userAffiliationIds);

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds);

        // Now the managed profile can set lock task packages.
        dpm.setLockTaskPackages(adminDifferentPackage, poPackages);
        MoreAsserts.assertEquals(poPackages, dpm.getLockTaskPackages(adminDifferentPackage));
        assertTrue(dpm.isLockTaskPermitted("poPackage1"));
        assertFalse(dpm.isLockTaskPermitted("doPackage2"));
        verify(mContext.iactivityManager)
                .updateLockTaskPackages(eq(MANAGED_PROFILE_USER_ID), eq(poPackages));

        // Unaffiliate the profile, lock task mode no longer available on the profile.
        dpm.setAffiliationIds(adminDifferentPackage, Collections.<String>emptyList());
        assertFalse(dpm.isLockTaskPermitted("poPackage1"));
        // Lock task packages cleared when loading user data and when the user becomes unaffiliated.
        verify(mContext.iactivityManager, times(2))
                .updateLockTaskPackages(eq(MANAGED_PROFILE_USER_ID), eq(new String[0]));

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        assertTrue(dpm.isLockTaskPermitted("doPackage1"));
    }

    public void testIsDeviceManaged() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();