summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/SystemServiceRegistry.java8
-rw-r--r--core/java/android/content/Context.java30
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java4
-rw-r--r--core/java/android/hardware/biometrics/IAuthService.aidl51
-rw-r--r--core/java/android/hardware/biometrics/IBiometricService.aidl5
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java228
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java54
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java194
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java44
10 files changed, 533 insertions, 91 deletions
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 33ea32b7e31e..69c174a47127 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -68,7 +68,7 @@ import android.hardware.SensorPrivacyManager;
import android.hardware.SerialManager;
import android.hardware.SystemSensorManager;
import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.IAuthService;
import android.hardware.camera2.CameraManager;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.DisplayManager;
@@ -947,9 +947,9 @@ public final class SystemServiceRegistry {
throws ServiceNotFoundException {
if (BiometricManager.hasBiometrics(ctx)) {
final IBinder binder =
- ServiceManager.getServiceOrThrow(Context.BIOMETRIC_SERVICE);
- final IBiometricService service =
- IBiometricService.Stub.asInterface(binder);
+ ServiceManager.getServiceOrThrow(Context.AUTH_SERVICE);
+ final IAuthService service =
+ IAuthService.Stub.asInterface(binder);
return new BiometricManager(ctx.getOuterContext(), service);
} else {
// Allow access to the manager when service is null. This saves memory
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 03b49136bde4..392353aac4a2 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3289,6 +3289,7 @@ public abstract class Context {
WIFI_RTT_RANGING_SERVICE,
NSD_SERVICE,
AUDIO_SERVICE,
+ AUTH_SERVICE,
FINGERPRINT_SERVICE,
//@hide: FACE_SERVICE,
BIOMETRIC_SERVICE,
@@ -4007,6 +4008,31 @@ public abstract class Context {
public static final String AUDIO_SERVICE = "audio";
/**
+ * AuthService orchestrates biometric and PIN/pattern/password authentication.
+ *
+ * BiometricService was split into two services, AuthService and BiometricService, where
+ * AuthService is the high level service that orchestrates all types of authentication, and
+ * BiometricService is a lower layer responsible only for biometric authentication.
+ *
+ * Ideally we should have renamed BiometricManager to AuthManager, because it logically
+ * corresponds to AuthService. However, because BiometricManager is a public API, we kept
+ * the old name but changed the internal implementation to use AuthService.
+ *
+ * As of now, the AUTH_SERVICE constant is only used to identify the service in
+ * SystemServiceRegistry and SELinux. To obtain the manager for AUTH_SERVICE, one should use
+ * BIOMETRIC_SERVICE with {@link #getSystemService(String)} to retrieve a
+ * {@link android.hardware.biometrics.BiometricManager}
+ *
+ * Map of the two services and their managers:
+ * [Service] [Manager]
+ * AuthService BiometricManager
+ * BiometricService N/A
+ *
+ * @hide
+ */
+ public static final String AUTH_SERVICE = "auth";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.hardware.fingerprint.FingerprintManager} for handling management
* of fingerprints.
@@ -4040,8 +4066,8 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve a
- * {@link android.hardware.biometrics.BiometricManager} for handling management
- * of face authentication.
+ * {@link android.hardware.biometrics.BiometricManager} for handling
+ * biometric and PIN/pattern/password authentication.
*
* @see #getSystemService
* @see android.hardware.biometrics.BiometricManager
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 9d427c8d8bab..f17b3ae2052f 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -66,7 +66,7 @@ public class BiometricManager {
@interface BiometricError {}
private final Context mContext;
- private final IBiometricService mService;
+ private final IAuthService mService;
private final boolean mHasHardware;
/**
@@ -86,7 +86,7 @@ public class BiometricManager {
* @param context
* @param service
*/
- public BiometricManager(Context context, IBiometricService service) {
+ public BiometricManager(Context context, IAuthService service) {
mContext = context;
mService = service;
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
new file mode 100644
index 000000000000..516a25d0b9b1
--- /dev/null
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 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.biometrics;
+
+import android.os.Bundle;
+import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
+import android.hardware.biometrics.IBiometricServiceReceiver;
+
+/**
+ * Communication channel from BiometricPrompt and BiometricManager to AuthService. The
+ * interface does not expose specific biometric modalities. The system will use the default
+ * biometric for apps. On devices with more than one, the choice is dictated by user preference in
+ * Settings.
+ * @hide
+ */
+interface IAuthService {
+ // Requests authentication. The service choose the appropriate biometric to use, and show
+ // the corresponding BiometricDialog.
+ void authenticate(IBinder token, long sessionId, int userId,
+ IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle);
+
+ // TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics.
+ // Checks if biometrics can be used.
+ int canAuthenticate(String opPackageName, int userId);
+
+ // Checks if any biometrics are enrolled.
+ boolean hasEnrolledBiometrics(int userId, String opPackageName);
+
+ // Register callback for when keyguard biometric eligibility changes.
+ void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
+
+ // Explicitly set the active user.
+ void setActiveUser(int userId);
+
+ // Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
+ void resetLockout(in byte [] token);
+}
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 06336a55ac5e..ca024215f782 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -22,10 +22,7 @@ import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricAuthenticator;
/**
- * Communication channel from BiometricPrompt and BiometricManager to BiometricService. The
- * interface does not expose specific biometric modalities. The system will use the default
- * biometric for apps. On devices with more than one, the choice is dictated by user preference in
- * Settings.
+ * Communication channel from AuthService to BiometricService.
* @hide
*/
interface IBiometricService {
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
new file mode 100644
index 000000000000..22cb507d449f
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2019 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;
+
+
+// TODO(b/141025588): Create separate internal and external permissions for AuthService.
+// TODO(b/141025588): Get rid of the USE_FINGERPRINT permission.
+
+import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+import static android.Manifest.permission.USE_FINGERPRINT;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.biometrics.IAuthService;
+import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
+import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.face.IFaceService;
+import android.hardware.fingerprint.IFingerprintService;
+import android.hardware.iris.IIrisService;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemService;
+import com.android.server.biometrics.face.FaceAuthenticator;
+import com.android.server.biometrics.fingerprint.FingerprintAuthenticator;
+import com.android.server.biometrics.iris.IrisAuthenticator;
+
+/**
+ * System service that provides an interface for authenticating with biometrics and
+ * PIN/pattern/password to BiometricPrompt and lock screen.
+ */
+public class AuthService extends SystemService {
+ private static final String TAG = "AuthService";
+ private static final boolean DEBUG = false;
+
+ private final boolean mHasFeatureFace;
+ private final boolean mHasFeatureFingerprint;
+ private final boolean mHasFeatureIris;
+ private final Injector mInjector;
+
+ private IBiometricService mBiometricService;
+ @VisibleForTesting
+ final IAuthService.Stub mImpl;
+
+ /**
+ * Class for injecting dependencies into AuthService.
+ * TODO(b/141025588): Replace with a dependency injection framework (e.g. Guice, Dagger).
+ */
+ @VisibleForTesting
+ public static class Injector {
+
+ /**
+ * Allows to mock BiometricService for testing.
+ */
+ @VisibleForTesting
+ public IBiometricService getBiometricService() {
+ return IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE));
+ }
+
+ /**
+ * Allows to stub publishBinderService(...) for testing.
+ */
+ @VisibleForTesting
+ public void publishBinderService(AuthService service, IAuthService.Stub impl) {
+ service.publishBinderService(Context.AUTH_SERVICE, impl);
+ }
+ }
+
+ private final class AuthServiceImpl extends IAuthService.Stub {
+ @Override
+ public void authenticate(IBinder token, long sessionId, int userId,
+ IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle)
+ throws RemoteException {
+ final int callingUserId = UserHandle.getCallingUserId();
+
+ // In the BiometricServiceBase, do the AppOps and foreground check.
+ if (userId == callingUserId) {
+ // Check the USE_BIOMETRIC permission here.
+ checkPermission();
+ } else {
+ // Only allow internal clients to authenticate with a different userId
+ Slog.w(TAG, "User " + callingUserId + " is requesting authentication of userid: "
+ + userId);
+ checkInternalPermission();
+ }
+
+ if (token == null || receiver == null || opPackageName == null || bundle == null) {
+ Slog.e(TAG, "Unable to authenticate, one or more null arguments");
+ return;
+ }
+
+ mBiometricService.authenticate(token, sessionId, userId, receiver, opPackageName,
+ bundle);
+ }
+
+ @Override
+ public int canAuthenticate(String opPackageName, int userId) throws RemoteException {
+ final int callingUserId = UserHandle.getCallingUserId();
+ Slog.d(TAG, "canAuthenticate, userId: " + userId
+ + ", callingUserId: " + callingUserId);
+
+ if (userId != callingUserId) {
+ checkInternalPermission();
+ } else {
+ checkPermission();
+ }
+ return mBiometricService.canAuthenticate(opPackageName, userId);
+ }
+
+ @Override
+ public boolean hasEnrolledBiometrics(int userId, String opPackageName)
+ throws RemoteException {
+ checkInternalPermission();
+ return mBiometricService.hasEnrolledBiometrics(userId, opPackageName);
+ }
+
+ @Override
+ public void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)
+ throws RemoteException {
+ checkInternalPermission();
+ mBiometricService.registerEnabledOnKeyguardCallback(callback);
+ }
+
+ @Override
+ public void setActiveUser(int userId) throws RemoteException {
+ checkInternalPermission();
+ mBiometricService.setActiveUser(userId);
+ }
+
+ @Override
+ public void resetLockout(byte[] token) throws RemoteException {
+ checkInternalPermission();
+ mBiometricService.resetLockout(token);
+ }
+ }
+
+ public AuthService(Context context) {
+ this(context, new Injector());
+ }
+
+ public AuthService(Context context, Injector injector) {
+ super(context);
+
+ mInjector = injector;
+ mImpl = new AuthServiceImpl();
+ final PackageManager pm = context.getPackageManager();
+ mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
+ mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
+ mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS);
+ }
+
+ @Override
+ public void onStart() {
+ mBiometricService = mInjector.getBiometricService();
+
+ if (mHasFeatureFace) {
+ final FaceAuthenticator faceAuthenticator = new FaceAuthenticator(
+ IFaceService.Stub.asInterface(ServiceManager.getService(Context.FACE_SERVICE)));
+ try {
+ // TODO(b/141025588): Pass down the real id, strength, and modality.
+ mBiometricService.registerAuthenticator(0, 0, TYPE_FACE, faceAuthenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+ if (mHasFeatureFingerprint) {
+ final FingerprintAuthenticator fingerprintAuthenticator = new FingerprintAuthenticator(
+ IFingerprintService.Stub.asInterface(
+ ServiceManager.getService(Context.FINGERPRINT_SERVICE)));
+ try {
+ // TODO(b/141025588): Pass down the real id, strength, and modality.
+ mBiometricService.registerAuthenticator(1, 0, TYPE_FINGERPRINT,
+ fingerprintAuthenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+ if (mHasFeatureIris) {
+ final IrisAuthenticator irisAuthenticator = new IrisAuthenticator(
+ IIrisService.Stub.asInterface(ServiceManager.getService(Context.IRIS_SERVICE)));
+ try {
+ // TODO(b/141025588): Pass down the real id, strength, and modality.
+ mBiometricService.registerAuthenticator(2, 0, TYPE_IRIS, irisAuthenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+ mInjector.publishBinderService(this, mImpl);
+ }
+
+ private void checkInternalPermission() {
+ getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL,
+ "Must have USE_BIOMETRIC_INTERNAL permission");
+ }
+
+ private void checkPermission() {
+ if (getContext().checkCallingOrSelfPermission(USE_FINGERPRINT)
+ != PackageManager.PERMISSION_GRANTED) {
+ getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC,
+ "Must have USE_BIOMETRIC permission");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 44c81fc09b2a..5d3679389b48 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -42,8 +42,6 @@ import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
-import android.hardware.face.IFaceService;
-import android.hardware.fingerprint.IFingerprintService;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -67,8 +65,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBarService;
import com.android.server.SystemService;
-import com.android.server.biometrics.face.FaceAuthenticator;
-import com.android.server.biometrics.fingerprint.FingerprintAuthenticator;
import java.util.ArrayList;
import java.util.HashMap;
@@ -215,9 +211,6 @@ public class BiometricService extends SystemService {
private final Injector mInjector;
@VisibleForTesting
final IBiometricService.Stub mImpl;
- private final boolean mHasFeatureFace;
- private final boolean mHasFeatureFingerprint;
- private final boolean mHasFeatureIris;
@VisibleForTesting
final SettingObserver mSettingObserver;
private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
@@ -702,6 +695,8 @@ public class BiometricService extends SystemService {
@Override
public void registerAuthenticator(int id, int strength, int modality,
IBiometricAuthenticator authenticator) {
+ checkInternalPermission();
+
mAuthenticators.add(new AuthenticatorWrapper(id, strength, modality, authenticator));
}
@@ -782,24 +777,6 @@ public class BiometricService extends SystemService {
}
/**
- * Allows to mock FaceAuthenticator for testing.
- */
- @VisibleForTesting
- public IBiometricAuthenticator getFingerprintAuthenticator() {
- return new FingerprintAuthenticator(IFingerprintService.Stub.asInterface(
- ServiceManager.getService(Context.FINGERPRINT_SERVICE)));
- }
-
- /**
- * Allows to mock FaceAuthenticator for testing.
- */
- @VisibleForTesting
- public IBiometricAuthenticator getFaceAuthenticator() {
- return new FaceAuthenticator(
- IFaceService.Stub.asInterface(ServiceManager.getService(Context.FACE_SERVICE)));
- }
-
- /**
* Allows to mock SettingObserver for testing.
*/
@VisibleForTesting
@@ -853,11 +830,6 @@ public class BiometricService extends SystemService {
mSettingObserver = mInjector.getSettingObserver(context, mHandler,
mEnabledOnKeyguardCallbacks);
- final PackageManager pm = context.getPackageManager();
- mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
- mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
- mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS);
-
try {
injector.getActivityManagerService().registerUserSwitchObserver(
new UserSwitchObserver() {
@@ -875,28 +847,6 @@ public class BiometricService extends SystemService {
@Override
public void onStart() {
- // TODO(b/141025588): remove this code block once AuthService is integrated.
- {
- if (mHasFeatureFace) {
- try {
- mImpl.registerAuthenticator(0, 0, TYPE_FACE, mInjector.getFaceAuthenticator());
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
- }
- if (mHasFeatureFingerprint) {
- try {
- mImpl.registerAuthenticator(0, 0, TYPE_FINGERPRINT,
- mInjector.getFingerprintAuthenticator());
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
- }
- if (mHasFeatureIris) {
- Slog.e(TAG, "Iris is not supported");
- }
- }
-
mKeyStore = mInjector.getKeyStore();
mStatusBarService = mInjector.getStatusBarService();
mInjector.publishBinderService(this, mImpl);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2a364e6e4aae..3043b6f9d80c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -83,6 +83,7 @@ import com.android.server.am.ActivityManagerService;
import com.android.server.appbinding.AppBindingService;
import com.android.server.attention.AttentionManagerService;
import com.android.server.audio.AudioService;
+import com.android.server.biometrics.AuthService;
import com.android.server.biometrics.BiometricService;
import com.android.server.biometrics.face.FaceService;
import com.android.server.biometrics.fingerprint.FingerprintService;
@@ -1775,8 +1776,13 @@ public final class SystemServer {
t.traceBegin("StartBiometricService");
mSystemServiceManager.startService(BiometricService.class);
t.traceEnd();
+
+ t.traceBegin("StartAuthService");
+ mSystemServiceManager.startService(AuthService.class);
+ t.traceEnd();
}
+
t.traceBegin("StartBackgroundDexOptService");
try {
BackgroundDexOptService.schedule(context);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
new file mode 100644
index 000000000000..106a7238e399
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2019 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;
+
+import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
+import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.os.Binder;
+import android.os.Bundle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class AuthServiceTest {
+
+ private static final String TAG = "AuthServiceTest";
+ private static final String TEST_OP_PACKAGE_NAME = "test_package";
+
+ private AuthService mAuthService;
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ IBiometricServiceReceiver mReceiver;
+ @Mock
+ AuthService.Injector mInjector;
+ @Mock
+ IBiometricService mBiometricService;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mInjector.getBiometricService()).thenReturn(mBiometricService);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IRIS)).thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ }
+
+
+ // TODO(b/141025588): Check that an exception is thrown when the userId != callingUserId
+ @Test
+ public void testAuthenticate_callsBiometricServiceAuthenticate() throws
+ Exception {
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final Binder token = new Binder();
+ final Bundle bundle = new Bundle();
+ final long sessionId = 0;
+ final int userId = 0;
+
+ mAuthService.mImpl.authenticate(
+ token,
+ sessionId,
+ userId,
+ mReceiver,
+ TEST_OP_PACKAGE_NAME,
+ bundle);
+ waitForIdle();
+ verify(mBiometricService).authenticate(
+ eq(token),
+ eq(sessionId),
+ eq(userId),
+ eq(mReceiver),
+ eq(TEST_OP_PACKAGE_NAME),
+ eq(bundle));
+ }
+
+ @Test
+ public void testCanAuthenticate_callsBiometricServiceCanAuthenticate() throws
+ Exception {
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final int userId = 0;
+ final int expectedResult = BIOMETRIC_SUCCESS;
+ when(mBiometricService.canAuthenticate(anyString(), anyInt())).thenReturn(expectedResult);
+
+ final int result = mAuthService.mImpl.canAuthenticate(TEST_OP_PACKAGE_NAME, userId);
+
+ assertEquals(expectedResult, result);
+ waitForIdle();
+ verify(mBiometricService).canAuthenticate(
+ eq(TEST_OP_PACKAGE_NAME),
+ eq(userId));
+ }
+
+
+ @Test
+ public void testHasEnrolledBiometrics_callsBiometricServiceHasEnrolledBiometrics() throws
+ Exception {
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final int userId = 0;
+ final boolean expectedResult = true;
+ when(mBiometricService.hasEnrolledBiometrics(anyInt(), anyString())).thenReturn(
+ expectedResult);
+
+ final boolean result = mAuthService.mImpl.hasEnrolledBiometrics(userId,
+ TEST_OP_PACKAGE_NAME);
+
+ assertEquals(expectedResult, result);
+ waitForIdle();
+ verify(mBiometricService).hasEnrolledBiometrics(
+ eq(userId),
+ eq(TEST_OP_PACKAGE_NAME));
+ }
+
+
+ @Test
+ public void testRegisterKeyguardCallback_callsBiometricServiceRegisterKeyguardCallback()
+ throws Exception {
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final IBiometricEnabledOnKeyguardCallback callback =
+ new IBiometricEnabledOnKeyguardCallback.Default();
+
+ mAuthService.mImpl.registerEnabledOnKeyguardCallback(callback);
+
+ waitForIdle();
+ verify(mBiometricService).registerEnabledOnKeyguardCallback(eq(callback));
+ }
+
+ @Test
+ public void testSetActiveUser_callsBiometricServiceSetActiveUser() throws
+ Exception {
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final int userId = 0;
+
+ mAuthService.mImpl.setActiveUser(userId);
+
+ waitForIdle();
+ verify(mBiometricService).setActiveUser(eq(userId));
+ }
+
+ @Test
+ public void testResetLockout_callsBiometricServiceResetLockout() throws
+ Exception {
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final byte[] token = new byte[0];
+
+ mAuthService.mImpl.resetLockout(token);
+
+ waitForIdle();
+ verify(mBiometricService).resetLockout(token);
+ }
+
+ private static void waitForIdle() {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index ec47a959de30..4ced421be63a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -36,7 +36,6 @@ import static org.mockito.Mockito.when;
import android.app.IActivityManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.biometrics.Authenticator;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -82,6 +81,8 @@ public class BiometricServiceTest {
private static final String FINGERPRINT_ACQUIRED_SENSOR_DIRTY = "sensor_dirty";
+ private static final int STRENGTH_STRONG = 1;
+
private BiometricService mBiometricService;
@Mock
@@ -91,8 +92,6 @@ public class BiometricServiceTest {
@Mock
private Resources mResources;
@Mock
- private PackageManager mPackageManager;
- @Mock
IBiometricServiceReceiver mReceiver1;
@Mock
IBiometricServiceReceiver mReceiver2;
@@ -107,14 +106,11 @@ public class BiometricServiceTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getResources()).thenReturn(mResources);
when(mInjector.getActivityManagerService()).thenReturn(mock(IActivityManager.class));
when(mInjector.getStatusBarService()).thenReturn(mock(IStatusBarService.class));
- when(mInjector.getFingerprintAuthenticator()).thenReturn(mFingerprintAuthenticator);
- when(mInjector.getFaceAuthenticator()).thenReturn(mFaceAuthenticator);
when(mInjector.getSettingObserver(any(), any(), any())).thenReturn(
mock(BiometricService.SettingObserver.class));
when(mInjector.getKeyStore()).thenReturn(mock(KeyStore.class));
@@ -131,11 +127,6 @@ public class BiometricServiceTest {
@Test
public void testAuthenticate_withoutHardware_returnsErrorHardwareNotPresent() throws
Exception {
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
- .thenReturn(false);
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IRIS)).thenReturn(false);
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
-
mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
@@ -150,11 +141,13 @@ public class BiometricServiceTest {
@Test
public void testAuthenticate_withoutEnrolled_returnsErrorNoBiometrics() throws Exception {
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true);
mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
+ mBiometricService.mImpl.registerAuthenticator(0 /* id */, STRENGTH_STRONG,
+ BiometricAuthenticator.TYPE_FINGERPRINT, mFingerprintAuthenticator);
+
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
false /* allowDeviceCredential */);
@@ -168,12 +161,13 @@ public class BiometricServiceTest {
@Test
public void testAuthenticate_whenHalIsDead_returnsErrorHardwareUnavailable() throws
Exception {
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(false);
mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
+ mBiometricService.mImpl.registerAuthenticator(0 /* id */, STRENGTH_STRONG,
+ BiometricAuthenticator.TYPE_FINGERPRINT, mFingerprintAuthenticator);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
false /* allowDeviceCredential */);
@@ -187,12 +181,13 @@ public class BiometricServiceTest {
@Test
public void testAuthenticateFace_respectsUserSetting()
throws Exception {
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true);
mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
+ mBiometricService.mImpl.registerAuthenticator(0 /* id */, STRENGTH_STRONG,
+ BiometricAuthenticator.TYPE_FACE, mFaceAuthenticator);
// Disabled in user settings receives onError
when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(false);
@@ -248,8 +243,6 @@ public class BiometricServiceTest {
@Test
public void testAuthenticate_happyPathWithoutConfirmation() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
- mBiometricService = new BiometricService(mContext, mInjector);
- mBiometricService.onStart();
// Start testing the happy path
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
@@ -861,27 +854,24 @@ public class BiometricServiceTest {
// Helper methods
private void setupAuthForOnly(int modality) throws RemoteException {
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
- .thenReturn(false);
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
+ mBiometricService = new BiometricService(mContext, mInjector);
+ mBiometricService.onStart();
+
+ when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
if (modality == BiometricAuthenticator.TYPE_FINGERPRINT) {
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
- .thenReturn(true);
when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true);
+ mBiometricService.mImpl.registerAuthenticator(0 /* id */, STRENGTH_STRONG, modality,
+ mFingerprintAuthenticator);
} else if (modality == BiometricAuthenticator.TYPE_FACE) {
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true);
+ mBiometricService.mImpl.registerAuthenticator(0 /* id */, STRENGTH_STRONG, modality,
+ mFaceAuthenticator);
} else {
fail("Unknown modality: " + modality);
}
-
- mBiometricService = new BiometricService(mContext, mInjector);
- mBiometricService.onStart();
-
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
}
private void resetReceiver() {