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

Commit 22f9645b authored by Felipe Leme's avatar Felipe Leme
Browse files

Added support to more @DevicePolicyOperation operations.

Also removed wrong permission check on lockNow()- it was only
allowing non-admin apps with the LOCK_NOW permission when the
device doesn't support the feature.

Test: manual verification trying to switch user when car is moving
Bug: 172376923

Change-Id: Icd1bde3a6f27e08c00d8851d16c1a072f7441f32
parent e67ba2a9
Loading
Loading
Loading
Loading
+28 −1
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -2453,19 +2454,45 @@ public class DevicePolicyManager {
    @Retention(RetentionPolicy.SOURCE)
    public @interface PersonalAppsSuspensionReason {}
    // TODO(b/172376923) - make all (or none) @TestApi
    /** @hide */
    @TestApi
    public static final int OPERATION_LOCK_NOW = 1;
    /** @hide */
    public static final int OPERATION_SWITCH_USER = 2;
    /** @hide */
    public static final int OPERATION_START_USER_IN_BACKGROUND = 3;
    /** @hide */
    public static final int OPERATION_STOP_USER = 4;
    /** @hide */
    public static final int OPERATION_CREATE_AND_MANAGE_USER = 5;
    /** @hide */
    public static final int OPERATION_REMOVE_USER = 6;
    private static final String PREFIX_OPERATION = "OPERATION_";
    // TODO(b/172376923) - add all operations
    /** @hide */
    @IntDef(prefix = "OPERATION_", value = {
    @IntDef(prefix = PREFIX_OPERATION, value = {
            OPERATION_LOCK_NOW,
            OPERATION_SWITCH_USER,
            OPERATION_START_USER_IN_BACKGROUND,
            OPERATION_STOP_USER,
            OPERATION_CREATE_AND_MANAGE_USER,
            OPERATION_REMOVE_USER
    })
    @Retention(RetentionPolicy.SOURCE)
    public static @interface DevicePolicyOperation {
    }
    /** @hide */
    public static String operationToString(@DevicePolicyOperation int operation) {
        return DebugUtils.constantToString(DevicePolicyManager.class, PREFIX_OPERATION, operation);
    }
    /**
     * Return true if the given administrator component is currently active (enabled) in the system.
     *
+20 −0
Original line number Diff line number Diff line
@@ -271,6 +271,26 @@ public class DebugUtils {
        return res.toString();
    }

    /**
     * Gets human-readable representation of constants (static final values).
     *
     * @hide
     */
    public static String constantToString(Class<?> clazz, String prefix, int value) {
        for (Field field : clazz.getDeclaredFields()) {
            final int modifiers = field.getModifiers();
            try {
                if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)
                        && field.getType().equals(int.class) && field.getName().startsWith(prefix)
                        && field.getInt(null) == value) {
                    return constNameWithoutPrefix(prefix, field);
                }
            } catch (IllegalAccessException ignored) {
            }
        }
        return prefix + Integer.toString(value);
    }

    private static String constNameWithoutPrefix(String prefix, Field field) {
        return field.getName().substring(prefix.length());
    }
+18 −23
Original line number Diff line number Diff line
@@ -972,29 +972,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    }
    /**
     * Checks if the feature is supported and it's safe to execute the given {@code operation}.
     *
     * <p>Typically called at the beginning of each API method as:
     *
     * <pre><code>
     *
     * if (!canExecute(operation, permission)) return;
     *
     * </code></pre>
     *
     * @return {@code true} when it's safe to execute, {@code false} when the feature is not
     * supported or the caller does not have the given {@code requiredPermission}.
     * Checks if it's safe to execute the given {@code operation}.
     *
     * @throws UnsafeStateException if it's not safe to execute the operation.
     */
    boolean canExecute(@DevicePolicyOperation int operation, @NonNull String requiredPermission) {
        if (!mHasFeature && !hasCallingPermission(requiredPermission)) {
            return false;
    private void checkCanExecuteOrThrowUnsafe(@DevicePolicyOperation int operation) {
        if (!canExecute(operation)) {
            throw mSafetyChecker.newUnsafeStateException(operation);
        }
        if (mSafetyChecker == null || mSafetyChecker.isDevicePolicyOperationSafe(operation)) {
            return true;
    }
        throw mSafetyChecker.newUnsafeStateException(operation);
    /**
     * Returns whether it's safe to execute the given {@code operation}.
     */
    boolean canExecute(@DevicePolicyOperation int operation) {
        return mSafetyChecker == null || mSafetyChecker.isDevicePolicyOperationSafe(operation);
    }
    /**
@@ -4780,10 +4772,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @Override
    public void lockNow(int flags, boolean parent) {
        if (!canExecute(DevicePolicyManager.OPERATION_LOCK_NOW, permission.LOCK_DEVICE)) {
            return;
        }
        final CallerIdentity caller = getCallerIdentity();
        final int callingUserId = caller.getUserId();
@@ -4796,6 +4784,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK,
                    parent,
                    android.Manifest.permission.LOCK_DEVICE);
            checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_LOCK_NOW);
            final long ident = mInjector.binderClearCallingIdentity();
            try {
                adminComponent = admin == null ? null : admin.info.getComponent();
@@ -9311,6 +9300,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        Preconditions.checkCallAuthorization(caller.getUserHandle().isSystem(),
                "createAndManageUser was called from non-system user");
        Preconditions.checkCallAuthorization(isDeviceOwner(caller));
        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_CREATE_AND_MANAGE_USER);
        final boolean ephemeral = (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0;
        final boolean demo = (flags & DevicePolicyManager.MAKE_USER_DEMO) != 0
                && UserManager.isDeviceInDemoMode(mContext);
@@ -9439,6 +9430,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        Objects.requireNonNull(userHandle, "UserHandle is null");
        final CallerIdentity caller = getCallerIdentity(who);
        Preconditions.checkCallAuthorization(isDeviceOwner(caller));
        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_REMOVE_USER);
        return mInjector.binderWithCleanCallingIdentity(() -> {
            String restriction = isManagedProfile(userHandle.getIdentifier())
@@ -9472,6 +9464,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        Objects.requireNonNull(who, "ComponentName is null");
        final CallerIdentity caller = getCallerIdentity(who);
        Preconditions.checkCallAuthorization(isDeviceOwner(caller));
        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SWITCH_USER);
        synchronized (getLockObject()) {
            long id = mInjector.binderClearCallingIdentity();
@@ -9496,6 +9489,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        Objects.requireNonNull(userHandle, "UserHandle is null");
        final CallerIdentity caller = getCallerIdentity(who);
        Preconditions.checkCallAuthorization(isDeviceOwner(caller));
        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_START_USER_IN_BACKGROUND);
        final int userId = userHandle.getIdentifier();
        if (isManagedProfile(userId)) {
@@ -9529,6 +9523,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        Objects.requireNonNull(userHandle, "UserHandle is null");
        final CallerIdentity caller = getCallerIdentity(who);
        Preconditions.checkCallAuthorization(isDeviceOwner(caller));
        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_STOP_USER);
        final int userId = userHandle.getIdentifier();
        if (isManagedProfile(userId)) {