4/n: Add and use Face AIDL start/stop user clients
Bug: 181984005 Test: atest CtsBiometricsTestCases Test: atest com.android.server.biometrics Change-Id: I1b62b12d3b99fd572450316168b6cea2c7a06e16
This commit is contained in:
@@ -78,7 +78,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
@NonNull private final String mHalInstanceName;
|
||||
@NonNull @VisibleForTesting
|
||||
final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
|
||||
@NonNull private final HalClientMonitor.LazyDaemon<IFace> mLazyDaemon;
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
|
||||
@NonNull private final UsageStats mUsageStats;
|
||||
@@ -126,7 +125,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
mContext = context;
|
||||
mHalInstanceName = halInstanceName;
|
||||
mSensors = new SparseArray<>();
|
||||
mLazyDaemon = this::getHalInstance;
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
mUsageStats = new UsageStats(context);
|
||||
mLockoutResetDispatcher = lockoutResetDispatcher;
|
||||
@@ -163,7 +161,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private synchronized IFace getHalInstance() {
|
||||
@VisibleForTesting
|
||||
synchronized IFace getHalInstance() {
|
||||
if (mTestHalEnabled) {
|
||||
return new TestHal();
|
||||
}
|
||||
@@ -214,22 +213,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
|
||||
}
|
||||
|
||||
private void createNewSessionWithoutHandler(@NonNull IFace daemon, int sensorId,
|
||||
int userId) throws RemoteException {
|
||||
// Note that per IFace createSession contract, this method will block until all
|
||||
// existing operations are canceled/finished. However, also note that this is fine, since
|
||||
// this method "withoutHandler" means it should only ever be invoked from the worker thread,
|
||||
// so callers will never be blocked.
|
||||
mSensors.get(sensorId).createNewSession(daemon, sensorId, userId);
|
||||
|
||||
if (FaceUtils.getInstance(sensorId).isInvalidationInProgress(mContext, userId)) {
|
||||
Slog.w(getTag(), "Scheduling unfinished invalidation request for sensor: " + sensorId
|
||||
+ ", user: " + userId);
|
||||
scheduleInvalidationRequest(sensorId, userId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void scheduleLoadAuthenticatorIds(int sensorId) {
|
||||
for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
|
||||
scheduleLoadAuthenticatorIdsForUser(sensorId, user.id);
|
||||
@@ -238,32 +221,16 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
|
||||
private void scheduleLoadAuthenticatorIdsForUser(int sensorId, int userId) {
|
||||
mHandler.post(() -> {
|
||||
final IFace daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during loadAuthenticatorIds, sensorId: " + sensorId);
|
||||
return;
|
||||
}
|
||||
final FaceGetAuthenticatorIdClient client = new FaceGetAuthenticatorIdClient(
|
||||
mContext, mSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId,
|
||||
mSensors.get(sensorId).getAuthenticatorIds());
|
||||
|
||||
try {
|
||||
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
|
||||
createNewSessionWithoutHandler(daemon, sensorId, userId);
|
||||
}
|
||||
|
||||
final FaceGetAuthenticatorIdClient client = new FaceGetAuthenticatorIdClient(
|
||||
mContext, mSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId,
|
||||
mSensors.get(sensorId).getAuthenticatorIds());
|
||||
|
||||
scheduleForSensor(sensorId, client);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Remote exception when scheduling loadAuthenticatorId"
|
||||
+ ", sensorId: " + sensorId
|
||||
+ ", userId: " + userId, e);
|
||||
}
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
private void scheduleInvalidationRequest(int sensorId, int userId) {
|
||||
void scheduleInvalidationRequest(int sensorId, int userId) {
|
||||
mHandler.post(() -> {
|
||||
final InvalidationRequesterClient<Face> client =
|
||||
new InvalidationRequesterClient<>(mContext, userId, sensorId,
|
||||
@@ -303,25 +270,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
public void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
|
||||
@NonNull IInvalidationCallback callback) {
|
||||
mHandler.post(() -> {
|
||||
final IFace daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during scheduleInvalidateAuthenticatorId: "
|
||||
+ sensorId);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
|
||||
createNewSessionWithoutHandler(daemon, sensorId, userId);
|
||||
}
|
||||
|
||||
final FaceInvalidationClient client = new FaceInvalidationClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), userId, sensorId,
|
||||
mSensors.get(sensorId).getAuthenticatorIds(), callback);
|
||||
scheduleForSensor(sensorId, client);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Remote exception", e);
|
||||
}
|
||||
final FaceInvalidationClient client = new FaceInvalidationClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), userId, sensorId,
|
||||
mSensors.get(sensorId).getAuthenticatorIds(), callback);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -344,25 +296,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
public void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token,
|
||||
@NonNull IFaceServiceReceiver receiver, String opPackageName) {
|
||||
mHandler.post(() -> {
|
||||
final IFace daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during generateChallenge, sensorId: " + sensorId);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
|
||||
createNewSessionWithoutHandler(daemon, sensorId, userId);
|
||||
}
|
||||
|
||||
final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), token,
|
||||
new ClientMonitorCallbackConverter(receiver), opPackageName, sensorId);
|
||||
|
||||
scheduleForSensor(sensorId, client);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Remote exception when scheduling generateChallenge", e);
|
||||
}
|
||||
final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), token,
|
||||
new ClientMonitorCallbackConverter(receiver), opPackageName, sensorId);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -370,25 +307,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
public void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token,
|
||||
@NonNull String opPackageName, long challenge) {
|
||||
mHandler.post(() -> {
|
||||
final IFace daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during revokeChallenge, sensorId: " + sensorId);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
|
||||
createNewSessionWithoutHandler(daemon, sensorId, userId);
|
||||
}
|
||||
|
||||
final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), token, opPackageName, sensorId,
|
||||
challenge);
|
||||
|
||||
scheduleForSensor(sensorId, client);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Remote exception when scheduling revokeChallenge", e);
|
||||
}
|
||||
final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), token, opPackageName, sensorId,
|
||||
challenge);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -398,41 +320,24 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
@NonNull String opPackageName, @NonNull int[] disabledFeatures,
|
||||
@Nullable NativeHandle previewSurface, boolean debugConsent) {
|
||||
mHandler.post(() -> {
|
||||
final IFace daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during enroll, sensorId: " + sensorId);
|
||||
// If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
|
||||
// this operation. We should not send the callback yet, since the scheduler may
|
||||
// be processing something else.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
|
||||
createNewSessionWithoutHandler(daemon, sensorId, userId);
|
||||
}
|
||||
|
||||
final int maxTemplatesPerUser = mSensors.get(
|
||||
sensorId).getSensorProperties().maxEnrollmentsPerUser;
|
||||
final FaceEnrollClient client = new FaceEnrollClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), token,
|
||||
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
|
||||
opPackageName, FaceUtils.getInstance(sensorId), disabledFeatures,
|
||||
ENROLL_TIMEOUT_SEC, previewSurface, sensorId, maxTemplatesPerUser,
|
||||
debugConsent);
|
||||
scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() {
|
||||
@Override
|
||||
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
|
||||
boolean success) {
|
||||
if (success) {
|
||||
scheduleLoadAuthenticatorIdsForUser(sensorId, userId);
|
||||
scheduleInvalidationRequest(sensorId, userId);
|
||||
}
|
||||
final int maxTemplatesPerUser = mSensors.get(
|
||||
sensorId).getSensorProperties().maxEnrollmentsPerUser;
|
||||
final FaceEnrollClient client = new FaceEnrollClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), token,
|
||||
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
|
||||
opPackageName, FaceUtils.getInstance(sensorId), disabledFeatures,
|
||||
ENROLL_TIMEOUT_SEC, previewSurface, sensorId, maxTemplatesPerUser,
|
||||
debugConsent);
|
||||
scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() {
|
||||
@Override
|
||||
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
|
||||
boolean success) {
|
||||
if (success) {
|
||||
scheduleLoadAuthenticatorIdsForUser(sensorId, userId);
|
||||
scheduleInvalidationRequest(sensorId, userId);
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Remote exception when scheduling enroll", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -447,31 +352,14 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
@NonNull String opPackageName, boolean restricted, int statsClient,
|
||||
boolean allowBackgroundAuthentication) {
|
||||
mHandler.post(() -> {
|
||||
final IFace daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during authenticate, sensorId: " + sensorId);
|
||||
// If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
|
||||
// this operation. We should not send the callback yet, since the scheduler may
|
||||
// be processing something else.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
|
||||
createNewSessionWithoutHandler(daemon, sensorId, userId);
|
||||
}
|
||||
|
||||
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
|
||||
final FaceAuthenticationClient client = new FaceAuthenticationClient(
|
||||
mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
|
||||
operationId, restricted, opPackageName, cookie,
|
||||
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
|
||||
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
|
||||
allowBackgroundAuthentication);
|
||||
scheduleForSensor(sensorId, client);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Remote exception when scheduling authenticate", e);
|
||||
}
|
||||
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
|
||||
final FaceAuthenticationClient client = new FaceAuthenticationClient(
|
||||
mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
|
||||
operationId, restricted, opPackageName, cookie,
|
||||
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
|
||||
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
|
||||
allowBackgroundAuthentication);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -503,56 +391,24 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
private void scheduleRemoveSpecifiedIds(int sensorId, @NonNull IBinder token, int[] faceIds,
|
||||
int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
|
||||
mHandler.post(() -> {
|
||||
final IFace daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during remove, sensorId: " + sensorId);
|
||||
// If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
|
||||
// this operation. We should not send the callback yet, since the scheduler may
|
||||
// be processing something else.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
|
||||
createNewSessionWithoutHandler(daemon, sensorId, userId);
|
||||
}
|
||||
|
||||
final FaceRemovalClient client = new FaceRemovalClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), token,
|
||||
new ClientMonitorCallbackConverter(receiver), faceIds, userId,
|
||||
opPackageName, FaceUtils.getInstance(sensorId), sensorId,
|
||||
mSensors.get(sensorId).getAuthenticatorIds());
|
||||
|
||||
scheduleForSensor(sensorId, client);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Remote exception when scheduling remove", e);
|
||||
}
|
||||
final FaceRemovalClient client = new FaceRemovalClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), token,
|
||||
new ClientMonitorCallbackConverter(receiver), faceIds, userId,
|
||||
opPackageName, FaceUtils.getInstance(sensorId), sensorId,
|
||||
mSensors.get(sensorId).getAuthenticatorIds());
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduleResetLockout(int sensorId, int userId, @NonNull byte[] hardwareAuthToken) {
|
||||
mHandler.post(() -> {
|
||||
final IFace daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during resetLockout, sensorId: " + sensorId);
|
||||
return;
|
||||
}
|
||||
final FaceResetLockoutClient client = new FaceResetLockoutClient(
|
||||
mContext, mSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId, hardwareAuthToken,
|
||||
mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher);
|
||||
|
||||
try {
|
||||
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
|
||||
createNewSessionWithoutHandler(daemon, sensorId, userId);
|
||||
}
|
||||
|
||||
final FaceResetLockoutClient client = new FaceResetLockoutClient(
|
||||
mContext, mSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId, hardwareAuthToken,
|
||||
mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher);
|
||||
|
||||
scheduleForSensor(sensorId, client);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Remote exception when scheduling resetLockout", e);
|
||||
}
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -580,29 +436,14 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
public void scheduleInternalCleanup(int sensorId, int userId,
|
||||
@Nullable BaseClientMonitor.Callback callback) {
|
||||
mHandler.post(() -> {
|
||||
final IFace daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during internal cleanup, sensorId: " + sensorId);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
|
||||
createNewSessionWithoutHandler(daemon, sensorId, userId);
|
||||
}
|
||||
|
||||
final List<Face> enrolledList = getEnrolledFaces(sensorId, userId);
|
||||
final FaceInternalCleanupClient client =
|
||||
new FaceInternalCleanupClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId, enrolledList,
|
||||
FaceUtils.getInstance(sensorId),
|
||||
mSensors.get(sensorId).getAuthenticatorIds());
|
||||
|
||||
scheduleForSensor(sensorId, client);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Remote exception when scheduling internal cleanup", e);
|
||||
}
|
||||
final List<Face> enrolledList = getEnrolledFaces(sensorId, userId);
|
||||
final FaceInternalCleanupClient client =
|
||||
new FaceInternalCleanupClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId, enrolledList,
|
||||
FaceUtils.getInstance(sensorId),
|
||||
mSensors.get(sensorId).getAuthenticatorIds());
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.face.IFace;
|
||||
import android.hardware.biometrics.face.ISession;
|
||||
import android.hardware.biometrics.face.ISessionCallback;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.biometrics.sensors.StartUserClient;
|
||||
|
||||
public class FaceStartUserClient extends StartUserClient<IFace, ISession> {
|
||||
private static final String TAG = "FaceStartUserClient";
|
||||
|
||||
@NonNull private final ISessionCallback mSessionCallback;
|
||||
|
||||
public FaceStartUserClient(@NonNull Context context, @NonNull LazyDaemon<IFace> lazyDaemon,
|
||||
@Nullable IBinder token, int userId, int sensorId,
|
||||
@NonNull ISessionCallback sessionCallback,
|
||||
@NonNull UserStartedCallback<ISession> callback) {
|
||||
super(context, lazyDaemon, token, userId, sensorId, callback);
|
||||
mSessionCallback = sessionCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(@NonNull Callback callback) {
|
||||
super.start(callback);
|
||||
startHalOperation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
try {
|
||||
final ISession newSession = getFreshDaemon().createSession(getSensorId(),
|
||||
getTargetUserId(), mSessionCallback);
|
||||
mUserStartedCallback.onUserStarted(getTargetUserId(), newSession);
|
||||
getCallback().onClientFinished(this, true /* success */);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
getCallback().onClientFinished(this, false /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unableToStart() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.face.ISession;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.biometrics.sensors.StopUserClient;
|
||||
|
||||
public class FaceStopUserClient extends StopUserClient<ISession> {
|
||||
private static final String TAG = "FaceStopUserClient";
|
||||
|
||||
public FaceStopUserClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
|
||||
@Nullable IBinder token, int userId, int sensorId,
|
||||
@NonNull UserStoppedCallback callback) {
|
||||
super(context, lazyDaemon, token, userId, sensorId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(@NonNull Callback callback) {
|
||||
super.start(callback);
|
||||
startHalOperation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
try {
|
||||
getFreshDaemon().close(mSequentialId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
getCallback().onClientFinished(this, false /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unableToStart() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,11 @@ import android.hardware.face.Face;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.FaceSensorPropertiesInternal;
|
||||
import android.hardware.keymaster.HardwareAuthToken;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Slog;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
@@ -54,6 +57,9 @@ import com.android.server.biometrics.sensors.Interruptable;
|
||||
import com.android.server.biometrics.sensors.LockoutCache;
|
||||
import com.android.server.biometrics.sensors.LockoutConsumer;
|
||||
import com.android.server.biometrics.sensors.RemovalConsumer;
|
||||
import com.android.server.biometrics.sensors.StartUserClient;
|
||||
import com.android.server.biometrics.sensors.StopUserClient;
|
||||
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
|
||||
import com.android.server.biometrics.sensors.face.FaceUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -70,9 +76,10 @@ public class Sensor {
|
||||
@NonNull private final String mTag;
|
||||
@NonNull private final FaceProvider mProvider;
|
||||
@NonNull private final Context mContext;
|
||||
@NonNull private final IBinder mToken;
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final FaceSensorPropertiesInternal mSensorProperties;
|
||||
@NonNull private final BiometricScheduler mScheduler;
|
||||
@NonNull private final UserAwareBiometricScheduler mScheduler;
|
||||
@NonNull private final LockoutCache mLockoutCache;
|
||||
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
|
||||
@NonNull private final HalClientMonitor.LazyDaemon<ISession> mLazySession;
|
||||
@@ -427,7 +434,15 @@ public class Sensor {
|
||||
@Override
|
||||
public void onSessionClosed() {
|
||||
mHandler.post(() -> {
|
||||
// TODO: implement this.
|
||||
final BaseClientMonitor client = mScheduler.getCurrentClient();
|
||||
if (!(client instanceof FaceStopUserClient)) {
|
||||
Slog.e(mTag, "onSessionClosed for wrong consumer: "
|
||||
+ Utils.getClientName(client));
|
||||
return;
|
||||
}
|
||||
|
||||
final FaceStopUserClient stopUserClient = (FaceStopUserClient) client;
|
||||
stopUserClient.onUserStopped();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -437,9 +452,53 @@ public class Sensor {
|
||||
mTag = tag;
|
||||
mProvider = provider;
|
||||
mContext = context;
|
||||
mToken = new Binder();
|
||||
mHandler = handler;
|
||||
mSensorProperties = sensorProperties;
|
||||
mScheduler = new BiometricScheduler(tag, null /* gestureAvailabilityDispatcher */);
|
||||
mScheduler = new UserAwareBiometricScheduler(tag, null /* gestureAvailabilityDispatcher */,
|
||||
() -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL,
|
||||
new UserAwareBiometricScheduler.UserSwitchCallback() {
|
||||
@NonNull
|
||||
@Override
|
||||
public StopUserClient<?> getStopUserClient(int userId) {
|
||||
return new FaceStopUserClient(mContext, mLazySession, mToken, userId,
|
||||
mSensorProperties.sensorId, () -> mCurrentSession = null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public StartUserClient<?, ?> getStartUserClient(int newUserId) {
|
||||
final HalSessionCallback.Callback callback = () -> {
|
||||
Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
|
||||
mCurrentSession = null;
|
||||
};
|
||||
|
||||
final int sensorId = mSensorProperties.sensorId;
|
||||
|
||||
final HalSessionCallback resultController = new HalSessionCallback(mContext,
|
||||
mHandler, mTag, mScheduler, sensorId, newUserId, callback);
|
||||
|
||||
final StartUserClient.UserStartedCallback<ISession> userStartedCallback =
|
||||
(userIdStarted, newSession) -> {
|
||||
mCurrentSession = new Session(mTag, newSession, userIdStarted,
|
||||
resultController);
|
||||
if (FaceUtils.getLegacyInstance(sensorId)
|
||||
.isInvalidationInProgress(mContext, userIdStarted)) {
|
||||
Slog.w(mTag,
|
||||
"Scheduling unfinished invalidation request for "
|
||||
+ "sensor: "
|
||||
+ sensorId
|
||||
+ ", user: " + userIdStarted);
|
||||
provider.scheduleInvalidationRequest(sensorId,
|
||||
userIdStarted);
|
||||
}
|
||||
};
|
||||
|
||||
return new FaceStartUserClient(mContext, provider::getHalInstance,
|
||||
mToken, newUserId, mSensorProperties.sensorId,
|
||||
resultController, userStartedCallback);
|
||||
}
|
||||
});
|
||||
mLockoutCache = new LockoutCache();
|
||||
mAuthenticatorIds = new HashMap<>();
|
||||
mLazySession = () -> mCurrentSession != null ? mCurrentSession.mSession : null;
|
||||
@@ -453,11 +512,6 @@ public class Sensor {
|
||||
return mSensorProperties;
|
||||
}
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
boolean hasSessionForUser(int userId) {
|
||||
return mCurrentSession != null && mCurrentSession.mUserId == userId;
|
||||
}
|
||||
|
||||
@Nullable Session getSessionForUser(int userId) {
|
||||
if (mCurrentSession != null && mCurrentSession.mUserId == userId) {
|
||||
return mCurrentSession;
|
||||
@@ -471,20 +525,6 @@ public class Sensor {
|
||||
mProvider, this);
|
||||
}
|
||||
|
||||
void createNewSession(@NonNull IFace daemon, int sensorId, int userId)
|
||||
throws RemoteException {
|
||||
|
||||
final HalSessionCallback.Callback callback = () -> {
|
||||
Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
|
||||
mCurrentSession = null;
|
||||
};
|
||||
final HalSessionCallback resultController = new HalSessionCallback(mContext, mHandler,
|
||||
mTag, mScheduler, sensorId, userId, callback);
|
||||
|
||||
final ISession newSession = daemon.createSession(sensorId, userId, resultController);
|
||||
mCurrentSession = new Session(mTag, newSession, userId, resultController);
|
||||
}
|
||||
|
||||
@NonNull BiometricScheduler getScheduler() {
|
||||
return mScheduler;
|
||||
}
|
||||
|
||||
@@ -24,10 +24,12 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.common.CommonProps;
|
||||
import android.hardware.biometrics.face.IFace;
|
||||
import android.hardware.biometrics.face.SensorProps;
|
||||
import android.os.UserManager;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
@@ -56,7 +58,7 @@ public class FaceProviderTest {
|
||||
|
||||
private SensorProps[] mSensorProps;
|
||||
private LockoutResetDispatcher mLockoutResetDispatcher;
|
||||
private FaceProvider mFaceProvider;
|
||||
private TestableFaceProvider mFaceProvider;
|
||||
|
||||
private static void waitForIdle() {
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
@@ -80,7 +82,7 @@ public class FaceProviderTest {
|
||||
|
||||
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
|
||||
|
||||
mFaceProvider = new FaceProvider(mContext, mSensorProps, TAG,
|
||||
mFaceProvider = new TestableFaceProvider(mContext, mSensorProps, TAG,
|
||||
mLockoutResetDispatcher);
|
||||
}
|
||||
|
||||
@@ -123,4 +125,19 @@ public class FaceProviderTest {
|
||||
assertEquals(0, scheduler.getCurrentPendingCount());
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestableFaceProvider extends FaceProvider {
|
||||
public TestableFaceProvider(@NonNull Context context,
|
||||
@NonNull SensorProps[] props,
|
||||
@NonNull String halInstanceName,
|
||||
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
|
||||
super(context, props, halInstanceName, lockoutResetDispatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized IFace getHalInstance() {
|
||||
return mock(IFace.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user