diff options
| author | 2019-11-19 02:03:13 +0000 | |
|---|---|---|
| committer | 2019-11-19 02:03:13 +0000 | |
| commit | d6b829939adb0736d39a2954e719fd38d88c9eac (patch) | |
| tree | 0e5b095b81d8e5f3a617404059b09e90aac71d97 | |
| parent | e5deb3f1c93e0750637252ca5d3b125e9d28bdc6 (diff) | |
| parent | e4675b30676a53f8d363b8a1d64cfa6cd5843270 (diff) | |
Merge "Implemented and integrated AuthService"
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() { |