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

Commit af9bb8d9 authored by Alex Chau's avatar Alex Chau
Browse files

Introduce more user management APIs

- boolean stopUser(ComponentName admin, UserHandle userHandle)
- boolean logoutUser(ComponentName admin)
- List<UserHandle> getManageableUsers(ComponentName admin)
- Introduced Injector.binderWithCleanCallingIdentity

Bug: 67580550
Test: manually try each added API with a DPC on both primary and non-prijmray user.
Test: CTS tracked in b/67581357
Change-Id: I9789b9b29978d47bc22be6ecad6c5577e0f8eb5b
parent 7742160e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -6370,6 +6370,7 @@ package android.app.admin {
    method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
    method public long getRequiredStrongAuthTimeout(android.content.ComponentName);
    method public boolean getScreenCaptureDisabled(android.content.ComponentName);
    method public java.util.List<android.os.UserHandle> getSecondaryUsers(android.content.ComponentName);
    method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
    method public boolean getStorageEncryption(android.content.ComponentName);
    method public int getStorageEncryptionStatus();
@@ -6402,6 +6403,7 @@ package android.app.admin {
    method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
    method public void lockNow();
    method public void lockNow(int);
    method public boolean logoutUser(android.content.ComponentName);
    method public void reboot(android.content.ComponentName);
    method public void removeActiveAdmin(android.content.ComponentName);
    method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -6476,6 +6478,7 @@ package android.app.admin {
    method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
    method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
    method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
    method public boolean stopUser(android.content.ComponentName, android.os.UserHandle);
    method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
    method public void uninstallAllUserCaCerts(android.content.ComponentName);
    method public void uninstallCaCert(android.content.ComponentName, byte[]);
+61 −1
Original line number Diff line number Diff line
@@ -6219,7 +6219,7 @@ public class DevicePolicyManager {
     * @return {@code true} if the user was removed, {@code false} otherwise.
     * @throws SecurityException if {@code admin} is not a device owner.
     */
    public boolean removeUser(@NonNull ComponentName admin, UserHandle userHandle) {
    public boolean removeUser(@NonNull ComponentName admin, @NonNull UserHandle userHandle) {
        throwIfParentInstance("removeUser");
        try {
            return mService.removeUser(admin, userHandle);
@@ -6230,6 +6230,7 @@ public class DevicePolicyManager {

    /**
     * Called by a device owner to switch the specified user to the foreground.
     * <p> This cannot be used to switch to a managed profile.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @param userHandle the user to switch to; null will switch to primary.
@@ -6246,6 +6247,65 @@ public class DevicePolicyManager {
        }
    }

    /**
     * Called by a device owner to stop the specified secondary user.
     * <p> This cannot be used to stop the primary user or a managed profile.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @param userHandle the user to be stopped.
     * @return {@code true} if the user can be stopped, {@code false} otherwise.
     * @throws SecurityException if {@code admin} is not a device owner.
     */
    public boolean stopUser(@NonNull ComponentName admin, @NonNull UserHandle userHandle) {
        throwIfParentInstance("stopUser");
        try {
            return mService.stopUser(admin, userHandle);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Called by a profile owner that is affiliated with the device owner to stop the calling user
     * and switch back to primary.
     * <p> This has no effect when called on a managed profile.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @return {@code true} if the exit was successful, {@code false} otherwise.
     * @throws SecurityException if {@code admin} is not a profile owner affiliated with the device
     * owner.
     */
    public boolean logoutUser(@NonNull ComponentName admin) {
        throwIfParentInstance("logoutUser");
        try {
            return mService.logoutUser(admin);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Called by a device owner to list all secondary users on the device, excluding managed
     * profiles.
     * <p> Used for various user management APIs, including {@link #switchUser}, {@link #removeUser}
     * and {@link #stopUser}.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @return list of other {@link UserHandle}s on the device.
     * @throws SecurityException if {@code admin} is not a device owner.
     * @see #switchUser
     * @see #removeUser
     * @see #stopUser
     */
    public List<UserHandle> getSecondaryUsers(@NonNull ComponentName admin) {
        throwIfParentInstance("getSecondaryUsers");
        try {
            return mService.getSecondaryUsers(admin);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Retrieves the application restrictions for a given target application running in the calling
     * user.
+3 −0
Original line number Diff line number Diff line
@@ -215,6 +215,9 @@ interface IDevicePolicyManager {
    UserHandle createAndManageUser(in ComponentName who, in String name, in ComponentName profileOwner, in PersistableBundle adminExtras, in int flags);
    boolean removeUser(in ComponentName who, in UserHandle userHandle);
    boolean switchUser(in ComponentName who, in UserHandle userHandle);
    boolean stopUser(in ComponentName who, in UserHandle userHandle);
    boolean logoutUser(in ComponentName who);
    List<UserHandle> getSecondaryUsers(in ComponentName who);

    void enableSystemApp(in ComponentName admin, in String callerPackage, in String packageName);
    int enableSystemAppWithIntent(in ComponentName admin, in String callerPackage, in Intent intent);
+85 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.devicepolicy;
import static android.Manifest.permission.BIND_DEVICE_ADMIN;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.USER_OP_SUCCESS;
import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY;
import static android.app.admin.DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED;
import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
@@ -8402,6 +8403,90 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }

    @Override
    public boolean stopUser(ComponentName who, UserHandle userHandle) {
        Preconditions.checkNotNull(who, "ComponentName is null");

        synchronized (this) {
            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
        }

        final int userId = userHandle.getIdentifier();
        if (isManagedProfile(userId)) {
            Log.w(LOG_TAG, "Managed profile cannot be stopped");
            return false;
        }

        final long id = mInjector.binderClearCallingIdentity();
        try {
            return mInjector.getIActivityManager().stopUser(userId, true /*force*/, null)
                    == USER_OP_SUCCESS;
        } catch (RemoteException e) {
            // Same process, should not happen.
            return false;
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }
    }

    @Override
    public boolean logoutUser(ComponentName who) {
        Preconditions.checkNotNull(who, "ComponentName is null");

        final int callingUserId = mInjector.userHandleGetCallingUserId();
        synchronized (this) {
            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
            if (!isUserAffiliatedWithDeviceLocked(callingUserId)) {
                throw new SecurityException("Admin " + who +
                        " is neither the device owner or affiliated user's profile owner.");
            }
        }

        if (isManagedProfile(callingUserId)) {
            Log.w(LOG_TAG, "Managed profile cannot be logout");
            return false;
        }

        final long id = mInjector.binderClearCallingIdentity();
        try {
            if (!mInjector.getIActivityManager().switchUser(UserHandle.USER_SYSTEM)) {
                Log.w(LOG_TAG, "Failed to switch to primary user");
                return false;
            }
            return mInjector.getIActivityManager().stopUser(callingUserId, true /*force*/, null)
                    == USER_OP_SUCCESS;
        } catch (RemoteException e) {
            // Same process, should not happen.
            return false;
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }
    }

    @Override
    public List<UserHandle> getSecondaryUsers(ComponentName who) {
        Preconditions.checkNotNull(who, "ComponentName is null");
        synchronized (this) {
            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
        }

        final long id = mInjector.binderClearCallingIdentity();
        try {
            final List<UserInfo> userInfos = mInjector.getUserManager().getUsers(true
                    /*excludeDying*/);
            final List<UserHandle> userHandles = new ArrayList<>();
            for (UserInfo userInfo : userInfos) {
                UserHandle userHandle = userInfo.getUserHandle();
                if (!userHandle.isSystem() && !isManagedProfile(userHandle.getIdentifier())) {
                    userHandles.add(userInfo.getUserHandle());
                }
            }
            return userHandles;
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }
    }

    @Override
    public Bundle getApplicationRestrictions(ComponentName who, String callerPackage,
            String packageName) {