Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +24 −1 Original line number Diff line number Diff line Loading @@ -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}. * Loading @@ -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); } } Loading @@ -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. */ Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java +15 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading @@ -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) { Loading @@ -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; } } services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java 0 → 100644 +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; } } Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +24 −1 Original line number Diff line number Diff line Loading @@ -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}. * Loading @@ -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); } } Loading @@ -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. */ Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java +15 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading @@ -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) { Loading @@ -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; } }
services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java 0 → 100644 +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; } }