From b3cf50a338ac7eaf897a11161135a49671994823 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Fri, 9 Oct 2020 12:43:20 -0700 Subject: [PATCH] 4/n: Add RevokeChallenge and ResetLockout for IFingerprint Bug: 168843828 Test: Builds Change-Id: I73631dd82498975044997ee623fdec61fd6b4599 --- .../fingerprint/FingerprintManager.java | 15 +++- .../fingerprint/IFingerprintService.aidl | 2 +- .../fingerprint/FingerprintService.java | 5 +- .../sensors/fingerprint/ServiceProvider.java | 2 +- .../FingerprintGenerateChallengeClient.java | 2 +- .../fingerprint/aidl/FingerprintProvider.java | 43 +++++++++- .../aidl/FingerprintResetLockoutClient.java | 78 +++++++++++++++++++ .../FingerprintRevokeChallengeClient.java | 65 ++++++++++++++++ .../fingerprint/aidl/LockoutCache.java | 47 +++++++++++ .../sensors/fingerprint/aidl/Sensor.java | 17 ++++ .../fingerprint/hidl/Fingerprint21.java | 2 +- 11 files changed, 266 insertions(+), 12 deletions(-) create mode 100644 services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRevokeChallengeClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index b76b877234d78..3eab1445563af 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -617,13 +617,24 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** - * Finishes enrollment and cancels the current auth token. + * Revokes the current challenge. * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) public void revokeChallenge() { + // On HALs with only single in-flight challenge such as IBiometricsFingerprint@2.1, + // this parameter is ignored. + revokeChallenge(0L); + } + + /** + * Revokes the specified challenge. + * @hide + */ + @RequiresPermission(MANAGE_FINGERPRINT) + public void revokeChallenge(long challenge) { if (mService != null) try { - mService.revokeChallenge(mToken, mContext.getOpPackageName()); + mService.revokeChallenge(mToken, mContext.getOpPackageName(), challenge); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index f467b1dbd412b..6b0fdd4ff80ff 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -91,7 +91,7 @@ interface IFingerprintService { void generateChallenge(IBinder token, int sensorId, IFingerprintServiceReceiver receiver, String opPackageName); // Finish an enrollment sequence and invalidate the authentication token - void revokeChallenge(IBinder token, String opPackageName); + void revokeChallenge(IBinder token, String opPackageName, long challenge); // Determine if a user has at least one enrolled fingerprint boolean hasEnrolledFingerprints(int userId, String opPackageName); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 165755a2febe9..3040791cd027c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -121,7 +121,7 @@ public class FingerprintService extends SystemService { } @Override // Binder call - public void revokeChallenge(IBinder token, String opPackageName) { + public void revokeChallenge(IBinder token, String opPackageName, long challenge) { Utils.checkPermission(getContext(), MANAGE_FINGERPRINT); final Pair provider = getSingleProvider(); @@ -130,7 +130,8 @@ public class FingerprintService extends SystemService { return; } - provider.second.scheduleRevokeChallenge(provider.first, token, opPackageName); + provider.second.scheduleRevokeChallenge(provider.first, token, opPackageName, + challenge); } @Override // Binder call diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java index 1162c9c1241f0..35d01882f0c6e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java @@ -68,7 +68,7 @@ public interface ServiceProvider { @NonNull IFingerprintServiceReceiver receiver, String opPackageName); void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token, - @NonNull String opPackageName); + @NonNull String opPackageName, long challenge); void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken, int userId, @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName, diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java index 3a6b11349b664..7db01eed571ef 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java @@ -34,7 +34,7 @@ public class FingerprintGenerateChallengeClient extends GenerateChallengeClient< private static final String TAG = "FingerprintGenerateChallengeClient"; private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes - private IGenerateChallengeCallback mGenerateChallengeCallback = + private final IGenerateChallengeCallback mGenerateChallengeCallback = new IGenerateChallengeCallback.Stub() { @Override public void onChallengeGenerated(int sensorId, int userId, long challenge) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index 44a23cff6324c..0b59086fb9071 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -24,6 +24,7 @@ import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.fingerprint.IFingerprint; import android.hardware.biometrics.fingerprint.SensorProps; import android.hardware.fingerprint.Fingerprint; +import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.IUdfpsOverlayController; @@ -58,6 +59,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @NonNull private final SparseArray mSensors; // Map of sensors that this HAL supports @NonNull private final ClientMonitor.LazyDaemon mLazyDaemon; @NonNull private final Handler mHandler; + @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; @Nullable private IUdfpsOverlayController mUdfpsOverlayController; @@ -69,6 +71,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi mSensors = new SparseArray<>(); mLazyDaemon = this::getHalInstance; mHandler = new Handler(Looper.getMainLooper()); + mLockoutResetDispatcher = lockoutResetDispatcher; for (SensorProps prop : props) { final int sensorId = prop.commonProps.sensorId; @@ -157,7 +160,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @NonNull @Override public List getSensorProperties() { - List props = new ArrayList<>(); + final List props = new ArrayList<>(); for (int i = 0; i < mSensors.size(); i++) { props.add(mSensors.valueAt(i).getSensorProperties()); } @@ -166,7 +169,27 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @Override public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) { + mHandler.post(() -> { + final IFingerprint daemon = getHalInstance(); + if (daemon == null) { + Slog.e(getTag(), "Null daemon during resetLockout, sensorId: " + sensorId); + return; + } + try { + if (!mSensors.get(sensorId).hasSessionForUser(userId)) { + scheduleCreateSessionWithoutHandler(daemon, sensorId, userId); + } + + final FingerprintResetLockoutClient client = new FingerprintResetLockoutClient( + mContext, mSensors.get(sensorId).getLazySession(), userId, + mContext.getOpPackageName(), sensorId, hardwareAuthToken, + mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher); + scheduleForSensor(sensorId, client); + } catch (RemoteException e) { + Slog.e(getTag(), "Remote exception when scheduling resetLockout", e); + } + }); } @Override @@ -176,14 +199,19 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi final FingerprintGenerateChallengeClient client = new FingerprintGenerateChallengeClient(mContext, mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), opPackageName, sensorId); - mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client); + scheduleForSensor(sensorId, client); }); } @Override public void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token, - @NonNull String opPackageName) { - + @NonNull String opPackageName, long challenge) { + mHandler.post(() -> { + final FingerprintRevokeChallengeClient client = + new FingerprintRevokeChallengeClient(mContext, mLazyDaemon, token, + opPackageName, sensorId, challenge); + scheduleForSensor(sensorId, client); + }); } @Override @@ -194,6 +222,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi final IFingerprint daemon = getHalInstance(); if (daemon == null) { Slog.e(getTag(), "Null daemon during enroll, sensorId: " + sensorId); + + try { + receiver.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, + 0 /* vendorCode */); + } catch (RemoteException e) { + Slog.e(getTag(), "Unable to send HW_UNAVAILABLE", e); + } return; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java new file mode 100644 index 0000000000000..bc35ad4b2807f --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors.fingerprint.aidl; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.fingerprint.IFingerprint; +import android.hardware.biometrics.fingerprint.ISession; +import android.hardware.keymaster.HardwareAuthToken; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.HardwareAuthTokenUtils; +import com.android.server.biometrics.sensors.ClientMonitor; +import com.android.server.biometrics.sensors.LockoutResetDispatcher; +import com.android.server.biometrics.sensors.LockoutTracker; + +/** + * Fingerprint-specific resetLockout client for the {@link IFingerprint} AIDL HAL interface. + * Updates the framework's lockout cache and notifies clients such as Keyguard when lockout is + * cleared. + */ +public class FingerprintResetLockoutClient extends ClientMonitor { + + private static final String TAG = "FingerprintResetLockoutClient"; + + private final HardwareAuthToken mHardwareAuthToken; + private final LockoutCache mLockoutCache; + private final LockoutResetDispatcher mLockoutResetDispatcher; + + public FingerprintResetLockoutClient(@NonNull Context context, + @NonNull LazyDaemon lazyDaemon, int userId, String owner, int sensorId, + @NonNull byte[] hardwareAuthToken, @NonNull LockoutCache lockoutTracker, + @NonNull LockoutResetDispatcher lockoutResetDispatcher) { + super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner, + 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN, + BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN); + mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken); + mLockoutCache = lockoutTracker; + mLockoutResetDispatcher = lockoutResetDispatcher; + } + + @Override + public void unableToStart() { + // Nothing to do here + } + + @Override + protected void startHalOperation() { + try { + getFreshDaemon().resetLockout(mSequentialId, mHardwareAuthToken); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to reset lockout", e); + mCallback.onClientFinished(this, false /* success */); + } + } + + void onLockoutCleared() { + mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_NONE); + mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId()); + mCallback.onClientFinished(this, true /* success */); + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRevokeChallengeClient.java new file mode 100644 index 0000000000000..e97dbe795f749 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRevokeChallengeClient.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors.fingerprint.aidl; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.fingerprint.IFingerprint; +import android.hardware.biometrics.fingerprint.IRevokeChallengeCallback; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.sensors.RevokeChallengeClient; + +/** + * Fingerprint-specific revokeChallenge client for the {@link IFingerprint} AIDL HAL interface. + */ +public class FingerprintRevokeChallengeClient extends RevokeChallengeClient { + + private static final String TAG = "FingerpirntRevokeChallengeClient"; + + private final long mChallenge; + + private final IRevokeChallengeCallback mRevokeChallengeCallback = + new IRevokeChallengeCallback.Stub() { + @Override + public void onChallengeRevoked(int sensorId, int userId, long challenge) { + final boolean success = challenge == mChallenge; + mCallback.onClientFinished(FingerprintRevokeChallengeClient.this, success); + } + }; + + public FingerprintRevokeChallengeClient( + @NonNull Context context, + @NonNull LazyDaemon lazyDaemon, + @NonNull IBinder token, + @NonNull String owner, int sensorId, long challenge) { + super(context, lazyDaemon, token, owner, sensorId); + mChallenge = challenge; + } + + @Override + protected void startHalOperation() { + try { + getFreshDaemon().revokeChallenge(getSensorId(), getTargetUserId(), mChallenge, + mRevokeChallengeCallback); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to revokeChallenge", e); + } + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java new file mode 100644 index 0000000000000..2abbcb0c7493b --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors.fingerprint.aidl; + +import android.util.SparseIntArray; + +import com.android.server.biometrics.sensors.LockoutTracker; + +/** + * For a single sensor, caches lockout states for all users. + */ +public class LockoutCache implements LockoutTracker { + + // Map of userId to LockoutMode + private final SparseIntArray mUserLockoutStates; + + LockoutCache() { + mUserLockoutStates = new SparseIntArray(); + } + + public void setLockoutModeForUser(int userId, @LockoutMode int mode) { + synchronized (this) { + mUserLockoutStates.put(userId, mode); + } + } + + @Override + public int getLockoutModeForUser(int userId) { + synchronized (this) { + return mUserLockoutStates.get(userId, LOCKOUT_NONE); + } + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java index 3c27f9c68c31f..2ed695d8821e6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java @@ -54,6 +54,7 @@ class Sensor { @NonNull private final Handler mHandler; @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties; @NonNull private final BiometricScheduler mScheduler; + @NonNull private final LockoutCache mLockoutCache; @Nullable private Session mCurrentSession; // TODO: Death recipient @NonNull private final ClientMonitor.LazyDaemon mLazySession; @@ -82,6 +83,7 @@ class Sensor { mHandler = handler; mSensorProperties = sensorProperties; mScheduler = new BiometricScheduler(tag, gestureAvailabilityDispatcher); + mLockoutCache = new LockoutCache(); mLazySession = () -> mCurrentSession != null ? mCurrentSession.mSession : null; } @@ -217,7 +219,18 @@ class Sensor { @Override public void onLockoutCleared() { + mHandler.post(() -> { + final ClientMonitor client = mScheduler.getCurrentClient(); + if (!(client instanceof FingerprintResetLockoutClient)) { + Slog.e(mTag, "onLockoutCleared for non-resetLockout client: " + + Utils.getClientName(client)); + return; + } + final FingerprintResetLockoutClient resetLockoutClient = + (FingerprintResetLockoutClient) client; + resetLockoutClient.onLockoutCleared(); + }); } @Override @@ -253,4 +266,8 @@ class Sensor { @NonNull BiometricScheduler getScheduler() { return mScheduler; } + + @NonNull LockoutCache getLockoutCache() { + return mLockoutCache; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index 8ce99f4e8decd..fedcfa576d354 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -518,7 +518,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider @Override public void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token, - @NonNull String opPackageName) { + @NonNull String opPackageName, long challenge) { mHandler.post(() -> { final FingerprintRevokeChallengeClient client = new FingerprintRevokeChallengeClient( mContext, mLazyDaemon, token, opPackageName, mSensorProperties.sensorId);