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

Commit 349cee65 authored by Grace Cheng's avatar Grace Cheng
Browse files

isSecureLockDeviceEnabled, isSecureLockDeviceAvailable APIs, persist across reboot

Adds new api AuthenticationPolicyManager#isSecureLockDeviceAvailable to
check if a device is eligible for Secure Lock Device: device must have a
strong biometric enrolled.

Adds isSecureLockDeviceEnabled API to check if the current
user is in secure lock device. This is determined by the value stored in
SecureSettings that is updated whenever secure lock device is enabled
or disabled.

The enableSecureLockDevice API is updated to check
isSecureLockDeviceAvailable and isSecureLockDeviceEnabled internally
before enabling secure lock device.

Defines SecureLockDeviceStore to store whether Secure Lock Device is enabled or
disabled, as well as the calling user that enabled secure lock device
when applicable. Updates Secure Lock Device to persist across reboot by
writing to XML in system data on changes.

Flag: android.security.secure_lock_device
Bug: 401645997
Fixes: 396640366
Fixes: 406266003
Fixes: 406532567
Bug: 396641431
Test: atest AuthenticationPolicyServiceTest
Test: atest SecureLockDeviceServiceTest
Test: atest CtsSecurityTestCases:android.security.cts.authenticationpolicy.AuthenticationPolicyManagerTest
Change-Id: I4cc57d1226619f253eb4ac22141a487029b5ab40
parent 555a11bf
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -12727,9 +12727,12 @@ package android.security.authenticationpolicy {
  @FlaggedApi("android.security.secure_lockdown") public final class AuthenticationPolicyManager {
    method @FlaggedApi("android.security.secure_lockdown") @RequiresPermission(android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE) public int disableSecureLockDevice(@NonNull android.security.authenticationpolicy.DisableSecureLockDeviceParams);
    method @FlaggedApi("android.security.secure_lockdown") @RequiresPermission(android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE) public int enableSecureLockDevice(@NonNull android.security.authenticationpolicy.EnableSecureLockDeviceParams);
    method @FlaggedApi("android.security.secure_lock_device") @RequiresPermission(android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE) public int isSecureLockDeviceAvailable();
    method @FlaggedApi("android.security.secure_lock_device") @RequiresPermission(android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE) public boolean isSecureLockDeviceEnabled();
    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_ALREADY_ENABLED = 6; // 0x6
    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_INSUFFICIENT_BIOMETRICS = 5; // 0x5
    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_INVALID_PARAMS = 3; // 0x3
    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_NOT_AUTHORIZED = 7; // 0x7
    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_NO_BIOMETRICS_ENROLLED = 4; // 0x4
    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_UNKNOWN = 1; // 0x1
    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_UNSUPPORTED = 2; // 0x2
+105 −18
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package android.security.authenticationpolicy;

import static android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE;
import static android.security.Flags.FLAG_SECURE_LOCKDOWN;
import static android.security.Flags.FLAG_SECURE_LOCK_DEVICE;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -48,6 +49,16 @@ import java.lang.annotation.RetentionPolicy;
 * To disable secure lock on the device, call {@link #disableSecureLockDevice}. This will require
 * the caller to have the {@link android.Manifest.permission#MANAGE_SECURE_LOCK_DEVICE} permission.
 *
 * <p>
 * To check if the device meets the requirements to enable secure lock, call
 * {@link #isSecureLockDeviceAvailable}. This will require the caller to have the
 * {@link android.Manifest.permission#MANAGE_SECURE_LOCK_DEVICE} permission.
 *
 * <p>
 * To check if secure lock is already enabled on the device, call
 * {@link #isSecureLockDeviceEnabled}. This will require the caller to have the
 * {@link android.Manifest.permission#MANAGE_SECURE_LOCK_DEVICE} permission.
 *
 * @hide
 */
@SystemApi
@@ -71,8 +82,7 @@ public final class AuthenticationPolicyManager {
    public static final int SUCCESS = 0;

    /**
     * Error result code for {@link #enableSecureLockDevice} and {@link
     * #disableSecureLockDevice}.
     * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
     *
     * Secure lock device request status unknown.
     *
@@ -141,6 +151,15 @@ public final class AuthenticationPolicyManager {
    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
    public static final int ERROR_ALREADY_ENABLED = 6;

    /**
     * Error result code for {@link #disableSecureLockDevice}
     *
     * @hide
     */
    @SystemApi
    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
    public static final int ERROR_NOT_AUTHORIZED = 7;

    /**
     * Communicates the current status of a request to enable secure lock on the device.
     *
@@ -168,10 +187,26 @@ public final class AuthenticationPolicyManager {
            ERROR_UNKNOWN,
            ERROR_UNSUPPORTED,
            ERROR_INVALID_PARAMS,
            ERROR_NOT_AUTHORIZED
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface DisableSecureLockDeviceRequestStatus {}

    /**
     * Communicates the current status of a request to check if the device meets the requirements
     * for secure lock device.
     *
     * @hide
     */
    @IntDef(prefix = {"IS_SECURE_LOCK_DEVICE_AVAILABLE_STATUS_"}, value = {
            SUCCESS,
            ERROR_UNSUPPORTED,
            ERROR_NO_BIOMETRICS_ENROLLED,
            ERROR_INSUFFICIENT_BIOMETRICS,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface IsSecureLockDeviceAvailableRequestStatus {}

    /** @hide */
    public AuthenticationPolicyManager(@NonNull Context context,
            @NonNull IAuthenticationPolicyService authenticationPolicyService) {
@@ -180,21 +215,51 @@ public final class AuthenticationPolicyManager {
    }

    /**
     * Called by a privileged component to remotely enable secure lock on the device.
     * Called by a privileged component to indicate if secure lock device is available for the
     * calling user.
     *
     * @return {@link IsSecureLockDeviceAvailableRequestStatus} int indicating whether secure lock
     * device is available for the calling user. This will return {@link #SUCCESS} if the device
     * meets all requirements to enable secure lock device, {@link #ERROR_INSUFFICIENT_BIOMETRICS}
     * if the device is missing a strong biometric enrollment, {@link #ERROR_NO_BIOMETRICS_ENROLLED}
     * if the device has no biometric enrollments, or {@link #ERROR_UNSUPPORTED} if secure lock
     * device is otherwise unsupported.
     *
     * @hide
     */
    @IsSecureLockDeviceAvailableRequestStatus
    @RequiresPermission(MANAGE_SECURE_LOCK_DEVICE)
    @SystemApi
    @FlaggedApi(FLAG_SECURE_LOCK_DEVICE)
    public int isSecureLockDeviceAvailable() {
        try {
            return mAuthenticationPolicyService.isSecureLockDeviceAvailable(mContext.getUser());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }


    /**
     * Called by a privileged component to remotely enable secure lock on the device across all
     * users. This operation will first check {@link #isSecureLockDeviceAvailable()} to see if the
     * calling user meets the requirements to enable secure lock device, including a strong
     * biometric enrollment, and will return an error if not.
     *
     * Secure lock is an enhanced security state that restricts access to sensitive data (app
     * notifications, widgets, quick settings, assistant, etc) and requires multi-factor
     * authentication for device entry, such as
     * notifications, widgets, quick settings, assistant, etc), and locks the device under the
     * calling user's credentials with multi-factor authentication for device entry, such as
     * {@link android.hardware.biometrics.BiometricManager.Authenticators#DEVICE_CREDENTIAL} and
     * {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_STRONG}.
     *
     * If secure lock is already enabled when this method is called, it will return
     * {@link ERROR_ALREADY_ENABLED}.
     * {@link #ERROR_ALREADY_ENABLED}.
     *
     * @param params EnableSecureLockDeviceParams for caller to supply params related to the secure
     *               lock device request
     * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the secure lock
     * device request
     * @param params {@link EnableSecureLockDeviceParams} for caller to supply params related to
     *                                                   the secure lock device request
     * @return {@link EnableSecureLockDeviceRequestStatus} int indicating the result of the secure
     * lock device request. This returns {@link #SUCCESS} if secure lock device is successfully
     * enabled, or an error code indicating more information about the failure otherwise.
     *
     * @hide
     */
@@ -204,22 +269,27 @@ public final class AuthenticationPolicyManager {
    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
    public int enableSecureLockDevice(@NonNull EnableSecureLockDeviceParams params) {
        try {
            return mAuthenticationPolicyService.enableSecureLockDevice(params);
            return mAuthenticationPolicyService.enableSecureLockDevice(mContext.getUser(), params);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Called by a privileged component to disable secure lock on the device.
     * Called by a privileged component to disable secure lock on the device across all users. This
     * operation is restricted to the user that originally enabled the current secure lock device
     * state.
     *
     * If the calling user identity does not match the user that enabled secure lock device, it
     * will return {@link #ERROR_NOT_AUTHORIZED}
     *
     * If secure lock is already disabled when this method is called, it will return
     * {@link SUCCESS}.
     * {@link #SUCCESS}.
     *
     * @param params @DisableSecureLockDeviceParams for caller to supply params related to the
     *               secure lock device request
     * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the secure lock
     * device request
     * @param params {@link DisableSecureLockDeviceParams} for caller to supply params related to
     *                                                    the secure lock device request
     * @return {@link DisableSecureLockDeviceRequestStatus} int indicating the result of the secure
     * lock device request
     *
     * @hide
     */
@@ -229,7 +299,24 @@ public final class AuthenticationPolicyManager {
    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
    public int disableSecureLockDevice(@NonNull DisableSecureLockDeviceParams params) {
        try {
            return mAuthenticationPolicyService.disableSecureLockDevice(params);
            return mAuthenticationPolicyService.disableSecureLockDevice(mContext.getUser(), params);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Called by a privileged component to query if secure lock device is currently enabled.
     * @return true if secure lock device is enabled, false otherwise.
     *
     * @hide
     */
    @RequiresPermission(MANAGE_SECURE_LOCK_DEVICE)
    @SystemApi
    @FlaggedApi(FLAG_SECURE_LOCK_DEVICE)
    public boolean isSecureLockDeviceEnabled() {
        try {
            return mAuthenticationPolicyService.isSecureLockDeviceEnabled();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+9 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.security.authenticationpolicy;

import android.os.UserHandle;
import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
import android.security.authenticationpolicy.DisableSecureLockDeviceParams;

@@ -25,8 +26,14 @@ import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
 */
interface IAuthenticationPolicyService {
    @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE")
    int enableSecureLockDevice(in EnableSecureLockDeviceParams params);
    int enableSecureLockDevice(in UserHandle user, in EnableSecureLockDeviceParams params);

    @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE")
    int disableSecureLockDevice(in DisableSecureLockDeviceParams params);
    int disableSecureLockDevice(in UserHandle user, in DisableSecureLockDeviceParams params);

    @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE")
    int isSecureLockDeviceAvailable(in UserHandle user);

    @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE")
    boolean isSecureLockDeviceEnabled();
}
 No newline at end of file
+95 −15
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.security.authenticationpolicy;

import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE;
import static android.security.Flags.disableAdaptiveAuthCounterLock;

@@ -34,18 +35,22 @@ import android.hardware.biometrics.events.AuthenticationHelpInfo;
import android.hardware.biometrics.events.AuthenticationStartedInfo;
import android.hardware.biometrics.events.AuthenticationStoppedInfo;
import android.hardware.biometrics.events.AuthenticationSucceededInfo;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.security.authenticationpolicy.AuthenticationPolicyManager;
import android.security.authenticationpolicy.AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus;
import android.security.authenticationpolicy.AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus;
import android.security.authenticationpolicy.AuthenticationPolicyManager.IsSecureLockDeviceAvailableRequestStatus;
import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
import android.security.authenticationpolicy.IAuthenticationPolicyService;
import android.util.Log;
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
@@ -67,7 +72,7 @@ import java.util.Objects;
 */
public class AuthenticationPolicyService extends SystemService {
    private static final String TAG = "AuthenticationPolicyService";
    private static final boolean DEBUG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.DEBUG);
    private static final boolean DEBUG = Build.IS_DEBUGGABLE;

    @VisibleForTesting
    static final int MAX_ALLOWED_FAILED_AUTH_ATTEMPTS = 5;
@@ -323,35 +328,110 @@ public class AuthenticationPolicyService extends SystemService {
        mLastLockedTimestamp.put(userId, SystemClock.elapsedRealtime());
    }

    /**
     * Require that the caller userId matches the context userId, or that the caller has the
     * permission to interact across users.
     *
     * @param targetUser userId of the target user of the operation
     * @param message a message to include in the exception if it is thrown.
     */
    private void enforceCrossUserPermission(UserHandle targetUser, String message) {
        if (targetUser.getIdentifier() == UserHandle.getCallingUserId()) {
            return;
        }
        getContext().enforceCallingOrSelfPermission(
                INTERACT_ACROSS_USERS_FULL,
                message);
    }

    private final IBinder mService = new IAuthenticationPolicyService.Stub() {
        /**
         * @see AuthenticationPolicyManager#isSecureLockDeviceAvailable()
         * @param user user associated with the calling context to check for secure lock device
         *             availability
         * @return {@link IsSecureLockDeviceAvailableRequestStatus} int indicating whether secure
         * lock device is available for the calling user
         */
        @Override
        @EnforcePermission(MANAGE_SECURE_LOCK_DEVICE)
        @IsSecureLockDeviceAvailableRequestStatus
        public int isSecureLockDeviceAvailable(UserHandle user) {
            isSecureLockDeviceAvailable_enforcePermission();
            enforceCrossUserPermission(user, TAG + "#isSecureLockDeviceAvailable");

            // Required for internal service to acquire necessary system permissions
            final long identity = Binder.clearCallingIdentity();
            try {
                return mSecureLockDeviceService.isSecureLockDeviceAvailable(user);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        /**
         * @see AuthenticationPolicyManager#enableSecureLockDevice(EnableSecureLockDeviceParams)
         * @param params EnableSecureLockDeviceParams for caller to supply params related
         *               to the secure lock device request
         * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the Secure
         * Lock Device request
         * @param user user associated with the calling context to check for secure lock device
         *             availability
         * @return {@link EnableSecureLockDeviceRequestStatus} int indicating the result of the
         * Secure Lock Device request
         */
        @Override
        @EnforcePermission(MANAGE_SECURE_LOCK_DEVICE)
        @AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus
        public int enableSecureLockDevice(EnableSecureLockDeviceParams params) {
        @EnableSecureLockDeviceRequestStatus
        public int enableSecureLockDevice(UserHandle user, EnableSecureLockDeviceParams params) {
            enableSecureLockDevice_enforcePermission();
            return mSecureLockDeviceService.enableSecureLockDevice(params);
            enforceCrossUserPermission(user, TAG + "#enableSecureLockDevice");
            // Required for internal service to acquire necessary system permissions
            final long identity = Binder.clearCallingIdentity();
            try {
                return mSecureLockDeviceService.enableSecureLockDevice(user, params);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        /**
         * @see AuthenticationPolicyManager#disableSecureLockDevice(DisableSecureLockDeviceParams)
         * @param params @DisableSecureLockDeviceParams for caller to supply params related
         *               to the secure lock device request
         * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the Secure
         * Lock Device request
         * @param user user associated with the calling context to verify it matches the user that
         *             enabled secure lock device
         * @return {@link DisableSecureLockDeviceRequestStatus} int indicating the result of the
         * Secure Lock Device request
         */
        @Override
        @EnforcePermission(MANAGE_SECURE_LOCK_DEVICE)
        @AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus
        public int disableSecureLockDevice(DisableSecureLockDeviceParams params) {
        @DisableSecureLockDeviceRequestStatus
        public int disableSecureLockDevice(UserHandle user, DisableSecureLockDeviceParams params) {
            disableSecureLockDevice_enforcePermission();
            return mSecureLockDeviceService.disableSecureLockDevice(params);
            enforceCrossUserPermission(user, TAG + "#disableSecureLockDevice");

            // Required for internal service to acquire necessary system permissions
            final long identity = Binder.clearCallingIdentity();
            try {
                return mSecureLockDeviceService.disableSecureLockDevice(user, params);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        /**
         * @see AuthenticationPolicyManager#isSecureLockDeviceEnabled()
         * @return true if secure lock device is enabled, false otherwise
         */
        @Override
        @EnforcePermission(MANAGE_SECURE_LOCK_DEVICE)
        public boolean isSecureLockDeviceEnabled() {
            isSecureLockDeviceEnabled_enforcePermission();
            // Required for internal service to acquire necessary system permissions
            final long identity = Binder.clearCallingIdentity();
            try {
                return mSecureLockDeviceService.isSecureLockDeviceEnabled();
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    };
}
 No newline at end of file
+451 −19

File changed.

Preview size limit exceeded, changes collapsed.

Loading