From 3a464785088e7fd206666f640912729533948ce8 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Fri, 28 Aug 2015 16:59:13 -0700 Subject: Add a private API to get notified about lockout resets SystemUI uses it to start authentication again after lockout reset expired. Bug: 22846755 Change-Id: I90a987c6aa4ac52cc7e7aff1bce262d1db3f12ee --- Android.mk | 1 + .../hardware/fingerprint/FingerprintManager.java | 43 ++++++++++++- .../hardware/fingerprint/IFingerprintService.aidl | 4 ++ .../IFingerprintServiceLockoutResetCallback.aidl | 28 +++++++++ .../android/keyguard/KeyguardUpdateMonitor.java | 16 +++++ .../server/fingerprint/FingerprintService.java | 70 +++++++++++++++++++++- 6 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl diff --git a/Android.mk b/Android.mk index 6f5f8f9..9ddb777 100644 --- a/Android.mk +++ b/Android.mk @@ -160,6 +160,7 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \ core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \ core/java/android/hardware/fingerprint/IFingerprintService.aidl \ + core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \ core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \ core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \ core/java/android/hardware/hdmi/IHdmiControlService.aidl \ diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 7cff11b..1f23c0a 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -392,6 +392,18 @@ public class FingerprintManager { }; /** + * @hide + */ + public static abstract class LockoutResetCallback { + + /** + * Called when lockout period expired and clients are allowed to listen for fingerprint + * again. + */ + public void onLockoutReset() { } + }; + + /** * Request authentication of a crypto object. This call warms up the fingerprint hardware * and starts scanning for a fingerprint. It terminates when * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or @@ -680,10 +692,37 @@ public class FingerprintManager { try { mService.resetTimeout(token); } catch (RemoteException e) { - Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e); + Log.v(TAG, "Remote exception in resetTimeout(): ", e); } } else { - Log.w(TAG, "getAuthenticatorId(): Service not connected!"); + Log.w(TAG, "resetTimeout(): Service not connected!"); + } + } + + /** + * @hide + */ + public void addLockoutResetCallback(final LockoutResetCallback callback) { + if (mService != null) { + try { + mService.addLockoutResetCallback( + new IFingerprintServiceLockoutResetCallback.Stub() { + + @Override + public void onLockoutReset(long deviceId) throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + callback.onLockoutReset(); + } + }); + } + }); + } catch (RemoteException e) { + Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e); + } + } else { + Log.w(TAG, "addLockoutResetCallback(): Service not connected!"); } } diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 3356354..690a751 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -17,6 +17,7 @@ package android.hardware.fingerprint; import android.os.Bundle; import android.hardware.fingerprint.IFingerprintServiceReceiver; +import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback; import android.hardware.fingerprint.Fingerprint; import java.util.List; @@ -71,4 +72,7 @@ interface IFingerprintService { // Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password) void resetTimeout(in byte [] cryptoToken); + + // Add a callback which gets notified when the fingerprint lockout period expired. + void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback); } diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl new file mode 100644 index 0000000..c9a5d59 --- /dev/null +++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 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.hardware.fingerprint; + +import android.hardware.fingerprint.Fingerprint; +import android.os.Bundle; +import android.os.UserHandle; + +/** + * Callback when lockout period expired and clients are allowed to authenticate again. + * @hide + */ +oneway interface IFingerprintServiceLockoutResetCallback { + void onLockoutReset(long deviceId); +} diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index fc6117f..cfc232c 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -29,6 +29,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; import android.graphics.Bitmap; +import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; @@ -472,6 +473,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } + private void handleFingerprintLockoutReset() { + updateFingerprintListeningState(); + } + private void setFingerprintRunningState(int fingerprintRunningState) { boolean wasRunning = mFingerprintRunningState == FINGERPRINT_STATE_RUNNING; boolean isRunning = fingerprintRunningState == FINGERPRINT_STATE_RUNNING; @@ -681,6 +686,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } }; + private final FingerprintManager.LockoutResetCallback mLockoutResetCallback + = new FingerprintManager.LockoutResetCallback() { + @Override + public void onLockoutReset() { + handleFingerprintLockoutReset(); + } + }; + private FingerprintManager.AuthenticationCallback mAuthenticationCallback = new AuthenticationCallback() { @@ -1003,6 +1016,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE); updateFingerprintListeningState(); + if (mFpm != null) { + mFpm.addLockoutResetCallback(mLockoutResetCallback); + } } private void updateFingerprintListeningState() { diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index 7e46db8..cbb3c39 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -24,7 +24,9 @@ import android.app.IUserSwitchObserver; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback; import android.os.Binder; +import android.os.DeadObjectException; import android.os.Environment; import android.os.Handler; import android.os.IBinder; @@ -51,7 +53,6 @@ import android.hardware.fingerprint.IFingerprintService; import android.hardware.fingerprint.IFingerprintDaemon; import android.hardware.fingerprint.IFingerprintDaemonCallback; import android.hardware.fingerprint.IFingerprintServiceReceiver; -import android.view.Display; import static android.Manifest.permission.MANAGE_FINGERPRINT; import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT; @@ -60,6 +61,7 @@ import static android.Manifest.permission.USE_FINGERPRINT; import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -83,6 +85,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe private ClientMonitor mAuthClient = null; private ClientMonitor mEnrollClient = null; private ClientMonitor mRemoveClient = null; + private final ArrayList mLockoutMonitors = + new ArrayList<>(); private final AppOpsManager mAppOps; private static final long MS_PER_SEC = 1000; @@ -259,6 +263,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe // If we're asked to reset failed attempts externally (i.e. from Keyguard), the runnable // may still be in the queue; remove it. mHandler.removeCallbacks(mLockoutReset); + notifyLockoutResetMonitors(); } private boolean handleFailedAttempt(ClientMonitor clientMonitor) { @@ -499,6 +504,23 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe opPackageName) == AppOpsManager.MODE_ALLOWED; } + private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) { + if (!mLockoutMonitors.contains(monitor)) { + mLockoutMonitors.add(monitor); + } + } + + private void removeLockoutResetCallback( + FingerprintServiceLockoutResetMonitor monitor) { + mLockoutMonitors.remove(monitor); + } + + private void notifyLockoutResetMonitors() { + for (int i = 0; i < mLockoutMonitors.size(); i++) { + mLockoutMonitors.get(i).sendLockoutReset(); + } + } + private class ClientMonitor implements IBinder.DeathRecipient { IBinder token; IFingerprintServiceReceiver receiver; @@ -614,7 +636,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe FingerprintUtils.vibrateFingerprintSuccess(getContext()); } result |= true; // we have a valid fingerprint - mLockoutReset.run(); + mHandler.post(mLockoutReset); } return result; } @@ -654,6 +676,36 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } } + private class FingerprintServiceLockoutResetMonitor { + + private final IFingerprintServiceLockoutResetCallback mCallback; + + public FingerprintServiceLockoutResetMonitor( + IFingerprintServiceLockoutResetCallback callback) { + mCallback = callback; + } + + public void sendLockoutReset() { + if (mCallback != null) { + try { + mCallback.onLockoutReset(mHalDeviceId); + } catch (DeadObjectException e) { + Slog.w(TAG, "Death object while invoking onLockoutReset: ", e); + mHandler.post(mRemoveCallbackRunnable); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to invoke onLockoutReset: ", e); + } + } + } + + private final Runnable mRemoveCallbackRunnable = new Runnable() { + @Override + public void run() { + removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this); + } + }; + } + private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() { @Override @@ -922,7 +974,19 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe public void resetTimeout(byte [] token) { checkPermission(RESET_FINGERPRINT_LOCKOUT); // TODO: confirm security token when we move timeout management into the HAL layer. - mLockoutReset.run(); + mHandler.post(mLockoutReset); + } + + @Override + public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback) + throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + addLockoutResetMonitor( + new FingerprintServiceLockoutResetMonitor(callback)); + } + }); } } -- cgit v1.1