Clear BiometricScheduler when biometric HAL dies
Operations cannot be expected to complete if the HAL dies. The easiest solution is to clear any existing operation, as well as any pending operations. It's dangerous if we leave pending operations in the queue, since for some HALs, subsequent operations depend on preceeding operations. For example, updateActiveUser + authenticate. Fixes: 172683967 Test: atest com.android.server.biometrics Change-Id: I50b5234d4b382b08767dc359c4a13404e73897c2
This commit is contained in:
@@ -543,6 +543,10 @@ public class BiometricScheduler {
|
||||
return mCurrentOperation.clientMonitor;
|
||||
}
|
||||
|
||||
public int getCurrentPendingCount() {
|
||||
return mPendingOperations.size();
|
||||
}
|
||||
|
||||
public void recordCrashState() {
|
||||
if (mCrashStates.size() >= CrashState.NUM_ENTRIES) {
|
||||
mCrashStates.removeFirst();
|
||||
@@ -568,4 +572,13 @@ public class BiometricScheduler {
|
||||
pw.println("Crash State " + crashState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the scheduler of anything work-related. This should be used for example when the
|
||||
* HAL dies.
|
||||
*/
|
||||
public void reset() {
|
||||
mPendingOperations.clear();
|
||||
mCurrentOperation = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
|
||||
return mSensorId;
|
||||
}
|
||||
|
||||
public final T getFreshDaemon() {
|
||||
public T getFreshDaemon() {
|
||||
return mLazyDaemon.getDaemon();
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.biometrics.Utils;
|
||||
import com.android.server.biometrics.sensors.AuthenticationClient;
|
||||
import com.android.server.biometrics.sensors.ClientMonitor;
|
||||
@@ -69,7 +70,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
@NonNull private final String mHalInstanceName;
|
||||
@NonNull private final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
|
||||
@NonNull @VisibleForTesting
|
||||
final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
|
||||
@NonNull private final ClientMonitor.LazyDaemon<IFace> mLazyDaemon;
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
|
||||
@@ -585,8 +587,11 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
mHandler.post(() -> {
|
||||
mDaemon = null;
|
||||
for (int i = 0; i < mSensors.size(); i++) {
|
||||
final Sensor sensor = mSensors.valueAt(i);
|
||||
final int sensorId = mSensors.keyAt(i);
|
||||
PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
|
||||
sensor.getScheduler().recordCrashState();
|
||||
sensor.getScheduler().reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -333,16 +333,17 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Face10(@NonNull Context context, int sensorId,
|
||||
Face10(@NonNull Context context, int sensorId,
|
||||
@BiometricManager.Authenticators.Types int strength,
|
||||
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
|
||||
boolean supportsSelfIllumination, int maxTemplatesAllowed) {
|
||||
boolean supportsSelfIllumination, int maxTemplatesAllowed,
|
||||
@NonNull BiometricScheduler scheduler) {
|
||||
mSensorProperties = new FaceSensorPropertiesInternal(sensorId,
|
||||
Utils.authenticatorStrengthToPropertyStrength(strength),
|
||||
maxTemplatesAllowed, false /* supportsFaceDetect */, supportsSelfIllumination);
|
||||
mContext = context;
|
||||
mSensorId = sensorId;
|
||||
mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */);
|
||||
mScheduler = scheduler;
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
mUsageStats = new UsageStats(context);
|
||||
mAuthenticatorIds = new HashMap<>();
|
||||
@@ -369,7 +370,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
|
||||
this(context, sensorId, strength, lockoutResetDispatcher,
|
||||
context.getResources().getBoolean(R.bool.config_faceAuthSupportsSelfIllumination),
|
||||
context.getResources().getInteger(R.integer.config_faceMaxTemplatesPerUser));
|
||||
context.getResources().getInteger(R.integer.config_faceMaxTemplatesPerUser),
|
||||
new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -388,12 +390,13 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
|
||||
interruptable.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */);
|
||||
|
||||
mScheduler.recordCrashState();
|
||||
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
|
||||
BiometricsProtoEnums.MODALITY_FACE,
|
||||
BiometricsProtoEnums.ISSUE_HAL_DEATH);
|
||||
}
|
||||
|
||||
mScheduler.recordCrashState();
|
||||
mScheduler.reset();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.biometrics.Utils;
|
||||
import com.android.server.biometrics.sensors.AuthenticationClient;
|
||||
import com.android.server.biometrics.sensors.ClientMonitor;
|
||||
@@ -67,7 +68,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
@NonNull private final String mHalInstanceName;
|
||||
@NonNull private final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
|
||||
@NonNull @VisibleForTesting
|
||||
final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
|
||||
@NonNull private final ClientMonitor.LazyDaemon<IFingerprint> mLazyDaemon;
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
|
||||
@@ -607,8 +609,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mDaemon = null;
|
||||
|
||||
for (int i = 0; i < mSensors.size(); i++) {
|
||||
final Sensor sensor = mSensors.valueAt(i);
|
||||
final int sensorId = mSensors.keyAt(i);
|
||||
PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
|
||||
sensor.getScheduler().recordCrashState();
|
||||
sensor.getScheduler().reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -386,12 +386,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
interruptable.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */);
|
||||
|
||||
mScheduler.recordCrashState();
|
||||
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
|
||||
BiometricsProtoEnums.MODALITY_FINGERPRINT,
|
||||
BiometricsProtoEnums.ISSUE_HAL_DEATH);
|
||||
}
|
||||
|
||||
mScheduler.recordCrashState();
|
||||
mScheduler.reset();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.sensors.face.aidl;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.common.CommonProps;
|
||||
import android.hardware.biometrics.face.SensorProps;
|
||||
import android.os.UserManager;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.server.biometrics.sensors.BiometricScheduler;
|
||||
import com.android.server.biometrics.sensors.ClientMonitor;
|
||||
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Presubmit
|
||||
@SmallTest
|
||||
public class FaceProviderTest {
|
||||
|
||||
private static final String TAG = "FaceProviderTest";
|
||||
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
|
||||
private SensorProps[] mSensorProps;
|
||||
private LockoutResetDispatcher mLockoutResetDispatcher;
|
||||
private FaceProvider mFaceProvider;
|
||||
|
||||
private static void waitForIdle() {
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
|
||||
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
|
||||
|
||||
final SensorProps sensor1 = new SensorProps();
|
||||
sensor1.commonProps = new CommonProps();
|
||||
sensor1.commonProps.sensorId = 0;
|
||||
final SensorProps sensor2 = new SensorProps();
|
||||
sensor2.commonProps = new CommonProps();
|
||||
sensor2.commonProps.sensorId = 1;
|
||||
|
||||
mSensorProps = new SensorProps[] {sensor1, sensor2};
|
||||
|
||||
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
|
||||
|
||||
mFaceProvider = new FaceProvider(mContext, mSensorProps, TAG,
|
||||
mLockoutResetDispatcher);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void halServiceDied_resetsAllSchedulers() {
|
||||
assertEquals(mSensorProps.length, mFaceProvider.getSensorProperties().size());
|
||||
|
||||
// Schedule N operations on each sensor
|
||||
final int numFakeOperations = 10;
|
||||
for (SensorProps prop : mSensorProps) {
|
||||
final BiometricScheduler scheduler =
|
||||
mFaceProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
|
||||
for (int i = 0; i < numFakeOperations; i++) {
|
||||
final ClientMonitor testMonitor = mock(ClientMonitor.class);
|
||||
when(testMonitor.getFreshDaemon()).thenReturn(new Object());
|
||||
scheduler.scheduleClientMonitor(testMonitor);
|
||||
}
|
||||
}
|
||||
|
||||
waitForIdle();
|
||||
// The right amount of pending and current operations are scheduled
|
||||
for (SensorProps prop : mSensorProps) {
|
||||
final BiometricScheduler scheduler =
|
||||
mFaceProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
|
||||
assertEquals(numFakeOperations - 1, scheduler.getCurrentPendingCount());
|
||||
assertNotNull(scheduler.getCurrentClient());
|
||||
}
|
||||
|
||||
// It's difficult to test the linkToDeath --> serviceDied path, so let's just invoke
|
||||
// serviceDied directly.
|
||||
mFaceProvider.binderDied();
|
||||
waitForIdle();
|
||||
|
||||
// No pending operations, no current operation.
|
||||
for (SensorProps prop : mSensorProps) {
|
||||
final BiometricScheduler scheduler =
|
||||
mFaceProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
|
||||
assertNull(scheduler.getCurrentClient());
|
||||
assertEquals(0, scheduler.getCurrentPendingCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.sensors.face;
|
||||
package com.android.server.biometrics.sensors.face.hidl;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -28,8 +29,8 @@ import android.platform.test.annotations.Presubmit;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.server.biometrics.sensors.BiometricScheduler;
|
||||
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
|
||||
import com.android.server.biometrics.sensors.face.hidl.Face10;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -49,6 +50,8 @@ public class Face10Test {
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private BiometricScheduler mScheduler;
|
||||
|
||||
private LockoutResetDispatcher mLockoutResetDispatcher;
|
||||
private com.android.server.biometrics.sensors.face.hidl.Face10 mFace10;
|
||||
@@ -68,7 +71,7 @@ public class Face10Test {
|
||||
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
|
||||
mFace10 = new Face10(mContext, SENSOR_ID, BiometricManager.Authenticators.BIOMETRIC_STRONG,
|
||||
mLockoutResetDispatcher, false /* supportsSelfIllumination */,
|
||||
1 /* maxTemplatesAllowed */);
|
||||
1 /* maxTemplatesAllowed */, mScheduler);
|
||||
mBinder = new Binder();
|
||||
}
|
||||
|
||||
@@ -78,4 +81,13 @@ public class Face10Test {
|
||||
0 /* challenge */);
|
||||
waitForIdle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void halServiceDied_resetsScheduler() {
|
||||
// It's difficult to test the linkToDeath --> serviceDied path, so let's just invoke
|
||||
// serviceDied directly.
|
||||
mFace10.serviceDied(0 /* cookie */);
|
||||
waitForIdle();
|
||||
verify(mScheduler).reset();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.sensors.fingerprint.aidl;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.common.CommonProps;
|
||||
import android.hardware.biometrics.fingerprint.SensorProps;
|
||||
import android.os.UserManager;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.server.biometrics.sensors.BiometricScheduler;
|
||||
import com.android.server.biometrics.sensors.ClientMonitor;
|
||||
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
|
||||
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Presubmit
|
||||
@SmallTest
|
||||
public class FingerprintProviderTest {
|
||||
|
||||
private static final String TAG = "FingerprintProviderTest";
|
||||
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
|
||||
|
||||
private SensorProps[] mSensorProps;
|
||||
private LockoutResetDispatcher mLockoutResetDispatcher;
|
||||
private FingerprintProvider mFingerprintProvider;
|
||||
|
||||
private static void waitForIdle() {
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
|
||||
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
|
||||
|
||||
final SensorProps sensor1 = new SensorProps();
|
||||
sensor1.commonProps = new CommonProps();
|
||||
sensor1.commonProps.sensorId = 0;
|
||||
final SensorProps sensor2 = new SensorProps();
|
||||
sensor2.commonProps = new CommonProps();
|
||||
sensor2.commonProps.sensorId = 1;
|
||||
|
||||
mSensorProps = new SensorProps[] {sensor1, sensor2};
|
||||
|
||||
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
|
||||
|
||||
mFingerprintProvider = new FingerprintProvider(mContext, mSensorProps, TAG,
|
||||
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void halServiceDied_resetsAllSchedulers() {
|
||||
assertEquals(mSensorProps.length, mFingerprintProvider.getSensorProperties().size());
|
||||
|
||||
// Schedule N operations on each sensor
|
||||
final int numFakeOperations = 10;
|
||||
for (SensorProps prop : mSensorProps) {
|
||||
final BiometricScheduler scheduler =
|
||||
mFingerprintProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
|
||||
for (int i = 0; i < numFakeOperations; i++) {
|
||||
final ClientMonitor testMonitor = mock(ClientMonitor.class);
|
||||
when(testMonitor.getFreshDaemon()).thenReturn(new Object());
|
||||
scheduler.scheduleClientMonitor(testMonitor);
|
||||
}
|
||||
}
|
||||
|
||||
waitForIdle();
|
||||
// The right amount of pending and current operations are scheduled
|
||||
for (SensorProps prop : mSensorProps) {
|
||||
final BiometricScheduler scheduler =
|
||||
mFingerprintProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
|
||||
assertEquals(numFakeOperations - 1, scheduler.getCurrentPendingCount());
|
||||
assertNotNull(scheduler.getCurrentClient());
|
||||
}
|
||||
|
||||
// It's difficult to test the linkToDeath --> serviceDied path, so let's just invoke
|
||||
// serviceDied directly.
|
||||
mFingerprintProvider.binderDied();
|
||||
waitForIdle();
|
||||
|
||||
// No pending operations, no current operation.
|
||||
for (SensorProps prop : mSensorProps) {
|
||||
final BiometricScheduler scheduler =
|
||||
mFingerprintProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
|
||||
assertNull(scheduler.getCurrentClient());
|
||||
assertEquals(0, scheduler.getCurrentPendingCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.sensors.fingerprint.hidl;
|
||||
|
||||
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.res.Resources;
|
||||
import android.hardware.biometrics.BiometricManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.UserManager;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.server.biometrics.sensors.BiometricScheduler;
|
||||
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Presubmit
|
||||
@SmallTest
|
||||
public class Fingerprint21Test {
|
||||
|
||||
private static final String TAG = "Fingerprint21Test";
|
||||
private static final int SENSOR_ID = 1;
|
||||
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private Resources mResources;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
Fingerprint21.HalResultController mHalResultController;
|
||||
@Mock
|
||||
private BiometricScheduler mScheduler;
|
||||
|
||||
private LockoutResetDispatcher mLockoutResetDispatcher;
|
||||
private Fingerprint21 mFingerprint21;
|
||||
|
||||
private static void waitForIdle() {
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
|
||||
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getInteger(eq(R.integer.config_fingerprintMaxTemplatesPerUser)))
|
||||
.thenReturn(5);
|
||||
|
||||
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
|
||||
mFingerprint21 = new Fingerprint21(mContext, mScheduler,
|
||||
new Handler(Looper.getMainLooper()), SENSOR_ID,
|
||||
BiometricManager.Authenticators.BIOMETRIC_WEAK, mLockoutResetDispatcher,
|
||||
mHalResultController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void halServiceDied_resetsScheduler() {
|
||||
// It's difficult to test the linkToDeath --> serviceDied path, so let's just invoke
|
||||
// serviceDied directly.
|
||||
mFingerprint21.serviceDied(0 /* cookie */);
|
||||
waitForIdle();
|
||||
verify(mScheduler).reset();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user