blob: 0bc0c21f64d63b6eccddaaea8a345b5070faa0f3 [file] [log] [blame]
/*
* 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.internal.car;
import static android.app.admin.DevicePolicyManager.OPERATION_CLEAR_APPLICATION_USER_DATA;
import static android.app.admin.DevicePolicyManager.OPERATION_LOGOUT_USER;
import static android.app.admin.DevicePolicyManager.OPERATION_REBOOT;
import static android.app.admin.DevicePolicyManager.OPERATION_REQUEST_BUGREPORT;
import static android.app.admin.DevicePolicyManager.OPERATION_SAFETY_REASON_DRIVING_DISTRACTION;
import static android.app.admin.DevicePolicyManager.OPERATION_SET_APPLICATION_HIDDEN;
import static android.app.admin.DevicePolicyManager.OPERATION_SET_APPLICATION_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.OPERATION_SET_KEYGUARD_DISABLED;
import static android.app.admin.DevicePolicyManager.OPERATION_SET_LOCK_TASK_FEATURES;
import static android.app.admin.DevicePolicyManager.OPERATION_SET_LOCK_TASK_PACKAGES;
import static android.app.admin.DevicePolicyManager.OPERATION_SET_PACKAGES_SUSPENDED;
import static android.app.admin.DevicePolicyManager.OPERATION_SET_STATUS_BAR_DISABLED;
import static android.app.admin.DevicePolicyManager.OPERATION_SET_SYSTEM_SETTING;
import static android.app.admin.DevicePolicyManager.OPERATION_SWITCH_USER;
import static android.app.admin.DevicePolicyManager.operationToString;
import android.annotation.NonNull;
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
import android.app.admin.DevicePolicyManagerLiteInternal;
import android.app.admin.DevicePolicySafetyChecker;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
* Integrates {@link android.app.admin.DevicePolicyManager} operations with car UX restrictions.
*/
final class CarDevicePolicySafetyChecker {
private static final String TAG = CarDevicePolicySafetyChecker.class.getSimpleName();
private static final boolean DEBUG = false;
private static final int[] UNSAFE_OPERATIONS = new int[] {
OPERATION_CLEAR_APPLICATION_USER_DATA,
OPERATION_LOGOUT_USER,
OPERATION_REBOOT,
OPERATION_REQUEST_BUGREPORT,
OPERATION_SET_APPLICATION_HIDDEN,
OPERATION_SET_APPLICATION_RESTRICTIONS,
OPERATION_SET_KEYGUARD_DISABLED,
OPERATION_SET_LOCK_TASK_FEATURES,
OPERATION_SET_LOCK_TASK_PACKAGES,
OPERATION_SET_PACKAGES_SUSPENDED,
OPERATION_SET_STATUS_BAR_DISABLED,
OPERATION_SET_SYSTEM_SETTING,
OPERATION_SWITCH_USER
};
private final AtomicBoolean mSafe = new AtomicBoolean(true);
private final DevicePolicySafetyChecker mCheckerImplementation;
private final DevicePolicyManagerLiteInternal mDpmi;
CarDevicePolicySafetyChecker(DevicePolicySafetyChecker checkerImplementation) {
this(checkerImplementation,
LocalServices.getService(DevicePolicyManagerLiteInternal.class));
}
@VisibleForTesting
CarDevicePolicySafetyChecker(DevicePolicySafetyChecker checkerImplementation,
DevicePolicyManagerLiteInternal dpmi) {
mCheckerImplementation = Objects.requireNonNull(checkerImplementation,
"DevicePolicySafetyChecker cannot be null");
mDpmi = Objects.requireNonNull(dpmi, "DevicePolicyManagerLiteInternal cannot be null");
}
boolean isDevicePolicyOperationSafe(@DevicePolicyOperation int operation) {
boolean safe = true;
boolean globalSafe = mSafe.get();
if (!globalSafe) {
for (int unsafeOperation : UNSAFE_OPERATIONS) {
if (unsafeOperation == operation) {
safe = false;
break;
}
}
}
if (DEBUG) {
Slog.d(TAG, "isDevicePolicyOperationSafe(" + operationToString(operation)
+ "): " + safe + " (mSafe=" + globalSafe + ")");
}
return safe;
}
// TODO(b/172376923): override getUnsafeStateException to show error message explaining how to
// wrap it under CarDevicePolicyManager
void setSafe(boolean safe) {
Slog.i(TAG, "Setting safe to " + safe);
mSafe.set(safe);
mDpmi.notifyUnsafeOperationStateChanged(mCheckerImplementation,
OPERATION_SAFETY_REASON_DRIVING_DISTRACTION, /* isSafe= */ safe);
}
boolean isSafe() {
return mSafe.get();
}
void dump(@NonNull IndentingPrintWriter pw) {
pw.printf("Safe to run device policy operations: %b\n", mSafe.get());
pw.printf("Unsafe operations: %s\n", Arrays.stream(UNSAFE_OPERATIONS)
.mapToObj(o -> operationToString(o)).collect(Collectors.toList()));
}
}