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

Commit 5d8030ed authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "New cmd to temporarily set safety operations."

parents b7cee931 107c162d
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -983,10 +983,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @Override
    public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
        Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as " + safetyChecker.getClass());
        Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as " + safetyChecker);
        mSafetyChecker = safetyChecker;
    }
    /**
     * Used by {@link OneTimeSafetyChecker} only.
     */
    DevicePolicySafetyChecker getDevicePolicySafetyChecker() {
        return mSafetyChecker;
    }
    /**
     * Checks if it's safe to execute the given {@code operation}.
     *
@@ -994,6 +1001,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
     */
    private void checkCanExecuteOrThrowUnsafe(@DevicePolicyOperation int operation) {
        if (!canExecute(operation)) {
            if (mSafetyChecker == null) {
                // Happens on CTS after it's set just once (by OneTimeSafetyChecker)
                throw new UnsafeStateException(operation);
            }
            // Let mSafetyChecker customize it (for example, by explaining how to retry)
            throw mSafetyChecker.newUnsafeStateException(operation);
        }
    }
@@ -1005,6 +1017,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        return mSafetyChecker == null || mSafetyChecker.isDevicePolicyOperationSafe(operation);
    }
    /**
     * Used by {@code cmd device_policy} to set the result of the next safety operation check.
     */
    void setNextOperationSafety(@DevicePolicyOperation int operation, boolean safe) {
        Preconditions.checkCallAuthorization(
                hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
        Slog.i(LOG_TAG, "setNextOperationSafety(" + DevicePolicyManager.operationToString(operation)
                + ", " + safe + ")");
        mSafetyChecker = new OneTimeSafetyChecker(this, operation, safe);
    }
    /**
     * Unit test will subclass it to inject mocks.
     */
+15 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import java.util.Objects;
final class DevicePolicyManagerServiceShellCommand extends ShellCommand {

    private static final String CMD_IS_SAFE_OPERATION = "is-operation-safe";
    private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe";

    private final DevicePolicyManagerService mService;

@@ -48,6 +49,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
            switch (cmd) {
                case CMD_IS_SAFE_OPERATION:
                    return runIsSafeOperation(pw);
                case CMD_SET_SAFE_OPERATION:
                    return runSetSafeOperation(pw);
                default:
                    return onInvalidCommand(pw, cmd);
            }
@@ -70,6 +73,9 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
        pw.printf("    Prints this help text.\n\n");
        pw.printf("  %s <OPERATION_ID>\n", CMD_IS_SAFE_OPERATION);
        pw.printf("    Checks if the give operation is safe \n\n");
        pw.printf("  %s <OPERATION_ID> <true|false>\n", CMD_SET_SAFE_OPERATION);
        pw.printf("    Emulates the result of the next call to check if the given operation is safe"
                + " \n\n");
    }

    private int runIsSafeOperation(PrintWriter pw) {
@@ -79,4 +85,13 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
                safe ? "SAFE" : "UNSAFE");
        return 0;
    }

    private int runSetSafeOperation(PrintWriter pw) {
        int operation = Integer.parseInt(getNextArgRequired());
        boolean safe = getNextArg().equals("true");
        mService.setNextOperationSafety(operation, safe);
        pw.printf("Next call to check operation %s will return %s\n",
                DevicePolicyManager.operationToString(operation), safe ? "SAFE" : "UNSAFE");
        return 0;
    }
}
+67 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.server.devicepolicy;

import static android.app.admin.DevicePolicyManager.operationToString;

import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
import android.app.admin.DevicePolicySafetyChecker;
import android.util.Slog;

import java.util.Objects;

//TODO(b/172376923): add unit tests

/**
 * {@code DevicePolicySafetyChecker} implementation that overrides the real checker for just
 * one command.
 *
 * <p>Used only for debugging and CTS tests.
 */
final class OneTimeSafetyChecker implements DevicePolicySafetyChecker {

    private static final String TAG = OneTimeSafetyChecker.class.getSimpleName();

    private final DevicePolicyManagerService mService;
    private final DevicePolicySafetyChecker mRealSafetyChecker;
    private final @DevicePolicyOperation int mOperation;
    private final boolean mSafe;

    OneTimeSafetyChecker(DevicePolicyManagerService service,
            @DevicePolicyOperation int operation, boolean safe) {
        mService = Objects.requireNonNull(service);
        mOperation = operation;
        mSafe = safe;
        mRealSafetyChecker = service.getDevicePolicySafetyChecker();
        Slog.i(TAG, "Saving real DevicePolicySafetyChecker as " + mRealSafetyChecker);
    }

    @Override
    public boolean isDevicePolicyOperationSafe(@DevicePolicyOperation int operation) {
        String name = operationToString(operation);
        boolean safe = true;
        if (operation == mOperation) {
            safe = mSafe;
        } else {
            Slog.wtf(TAG, "invalid call to isDevicePolicyOperationSafe(): asked for " + name
                    + ", should be " + operationToString(mOperation));
        }
        Slog.i(TAG, "isDevicePolicyOperationSafe(" + name + "): returning " + safe
                + " and restoring DevicePolicySafetyChecker to " + mRealSafetyChecker);
        mService.setDevicePolicySafetyChecker(mRealSafetyChecker);
        return safe;
    }
}