Merge changes from topic "biometric-and-credential"

* changes:
  Always start AuthController
  Clean up biometric system server
This commit is contained in:
Kevin Chyn
2020-02-21 21:37:14 +00:00
committed by Android (Google) Code Review
24 changed files with 212 additions and 238 deletions

View File

@@ -922,17 +922,11 @@ public final class SystemServiceRegistry {
@Override
public BiometricManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
if (BiometricManager.hasBiometrics(ctx)) {
final IBinder 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
// on devices without biometric hardware.
return new BiometricManager(ctx.getOuterContext(), null);
}
final IBinder binder =
ServiceManager.getServiceOrThrow(Context.AUTH_SERVICE);
final IAuthService service =
IAuthService.Stub.asInterface(binder);
return new BiometricManager(ctx.getOuterContext(), service);
}
});

View File

@@ -25,7 +25,6 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.util.Slog;
@@ -160,19 +159,6 @@ public class BiometricManager {
private final Context mContext;
private final IAuthService mService;
private final boolean mHasHardware;
/**
* @param context
* @return
* @hide
*/
public static boolean hasBiometrics(Context context) {
final PackageManager pm = context.getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
|| pm.hasSystemFeature(PackageManager.FEATURE_IRIS)
|| pm.hasSystemFeature(PackageManager.FEATURE_FACE);
}
/**
* @hide
@@ -182,8 +168,6 @@ public class BiometricManager {
public BiometricManager(Context context, IAuthService service) {
mContext = context;
mService = service;
mHasHardware = hasBiometrics(context);
}
/**
@@ -249,12 +233,8 @@ public class BiometricManager {
throw e.rethrowFromSystemServer();
}
} else {
if (!mHasHardware) {
return BIOMETRIC_ERROR_NO_HARDWARE;
} else {
Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
return BIOMETRIC_ERROR_HW_UNAVAILABLE;
}
Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
return BIOMETRIC_ERROR_HW_UNAVAILABLE;
}
}
@@ -331,5 +311,25 @@ public class BiometricManager {
}
}
/**
* Get a list of AuthenticatorIDs for biometric authenticators which have 1) enrolled templates,
* and 2) meet the requirements for integrating with Keystore. The AuthenticatorIDs are known
* in Keystore land as SIDs, and are used during key generation.
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public long[] getAuthenticatorIds() {
if (mService != null) {
try {
return mService.getAuthenticatorIds();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else {
Slog.w(TAG, "getAuthenticatorIds(): Service not connected");
return new long[0];
}
}
}

View File

@@ -898,29 +898,24 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
mExecutor = executor;
mAuthenticationCallback = callback;
final long sessionId = crypto != null ? crypto.getOpId() : 0;
if (BiometricManager.hasBiometrics(mContext)) {
final Bundle bundle;
if (crypto != null) {
// Allowed authenticators should default to BIOMETRIC_STRONG for crypto auth.
// Note that we use a new bundle here so as to not overwrite the application's
// preference, since it is possible that the same prompt configuration be used
// without a crypto object later.
bundle = new Bundle(mBundle);
bundle.putInt(KEY_AUTHENTICATORS_ALLOWED,
mBundle.getInt(KEY_AUTHENTICATORS_ALLOWED,
Authenticators.BIOMETRIC_STRONG));
} else {
bundle = mBundle;
}
mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver,
mContext.getOpPackageName(), bundle);
final Bundle bundle;
if (crypto != null) {
// Allowed authenticators should default to BIOMETRIC_STRONG for crypto auth.
// Note that we use a new bundle here so as to not overwrite the application's
// preference, since it is possible that the same prompt configuration be used
// without a crypto object later.
bundle = new Bundle(mBundle);
bundle.putInt(KEY_AUTHENTICATORS_ALLOWED,
mBundle.getInt(KEY_AUTHENTICATORS_ALLOWED,
Authenticators.BIOMETRIC_STRONG));
} else {
mExecutor.execute(() -> {
callback.onAuthenticationError(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT,
mContext.getString(R.string.biometric_error_hw_unavailable));
});
bundle = mBundle;
}
mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver,
mContext.getOpPackageName(), bundle);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception while authenticating", e);
mExecutor.execute(() -> {

View File

@@ -51,4 +51,9 @@ interface IAuthService {
// Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetLockout(in byte [] token);
// Get a list of AuthenticatorIDs for authenticators which have enrolled templates and meet
// the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore
// land as SIDs, and are used during key generation.
long[] getAuthenticatorIds();
}

View File

@@ -55,4 +55,7 @@ interface IBiometricAuthenticator {
// Explicitly set the active user (for enrolling work profile)
void setActiveUser(int uid);
// Gets the authenticator ID representing the current set of enrolled templates
long getAuthenticatorId();
}

View File

@@ -61,4 +61,9 @@ interface IBiometricService {
// Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetLockout(in byte [] token);
// Get a list of AuthenticatorIDs for authenticators which have enrolled templates and meet
// the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore
// land as SIDs, and are used during key generation.
long[] getAuthenticatorIds();
}

View File

@@ -586,25 +586,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
return false;
}
/**
* Retrieves the authenticator token for binding keys to the lifecycle
* of the calling user's face. Used only by internal clients.
*
* @hide
*/
public long getAuthenticatorId() {
if (mService != null) {
try {
return mService.getAuthenticatorId(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else {
Log.w(TAG, "getAuthenticatorId(): Service not connected!");
}
return 0;
}
/**
* @hide
*/

View File

@@ -90,7 +90,7 @@ interface IFaceService {
// long getHardwareDevice(int i);
// Gets the authenticator ID for face
long getAuthenticatorId(String opPackageName);
long getAuthenticatorId();
// Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetLockout(in byte [] token);

View File

@@ -768,26 +768,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
return false;
}
/**
* Retrieves the authenticator token for binding keys to the lifecycle
* of the calling user's fingerprints. Used only by internal clients.
*
* @hide
*/
@UnsupportedAppUsage
public long getAuthenticatorId() {
if (mService != null) {
try {
return mService.getAuthenticatorId(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else {
Slog.w(TAG, "getAuthenticatorId(): Service not connected!");
}
return 0;
}
/**
* @hide
*/

View File

@@ -91,7 +91,7 @@ interface IFingerprintService {
// long getHardwareDevice(int i);
// Gets the authenticator ID for fingerprint
long getAuthenticatorId(String opPackageName);
long getAuthenticatorId();
// Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetTimeout(in byte [] cryptoToken);

View File

@@ -21,9 +21,7 @@ import android.app.Application;
import android.app.KeyguardManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.biometrics.BiometricManager;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
@@ -1348,19 +1346,26 @@ public class KeyStore {
return new UserNotAuthenticatedException();
}
final long fingerprintOnlySid = getFingerprintOnlySid();
if ((fingerprintOnlySid != 0)
&& (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
// One of the key's SIDs is the current fingerprint SID -- user can be
// authenticated against that SID.
return new UserNotAuthenticatedException();
final BiometricManager bm = mContext.getSystemService(BiometricManager.class);
long[] biometricSids = bm.getAuthenticatorIds();
// The key must contain every biometric SID. This is because the current API surface
// treats all biometrics (capable of keystore integration) equally. e.g. if the
// device has multiple keystore-capable sensors, and one of the sensor's SIDs
// changed, 1) there is no way for a developer to specify authentication with a
// specific sensor (the one that hasn't changed), and 2) currently the only
// signal to developers is the UserNotAuthenticatedException, which doesn't
// indicate a specific sensor.
boolean canUnlockViaBiometrics = true;
for (long sid : biometricSids) {
if (!keySids.contains(KeymasterArguments.toUint64(sid))) {
canUnlockViaBiometrics = false;
break;
}
}
final long faceOnlySid = getFaceOnlySid();
if ((faceOnlySid != 0)
&& (keySids.contains(KeymasterArguments.toUint64(faceOnlySid)))) {
// One of the key's SIDs is the current face SID -- user can be
// authenticated against that SID.
if (canUnlockViaBiometrics) {
// All of the biometric SIDs are contained in the key's SIDs.
return new UserNotAuthenticatedException();
}
@@ -1374,36 +1379,6 @@ public class KeyStore {
}
}
private long getFaceOnlySid() {
final PackageManager packageManager = mContext.getPackageManager();
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
return 0;
}
FaceManager faceManager = mContext.getSystemService(FaceManager.class);
if (faceManager == null) {
return 0;
}
// TODO: Restore USE_BIOMETRIC or USE_BIOMETRIC_INTERNAL permission check in
// FaceManager.getAuthenticatorId once the ID is no longer needed here.
return faceManager.getAuthenticatorId();
}
private long getFingerprintOnlySid() {
final PackageManager packageManager = mContext.getPackageManager();
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
return 0;
}
FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
if (fingerprintManager == null) {
return 0;
}
// TODO: Restore USE_FINGERPRINT permission check in
// FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
return fingerprintManager.getAuthenticatorId();
}
/**
* Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
* code.

View File

@@ -16,9 +16,7 @@
package android.security.keystore;
import android.content.pm.PackageManager;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.biometrics.BiometricManager;
import android.security.GateKeeper;
import android.security.KeyStore;
import android.security.keymaster.KeymasterArguments;
@@ -115,28 +113,16 @@ public abstract class KeymasterUtils {
}
if (spec.getUserAuthenticationValidityDurationSeconds() == 0) {
PackageManager pm = KeyStore.getApplicationContext().getPackageManager();
// Every use of this key needs to be authorized by the user. This currently means
// fingerprint or face auth.
FingerprintManager fingerprintManager = null;
FaceManager faceManager = null;
// Every use of this key needs to be authorized by the user.
final BiometricManager bm = KeyStore.getApplicationContext()
.getSystemService(BiometricManager.class);
if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
fingerprintManager = KeyStore.getApplicationContext()
.getSystemService(FingerprintManager.class);
}
if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
faceManager = KeyStore.getApplicationContext().getSystemService(FaceManager.class);
}
// TODO: Restore permission check in getAuthenticatorIds once the ID is no longer
// needed here.
// TODO: Restore USE_FINGERPRINT permission check in
// FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
final long fingerprintOnlySid =
(fingerprintManager != null) ? fingerprintManager.getAuthenticatorId() : 0;
final long faceOnlySid =
(faceManager != null) ? faceManager.getAuthenticatorId() : 0;
final long[] biometricSids = bm.getAuthenticatorIds();
if (fingerprintOnlySid == 0 && faceOnlySid == 0) {
if (biometricSids.length == 0) {
throw new IllegalStateException(
"At least one biometric must be enrolled to create keys requiring user"
+ " authentication for every use");
@@ -148,8 +134,9 @@ public abstract class KeymasterUtils {
} else if (spec.isInvalidatedByBiometricEnrollment()) {
// The biometric-only SIDs will change on biometric enrollment or removal of all
// enrolled templates, invalidating the key.
sids.add(fingerprintOnlySid);
sids.add(faceOnlySid);
for (long sid : biometricSids) {
sids.add(sid);
}
} else {
// The root SID will *not* change on fingerprint enrollment, or removal of all
// enrolled fingerprints, allowing the key to remain valid.

View File

@@ -28,7 +28,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
@@ -238,20 +237,15 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
@Override
public void start() {
final PackageManager pm = mContext.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
|| pm.hasSystemFeature(PackageManager.FEATURE_FACE)
|| pm.hasSystemFeature(PackageManager.FEATURE_IRIS)) {
mCommandQueue.addCallback(this);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mActivityTaskManager = mInjector.getActivityTaskManager();
mCommandQueue.addCallback(this);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mActivityTaskManager = mInjector.getActivityTaskManager();
try {
mTaskStackListener = new BiometricTaskStackListener();
mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
} catch (RemoteException e) {
Log.w(TAG, "Unable to register task stack listener", e);
}
try {
mTaskStackListener = new BiometricTaskStackListener();
mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
} catch (RemoteException e) {
Log.w(TAG, "Unable to register task stack listener", e);
}
}

View File

@@ -265,6 +265,32 @@ public class AuthService extends SystemService {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public long[] getAuthenticatorIds() throws RemoteException {
// In this method, we're not checking whether the caller is permitted to use face
// API because current authenticator ID is leaked (in a more contrived way) via Android
// Keystore (android.security.keystore package): the user of that API can create a key
// which requires face authentication for its use, and then query the key's
// characteristics (hidden API) which returns, among other things, face
// authenticator ID which was active at key creation time.
//
// Reason: The part of Android Keystore which runs inside an app's process invokes this
// method in certain cases. Those cases are not always where the developer demonstrates
// explicit intent to use biometric functionality. Thus, to avoiding throwing an
// unexpected SecurityException this method does not check whether its caller is
// permitted to use face API.
//
// The permission check should be restored once Android Keystore no longer invokes this
// method from inside app processes.
final long identity = Binder.clearCallingIdentity();
try {
return mBiometricService.getAuthenticatorIds();
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
public AuthService(Context context) {
@@ -305,8 +331,8 @@ public class AuthService extends SystemService {
case TYPE_FINGERPRINT:
final IFingerprintService fingerprintService = mInjector.getFingerprintService();
if (fingerprintService == null) {
Slog.e(TAG, "Attempting to register with null FingerprintService. Please check"
+ " your device configuration.");
Slog.e(TAG, "Attempting to register with null FingerprintService."
+ " Please check your device configuration.");
return;
}
@@ -317,8 +343,8 @@ public class AuthService extends SystemService {
case TYPE_FACE:
final IFaceService faceService = mInjector.getFaceService();
if (faceService == null) {
Slog.e(TAG, "Attempting to register with null FaceService. Please check your"
+ " device configuration.");
Slog.e(TAG, "Attempting to register with null FaceService. Please check "
+ " your device configuration.");
return;
}
@@ -329,8 +355,8 @@ public class AuthService extends SystemService {
case TYPE_IRIS:
final IIrisService irisService = mInjector.getIrisService();
if (irisService == null) {
Slog.e(TAG, "Attempting to register with null IrisService. Please check your"
+ " device configuration.");
Slog.e(TAG, "Attempting to register with null IrisService. Please check"
+ " your device configuration.");
return;
}
@@ -347,7 +373,6 @@ public class AuthService extends SystemService {
authenticator);
}
private void checkInternalPermission() {
getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL,
"Must have USE_BIOMETRIC_INTERNAL permission");

View File

@@ -825,6 +825,33 @@ public class BiometricService extends SystemService {
Slog.e(TAG, "Remote exception", e);
}
}
@Override // Binder call
public long[] getAuthenticatorIds() {
checkInternalPermission();
final List<Long> ids = new ArrayList<>();
for (AuthenticatorWrapper authenticator : mAuthenticators) {
try {
final long id = authenticator.impl.getAuthenticatorId();
if (Utils.isAtLeastStrength(authenticator.getActualStrength(),
Authenticators.BIOMETRIC_STRONG) && id != 0) {
ids.add(id);
} else {
Slog.d(TAG, "Authenticator " + authenticator + ", authenticatorID " + id
+ " cannot participate in Keystore operations");
}
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException", e);
}
}
long[] result = new long[ids.size()];
for (int i = 0; i < ids.size(); i++) {
result[i] = ids.get(i);
}
return result;
}
}
private void checkInternalPermission() {

View File

@@ -16,7 +16,6 @@
package com.android.server.biometrics;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
import android.app.ActivityManager;
@@ -1228,16 +1227,11 @@ public abstract class BiometricServiceBase extends SystemService
}
/***
* @param opPackageName the name of the calling package
* @return authenticator id for the calling user
*/
protected long getAuthenticatorId(String opPackageName) {
if (isKeyguard(opPackageName)) {
// If an app tells us it's keyguard, check that it actually is.
checkPermission(USE_BIOMETRIC_INTERNAL);
}
final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
protected long getAuthenticatorId() {
final int userId = getUserOrWorkProfileId(null /* clientPackage */,
UserHandle.getCallingUserId());
return mAuthenticatorIds.getOrDefault(userId, 0L);
}

View File

@@ -130,8 +130,24 @@ public class Utils {
* @return true only if the sensor is at least as strong as the requested strength
*/
public static boolean isAtLeastStrength(int sensorStrength, int requestedStrength) {
// Clear out any bits that are not reserved for biometric
sensorStrength &= Authenticators.BIOMETRIC_MIN_STRENGTH;
// If the authenticator contains bits outside of the requested strength, it is too weak.
return (~requestedStrength & sensorStrength) == 0;
if ((sensorStrength & ~requestedStrength) != 0) {
return false;
}
for (int i = Authenticators.BIOMETRIC_MAX_STRENGTH;
i <= requestedStrength; i = (i << 1) | 1) {
if (i == sensorStrength) {
return true;
}
}
Slog.e(BiometricService.TAG, "Unknown sensorStrength: " + sensorStrength
+ ", requestedStrength: " + requestedStrength);
return false;
}
/**

View File

@@ -72,4 +72,9 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
public void setActiveUser(int uid) throws RemoteException {
mFaceService.setActiveUser(uid);
}
@Override
public long getAuthenticatorId() throws RemoteException {
return mFaceService.getAuthenticatorId();
}
}

View File

@@ -611,24 +611,9 @@ public class FaceService extends BiometricServiceBase {
}
@Override // Binder call
public long getAuthenticatorId(String opPackageName) {
// In this method, we're not checking whether the caller is permitted to use face
// API because current authenticator ID is leaked (in a more contrived way) via Android
// Keystore (android.security.keystore package): the user of that API can create a key
// which requires face authentication for its use, and then query the key's
// characteristics (hidden API) which returns, among other things, face
// authenticator ID which was active at key creation time.
//
// Reason: The part of Android Keystore which runs inside an app's process invokes this
// method in certain cases. Those cases are not always where the developer demonstrates
// explicit intent to use face functionality. Thus, to avoiding throwing an
// unexpected SecurityException this method does not check whether its caller is
// permitted to use face API.
//
// The permission check should be restored once Android Keystore no longer invokes this
// method from inside app processes.
return FaceService.this.getAuthenticatorId(opPackageName);
public long getAuthenticatorId() {
checkPermission(USE_BIOMETRIC_INTERNAL);
return FaceService.this.getAuthenticatorId();
}
@Override // Binder call

View File

@@ -72,4 +72,9 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub
public void setActiveUser(int uid) throws RemoteException {
mFingerprintService.setActiveUser(uid);
}
@Override
public long getAuthenticatorId() throws RemoteException {
return mFingerprintService.getAuthenticatorId();
}
}

View File

@@ -411,24 +411,9 @@ public class FingerprintService extends BiometricServiceBase {
}
@Override // Binder call
public long getAuthenticatorId(String opPackageName) {
// In this method, we're not checking whether the caller is permitted to use fingerprint
// API because current authenticator ID is leaked (in a more contrived way) via Android
// Keystore (android.security.keystore package): the user of that API can create a key
// which requires fingerprint authentication for its use, and then query the key's
// characteristics (hidden API) which returns, among other things, fingerprint
// authenticator ID which was active at key creation time.
//
// Reason: The part of Android Keystore which runs inside an app's process invokes this
// method in certain cases. Those cases are not always where the developer demonstrates
// explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
// unexpected SecurityException this method does not check whether its caller is
// permitted to use fingerprint API.
//
// The permission check should be restored once Android Keystore no longer invokes this
// method from inside app processes.
return FingerprintService.super.getAuthenticatorId(opPackageName);
public long getAuthenticatorId() {
checkPermission(USE_BIOMETRIC_INTERNAL);
return FingerprintService.this.getAuthenticatorId();
}
@Override // Binder call

View File

@@ -65,4 +65,9 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {
@Override
public void setActiveUser(int uid) throws RemoteException {
}
@Override
public long getAuthenticatorId() throws RemoteException {
return 0;
}
}

View File

@@ -1908,16 +1908,14 @@ public final class SystemServer {
t.traceEnd();
}
if (hasFeatureFace || hasFeatureIris || hasFeatureFingerprint) {
// Start this service after all biometric services.
t.traceBegin("StartBiometricService");
mSystemServiceManager.startService(BiometricService.class);
t.traceEnd();
// Start this service after all biometric services.
t.traceBegin("StartBiometricService");
mSystemServiceManager.startService(BiometricService.class);
t.traceEnd();
t.traceBegin("StartAuthService");
mSystemServiceManager.startService(AuthService.class);
t.traceEnd();
}
t.traceBegin("StartAuthService");
mSystemServiceManager.startService(AuthService.class);
t.traceEnd();
t.traceBegin("StartBackgroundDexOptService");

View File

@@ -201,6 +201,16 @@ public class UtilsTest {
requestedStrength = Authenticators.BIOMETRIC_WEAK;
assertTrue(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
// Test invalid inputs
sensorStrength = Authenticators.BIOMETRIC_STRONG;
requestedStrength = Authenticators.DEVICE_CREDENTIAL;
assertFalse(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
requestedStrength = 1 << 2;
assertFalse(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
}
@Test