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

Commit 596c2880 authored by Alex Chau's avatar Alex Chau
Browse files

API Review: Return status code for user management APIs

- Replaced boolean return value with error code

Bug: 71866621
Test: com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_StartInBackground
Test: com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_StartInBackground_MaxRunningUsers
Test: com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_CannotStopCurrentUser
Test: com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_StopUser
Test: com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_LogoutUser
Test: com.android.cts.devicepolicy.DeviceOwnerPlusProfileOwnerTest#testCannotStartManagedProfileInBackground
Test: com.android.cts.devicepolicy.DeviceOwnerPlusProfileOwnerTest#testCannotStopManagedProfile
Test: com.android.cts.devicepolicy.DeviceOwnerPlusProfileOwnerTest#testCannotLogoutManagedProfile
Change-Id: Iddc3e33c91c3f9584d53e537dbab3f61b8772fb1
parent 5e25d9aa
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -6498,7 +6498,7 @@ package android.app.admin {
    method public boolean isUsingUnifiedPassword(android.content.ComponentName);
    method public void lockNow();
    method public void lockNow(int);
    method public boolean logoutUser(android.content.ComponentName);
    method public int 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);
@@ -6583,8 +6583,8 @@ 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 startUserInBackground(android.content.ComponentName, android.os.UserHandle);
    method public boolean stopUser(android.content.ComponentName, android.os.UserHandle);
    method public int startUserInBackground(android.content.ComponentName, android.os.UserHandle);
    method public int stopUser(android.content.ComponentName, android.os.UserHandle);
    method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
    method public void transferOwnership(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
    method public void uninstallAllUserCaCerts(android.content.ComponentName);
@@ -6698,6 +6698,11 @@ 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 USER_OPERATION_ERROR_CURRENT_USER = 4; // 0x4
    field public static final int USER_OPERATION_ERROR_MANAGED_PROFILE = 2; // 0x2
    field public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3; // 0x3
    field public static final int USER_OPERATION_ERROR_UNKNOWN = 1; // 0x1
    field public static final int USER_OPERATION_SUCCESS = 0; // 0x0
    field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
    field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
  }
+82 −7
Original line number Diff line number Diff line
@@ -6608,16 +6608,82 @@ public class DevicePolicyManager {
        }
    }

    /**
     * Indicates user operation is successful.
     *
     * @see #startUserInBackground(ComponentName, UserHandle)
     * @see #stopUser(ComponentName, UserHandle)
     * @see #logoutUser(ComponentName)
     */
    public static final int USER_OPERATION_SUCCESS = 0;

    /**
     * Indicates user operation failed for unknown reason.
     *
     * @see #startUserInBackground(ComponentName, UserHandle)
     * @see #stopUser(ComponentName, UserHandle)
     * @see #logoutUser(ComponentName)
     */
    public static final int USER_OPERATION_ERROR_UNKNOWN = 1;

    /**
     * Indicates user operation failed because target user is a managed profile.
     *
     * @see #startUserInBackground(ComponentName, UserHandle)
     * @see #stopUser(ComponentName, UserHandle)
     * @see #logoutUser(ComponentName)
     */
    public static final int USER_OPERATION_ERROR_MANAGED_PROFILE = 2;

    /**
     * Indicates user operation failed because maximum running user limit has reached.
     *
     * @see #startUserInBackground(ComponentName, UserHandle)
     */
    public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3;

    /**
     * Indicates user operation failed because the target user is in foreground.
     *
     * @see #stopUser(ComponentName, UserHandle)
     * @see #logoutUser(ComponentName)
     */
    public static final int USER_OPERATION_ERROR_CURRENT_USER = 4;

    /**
     * Result returned from
     * <ul>
     * <li>{@link #startUserInBackground(ComponentName, UserHandle)}</li>
     * <li>{@link #stopUser(ComponentName, UserHandle)}</li>
     * <li>{@link #logoutUser(ComponentName)}</li>
     * </ul>
     *
     * @hide
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = { "USER_OPERATION_" }, value = {
            USER_OPERATION_SUCCESS,
            USER_OPERATION_ERROR_UNKNOWN,
            USER_OPERATION_ERROR_MANAGED_PROFILE,
            USER_OPERATION_ERROR_MAX_RUNNING_USERS,
            USER_OPERATION_ERROR_CURRENT_USER
    })
    public @interface UserOperationResult {}

    /**
     * Called by a device owner to start the specified secondary user in background.
     *
     * @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 started, {@code false} otherwise.
     * @param userHandle the user to be started in background.
     * @return one of the following result codes:
     * {@link #USER_OPERATION_ERROR_UNKNOWN},
     * {@link #USER_OPERATION_SUCCESS},
     * {@link #USER_OPERATION_ERROR_MANAGED_PROFILE},
     * {@link #USER_OPERATION_ERROR_MAX_RUNNING_USERS},
     * @throws SecurityException if {@code admin} is not a device owner.
     * @see #getSecondaryUsers(ComponentName)
     */
    public boolean startUserInBackground(
    public @UserOperationResult int startUserInBackground(
            @NonNull ComponentName admin, @NonNull UserHandle userHandle) {
        throwIfParentInstance("startUserInBackground");
        try {
@@ -6632,11 +6698,16 @@ public class DevicePolicyManager {
     *
     * @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.
     * @return one of the following result codes:
     * {@link #USER_OPERATION_ERROR_UNKNOWN},
     * {@link #USER_OPERATION_SUCCESS},
     * {@link #USER_OPERATION_ERROR_MANAGED_PROFILE},
     * {@link #USER_OPERATION_ERROR_CURRENT_USER}
     * @throws SecurityException if {@code admin} is not a device owner.
     * @see #getSecondaryUsers(ComponentName)
     */
    public boolean stopUser(@NonNull ComponentName admin, @NonNull UserHandle userHandle) {
    public @UserOperationResult int stopUser(
            @NonNull ComponentName admin, @NonNull UserHandle userHandle) {
        throwIfParentInstance("stopUser");
        try {
            return mService.stopUser(admin, userHandle);
@@ -6650,11 +6721,15 @@ public class DevicePolicyManager {
     * calling user and switch back to primary.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @return {@code true} if the exit was successful, {@code false} otherwise.
     * @return one of the following result codes:
     * {@link #USER_OPERATION_ERROR_UNKNOWN},
     * {@link #USER_OPERATION_SUCCESS},
     * {@link #USER_OPERATION_ERROR_MANAGED_PROFILE},
     * {@link #USER_OPERATION_ERROR_CURRENT_USER}
     * @throws SecurityException if {@code admin} is not a profile owner affiliated with the device.
     * @see #getSecondaryUsers(ComponentName)
     */
    public boolean logoutUser(@NonNull ComponentName admin) {
    public @UserOperationResult int logoutUser(@NonNull ComponentName admin) {
        throwIfParentInstance("logoutUser");
        try {
            return mService.logoutUser(admin);
+3 −3
Original line number Diff line number Diff line
@@ -227,9 +227,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 startUserInBackground(in ComponentName who, in UserHandle userHandle);
    boolean stopUser(in ComponentName who, in UserHandle userHandle);
    boolean logoutUser(in ComponentName who);
    int startUserInBackground(in ComponentName who, in UserHandle userHandle);
    int stopUser(in ComponentName who, in UserHandle userHandle);
    int logoutUser(in ComponentName who);
    List<UserHandle> getSecondaryUsers(in ComponentName who);

    void enableSystemApp(in ComponentName admin, in String callerPackage, in String packageName);
+0 −7
Original line number Diff line number Diff line
@@ -19,12 +19,10 @@ import android.annotation.UserIdInt;
import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keystore.ParcelableKeyGenParameterSpec;
import android.telephony.data.ApnSetting;

import com.android.internal.R;
import com.android.server.SystemService;

import java.util.ArrayList;
@@ -106,11 +104,6 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
        return false;
    }

    @Override
    public boolean startUserInBackground(ComponentName who, UserHandle userHandle) {
        return false;
    }

    @Override
    public void setStartUserSessionMessage(
            ComponentName admin, CharSequence startUserSessionMessage) {}
+38 −28
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ 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.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY;
@@ -68,9 +67,6 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
        .STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER;
import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER;
@@ -249,7 +245,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -9030,7 +9025,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    }
    @Override
    public boolean startUserInBackground(ComponentName who, UserHandle userHandle) {
    public int startUserInBackground(ComponentName who, UserHandle userHandle) {
        Preconditions.checkNotNull(who, "ComponentName is null");
        Preconditions.checkNotNull(userHandle, "UserHandle is null");
@@ -9041,27 +9036,31 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        final int userId = userHandle.getIdentifier();
        if (isManagedProfile(userId)) {
            Log.w(LOG_TAG, "Managed profile cannot be started in background");
            return false;
            return DevicePolicyManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
        }
        final long id = mInjector.binderClearCallingIdentity();
        try {
            if (!mInjector.getActivityManagerInternal().canStartMoreUsers()) {
                Log.w(LOG_TAG, "Cannot start more users in background");
                return false;
                return DevicePolicyManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS;
            }
            return mInjector.getIActivityManager().startUserInBackground(userId);
            if (mInjector.getIActivityManager().startUserInBackground(userId)) {
                return DevicePolicyManager.USER_OPERATION_SUCCESS;
            } else {
                return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
            }
        } catch (RemoteException e) {
            // Same process, should not happen.
            return false;
            return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }
    }
    @Override
    public boolean stopUser(ComponentName who, UserHandle userHandle) {
    public int stopUser(ComponentName who, UserHandle userHandle) {
        Preconditions.checkNotNull(who, "ComponentName is null");
        Preconditions.checkNotNull(userHandle, "UserHandle is null");
@@ -9072,23 +9071,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        final int userId = userHandle.getIdentifier();
        if (isManagedProfile(userId)) {
            Log.w(LOG_TAG, "Managed profile cannot be stopped");
            return false;
            return DevicePolicyManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
        }
        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);
        }
        return stopUserUnchecked(userId);
    }
    @Override
    public boolean logoutUser(ComponentName who) {
    public int logoutUser(ComponentName who) {
        Preconditions.checkNotNull(who, "ComponentName is null");
        final int callingUserId = mInjector.userHandleGetCallingUserId();
@@ -9102,20 +9092,40 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        if (isManagedProfile(callingUserId)) {
            Log.w(LOG_TAG, "Managed profile cannot be logout");
            return false;
            return DevicePolicyManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
        }
        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;
                // This should never happen as target user is UserHandle.USER_SYSTEM
                return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
            }
            return mInjector.getIActivityManager().stopUser(callingUserId, true /*force*/, null)
                    == USER_OP_SUCCESS;
        } catch (RemoteException e) {
            // Same process, should not happen.
            return false;
            return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }
        return stopUserUnchecked(callingUserId);
    }
    private int stopUserUnchecked(int userId) {
        final long id = mInjector.binderClearCallingIdentity();
        try {
            switch (mInjector.getIActivityManager().stopUser(userId, true /*force*/, null)) {
                case ActivityManager.USER_OP_SUCCESS:
                    return DevicePolicyManager.USER_OPERATION_SUCCESS;
                case ActivityManager.USER_OP_IS_CURRENT:
                    return DevicePolicyManager.USER_OPERATION_ERROR_CURRENT_USER;
                default:
                    return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
            }
        } catch (RemoteException e) {
            // Same process, should not happen.
            return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }