diff options
| author | 2024-11-14 15:48:59 +0000 | |
|---|---|---|
| committer | 2024-11-18 05:13:33 +0000 | |
| commit | 43300b49dce6cb286ce5535b59b116d2033affec (patch) | |
| tree | 06ea35e541a06f5ef5930b72059a65fe479f264a | |
| parent | 0e92f9364ff9eaf79d31f934029ca06ebdee9eaa (diff) | |
Define Secure Lock Device API surface
Secure Lock is a new feature that enables users to remotely lock
down their mobile device via authorized clients into an enhanced
security state, which restricts access to sensitive data (app
notifications, widgets, quick settings, assistant, etc) and requires
both credential and biometric authentication for device entry.
This change introduces a new AuthenticationPolicyManager, which
external clients will use to call into SecureLockDeviceService via
AuthenticationPolicyService. SecureLockDeviceService implements the new
enableSecureLockDevice and disableSecureLockDevice API methods, which
currently have a placeholder no-op implementation that will be filled
out at a later time.
Bug: 373422357
API-Coverage-Bug: 376456619
Flag: android.security.secure_lockdown
Test: atest AuthenticationPolicyServiceTest
Ignore-AOSP-First: adding flag to security package
Change-Id: I7d2c97a8f51cb8a4475761a6c04ce9f32b38fd19
15 files changed, 797 insertions, 2 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 9456f9f5eaea..433d80a22a6e 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3870,6 +3870,7 @@ package android.content { field public static final String APP_INTEGRITY_SERVICE = "app_integrity"; field public static final String APP_PREDICTION_SERVICE = "app_prediction"; field public static final String AUDIO_DEVICE_VOLUME_SERVICE = "audio_device_volume"; + field @FlaggedApi("android.security.secure_lockdown") public static final String AUTHENTICATION_POLICY_SERVICE = "authentication_policy"; field public static final String BACKUP_SERVICE = "backup"; field public static final String BATTERY_STATS_SERVICE = "batterystats"; field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000 @@ -12859,6 +12860,36 @@ package android.security.advancedprotection { } +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); + 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_NO_BIOMETRICS_ENROLLED = 4; // 0x4 + field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_UNKNOWN = 0; // 0x0 + field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_UNSUPPORTED = 2; // 0x2 + field @FlaggedApi("android.security.secure_lockdown") public static final int SUCCESS = 1; // 0x1 + } + + @FlaggedApi("android.security.secure_lockdown") public final class DisableSecureLockDeviceParams implements android.os.Parcelable { + ctor public DisableSecureLockDeviceParams(@NonNull String); + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.DisableSecureLockDeviceParams> CREATOR; + } + + @FlaggedApi("android.security.secure_lockdown") public final class EnableSecureLockDeviceParams implements android.os.Parcelable { + ctor public EnableSecureLockDeviceParams(@NonNull String); + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.EnableSecureLockDeviceParams> CREATOR; + } + +} + package android.security.forensic { @FlaggedApi("android.security.afl_api") public class ForensicManager { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 53a7dad76788..6a23349bf8aa 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -241,6 +241,8 @@ import android.security.advancedprotection.AdvancedProtectionManager; import android.security.advancedprotection.IAdvancedProtectionService; import android.security.attestationverification.AttestationVerificationManager; import android.security.attestationverification.IAttestationVerificationManagerService; +import android.security.authenticationpolicy.AuthenticationPolicyManager; +import android.security.authenticationpolicy.IAuthenticationPolicyService; import android.security.forensic.ForensicManager; import android.security.forensic.IForensicService; import android.security.keystore.KeyStoreManager; @@ -1025,6 +1027,25 @@ public final class SystemServiceRegistry { } }); + registerService(Context.AUTHENTICATION_POLICY_SERVICE, + AuthenticationPolicyManager.class, + new CachedServiceFetcher<AuthenticationPolicyManager>() { + @Override + public AuthenticationPolicyManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + if (!android.security.Flags.secureLockdown()) { + throw new ServiceNotFoundException( + Context.AUTHENTICATION_POLICY_SERVICE); + } + + final IBinder binder = ServiceManager.getServiceOrThrow( + Context.AUTHENTICATION_POLICY_SERVICE); + final IAuthenticationPolicyService service = + IAuthenticationPolicyService.Stub.asInterface(binder); + return new AuthenticationPolicyManager(ctx.getOuterContext(), service); + } + }); + registerService(Context.TV_INTERACTIVE_APP_SERVICE, TvInteractiveAppManager.class, new CachedServiceFetcher<TvInteractiveAppManager>() { @Override diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 6086f2455a31..5754e7e30c34 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -18,6 +18,7 @@ package android.content; import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER; import static android.content.flags.Flags.FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS; +import static android.security.Flags.FLAG_SECURE_LOCKDOWN; import android.annotation.AttrRes; import android.annotation.CallbackExecutor; @@ -4256,6 +4257,7 @@ public abstract class Context { FINGERPRINT_SERVICE, //@hide: FACE_SERVICE, BIOMETRIC_SERVICE, + AUTHENTICATION_POLICY_SERVICE, MEDIA_ROUTER_SERVICE, TELEPHONY_SERVICE, TELEPHONY_SUBSCRIPTION_SERVICE, @@ -4437,6 +4439,9 @@ public abstract class Context { * web domain approval state. * <dt> {@link #DISPLAY_HASH_SERVICE} ("display_hash") * <dd> A {@link android.view.displayhash.DisplayHashManager} for management of display hashes. + * <dt> {@link #AUTHENTICATION_POLICY_SERVICE} ("authentication_policy") + * <dd> A {@link android.security.authenticationpolicy.AuthenticationPolicyManager} + * for managing authentication related policies on the device. * </dl> * * <p>Note: System services obtained via this API may be closely associated with @@ -4521,6 +4526,8 @@ public abstract class Context { * @see android.content.pm.verify.domain.DomainVerificationManager * @see #DISPLAY_HASH_SERVICE * @see android.view.displayhash.DisplayHashManager + * @see #AUTHENTICATION_POLICY_SERVICE + * @see android.security.authenticationpolicy.AuthenticationPolicyManager */ // TODO(b/347269120): Re-add @Nullable public abstract Object getSystemService(@ServiceName @NonNull String name); @@ -4543,7 +4550,8 @@ public abstract class Context { * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler}, * {@link android.app.usage.NetworkStatsManager}, * {@link android.content.pm.verify.domain.DomainVerificationManager}, - * {@link android.view.displayhash.DisplayHashManager}. + * {@link android.view.displayhash.DisplayHashManager} + * {@link android.security.authenticationpolicy.AuthenticationPolicyManager}. * </p> * * <p> @@ -5183,6 +5191,18 @@ public abstract class Context { public static final String AUTH_SERVICE = "auth"; /** + * Use with {@link #getSystemService(String)} to retrieve an {@link + * android.security.authenticationpolicy.AuthenticationPolicyManager}. + * @see #getSystemService + * @see android.security.authenticationpolicy.AuthenticationPolicyManager + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final String AUTHENTICATION_POLICY_SERVICE = "authentication_policy"; + + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.hardware.fingerprint.FingerprintManager} for handling management * of fingerprints. diff --git a/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java b/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java new file mode 100644 index 000000000000..75abd5fa4bb0 --- /dev/null +++ b/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2024 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.security.authenticationpolicy; + +import static android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE; +import static android.security.Flags.FLAG_SECURE_LOCKDOWN; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.content.Context; +import android.os.RemoteException; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * AuthenticationPolicyManager is a centralized interface for managing authentication related + * policies on the device. This includes device locking capabilities to protect users in "at risk" + * environments. + * + * AuthenticationPolicyManager is designed to protect Android users by integrating with apps and + * key system components, such as the lock screen. It is not related to enterprise control surfaces + * and does not offer additional administrative controls. + * + * <p> + * To use this class, call {@link #enableSecureLockDevice} to enable secure lock on the device. + * This will require the caller to have the + * {@link android.Manifest.permission#MANAGE_SECURE_LOCK_DEVICE} permission. + * + * <p> + * 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. + * + * @hide + */ +@SystemApi +@FlaggedApi(FLAG_SECURE_LOCKDOWN) +@SystemService(Context.AUTHENTICATION_POLICY_SERVICE) +public final class AuthenticationPolicyManager { + private static final String TAG = "AuthenticationPolicyManager"; + + @NonNull private final IAuthenticationPolicyService mAuthenticationPolicyService; + @NonNull private final Context mContext; + + /** + * Error result code for {@link #enableSecureLockDevice} and {@link + * #disableSecureLockDevice}. + * + * Secure lock device request status unknown. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_UNKNOWN = 0; + + /** + * Success result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}. + * + * Secure lock device request successful. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int SUCCESS = 1; + + /** + * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}. + * + * Secure lock device is unsupported. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_UNSUPPORTED = 2; + + + /** + * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}. + * + * Invalid secure lock device request params provided. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_INVALID_PARAMS = 3; + + + /** + * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}. + * + * Secure lock device is unavailable because there are no biometrics enrolled on the device. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_NO_BIOMETRICS_ENROLLED = 4; + + /** + * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}. + * + * Secure lock device is unavailable because the device has no biometric hardware or the + * biometric sensors do not meet + * {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_STRONG} + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_INSUFFICIENT_BIOMETRICS = 5; + + /** + * Error result code for {@link #enableSecureLockDevice}. + * + * Secure lock is already enabled. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_ALREADY_ENABLED = 6; + + /** + * Communicates the current status of a request to enable secure lock on the device. + * + * @hide + */ + @IntDef(prefix = {"ENABLE_SECURE_LOCK_DEVICE_STATUS_"}, value = { + ERROR_UNKNOWN, + SUCCESS, + ERROR_UNSUPPORTED, + ERROR_INVALID_PARAMS, + ERROR_NO_BIOMETRICS_ENROLLED, + ERROR_INSUFFICIENT_BIOMETRICS, + ERROR_ALREADY_ENABLED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EnableSecureLockDeviceRequestStatus {} + + /** + * Communicates the current status of a request to disable secure lock on the device. + * + * @hide + */ + @IntDef(prefix = {"DISABLE_SECURE_LOCK_DEVICE_STATUS_"}, value = { + ERROR_UNKNOWN, + SUCCESS, + ERROR_UNSUPPORTED, + ERROR_INVALID_PARAMS, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DisableSecureLockDeviceRequestStatus {} + + /** @hide */ + public AuthenticationPolicyManager(@NonNull Context context, + @NonNull IAuthenticationPolicyService authenticationPolicyService) { + mContext = context; + mAuthenticationPolicyService = authenticationPolicyService; + } + + /** + * Called by a privileged component to remotely enable secure lock on the device. + * + * 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 + * {@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}. + * + * @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 + * + * @hide + */ + @EnableSecureLockDeviceRequestStatus + @RequiresPermission(MANAGE_SECURE_LOCK_DEVICE) + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public int enableSecureLockDevice(@NonNull EnableSecureLockDeviceParams params) { + try { + return mAuthenticationPolicyService.enableSecureLockDevice(params); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Called by a privileged component to disable secure lock on the device. + * + * If secure lock is already disabled when this method is called, it will return + * {@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 + * + * @hide + */ + @DisableSecureLockDeviceRequestStatus + @RequiresPermission(MANAGE_SECURE_LOCK_DEVICE) + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public int disableSecureLockDevice(@NonNull DisableSecureLockDeviceParams params) { + try { + return mAuthenticationPolicyService.disableSecureLockDevice(params); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl new file mode 100644 index 000000000000..81f7726a500c --- /dev/null +++ b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 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.security.authenticationpolicy; + +/** + * @hide + */ +parcelable DisableSecureLockDeviceParams;
\ No newline at end of file diff --git a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java new file mode 100644 index 000000000000..64a3f0f60f96 --- /dev/null +++ b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 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.security.authenticationpolicy; + +import static android.security.Flags.FLAG_SECURE_LOCKDOWN; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Parameters related to a request to disable secure lock on the device. + * + * @hide + */ +@SystemApi +@FlaggedApi(FLAG_SECURE_LOCKDOWN) +public final class DisableSecureLockDeviceParams implements Parcelable { + + /** + * Client message associated with the request to disable secure lock on the device. This message + * will be shown on the device when secure lock mode is disabled. + */ + private final @NonNull String mMessage; + + /** + * Creates DisableSecureLockDeviceParams with the given params. + * + * @param message Allows clients to pass in a message with information about the request to + * disable secure lock on the device. This message will be shown to the user when + * secure lock mode is disabled. If an empty string is provided, it will default + * to a system-defined string (e.g. "Secure lock mode has been disabled.") + */ + public DisableSecureLockDeviceParams(@NonNull String message) { + mMessage = message; + } + + private DisableSecureLockDeviceParams(@NonNull Parcel in) { + mMessage = Objects.requireNonNull(in.readString8()); + } + + public static final @NonNull Creator<DisableSecureLockDeviceParams> CREATOR = + new Creator<DisableSecureLockDeviceParams>() { + @Override + public DisableSecureLockDeviceParams createFromParcel(Parcel in) { + return new DisableSecureLockDeviceParams(in); + } + + @Override + public DisableSecureLockDeviceParams[] newArray(int size) { + return new DisableSecureLockDeviceParams[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString8(mMessage); + } +} diff --git a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl new file mode 100644 index 000000000000..9e496f82ec69 --- /dev/null +++ b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 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.security.authenticationpolicy; + +/** + * @hide + */ +parcelable EnableSecureLockDeviceParams;
\ No newline at end of file diff --git a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java new file mode 100644 index 000000000000..1d727727ce37 --- /dev/null +++ b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 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.security.authenticationpolicy; + +import static android.security.Flags.FLAG_SECURE_LOCKDOWN; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + + +/** + * Parameters related to a request to enable secure lock on the device. + * + * @hide + */ +@SystemApi +@FlaggedApi(FLAG_SECURE_LOCKDOWN) +public final class EnableSecureLockDeviceParams implements Parcelable { + + /** + * Client message associated with the request to enable secure lock on the device. This message + * will be shown on the device when secure lock mode is enabled. + */ + private final @NonNull String mMessage; + + /** + * Creates EnableSecureLockDeviceParams with the given params. + * + * @param message Allows clients to pass in a message with information about the request to + * enable secure lock on the device. This message will be shown to the user when + * secure lock mode is enabled. If an empty string is provided, it will default + * to a system-defined string (e.g. "Device is securely locked remotely.") + */ + public EnableSecureLockDeviceParams(@NonNull String message) { + mMessage = message; + } + + private EnableSecureLockDeviceParams(@NonNull Parcel in) { + mMessage = Objects.requireNonNull(in.readString8()); + } + + public static final @NonNull Creator<EnableSecureLockDeviceParams> CREATOR = + new Creator<EnableSecureLockDeviceParams>() { + @Override + public EnableSecureLockDeviceParams createFromParcel(Parcel in) { + return new EnableSecureLockDeviceParams(in); + } + + @Override + public EnableSecureLockDeviceParams[] newArray(int size) { + return new EnableSecureLockDeviceParams[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString8(mMessage); + } +} diff --git a/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl b/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl new file mode 100644 index 000000000000..5ad4534c257a --- /dev/null +++ b/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 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.security.authenticationpolicy; + +import android.security.authenticationpolicy.EnableSecureLockDeviceParams; +import android.security.authenticationpolicy.DisableSecureLockDeviceParams; + +/** + * Communication channel from AuthenticationPolicyManager to AuthenticationPolicyService. + * @hide + */ +interface IAuthenticationPolicyService { + @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE") + int enableSecureLockDevice(in EnableSecureLockDeviceParams params); + + @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE") + int disableSecureLockDevice(in DisableSecureLockDeviceParams params); +}
\ No newline at end of file diff --git a/core/java/android/security/authenticationpolicy/OWNERS b/core/java/android/security/authenticationpolicy/OWNERS new file mode 100644 index 000000000000..4310d1a3a9db --- /dev/null +++ b/core/java/android/security/authenticationpolicy/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/security/authenticationpolicy/OWNERS
\ No newline at end of file diff --git a/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java index b8a4a9c26feb..6798a6146ae0 100644 --- a/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java +++ b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java @@ -16,8 +16,11 @@ package com.android.server.security.authenticationpolicy; +import static android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE; + import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST; +import android.annotation.EnforcePermission; import android.app.KeyguardManager; import android.content.Context; import android.content.pm.PackageManager; @@ -32,9 +35,14 @@ import android.hardware.biometrics.events.AuthenticationStoppedInfo; import android.hardware.biometrics.events.AuthenticationSucceededInfo; 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.security.authenticationpolicy.AuthenticationPolicyManager; +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; @@ -74,6 +82,7 @@ public class AuthenticationPolicyService extends SystemService { private final KeyguardManager mKeyguardManager; private final WindowManagerInternal mWindowManager; private final UserManagerInternal mUserManager; + private SecureLockDeviceServiceInternal mSecureLockDeviceService; @VisibleForTesting final SparseIntArray mFailedAttemptsForUser = new SparseIntArray(); private final SparseLongArray mLastLockedTimestamp = new SparseLongArray(); @@ -94,10 +103,16 @@ public class AuthenticationPolicyService extends SystemService { mWindowManager = Objects.requireNonNull( LocalServices.getService(WindowManagerInternal.class)); mUserManager = Objects.requireNonNull(LocalServices.getService(UserManagerInternal.class)); + if (android.security.Flags.secureLockdown()) { + mSecureLockDeviceService = Objects.requireNonNull( + LocalServices.getService(SecureLockDeviceServiceInternal.class)); + } } @Override - public void onStart() {} + public void onStart() { + publishBinderService(Context.AUTHENTICATION_POLICY_SERVICE, mService); + } @Override public void onBootPhase(int phase) { @@ -294,4 +309,36 @@ public class AuthenticationPolicyService extends SystemService { // next successful primary or biometric auth happens mLastLockedTimestamp.put(userId, SystemClock.elapsedRealtime()); } + + private final IBinder mService = new IAuthenticationPolicyService.Stub() { + /** + * @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 + */ + @Override + @EnforcePermission(MANAGE_SECURE_LOCK_DEVICE) + @AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus + public int enableSecureLockDevice(EnableSecureLockDeviceParams params) { + enableSecureLockDevice_enforcePermission(); + return mSecureLockDeviceService.enableSecureLockDevice(params); + } + + /** + * @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 + */ + @Override + @EnforcePermission(MANAGE_SECURE_LOCK_DEVICE) + @AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus + public int disableSecureLockDevice(DisableSecureLockDeviceParams params) { + disableSecureLockDevice_enforcePermission(); + return mSecureLockDeviceService.disableSecureLockDevice(params); + } + }; } diff --git a/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceService.java b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceService.java new file mode 100644 index 000000000000..7b89723deb6c --- /dev/null +++ b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceService.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2024 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.server.security.authenticationpolicy; + +import android.annotation.NonNull; +import android.content.Context; +import android.security.authenticationpolicy.AuthenticationPolicyManager; +import android.security.authenticationpolicy.AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus; +import android.security.authenticationpolicy.AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus; +import android.security.authenticationpolicy.DisableSecureLockDeviceParams; +import android.security.authenticationpolicy.EnableSecureLockDeviceParams; +import android.util.Slog; + +import com.android.server.LocalServices; +import com.android.server.SystemService; + +/** + * System service for remotely calling secure lock on the device. + * + * Callers will access this class via + * {@link com.android.server.security.authenticationpolicy.AuthenticationPolicyService}. + * + * @see AuthenticationPolicyService + * @see AuthenticationPolicyManager#enableSecureLockDevice + * @see AuthenticationPolicyManager#disableSecureLockDevice + * @hide + */ +public class SecureLockDeviceService extends SecureLockDeviceServiceInternal { + private static final String TAG = "SecureLockDeviceService"; + private final Context mContext; + + public SecureLockDeviceService(@NonNull Context context) { + mContext = context; + } + + private void start() { + // Expose private service for system components to use. + LocalServices.addService(SecureLockDeviceServiceInternal.class, this); + } + + /** + * @see AuthenticationPolicyManager#enableSecureLockDevice + * @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 + * + * @hide + */ + @Override + @EnableSecureLockDeviceRequestStatus + public int enableSecureLockDevice(EnableSecureLockDeviceParams params) { + // (1) Call into system_server to lock device, configure allowed auth types + // for secure lock + // TODO: lock device, configure allowed authentication types for device entry + // (2) Call into framework to configure secure lock 2FA lockscreen + // update, UI & string updates + // TODO: implement 2FA lockscreen when SceneContainerFlag.isEnabled() + // TODO: implement 2FA lockscreen when !SceneContainerFlag.isEnabled() + // (3) Call into framework to configure keyguard security updates + // TODO: implement security updates + return AuthenticationPolicyManager.ERROR_UNSUPPORTED; + } + + /** + * @see AuthenticationPolicyManager#disableSecureLockDevice + * @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 + * + * @hide + */ + @Override + @DisableSecureLockDeviceRequestStatus + public int disableSecureLockDevice(DisableSecureLockDeviceParams params) { + // (1) Call into system_server to reset allowed auth types + // TODO: reset allowed authentication types for device entry; + // (2) Call into framework to disable secure lock 2FA lockscreen, reset UI + // & string updates + // TODO: implement reverting to normal lockscreen when SceneContainerFlag.isEnabled() + // TODO: implement reverting to normal lockscreen when !SceneContainerFlag.isEnabled() + // (3) Call into framework to revert keyguard security updates + // TODO: implement reverting security updates + return AuthenticationPolicyManager.ERROR_UNSUPPORTED; + } + + /** + * System service lifecycle. + */ + public static final class Lifecycle extends SystemService { + private final SecureLockDeviceService mService; + + public Lifecycle(@NonNull Context context) { + super(context); + mService = new SecureLockDeviceService(context); + } + + @Override + public void onStart() { + Slog.i(TAG, "Starting SecureLockDeviceService"); + mService.start(); + Slog.i(TAG, "Started SecureLockDeviceService"); + } + } +} diff --git a/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceServiceInternal.java b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceServiceInternal.java new file mode 100644 index 000000000000..b90370956d8b --- /dev/null +++ b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceServiceInternal.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2024 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.server.security.authenticationpolicy; + +import android.security.authenticationpolicy.AuthenticationPolicyManager; +import android.security.authenticationpolicy.AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus; +import android.security.authenticationpolicy.AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus; +import android.security.authenticationpolicy.DisableSecureLockDeviceParams; +import android.security.authenticationpolicy.EnableSecureLockDeviceParams; + +/** + * Local system service interface for {@link SecureLockDeviceService}. + * + * <p>No permission / argument checks will be performed inside. + * Callers must check the calling app permission and the calling package name. + * + * @hide + */ +public abstract class SecureLockDeviceServiceInternal { + private static final String TAG = "SecureLockDeviceServiceInternal"; + + /** + * @see AuthenticationPolicyManager#enableSecureLockDevice(EnableSecureLockDeviceParams) + * @param params EnableSecureLockDeviceParams for caller to supply params related + * to the secure lock request + * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the + * secure lock request + */ + @EnableSecureLockDeviceRequestStatus + public abstract int enableSecureLockDevice(EnableSecureLockDeviceParams params); + + /** + * @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 + */ + @DisableSecureLockDeviceRequestStatus + public abstract int disableSecureLockDevice(DisableSecureLockDeviceParams params); +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index da478f38498b..0dc1ac32c379 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -251,6 +251,7 @@ import com.android.server.security.KeyAttestationApplicationIdProviderService; import com.android.server.security.KeyChainSystemService; import com.android.server.security.advancedprotection.AdvancedProtectionService; import com.android.server.security.authenticationpolicy.AuthenticationPolicyService; +import com.android.server.security.authenticationpolicy.SecureLockDeviceService; import com.android.server.security.forensic.ForensicService; import com.android.server.security.rkp.RemoteProvisioningService; import com.android.server.selinux.SelinuxAuditLogsService; @@ -2659,6 +2660,12 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(AuthService.class); t.traceEnd(); + if (android.security.Flags.secureLockdown()) { + t.traceBegin("StartSecureLockDeviceService.Lifecycle"); + mSystemServiceManager.startService(SecureLockDeviceService.Lifecycle.class); + t.traceEnd(); + } + if (android.adaptiveauth.Flags.enableAdaptiveAuth()) { t.traceBegin("StartAuthenticationPolicyService"); mSystemServiceManager.startService(AuthenticationPolicyService.class); diff --git a/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java index 2238a1be97a1..ee8eb9b35088 100644 --- a/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java @@ -19,12 +19,14 @@ package com.android.server.security.authenticationpolicy; import static android.adaptiveauth.Flags.FLAG_ENABLE_ADAPTIVE_AUTH; import static android.adaptiveauth.Flags.FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS; import static android.security.Flags.FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS; +import static android.security.authenticationpolicy.AuthenticationPolicyManager.ERROR_UNSUPPORTED; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST; import static com.android.server.security.authenticationpolicy.AuthenticationPolicyService.MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; import static org.junit.Assert.assertEquals; import static org.junit.Assume.assumeTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -95,6 +97,8 @@ public class AuthenticationPolicyServiceTest { private WindowManagerInternal mWindowManager; @Mock private UserManagerInternal mUserManager; + @Mock + private SecureLockDeviceServiceInternal mSecureLockDeviceService; @Captor ArgumentCaptor<LockSettingsStateListener> mLockSettingsStateListenerCaptor; @@ -123,6 +127,11 @@ public class AuthenticationPolicyServiceTest { LocalServices.addService(WindowManagerInternal.class, mWindowManager); LocalServices.removeServiceForTest(UserManagerInternal.class); LocalServices.addService(UserManagerInternal.class, mUserManager); + if (android.security.Flags.secureLockdown()) { + LocalServices.removeServiceForTest(SecureLockDeviceServiceInternal.class); + LocalServices.addService(SecureLockDeviceServiceInternal.class, + mSecureLockDeviceService); + } mAuthenticationPolicyService = new AuthenticationPolicyService( mContext, mLockPatternUtils); @@ -136,6 +145,12 @@ public class AuthenticationPolicyServiceTest { // Set PRIMARY_USER_ID as the parent of MANAGED_PROFILE_USER_ID when(mUserManager.getProfileParentId(eq(MANAGED_PROFILE_USER_ID))) .thenReturn(PRIMARY_USER_ID); + if (android.security.Flags.secureLockdown()) { + when(mSecureLockDeviceService.enableSecureLockDevice(any())) + .thenReturn(ERROR_UNSUPPORTED); + when(mSecureLockDeviceService.disableSecureLockDevice(any())) + .thenReturn(ERROR_UNSUPPORTED); + } } @After @@ -143,6 +158,9 @@ public class AuthenticationPolicyServiceTest { LocalServices.removeServiceForTest(LockSettingsInternal.class); LocalServices.removeServiceForTest(WindowManagerInternal.class); LocalServices.removeServiceForTest(UserManagerInternal.class); + if (android.security.Flags.secureLockdown()) { + LocalServices.removeServiceForTest(SecureLockDeviceServiceInternal.class); + } } @Test |