Merge "Initial definition of DevicePolicySafetyChecker."
This commit is contained in:
committed by
Android (Google) Code Review
commit
62a648da25
@@ -122,6 +122,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
// TODO(b/172376923) - add CarDevicePolicyManager examples below (or remove reference to it).
|
||||
/**
|
||||
* Public interface for managing policies enforced on a device. Most clients of this class must be
|
||||
* registered with the system as a <a href="{@docRoot}guide/topics/admin/device-admin.html">device
|
||||
@@ -130,6 +131,13 @@ import java.util.concurrent.Executor;
|
||||
* for that method specifies that it is restricted to either device or profile owners. Any
|
||||
* application calling an api may only pass as an argument a device administrator component it
|
||||
* owns. Otherwise, a {@link SecurityException} will be thrown.
|
||||
*
|
||||
* <p><b>Note: </b>on
|
||||
* {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}, some methods can
|
||||
* throw an {@link UnsafeStateException} exception (for example, if the vehicle is moving), so
|
||||
* callers running on automotive builds should wrap every method call under the methods provided by
|
||||
* {@code android.car.admin.CarDevicePolicyManager}.
|
||||
*
|
||||
* <div class="special reference">
|
||||
* <h3>Developer Guides</h3>
|
||||
* <p>
|
||||
@@ -2445,6 +2453,19 @@ public class DevicePolicyManager {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface PersonalAppsSuspensionReason {}
|
||||
|
||||
/** @hide */
|
||||
// TODO(b/172376923): make it TestApi
|
||||
public static final int OPERATION_LOCK_NOW = 1;
|
||||
|
||||
// TODO(b/172376923) - add all operations
|
||||
/** @hide */
|
||||
@IntDef(prefix = "OPERATION_", value = {
|
||||
OPERATION_LOCK_NOW,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public static @interface DevicePolicyOperation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given administrator component is currently active (enabled) in the system.
|
||||
*
|
||||
|
||||
42
core/java/android/app/admin/DevicePolicySafetyChecker.java
Normal file
42
core/java/android/app/admin/DevicePolicySafetyChecker.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 android.app.admin;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
|
||||
|
||||
/**
|
||||
* Interface responsible to check if a {@link DevicePolicyManager} API can be safely executed.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface DevicePolicySafetyChecker {
|
||||
|
||||
/**
|
||||
* Returns whether the given {@code operation} can be safely executed at the moment.
|
||||
*/
|
||||
default boolean isDevicePolicyOperationSafe(@DevicePolicyOperation int operation) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new exception for when the given {@code operation} cannot be safely executed.
|
||||
*/
|
||||
@NonNull
|
||||
default UnsafeStateException newUnsafeStateException(@DevicePolicyOperation int operation) {
|
||||
return new UnsafeStateException(operation);
|
||||
}
|
||||
}
|
||||
76
core/java/android/app/admin/UnsafeStateException.java
Normal file
76
core/java/android/app/admin/UnsafeStateException.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 android.app.admin;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Exception thrown when a {@link DevicePolicyManager} operation failed because it was not safe
|
||||
* to be executed at that moment.
|
||||
*
|
||||
* <p>For example, it can be thrown on
|
||||
* {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive devices} when the vehicle
|
||||
* is moving.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// TODO(b/172376923): make it public
|
||||
@SuppressWarnings("serial")
|
||||
public final class UnsafeStateException extends IllegalStateException implements Parcelable {
|
||||
|
||||
private final @DevicePolicyOperation int mOperation;
|
||||
|
||||
/** @hide */
|
||||
public UnsafeStateException(@DevicePolicyOperation int operation) {
|
||||
super();
|
||||
|
||||
mOperation = operation;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
// TODO(b/172376923): make it TestApi
|
||||
public @DevicePolicyOperation int getOperation() {
|
||||
return mOperation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mOperation);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<UnsafeStateException> CREATOR =
|
||||
new Creator<UnsafeStateException>() {
|
||||
|
||||
@Override
|
||||
public UnsafeStateException createFromParcel(Parcel source) {
|
||||
return new UnsafeStateException(source.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnsafeStateException[] newArray(int size) {
|
||||
return new UnsafeStateException[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package com.android.server.devicepolicy;
|
||||
|
||||
import android.app.admin.DevicePolicySafetyChecker;
|
||||
import android.app.admin.IDevicePolicyManager;
|
||||
import android.content.ComponentName;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.SystemService;
|
||||
|
||||
@@ -30,6 +32,9 @@ import com.android.server.SystemService;
|
||||
* should be added here to avoid build breakage in downstream branches.
|
||||
*/
|
||||
abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
|
||||
|
||||
private static final String TAG = BaseIDevicePolicyManager.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* To be called by {@link DevicePolicyManagerService#Lifecycle} during the various boot phases.
|
||||
*
|
||||
@@ -55,6 +60,16 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
|
||||
*/
|
||||
abstract void handleStopUser(int userId);
|
||||
|
||||
/**
|
||||
* Sets the {@link DevicePolicySafetyChecker}.
|
||||
*
|
||||
* <p>Currently, it's called only by {@code SystemServer} on
|
||||
* {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}
|
||||
*/
|
||||
public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
|
||||
Slog.w(TAG, "setDevicePolicySafetyChecker() not implemented by " + getClass());
|
||||
}
|
||||
|
||||
public void clearSystemUpdatePolicyFreezePeriodRecord() {
|
||||
}
|
||||
|
||||
|
||||
@@ -135,9 +135,11 @@ import android.app.admin.DeviceAdminReceiver;
|
||||
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.PasswordComplexity;
|
||||
import android.app.admin.DevicePolicyManager.PersonalAppsSuspensionReason;
|
||||
import android.app.admin.DevicePolicyManagerInternal;
|
||||
import android.app.admin.DevicePolicySafetyChecker;
|
||||
import android.app.admin.DeviceStateCache;
|
||||
import android.app.admin.FactoryResetProtectionPolicy;
|
||||
import android.app.admin.NetworkEvent;
|
||||
@@ -148,6 +150,7 @@ import android.app.admin.SecurityLog.SecurityEvent;
|
||||
import android.app.admin.StartInstallingUpdateCallback;
|
||||
import android.app.admin.SystemUpdateInfo;
|
||||
import android.app.admin.SystemUpdatePolicy;
|
||||
import android.app.admin.UnsafeStateException;
|
||||
import android.app.backup.IBackupManager;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
@@ -634,6 +637,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
@VisibleForTesting
|
||||
final TransferOwnershipMetadataManager mTransferOwnershipMetadataManager;
|
||||
|
||||
@Nullable
|
||||
private DevicePolicySafetyChecker mSafetyChecker;
|
||||
|
||||
public static final class Lifecycle extends SystemService {
|
||||
private BaseIDevicePolicyManager mService;
|
||||
|
||||
@@ -645,8 +651,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
dpmsClassName = DevicePolicyManagerService.class.getName();
|
||||
}
|
||||
try {
|
||||
Class serviceClass = Class.forName(dpmsClassName);
|
||||
Constructor constructor = serviceClass.getConstructor(Context.class);
|
||||
Class<?> serviceClass = Class.forName(dpmsClassName);
|
||||
Constructor<?> constructor = serviceClass.getConstructor(Context.class);
|
||||
mService = (BaseIDevicePolicyManager) constructor.newInstance(context);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
@@ -655,6 +661,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the {@link DevicePolicySafetyChecker}. */
|
||||
public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
|
||||
mService.setDevicePolicySafetyChecker(safetyChecker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishBinderService(Context.DEVICE_POLICY_SERVICE, mService);
|
||||
@@ -953,6 +964,38 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
|
||||
Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as " + safetyChecker.getClass());
|
||||
mSafetyChecker = safetyChecker;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
if (mSafetyChecker == null || mSafetyChecker.isDevicePolicyOperationSafe(operation)) {
|
||||
return true;
|
||||
}
|
||||
throw mSafetyChecker.newUnsafeStateException(operation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit test will subclass it to inject mocks.
|
||||
*/
|
||||
@@ -4760,9 +4803,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
|
||||
@Override
|
||||
public void lockNow(int flags, boolean parent) {
|
||||
if (!mHasFeature && !hasCallingPermission(permission.LOCK_DEVICE)) {
|
||||
if (!canExecute(DevicePolicyManager.OPERATION_LOCK_NOW, permission.LOCK_DEVICE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final CallerIdentity caller = getCallerIdentity();
|
||||
|
||||
final int callingUserId = caller.getUserId();
|
||||
@@ -8554,6 +8598,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
pw.printf("mIsWatch=%b\n", mIsWatch);
|
||||
pw.printf("mIsAutomotive=%b\n", mIsAutomotive);
|
||||
pw.printf("mHasTelephonyFeature=%b\n", mHasTelephonyFeature);
|
||||
String safetyChecker = mSafetyChecker == null ? "N/A" : mSafetyChecker.getClass().getName();
|
||||
pw.printf("mSafetyChecker=%b\n", safetyChecker);
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.app.AppCompatCallbacks;
|
||||
import android.app.ApplicationErrorReport;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.SystemServiceRegistry;
|
||||
import android.app.admin.DevicePolicySafetyChecker;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -1468,7 +1469,10 @@ public final class SystemServer implements Dumpable {
|
||||
}
|
||||
t.traceEnd();
|
||||
|
||||
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
|
||||
final DevicePolicyManagerService.Lifecycle dpms;
|
||||
if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
|
||||
dpms = null;
|
||||
} else {
|
||||
t.traceBegin("StartLockSettingsService");
|
||||
try {
|
||||
mSystemServiceManager.startService(LOCK_SETTINGS_SERVICE_CLASS);
|
||||
@@ -1505,7 +1509,7 @@ public final class SystemServer implements Dumpable {
|
||||
// Always start the Device Policy Manager, so that the API is compatible with
|
||||
// API8.
|
||||
t.traceBegin("StartDevicePolicyManager");
|
||||
mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
|
||||
dpms = mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
|
||||
t.traceEnd();
|
||||
|
||||
if (!isWatch) {
|
||||
@@ -2427,6 +2431,9 @@ public final class SystemServer implements Dumpable {
|
||||
if (cshs instanceof Dumpable) {
|
||||
mDumper.addDumpable((Dumpable) cshs);
|
||||
}
|
||||
if (cshs instanceof DevicePolicySafetyChecker) {
|
||||
dpms.setDevicePolicySafetyChecker((DevicePolicySafetyChecker) cshs);
|
||||
}
|
||||
t.traceEnd();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user