Merge "New device policy API: DeviceAdminReceiver.onUnsafeOperationStateChanged()" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d95e8ac64b
@@ -6896,6 +6896,7 @@ package android.app.admin {
|
||||
method public void onLockTaskModeEntering(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull String);
|
||||
method public void onLockTaskModeExiting(@NonNull android.content.Context, @NonNull android.content.Intent);
|
||||
method public void onNetworkLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent, long, @IntRange(from=1) int);
|
||||
method public void onOperationSafetyStateChanged(@NonNull android.content.Context, int, boolean);
|
||||
method @Deprecated public void onPasswordChanged(@NonNull android.content.Context, @NonNull android.content.Intent);
|
||||
method public void onPasswordChanged(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
|
||||
method @Deprecated public void onPasswordExpiring(@NonNull android.content.Context, @NonNull android.content.Intent);
|
||||
@@ -7072,6 +7073,7 @@ package android.app.admin {
|
||||
method public boolean isProfileOwnerApp(String);
|
||||
method public boolean isProvisioningAllowed(@NonNull String);
|
||||
method public boolean isResetPasswordTokenActive(android.content.ComponentName);
|
||||
method public boolean isSafeOperation(int);
|
||||
method public boolean isSecurityLoggingEnabled(@Nullable android.content.ComponentName);
|
||||
method public boolean isUninstallBlocked(@Nullable android.content.ComponentName, String);
|
||||
method public boolean isUniqueDeviceAttestationSupported();
|
||||
@@ -7300,6 +7302,7 @@ package android.app.admin {
|
||||
field public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1; // 0x1
|
||||
field public static final int MAKE_USER_EPHEMERAL = 2; // 0x2
|
||||
field public static final String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
|
||||
field public static final int OPERATION_SAFETY_REASON_DRIVING_DISTRACTION = 1; // 0x1
|
||||
field public static final int PASSWORD_COMPLEXITY_HIGH = 327680; // 0x50000
|
||||
field public static final int PASSWORD_COMPLEXITY_LOW = 65536; // 0x10000
|
||||
field public static final int PASSWORD_COMPLEXITY_MEDIUM = 196608; // 0x30000
|
||||
@@ -7336,7 +7339,6 @@ 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 UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION = 1; // 0x1
|
||||
field public static final int WIPE_EUICC = 4; // 0x4
|
||||
field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
|
||||
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
|
||||
@@ -7490,7 +7492,7 @@ package android.app.admin {
|
||||
|
||||
public final class UnsafeStateException extends java.lang.IllegalStateException implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public int getReason();
|
||||
method @NonNull public java.util.List<java.lang.Integer> getReasons();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.UnsafeStateException> CREATOR;
|
||||
}
|
||||
|
||||
@@ -391,11 +391,11 @@ package android.app.admin {
|
||||
method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);
|
||||
method public boolean isCurrentInputMethodSetByOwner();
|
||||
method public boolean isFactoryResetProtectionPolicySupported();
|
||||
method @NonNull public static String operationSafetyReasonToString(int);
|
||||
method @NonNull public static String operationToString(int);
|
||||
method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
|
||||
method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void resetDefaultCrossProfileIntentFilters(int);
|
||||
method @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public void setNextOperationSafety(int, int);
|
||||
method @NonNull public static String unsafeOperationReasonToString(int);
|
||||
field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
|
||||
field public static final int CODE_ACCOUNTS_NOT_EMPTY = 6; // 0x6
|
||||
field public static final int CODE_CANNOT_ADD_MANAGED_PROFILE = 11; // 0xb
|
||||
@@ -425,6 +425,7 @@ package android.app.admin {
|
||||
field public static final int OPERATION_REMOVE_KEY_PAIR = 28; // 0x1c
|
||||
field public static final int OPERATION_REMOVE_USER = 6; // 0x6
|
||||
field public static final int OPERATION_REQUEST_BUGREPORT = 29; // 0x1d
|
||||
field public static final int OPERATION_SAFETY_REASON_NONE = -1; // 0xffffffff
|
||||
field public static final int OPERATION_SET_ALWAYS_ON_VPN_PACKAGE = 30; // 0x1e
|
||||
field public static final int OPERATION_SET_APPLICATION_HIDDEN = 15; // 0xf
|
||||
field public static final int OPERATION_SET_APPLICATION_RESTRICTIONS = 16; // 0x10
|
||||
@@ -460,7 +461,6 @@ package android.app.admin {
|
||||
field public static final int PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED = 4; // 0x4
|
||||
field public static final int PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED = 7; // 0x7
|
||||
field public static final int PROVISIONING_RESULT_STARTING_PROFILE_FAILED = 5; // 0x5
|
||||
field public static final int UNSAFE_OPERATION_REASON_NONE = -1; // 0xffffffff
|
||||
}
|
||||
|
||||
public final class FullyManagedDeviceProvisioningParams implements android.os.Parcelable {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.app.admin;
|
||||
|
||||
import static android.app.admin.DevicePolicyManager.OperationSafetyReason;
|
||||
|
||||
import android.accounts.AccountManager;
|
||||
import android.annotation.BroadcastBehavior;
|
||||
import android.annotation.IntDef;
|
||||
@@ -35,6 +37,7 @@ import android.os.PersistableBundle;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.security.KeyChain;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -72,8 +75,8 @@ import java.lang.annotation.RetentionPolicy;
|
||||
* </div>
|
||||
*/
|
||||
public class DeviceAdminReceiver extends BroadcastReceiver {
|
||||
private static String TAG = "DevicePolicy";
|
||||
private static boolean localLOGV = false;
|
||||
private static final String TAG = "DevicePolicy";
|
||||
private static final boolean LOCAL_LOGV = false;
|
||||
|
||||
/**
|
||||
* This is the primary action that a device administrator must implement to be
|
||||
@@ -509,6 +512,36 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
|
||||
public static final String EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE =
|
||||
"android.app.extra.TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE";
|
||||
|
||||
/**
|
||||
* Broadcast action: notify the admin that the state of operations that can be unsafe because
|
||||
* of a given reason (specified by the {@link #EXTRA_OPERATION_SAFETY_REASON} {@code int} extra)
|
||||
* has changed (the new value is specified by the {@link #EXTRA_OPERATION_SAFETY_STATE}
|
||||
* {@code boolean} extra).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_OPERATION_SAFETY_STATE_CHANGED =
|
||||
"android.app.action.OPERATION_SAFETY_STATE_CHANGED";
|
||||
|
||||
/**
|
||||
* An {@code int} extra specifying an {@link OperationSafetyReason}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_OPERATION_SAFETY_REASON =
|
||||
"android.app.extra.OPERATION_SAFETY_REASON";
|
||||
|
||||
/**
|
||||
* An {@code boolean} extra specifying whether an operation will fail due to a
|
||||
* {@link OperationSafetyReason}. {@code true} means operations that rely on that reason are
|
||||
* safe, while {@code false} means they're unsafe.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_OPERATION_SAFETY_STATE =
|
||||
"android.app.extra.OPERATION_SAFETY_STATE";
|
||||
|
||||
private DevicePolicyManager mManager;
|
||||
private ComponentName mWho;
|
||||
|
||||
@@ -1017,6 +1050,51 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
|
||||
@NonNull UserHandle user) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to notify the state of operations that can be unsafe to execute has changed.
|
||||
*
|
||||
* <p><b>Note:/b> notice that the operation safety state might change between the time this
|
||||
* callback is received and the operation's method on {@link DevicePolicyManager} is called, so
|
||||
* calls to the latter could still throw a {@link UnsafeStateException} even when this method
|
||||
* is called with {@code isSafe} as {@code true}
|
||||
*
|
||||
* @param context the running context as per {@link #onReceive}
|
||||
* @param reason the reason an operation could be unsafe.
|
||||
* @param isSafe whether the operation is safe to be executed.
|
||||
*/
|
||||
public void onOperationSafetyStateChanged(@NonNull Context context,
|
||||
@OperationSafetyReason int reason, boolean isSafe) {
|
||||
if (LOCAL_LOGV) {
|
||||
Log.v(TAG, String.format("onOperationSafetyStateChanged(): %s=%b",
|
||||
DevicePolicyManager.operationSafetyReasonToString(reason), isSafe));
|
||||
}
|
||||
}
|
||||
|
||||
private void onOperationSafetyStateChanged(Context context, Intent intent) {
|
||||
if (!hasRequiredExtra(intent, EXTRA_OPERATION_SAFETY_REASON)
|
||||
|| !hasRequiredExtra(intent, EXTRA_OPERATION_SAFETY_STATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int reason = intent.getIntExtra(EXTRA_OPERATION_SAFETY_REASON,
|
||||
DevicePolicyManager.OPERATION_SAFETY_REASON_NONE);
|
||||
if (!DevicePolicyManager.isValidOperationSafetyReason(reason)) {
|
||||
Log.wtf(TAG, "Received invalid reason on " + intent.getAction() + ": " + reason);
|
||||
return;
|
||||
}
|
||||
boolean isSafe = intent.getBooleanExtra(EXTRA_OPERATION_SAFETY_STATE,
|
||||
/* defaultValue=*/ false);
|
||||
|
||||
onOperationSafetyStateChanged(context, reason, isSafe);
|
||||
}
|
||||
|
||||
private boolean hasRequiredExtra(Intent intent, String extra) {
|
||||
if (intent.hasExtra(extra)) return true;
|
||||
|
||||
Log.wtf(TAG, "Missing '" + extra + "' on intent " + intent);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept standard device administrator broadcasts. Implementations
|
||||
* should not override this method; it is better to implement the
|
||||
@@ -1025,6 +1103,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (LOCAL_LOGV) {
|
||||
Log.v(TAG, "onReceive(): received " + action + " on user " + context.getUserId());
|
||||
}
|
||||
|
||||
if (ACTION_PASSWORD_CHANGED.equals(action)) {
|
||||
onPasswordChanged(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
|
||||
@@ -1092,6 +1173,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
|
||||
} else if (ACTION_AFFILIATED_PROFILE_TRANSFER_OWNERSHIP_COMPLETE.equals(action)) {
|
||||
onTransferAffiliatedProfileOwnershipComplete(context,
|
||||
intent.getParcelableExtra(Intent.EXTRA_USER));
|
||||
} else if (ACTION_OPERATION_SAFETY_STATE_CHANGED.equals(action)) {
|
||||
onOperationSafetyStateChanged(context, intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2922,33 +2922,61 @@ public class DevicePolicyManager {
|
||||
return DebugUtils.constantToString(DevicePolicyManager.class, PREFIX_OPERATION, operation);
|
||||
}
|
||||
|
||||
private static final String PREFIX_UNSAFE_OPERATION_REASON = "UNSAFE_OPERATION_REASON_";
|
||||
private static final String PREFIX_OPERATION_SAFETY_REASON = "OPERATION_SAFETY_REASON_";
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = PREFIX_UNSAFE_OPERATION_REASON, value = {
|
||||
UNSAFE_OPERATION_REASON_NONE,
|
||||
UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION
|
||||
@IntDef(prefix = PREFIX_OPERATION_SAFETY_REASON, value = {
|
||||
OPERATION_SAFETY_REASON_NONE,
|
||||
OPERATION_SAFETY_REASON_DRIVING_DISTRACTION
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public static @interface UnsafeOperationReason {
|
||||
public static @interface OperationSafetyReason {
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@TestApi
|
||||
public static final int UNSAFE_OPERATION_REASON_NONE = -1;
|
||||
public static final int OPERATION_SAFETY_REASON_NONE = -1;
|
||||
|
||||
/**
|
||||
* Indicates that a {@link UnsafeStateException} was thrown because the operation would distract
|
||||
* the driver of the vehicle.
|
||||
*/
|
||||
public static final int UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION = 1;
|
||||
public static final int OPERATION_SAFETY_REASON_DRIVING_DISTRACTION = 1;
|
||||
|
||||
/** @hide */
|
||||
@NonNull
|
||||
@TestApi
|
||||
public static String unsafeOperationReasonToString(@UnsafeOperationReason int reason) {
|
||||
public static String operationSafetyReasonToString(@OperationSafetyReason int reason) {
|
||||
return DebugUtils.constantToString(DevicePolicyManager.class,
|
||||
PREFIX_UNSAFE_OPERATION_REASON, reason);
|
||||
PREFIX_OPERATION_SAFETY_REASON, reason);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static boolean isValidOperationSafetyReason(@OperationSafetyReason int reason) {
|
||||
return reason == OPERATION_SAFETY_REASON_DRIVING_DISTRACTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if it's safe to run operations that can be affected by the given {@code reason}.
|
||||
*
|
||||
* <p><b>Note:/b> notice that the operation safety state might change between the time this
|
||||
* method returns and the operation's method is called, so calls to the latter could still throw
|
||||
* a {@link UnsafeStateException} even when this method returns {@code true}.
|
||||
*
|
||||
* @param reason currently, only supported reason is
|
||||
* {@link #OPERATION_SAFETY_REASON_DRIVING_DISTRACTION}.
|
||||
*
|
||||
* @return whether it's safe to run operations that can be affected by the given {@code reason}.
|
||||
*/
|
||||
// TODO(b/173541467): should it throw SecurityException if caller is not admin?
|
||||
public boolean isSafeOperation(@OperationSafetyReason int reason) {
|
||||
if (mService == null) return false;
|
||||
|
||||
try {
|
||||
return mService.isSafeOperation(reason);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@@ -13157,7 +13185,7 @@ public class DevicePolicyManager {
|
||||
@TestApi
|
||||
@RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS)
|
||||
public void setNextOperationSafety(@DevicePolicyOperation int operation,
|
||||
@UnsafeOperationReason int reason) {
|
||||
@OperationSafetyReason int reason) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
mService.setNextOperationSafety(operation, reason);
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.app.admin;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.admin.DevicePolicyManager.OperationSafetyReason;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.os.UserHandle;
|
||||
@@ -255,4 +256,14 @@ public abstract class DevicePolicyManagerInternal {
|
||||
* {@link #supportsResetOp(int)} is true.
|
||||
*/
|
||||
public abstract void resetOp(int op, String packageName, @UserIdInt int userId);
|
||||
|
||||
/**
|
||||
* Notifies the system that an unsafe operation reason has changed.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code checker} is not the same as set on
|
||||
* {@code DevicePolicyManagerService}.
|
||||
*/
|
||||
public abstract void notifyUnsafeOperationStateChanged(DevicePolicySafetyChecker checker,
|
||||
@OperationSafetyReason int reason, boolean isSafe);
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ package android.app.admin;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
|
||||
import android.app.admin.DevicePolicyManager.UnsafeOperationReason;
|
||||
import android.app.admin.DevicePolicyManager.OperationSafetyReason;
|
||||
|
||||
import com.android.internal.os.IResultReceiver;
|
||||
|
||||
@@ -31,15 +31,20 @@ public interface DevicePolicySafetyChecker {
|
||||
/**
|
||||
* Returns whether the given {@code operation} can be safely executed at the moment.
|
||||
*/
|
||||
@UnsafeOperationReason
|
||||
@OperationSafetyReason
|
||||
int getUnsafeOperationReason(@DevicePolicyOperation int operation);
|
||||
|
||||
/**
|
||||
* Return whether it's safe to run operations that can be affected by the given {@code reason}.
|
||||
*/
|
||||
boolean isSafeOperation(@OperationSafetyReason int reason);
|
||||
|
||||
/**
|
||||
* Returns a new exception for when the given {@code operation} cannot be safely executed.
|
||||
*/
|
||||
@NonNull
|
||||
default UnsafeStateException newUnsafeStateException(@DevicePolicyOperation int operation,
|
||||
@UnsafeOperationReason int reason) {
|
||||
@OperationSafetyReason int reason) {
|
||||
return new UnsafeStateException(operation, reason);
|
||||
}
|
||||
|
||||
|
||||
@@ -492,6 +492,7 @@ interface IDevicePolicyManager {
|
||||
boolean canProfileOwnerResetPasswordWhenLocked(int userId);
|
||||
|
||||
void setNextOperationSafety(int operation, int reason);
|
||||
boolean isSafeOperation(int reason);
|
||||
|
||||
String getEnrollmentSpecificId(String callerPackage);
|
||||
void setOrganizationIdForUser(in String callerPackage, in String enterpriseId, int userId);
|
||||
|
||||
@@ -15,18 +15,20 @@
|
||||
*/
|
||||
package android.app.admin;
|
||||
|
||||
import static android.app.admin.DevicePolicyManager.UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION;
|
||||
import static android.app.admin.DevicePolicyManager.unsafeOperationReasonToString;
|
||||
import static android.app.admin.DevicePolicyManager.isValidOperationSafetyReason;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.TestApi;
|
||||
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
|
||||
import android.app.admin.DevicePolicyManager.UnsafeOperationReason;
|
||||
import android.app.admin.DevicePolicyManager.OperationSafetyReason;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Exception thrown when a {@link android.app.admin.DevicePolicyManager} operation failed because it
|
||||
* was not safe to be executed at that moment.
|
||||
@@ -39,17 +41,15 @@ import com.android.internal.util.Preconditions;
|
||||
public final class UnsafeStateException extends IllegalStateException implements Parcelable {
|
||||
|
||||
private final @DevicePolicyOperation int mOperation;
|
||||
private final @UnsafeOperationReason int mReason;
|
||||
private final @OperationSafetyReason int mReason;
|
||||
|
||||
/** @hide */
|
||||
@TestApi
|
||||
public UnsafeStateException(@DevicePolicyOperation int operation,
|
||||
@UnsafeOperationReason int reason) {
|
||||
@OperationSafetyReason int reason) {
|
||||
super();
|
||||
Preconditions.checkArgument(reason == UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION,
|
||||
"invalid reason %d, must be %d (%s)", reason,
|
||||
UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION,
|
||||
unsafeOperationReasonToString(UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION));
|
||||
Preconditions.checkArgument(isValidOperationSafetyReason(reason), "invalid reason %d",
|
||||
reason);
|
||||
mOperation = operation;
|
||||
mReason = reason;
|
||||
}
|
||||
@@ -61,19 +61,20 @@ public final class UnsafeStateException extends IllegalStateException implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason the operation is unsafe.
|
||||
* Gets the reasons the operation is unsafe.
|
||||
*
|
||||
* @return currently, only valid reason is
|
||||
* {@link android.app.admin.DevicePolicyManager#UNSAFE_OPERATION_REASON_DRIVING_DISTRACTION}.
|
||||
* {@link android.app.admin.DevicePolicyManager#OPERATION_SAFETY_REASON_DRIVING_DISTRACTION}.
|
||||
*/
|
||||
public @UnsafeOperationReason int getReason() {
|
||||
return mReason;
|
||||
@NonNull
|
||||
public List<Integer> getReasons() {
|
||||
return Arrays.asList(mReason);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return DevicePolicyManager.unsafeOperationReasonToString(mReason);
|
||||
return DevicePolicyManager.operationSafetyReasonToString(mReason);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -62,6 +62,7 @@ import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME;
|
||||
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
|
||||
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
|
||||
import static android.app.admin.DevicePolicyManager.NON_ORG_OWNED_PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
|
||||
import static android.app.admin.DevicePolicyManager.OPERATION_SAFETY_REASON_NONE;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
|
||||
@@ -92,7 +93,6 @@ import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_REMOVE_N
|
||||
import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED;
|
||||
import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED;
|
||||
import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_STARTING_PROFILE_FAILED;
|
||||
import static android.app.admin.DevicePolicyManager.UNSAFE_OPERATION_REASON_NONE;
|
||||
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
|
||||
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
|
||||
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
|
||||
@@ -157,9 +157,9 @@ import android.app.admin.DevicePolicyCache;
|
||||
import android.app.admin.DevicePolicyEventLogger;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
|
||||
import android.app.admin.DevicePolicyManager.OperationSafetyReason;
|
||||
import android.app.admin.DevicePolicyManager.PasswordComplexity;
|
||||
import android.app.admin.DevicePolicyManager.PersonalAppsSuspensionReason;
|
||||
import android.app.admin.DevicePolicyManager.UnsafeOperationReason;
|
||||
import android.app.admin.DevicePolicyManagerInternal;
|
||||
import android.app.admin.DevicePolicySafetyChecker;
|
||||
import android.app.admin.DeviceStateCache;
|
||||
@@ -1101,7 +1101,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
*/
|
||||
private void checkCanExecuteOrThrowUnsafe(@DevicePolicyOperation int operation) {
|
||||
int reason = getUnsafeOperationReason(operation);
|
||||
if (reason == UNSAFE_OPERATION_REASON_NONE) return;
|
||||
if (reason == OPERATION_SAFETY_REASON_NONE) return;
|
||||
|
||||
if (mSafetyChecker == null) {
|
||||
// Happens on CTS after it's set just once (by OneTimeSafetyChecker)
|
||||
@@ -1114,23 +1114,28 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
/**
|
||||
* Returns whether it's safe to execute the given {@code operation}, and why.
|
||||
*/
|
||||
@UnsafeOperationReason
|
||||
@OperationSafetyReason
|
||||
int getUnsafeOperationReason(@DevicePolicyOperation int operation) {
|
||||
return mSafetyChecker == null ? UNSAFE_OPERATION_REASON_NONE
|
||||
return mSafetyChecker == null ? OPERATION_SAFETY_REASON_NONE
|
||||
: mSafetyChecker.getUnsafeOperationReason(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextOperationSafety(@DevicePolicyOperation int operation,
|
||||
@UnsafeOperationReason int reason) {
|
||||
@OperationSafetyReason int reason) {
|
||||
Preconditions.checkCallAuthorization(
|
||||
hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
|
||||
Slog.i(LOG_TAG, String.format("setNextOperationSafety(%s, %s)",
|
||||
DevicePolicyManager.operationToString(operation),
|
||||
DevicePolicyManager.unsafeOperationReasonToString(reason)));
|
||||
DevicePolicyManager.operationSafetyReasonToString(reason)));
|
||||
mSafetyChecker = new OneTimeSafetyChecker(this, operation, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSafeOperation(@OperationSafetyReason int reason) {
|
||||
return mSafetyChecker == null ? true : mSafetyChecker.isSafeOperation(reason);
|
||||
}
|
||||
|
||||
// Used by DevicePolicyManagerServiceShellCommand
|
||||
List<OwnerDto> listAllOwners() {
|
||||
Preconditions.checkCallAuthorization(
|
||||
@@ -7522,19 +7527,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
sendActiveAdminCommand(action, extras, deviceOwnerUserId, receiverComponent);
|
||||
}
|
||||
|
||||
private void sendProfileOwnerCommand(String action, Bundle extras, int userHandle) {
|
||||
sendActiveAdminCommand(action, extras, userHandle,
|
||||
mOwners.getProfileOwnerComponent(userHandle));
|
||||
private void sendProfileOwnerCommand(String action, Bundle extras, @UserIdInt int userId) {
|
||||
sendActiveAdminCommand(action, extras, userId,
|
||||
mOwners.getProfileOwnerComponent(userId));
|
||||
}
|
||||
|
||||
private void sendActiveAdminCommand(String action, Bundle extras,
|
||||
int userHandle, ComponentName receiverComponent) {
|
||||
@UserIdInt int userId, ComponentName receiverComponent) {
|
||||
if (VERBOSE_LOG) {
|
||||
Slog.v(LOG_TAG, "sending intent " + action + " to "
|
||||
+ receiverComponent.flattenToShortString() + " on user " + userId);
|
||||
}
|
||||
final Intent intent = new Intent(action);
|
||||
intent.setComponent(receiverComponent);
|
||||
if (extras != null) {
|
||||
intent.putExtras(extras);
|
||||
}
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.of(userHandle));
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
|
||||
}
|
||||
|
||||
private void sendOwnerChangedBroadcast(String broadcast, int userId) {
|
||||
@@ -12224,6 +12233,32 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
packageName, findInteractAcrossProfilesResetMode(packageName), userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyUnsafeOperationStateChanged(DevicePolicySafetyChecker checker, int reason,
|
||||
boolean isSafe) {
|
||||
// TODO(b/178494483): use EventLog instead
|
||||
// TODO(b/178494483): log metrics?
|
||||
if (VERBOSE_LOG) {
|
||||
Slog.v(LOG_TAG, String.format("notifyUnsafeOperationStateChanged(): %s=%b",
|
||||
DevicePolicyManager.operationSafetyReasonToString(reason), isSafe));
|
||||
}
|
||||
|
||||
Preconditions.checkArgument(mSafetyChecker == checker,
|
||||
"invalid checker: should be %s, was %s", mSafetyChecker, checker);
|
||||
|
||||
Bundle extras = new Bundle();
|
||||
extras.putInt(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_REASON, reason);
|
||||
extras.putBoolean(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_STATE, isSafe);
|
||||
|
||||
// TODO(b/178494483): add CTS test
|
||||
sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
|
||||
extras);
|
||||
for (int profileOwnerId : mOwners.getProfileOwnerKeys()) {
|
||||
sendProfileOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
|
||||
extras, profileOwnerId);
|
||||
}
|
||||
}
|
||||
|
||||
private @Mode int findInteractAcrossProfilesResetMode(String packageName) {
|
||||
return getDefaultCrossProfilePackages().contains(packageName)
|
||||
? AppOpsManager.MODE_ALLOWED
|
||||
|
||||
@@ -27,6 +27,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_IS_SAFE_OPERATION_BY_REASON = "is-operation-safe-by-reason";
|
||||
private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe";
|
||||
private static final String CMD_LIST_OWNERS = "list-owners";
|
||||
|
||||
@@ -53,6 +54,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
|
||||
switch (cmd) {
|
||||
case CMD_IS_SAFE_OPERATION:
|
||||
return runIsSafeOperation(pw);
|
||||
case CMD_IS_SAFE_OPERATION_BY_REASON:
|
||||
return runIsSafeOperationByReason(pw);
|
||||
case CMD_SET_SAFE_OPERATION:
|
||||
return runSetSafeOperation(pw);
|
||||
case CMD_LIST_OWNERS:
|
||||
@@ -73,12 +76,13 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private void showHelp(PrintWriter pw) {
|
||||
pw.printf(" help\n");
|
||||
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 <REASON_ID>\n", CMD_IS_SAFE_OPERATION_BY_REASON);
|
||||
pw.printf(" Checks if the operations are safe for the given reason\n\n");
|
||||
pw.printf(" %s <OPERATION_ID> <REASON_ID>\n", CMD_SET_SAFE_OPERATION);
|
||||
pw.printf(" Emulates the result of the next call to check if the given operation is safe"
|
||||
+ " \n\n");
|
||||
@@ -89,10 +93,19 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
|
||||
private int runIsSafeOperation(PrintWriter pw) {
|
||||
int operation = Integer.parseInt(getNextArgRequired());
|
||||
int reason = mService.getUnsafeOperationReason(operation);
|
||||
boolean safe = reason == DevicePolicyManager.UNSAFE_OPERATION_REASON_NONE;
|
||||
boolean safe = reason == DevicePolicyManager.OPERATION_SAFETY_REASON_NONE;
|
||||
pw.printf("Operation %s is %b. Reason: %s\n",
|
||||
DevicePolicyManager.operationToString(operation), safe,
|
||||
DevicePolicyManager.unsafeOperationReasonToString(reason));
|
||||
DevicePolicyManager.operationSafetyReasonToString(reason));
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int runIsSafeOperationByReason(PrintWriter pw) {
|
||||
int reason = Integer.parseInt(getNextArgRequired());
|
||||
boolean safe = mService.isSafeOperation(reason);
|
||||
pw.printf("Operations affected by %s are %s\n",
|
||||
DevicePolicyManager.operationSafetyReasonToString(reason),
|
||||
(safe ? "SAFE" : "UNSAFE"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -102,7 +115,7 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
|
||||
mService.setNextOperationSafety(operation, reason);
|
||||
pw.printf("Next call to check operation %s will return %s\n",
|
||||
DevicePolicyManager.operationToString(operation),
|
||||
DevicePolicyManager.unsafeOperationReasonToString(reason));
|
||||
DevicePolicyManager.operationSafetyReasonToString(reason));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,16 +15,18 @@
|
||||
*/
|
||||
package com.android.server.devicepolicy;
|
||||
|
||||
import static android.app.admin.DevicePolicyManager.UNSAFE_OPERATION_REASON_NONE;
|
||||
import static android.app.admin.DevicePolicyManager.OPERATION_SAFETY_REASON_NONE;
|
||||
import static android.app.admin.DevicePolicyManager.operationSafetyReasonToString;
|
||||
import static android.app.admin.DevicePolicyManager.operationToString;
|
||||
import static android.app.admin.DevicePolicyManager.unsafeOperationReasonToString;
|
||||
|
||||
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
|
||||
import android.app.admin.DevicePolicyManager.UnsafeOperationReason;
|
||||
import android.app.admin.DevicePolicyManager.OperationSafetyReason;
|
||||
import android.app.admin.DevicePolicyManagerInternal;
|
||||
import android.app.admin.DevicePolicySafetyChecker;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.os.IResultReceiver;
|
||||
import com.android.server.LocalServices;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -43,10 +45,10 @@ final class OneTimeSafetyChecker implements DevicePolicySafetyChecker {
|
||||
private final DevicePolicyManagerService mService;
|
||||
private final DevicePolicySafetyChecker mRealSafetyChecker;
|
||||
private final @DevicePolicyOperation int mOperation;
|
||||
private final @UnsafeOperationReason int mReason;
|
||||
private final @OperationSafetyReason int mReason;
|
||||
|
||||
OneTimeSafetyChecker(DevicePolicyManagerService service,
|
||||
@DevicePolicyOperation int operation, @UnsafeOperationReason int reason) {
|
||||
@DevicePolicyOperation int operation, @OperationSafetyReason int reason) {
|
||||
mService = Objects.requireNonNull(service);
|
||||
mOperation = operation;
|
||||
mReason = reason;
|
||||
@@ -55,23 +57,41 @@ final class OneTimeSafetyChecker implements DevicePolicySafetyChecker {
|
||||
}
|
||||
|
||||
@Override
|
||||
@UnsafeOperationReason
|
||||
@OperationSafetyReason
|
||||
public int getUnsafeOperationReason(@DevicePolicyOperation int operation) {
|
||||
String name = operationToString(operation);
|
||||
int reason = UNSAFE_OPERATION_REASON_NONE;
|
||||
Slog.i(TAG, "getUnsafeOperationReason(" + name + ")");
|
||||
int reason = OPERATION_SAFETY_REASON_NONE;
|
||||
if (operation == mOperation) {
|
||||
reason = mReason;
|
||||
} else {
|
||||
Slog.wtf(TAG, "invalid call to isDevicePolicyOperationSafe(): asked for " + name
|
||||
+ ", should be " + operationToString(mOperation));
|
||||
}
|
||||
Slog.i(TAG, "getDevicePolicyOperationSafety(" + name + "): returning "
|
||||
+ unsafeOperationReasonToString(reason)
|
||||
String reasonName = operationSafetyReasonToString(reason);
|
||||
DevicePolicyManagerInternal dpmi = LocalServices
|
||||
.getService(DevicePolicyManagerInternal.class);
|
||||
|
||||
Slog.i(TAG, "notifying " + reasonName + " is active");
|
||||
dpmi.notifyUnsafeOperationStateChanged(this, reason, true);
|
||||
|
||||
Slog.i(TAG, "notifying " + reasonName + " is inactive");
|
||||
dpmi.notifyUnsafeOperationStateChanged(this, reason, false);
|
||||
|
||||
Slog.i(TAG, "returning " + reasonName
|
||||
+ " and restoring DevicePolicySafetyChecker to " + mRealSafetyChecker);
|
||||
mService.setDevicePolicySafetyCheckerUnchecked(mRealSafetyChecker);
|
||||
return reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSafeOperation(@OperationSafetyReason int reason) {
|
||||
boolean safe = mReason != reason;
|
||||
Slog.i(TAG, "isSafeOperation(" + operationSafetyReasonToString(reason) + "): " + safe);
|
||||
|
||||
return safe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFactoryReset(IResultReceiver callback) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
Reference in New Issue
Block a user