summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/KeyguardManager.java198
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl8
-rw-r--r--core/java/com/android/internal/widget/IWeakEscrowTokenActivatedListener.aidl22
-rw-r--r--core/java/com/android/internal/widget/IWeakEscrowTokenRemovedListener.aidl22
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java87
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.