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

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

Merge "Initial definition of DevicePolicySafetyChecker."

parents a14eb1ec 6b94ea47
Loading
Loading
Loading
Loading
+21 −0
Original line number Original line Diff line number Diff line
@@ -122,6 +122,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
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
 * 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
 * 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
 * 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
 * application calling an api may only pass as an argument a device administrator component it
 * owns. Otherwise, a {@link SecurityException} will be thrown.
 * 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">
 * <div class="special reference">
 * <h3>Developer Guides</h3>
 * <h3>Developer Guides</h3>
 * <p>
 * <p>
@@ -2445,6 +2453,19 @@ public class DevicePolicyManager {
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface PersonalAppsSuspensionReason {}
    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.
     * Return true if the given administrator component is currently active (enabled) in the system.
     *
     *
+42 −0
Original line number Original line 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 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 −0
Original line number Original line 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 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 −0
Original line number Original line Diff line number Diff line
@@ -15,8 +15,10 @@
 */
 */
package com.android.server.devicepolicy;
package com.android.server.devicepolicy;


import android.app.admin.DevicePolicySafetyChecker;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
import android.content.ComponentName;
import android.util.Slog;


import com.android.server.SystemService;
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.
 * should be added here to avoid build breakage in downstream branches.
 */
 */
abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
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.
     * 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);
    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() {
    public void clearSystemUpdatePolicyFreezePeriodRecord() {
    }
    }


+49 −3
Original line number Original line Diff line number Diff line
@@ -135,9 +135,11 @@ import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.DevicePolicyManager.PersonalAppsSuspensionReason;
import android.app.admin.DevicePolicyManager.PersonalAppsSuspensionReason;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicySafetyChecker;
import android.app.admin.DeviceStateCache;
import android.app.admin.DeviceStateCache;
import android.app.admin.FactoryResetProtectionPolicy;
import android.app.admin.FactoryResetProtectionPolicy;
import android.app.admin.NetworkEvent;
import android.app.admin.NetworkEvent;
@@ -148,6 +150,7 @@ import android.app.admin.SecurityLog.SecurityEvent;
import android.app.admin.StartInstallingUpdateCallback;
import android.app.admin.StartInstallingUpdateCallback;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.UnsafeStateException;
import android.app.backup.IBackupManager;
import android.app.backup.IBackupManager;
import android.app.trust.TrustManager;
import android.app.trust.TrustManager;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
@@ -634,6 +637,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @VisibleForTesting
    @VisibleForTesting
    final TransferOwnershipMetadataManager mTransferOwnershipMetadataManager;
    final TransferOwnershipMetadataManager mTransferOwnershipMetadataManager;
    @Nullable
    private DevicePolicySafetyChecker mSafetyChecker;
    public static final class Lifecycle extends SystemService {
    public static final class Lifecycle extends SystemService {
        private BaseIDevicePolicyManager mService;
        private BaseIDevicePolicyManager mService;
@@ -645,8 +651,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                dpmsClassName = DevicePolicyManagerService.class.getName();
                dpmsClassName = DevicePolicyManagerService.class.getName();
            }
            }
            try {
            try {
                Class serviceClass = Class.forName(dpmsClassName);
                Class<?> serviceClass = Class.forName(dpmsClassName);
                Constructor constructor = serviceClass.getConstructor(Context.class);
                Constructor<?> constructor = serviceClass.getConstructor(Context.class);
                mService = (BaseIDevicePolicyManager) constructor.newInstance(context);
                mService = (BaseIDevicePolicyManager) constructor.newInstance(context);
            } catch (Exception e) {
            } catch (Exception e) {
                throw new IllegalStateException(
                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
        @Override
        public void onStart() {
        public void onStart() {
            publishBinderService(Context.DEVICE_POLICY_SERVICE, mService);
            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.
     * Unit test will subclass it to inject mocks.
     */
     */
@@ -4760,9 +4803,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @Override
    @Override
    public void lockNow(int flags, boolean parent) {
    public void lockNow(int flags, boolean parent) {
        if (!mHasFeature && !hasCallingPermission(permission.LOCK_DEVICE)) {
        if (!canExecute(DevicePolicyManager.OPERATION_LOCK_NOW, permission.LOCK_DEVICE)) {
            return;
            return;
        }
        }
        final CallerIdentity caller = getCallerIdentity();
        final CallerIdentity caller = getCallerIdentity();
        final int callingUserId = caller.getUserId();
        final int callingUserId = caller.getUserId();
@@ -8554,6 +8598,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        pw.printf("mIsWatch=%b\n", mIsWatch);
        pw.printf("mIsWatch=%b\n", mIsWatch);
        pw.printf("mIsAutomotive=%b\n", mIsAutomotive);
        pw.printf("mIsAutomotive=%b\n", mIsAutomotive);
        pw.printf("mHasTelephonyFeature=%b\n", mHasTelephonyFeature);
        pw.printf("mHasTelephonyFeature=%b\n", mHasTelephonyFeature);
        String safetyChecker = mSafetyChecker == null ? "N/A" : mSafetyChecker.getClass().getName();
        pw.printf("mSafetyChecker=%b\n", safetyChecker);
        pw.decreaseIndent();
        pw.decreaseIndent();
    }
    }
Loading