diff options
Diffstat (limited to 'core/java')
5 files changed, 329 insertions, 8 deletions
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index dc71a3237b0b..14afd0fcebf8 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -17,6 +17,7 @@ package android.app; import android.Manifest; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -40,8 +41,10 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; +import android.os.UserHandle; import android.provider.Settings; import android.service.persistentdata.IPersistentDataBlockService; +import android.util.ArrayMap; import android.util.Log; import android.view.IOnKeyguardExitResult; import android.view.IWindowManager; @@ -49,6 +52,9 @@ import android.view.WindowManager.LayoutParams; import android.view.WindowManagerGlobal; import com.android.internal.policy.IKeyguardDismissCallback; +import com.android.internal.util.Preconditions; +import com.android.internal.widget.IWeakEscrowTokenActivatedListener; +import com.android.internal.widget.IWeakEscrowTokenRemovedListener; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockscreenCredential; @@ -57,6 +63,8 @@ import com.android.internal.widget.VerifyCredentialResponse; import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executor; /** * Class that can be used to lock and unlock the keyguard. The @@ -69,10 +77,13 @@ public class KeyguardManager { private static final String TAG = "KeyguardManager"; private final Context mContext; + private final LockPatternUtils mLockPatternUtils; private final IWindowManager mWM; private final IActivityManager mAm; private final ITrustManager mTrustManager; private final INotificationManager mNotificationManager; + private final ArrayMap<WeakEscrowTokenRemovedListener, IWeakEscrowTokenRemovedListener> + mListeners = new ArrayMap<>(); /** * Intent used to prompt user for device credentials. @@ -455,8 +466,42 @@ public class KeyguardManager { public void onDismissCancelled() { } } + /** + * Callback passed to + * {@link KeyguardManager#addWeakEscrowToken} + * to notify caller of state change. + * @hide + */ + @SystemApi + public interface WeakEscrowTokenActivatedListener { + /** + * The method to be called when the token is activated. + * @param handle 64 bit handle corresponding to the escrow token + * @param user user for whom the weak escrow token has been added + */ + void onWeakEscrowTokenActivated(long handle, @NonNull UserHandle user); + } + + /** + * Listener passed to + * {@link KeyguardManager#registerWeakEscrowTokenRemovedListener} and + * {@link KeyguardManager#unregisterWeakEscrowTokenRemovedListener} + * to notify caller of an weak escrow token has been removed. + * @hide + */ + @SystemApi + public interface WeakEscrowTokenRemovedListener { + /** + * The method to be called when the token is removed. + * @param handle 64 bit handle corresponding to the escrow token + * @param user user for whom the escrow token has been added + */ + void onWeakEscrowTokenRemoved(long handle, @NonNull UserHandle user); + } + KeyguardManager(Context context) throws ServiceNotFoundException { mContext = context; + mLockPatternUtils = new LockPatternUtils(context); mWM = WindowManagerGlobal.getWindowManagerService(); mAm = ActivityManager.getService(); mTrustManager = ITrustManager.Stub.asInterface( @@ -785,7 +830,6 @@ public class KeyguardManager { return false; } - LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); int userId = mContext.getUserId(); if (isDeviceSecure(userId)) { Log.e(TAG, "Password already set, rejecting call to setLock"); @@ -799,7 +843,7 @@ public class KeyguardManager { try { LockscreenCredential credential = createLockscreenCredential( lockType, password); - success = lockPatternUtils.setLockCredential( + success = mLockPatternUtils.setLockCredential( credential, /* savedPassword= */ LockscreenCredential.createNone(), userId); @@ -813,6 +857,150 @@ public class KeyguardManager { } /** + * Create a weak escrow token for the current user, which can later be used to unlock FBE + * or change user password. + * + * After adding, if the user currently has a secure lockscreen, they will need to perform a + * confirm credential operation in order to activate the token for future use. If the user + * has no secure lockscreen, then the token is activated immediately. + * + * If the user changes or removes the lockscreen password, any activated weak escrow token will + * be removed. + * + * @return a unique 64-bit token handle which is needed to refer to this token later. + * @hide + */ + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) + @SystemApi + public long addWeakEscrowToken(@NonNull byte[] token, @NonNull UserHandle user, + @NonNull @CallbackExecutor Executor executor, + @NonNull WeakEscrowTokenActivatedListener listener) { + Objects.requireNonNull(token, "Token cannot be null."); + Objects.requireNonNull(user, "User cannot be null."); + Objects.requireNonNull(executor, "Executor cannot be null."); + Objects.requireNonNull(listener, "Listener cannot be null."); + int userId = user.getIdentifier(); + IWeakEscrowTokenActivatedListener internalListener = + new IWeakEscrowTokenActivatedListener.Stub() { + @Override + public void onWeakEscrowTokenActivated(long handle, int userId) { + UserHandle user = UserHandle.of(userId); + final long restoreToken = Binder.clearCallingIdentity(); + try { + executor.execute(() -> listener.onWeakEscrowTokenActivated(handle, user)); + } finally { + Binder.restoreCallingIdentity(restoreToken); + } + Log.i(TAG, "Weak escrow token activated."); + } + }; + return mLockPatternUtils.addWeakEscrowToken(token, userId, internalListener); + } + + /** + * Remove a weak escrow token. + * + * @return true if the given handle refers to a valid weak token previously returned from + * {@link #addWeakEscrowToken}, whether it's active or not. return false otherwise. + * @hide + */ + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) + @SystemApi + public boolean removeWeakEscrowToken(long handle, @NonNull UserHandle user) { + Objects.requireNonNull(user, "User cannot be null."); + return mLockPatternUtils.removeWeakEscrowToken(handle, user.getIdentifier()); + } + + /** + * Check if the given weak escrow token is active or not. + * @hide + */ + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) + @SystemApi + public boolean isWeakEscrowTokenActive(long handle, @NonNull UserHandle user) { + Objects.requireNonNull(user, "User cannot be null."); + return mLockPatternUtils.isWeakEscrowTokenActive(handle, user.getIdentifier()); + } + + /** + * Check if the given weak escrow token is validate. + * @hide + */ + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) + @SystemApi + public boolean isWeakEscrowTokenValid(long handle, @NonNull byte[] token, + @NonNull UserHandle user) { + Objects.requireNonNull(token, "Token cannot be null."); + Objects.requireNonNull(user, "User cannot be null."); + return mLockPatternUtils.isWeakEscrowTokenValid(handle, token, user.getIdentifier()); + } + + /** + * Register the given WeakEscrowTokenRemovedListener. + * + * @return true if the listener is registered successfully, return false otherwise. + * @hide + */ + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) + @SystemApi + public boolean registerWeakEscrowTokenRemovedListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull WeakEscrowTokenRemovedListener listener) { + Objects.requireNonNull(listener, "Listener cannot be null."); + Objects.requireNonNull(executor, "Executor cannot be null."); + Preconditions.checkArgument(!mListeners.containsKey(listener), + "Listener already registered: %s", listener); + IWeakEscrowTokenRemovedListener internalListener = + new IWeakEscrowTokenRemovedListener.Stub() { + @Override + public void onWeakEscrowTokenRemoved(long handle, int userId) { + UserHandle user = UserHandle.of(userId); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> listener.onWeakEscrowTokenRemoved(handle, user)); + } finally { + Binder.restoreCallingIdentity(token); + } + } + }; + if (mLockPatternUtils.registerWeakEscrowTokenRemovedListener(internalListener)) { + mListeners.put(listener, internalListener); + return true; + } else { + Log.e(TAG, "Listener failed to register"); + return false; + } + } + + /** + * Unregister the given WeakEscrowTokenRemovedListener. + * + * @return true if the listener is unregistered successfully, return false otherwise. + * @hide + */ + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + @RequiresPermission(Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) + @SystemApi + public boolean unregisterWeakEscrowTokenRemovedListener( + @NonNull WeakEscrowTokenRemovedListener listener) { + Objects.requireNonNull(listener, "Listener cannot be null."); + IWeakEscrowTokenRemovedListener internalListener = mListeners.get(listener); + Preconditions.checkArgument(internalListener != null, "Listener was not registered"); + if (mLockPatternUtils.unregisterWeakEscrowTokenRemovedListener(internalListener)) { + mListeners.remove(listener); + return true; + } else { + Log.e(TAG, "Listener failed to unregister."); + return false; + } + } + + /** * Set the lockscreen password to {@code newPassword} after validating the current password * against {@code currentPassword}. * <p>If no password is currently set, {@code currentPassword} should be set to {@code null}. @@ -832,13 +1020,12 @@ public class KeyguardManager { }) public boolean setLock(@LockTypes int newLockType, @Nullable byte[] newPassword, @LockTypes int currentLockType, @Nullable byte[] currentPassword) { - final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); final int userId = mContext.getUserId(); LockscreenCredential currentCredential = createLockscreenCredential( currentLockType, currentPassword); LockscreenCredential newCredential = createLockscreenCredential( newLockType, newPassword); - return lockPatternUtils.setLockCredential(newCredential, currentCredential, userId); + return mLockPatternUtils.setLockCredential(newCredential, currentCredential, userId); } /** @@ -857,10 +1044,9 @@ public class KeyguardManager { Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE }) public boolean checkLock(@LockTypes int lockType, @Nullable byte[] password) { - final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); final LockscreenCredential credential = createLockscreenCredential( lockType, password); - final VerifyCredentialResponse response = lockPatternUtils.verifyCredential( + final VerifyCredentialResponse response = mLockPatternUtils.verifyCredential( credential, mContext.getUserId(), /* flags= */ 0); if (response == null) { return false; diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index d16d9c619403..db4bc2c7e24a 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -24,6 +24,8 @@ import android.security.keystore.recovery.KeyChainSnapshot; import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.RecoveryCertPath; import com.android.internal.widget.ICheckCredentialProgressCallback; +import com.android.internal.widget.IWeakEscrowTokenActivatedListener; +import com.android.internal.widget.IWeakEscrowTokenRemovedListener; import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.VerifyCredentialResponse; @@ -96,4 +98,10 @@ interface ILockSettings { boolean tryUnlockWithCachedUnifiedChallenge(int userId); void removeCachedUnifiedChallenge(int userId); void updateEncryptionPassword(int type, in byte[] password); + boolean registerWeakEscrowTokenRemovedListener(in IWeakEscrowTokenRemovedListener listener); + boolean unregisterWeakEscrowTokenRemovedListener(in IWeakEscrowTokenRemovedListener listener); + long addWeakEscrowToken(in byte[] token, int userId, in IWeakEscrowTokenActivatedListener callback); + boolean removeWeakEscrowToken(long handle, int userId); + boolean isWeakEscrowTokenActive(long handle, int userId); + boolean isWeakEscrowTokenValid(long handle, in byte[] token, int userId); } diff --git a/core/java/com/android/internal/widget/IWeakEscrowTokenActivatedListener.aidl b/core/java/com/android/internal/widget/IWeakEscrowTokenActivatedListener.aidl new file mode 100644 index 000000000000..9c8d9d61848d --- /dev/null +++ b/core/java/com/android/internal/widget/IWeakEscrowTokenActivatedListener.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 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.internal.widget; + +/** @hide */ +oneway interface IWeakEscrowTokenActivatedListener { + void onWeakEscrowTokenActivated(long handle, int userId); +} diff --git a/core/java/com/android/internal/widget/IWeakEscrowTokenRemovedListener.aidl b/core/java/com/android/internal/widget/IWeakEscrowTokenRemovedListener.aidl new file mode 100644 index 000000000000..70180484ce58 --- /dev/null +++ b/core/java/com/android/internal/widget/IWeakEscrowTokenRemovedListener.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 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.internal.widget; + +/** @hide */ +oneway interface IWeakEscrowTokenRemovedListener { + void onWeakEscrowTokenRemoved(long handle, int userId); +} diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 5a032774c207..f91776eaf259 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -1236,6 +1236,28 @@ public class LockPatternUtils { } } + /** Register the given WeakEscrowTokenRemovedListener. */ + public boolean registerWeakEscrowTokenRemovedListener( + @NonNull final IWeakEscrowTokenRemovedListener listener) { + try { + return getLockSettings().registerWeakEscrowTokenRemovedListener(listener); + } catch (RemoteException e) { + Log.e(TAG, "Could not register WeakEscrowTokenRemovedListener."); + throw e.rethrowFromSystemServer(); + } + } + + /** Unregister the given WeakEscrowTokenRemovedListener. */ + public boolean unregisterWeakEscrowTokenRemovedListener( + @NonNull final IWeakEscrowTokenRemovedListener listener) { + try { + return getLockSettings().unregisterWeakEscrowTokenRemovedListener(listener); + } catch (RemoteException e) { + Log.e(TAG, "Could not register WeakEscrowTokenRemovedListener."); + throw e.rethrowFromSystemServer(); + } + } + public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) { try { getLockSettings().reportSuccessfulBiometricUnlock(isStrongBiometric, userId); @@ -1355,15 +1377,38 @@ public class LockPatternUtils { } /** + * Create a weak escrow token for the current user, which can later be used to unlock FBE + * or change user password. + * + * After adding, if the user currently has lockscreen password, they will need to perform a + * confirm credential operation in order to activate the token for future use. If the user + * has no secure lockscreen, then the token is activated immediately. + * + * If the user changes or removes lockscreen password, activated weak escrow tokens will be + * removed. + * + * @return a unique 64-bit token handle which is needed to refer to this token later. + */ + public long addWeakEscrowToken(byte[] token, int userId, + @NonNull IWeakEscrowTokenActivatedListener callback) { + try { + return getLockSettings().addWeakEscrowToken(token, userId, callback); + } catch (RemoteException e) { + Log.e(TAG, "Could not add weak token."); + throw e.rethrowFromSystemServer(); + } + } + + /** * Callback interface to notify when an added escrow token has been activated. */ public interface EscrowTokenStateChangeCallback { /** * The method to be called when the token is activated. * @param handle 64 bit handle corresponding to the escrow token - * @param userid user for whom the escrow token has been added + * @param userId user for whom the escrow token has been added */ - void onEscrowTokenActivated(long handle, int userid); + void onEscrowTokenActivated(long handle, int userId); } /** @@ -1379,6 +1424,21 @@ public class LockPatternUtils { } /** + * Remove a weak escrow token. + * + * @return true if the given handle refers to a valid weak token previously returned from + * {@link #addWeakEscrowToken}, whether it's active or not. return false otherwise. + */ + public boolean removeWeakEscrowToken(long handle, int userId) { + try { + return getLockSettings().removeWeakEscrowToken(handle, userId); + } catch (RemoteException e) { + Log.e(TAG, "Could not remove the weak token."); + throw e.rethrowFromSystemServer(); + } + } + + /** * Check if the given escrow token is active or not. Only active token can be used to call * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken} * @@ -1389,6 +1449,29 @@ public class LockPatternUtils { } /** + * Check if the given weak escrow token is active or not. Only active token can be used to call + * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken} + */ + public boolean isWeakEscrowTokenActive(long handle, int userId) { + try { + return getLockSettings().isWeakEscrowTokenActive(handle, userId); + } catch (RemoteException e) { + Log.e(TAG, "Could not check the weak token."); + throw e.rethrowFromSystemServer(); + } + } + + /** Check if the given weak escrow token is valid. */ + public boolean isWeakEscrowTokenValid(long handle, byte[] token, int userId) { + try { + return getLockSettings().isWeakEscrowTokenValid(handle, token, userId); + } catch (RemoteException e) { + Log.e(TAG, "Could not validate the weak token."); + throw e.rethrowFromSystemServer(); + } + } + + /** * Change a user's lock credential with a pre-configured escrow token. * * <p>This method is only available to code running in the system server process itself. |
