summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjhenrique09 <jhenrique09.mcz@hotmail.com>2021-02-07 17:04:10 -0300
committeralk3pInjection <webmaster@raspii.tech>2021-09-27 21:17:05 +0800
commit7daab42d9d514cee5e834cdfb8f22b133cf82837 (patch)
treee73ecf6ae96997280422a9d92f74062daaaa66a8
parent91979844fefd134ca24ced2b4f8a318cd4a9b445 (diff)
[ArrowOS][11.0] base: Port face unlock feature
From motorola/nio_retcn/nio:11/RRN31.Q1-20-17-1/1cbc0:user/release-keys Change-Id: I493fb57047ae7b9fe7ce775667207b60889070ba
-rw-r--r--packages/SystemUI/Android.bp1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java14
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricServiceBase.java18
-rw-r--r--services/core/java/com/android/server/biometrics/face/CustomFaceService.java448
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java96
6 files changed, 562 insertions, 16 deletions
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index c78630c05f08..7e481112aaca 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -73,6 +73,7 @@ android_library {
"org.lineageos.platform.internal",
"vendor.lineage.biometrics.fingerprint.inscreen-V1.0-java",
"vendor.lineage.powershare-V1.0-java",
+ "faceunlock_framework",
],
manifest: "AndroidManifest.xml",
additional_manifests: ["LineageManifest.xml"],
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 4f6447849741..5e55df5eb388 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -127,6 +127,8 @@ import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Singleton;
+import com.android.internal.util.custom.faceunlock.FaceUnlockUtils;
+
/**
* Watches for updates that may be interesting to the keyguard, and provides
* the up to date information as well as a registration for callbacks that care
@@ -289,6 +291,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private final boolean mFingerprintWakeAndUnlock;
+ // Face unlock
+ private static final boolean mCustomFaceUnlockSupported = FaceUnlockUtils.isFaceUnlockSupported();
+
/**
* Short delay before restarting fingerprint authentication after a successful try. This should
* be slightly longer than the time between onFingerprintAuthenticated and
@@ -979,6 +984,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean isFaceDisabled(int userId) {
final DevicePolicyManager dpm =
(DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (mCustomFaceUnlockSupported && dpm != null) {
+ try {
+ if (dpm.getPasswordQuality(null, userId) > 32768) {
+ return true;
+ }
+ } catch (SecurityException e) {
+ Log.e("KeyguardUpdateMonitor", "isFaceDisabled error:", e);
+ }
+ }
// TODO(b/140035044)
return whitelistIpcs(() -> dpm != null && (dpm.getKeyguardDisabledFeatures(null, userId)
& DevicePolicyManager.KEYGUARD_DISABLE_FACE) != 0
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 55e109e33295..59f286dbe8f5 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -142,6 +142,7 @@ java_library_static {
"overlayable_policy_aidl-java",
"SurfaceFlingerProperties",
"vendor.lineage.biometrics.fingerprint.inscreen-V1.0-java",
+ "faceunlock_framework",
],
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 5bb4d272eae8..c79e9555337f 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -718,7 +718,7 @@ public abstract class BiometricServiceBase extends SystemService
* Callback handlers from the daemon. The caller must put this on a handler.
*/
- protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
+ public void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
ClientMonitor client = mCurrentClient;
if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
removeClient(client);
@@ -730,7 +730,7 @@ public abstract class BiometricServiceBase extends SystemService
}
}
- protected void handleAuthenticated(boolean authenticated,
+ public void handleAuthenticated(boolean authenticated,
BiometricAuthenticator.Identifier identifier, ArrayList<Byte> token) {
ClientMonitor client = mCurrentClient;
@@ -746,7 +746,7 @@ public abstract class BiometricServiceBase extends SystemService
}
}
- protected void handleEnrollResult(BiometricAuthenticator.Identifier identifier,
+ public void handleEnrollResult(BiometricAuthenticator.Identifier identifier,
int remaining) {
ClientMonitor client = mCurrentClient;
if (client != null && client.onEnrollResult(identifier, remaining)) {
@@ -759,7 +759,7 @@ public abstract class BiometricServiceBase extends SystemService
}
}
- protected void handleError(long deviceId, int error, int vendorCode) {
+ public void handleError(long deviceId, int error, int vendorCode) {
final ClientMonitor client = mCurrentClient;
if (DEBUG) Slog.v(getTag(), "handleError(client="
@@ -785,7 +785,7 @@ public abstract class BiometricServiceBase extends SystemService
}
}
- protected void handleRemoved(BiometricAuthenticator.Identifier identifier,
+ public void handleRemoved(BiometricAuthenticator.Identifier identifier,
final int remaining) {
if (DEBUG) Slog.w(getTag(), "Removed: fid=" + identifier.getBiometricId()
+ ", dev=" + identifier.getDeviceId()
@@ -811,7 +811,7 @@ public abstract class BiometricServiceBase extends SystemService
}
}
- protected void handleEnumerate(BiometricAuthenticator.Identifier identifier, int remaining) {
+ public void handleEnumerate(BiometricAuthenticator.Identifier identifier, int remaining) {
ClientMonitor client = mCurrentClient;
if (client != null) {
client.onEnumerationResult(identifier, remaining);
@@ -1170,7 +1170,7 @@ public abstract class BiometricServiceBase extends SystemService
/**
* Populates existing authenticator ids. To be used only during the start of the service.
*/
- protected void loadAuthenticatorIds() {
+ public void loadAuthenticatorIds() {
// This operation can be expensive, so keep track of the elapsed time. Might need to move to
// background if it takes too long.
long t = System.currentTimeMillis();
@@ -1249,7 +1249,7 @@ public abstract class BiometricServiceBase extends SystemService
* This method should be called upon connection to the daemon, and when user switches.
* @param userId
*/
- protected void doTemplateCleanupForUser(int userId) {
+ public void doTemplateCleanupForUser(int userId) {
if (mCleanupUnusedFingerprints) {
enumerateUser(userId);
}
@@ -1313,7 +1313,7 @@ public abstract class BiometricServiceBase extends SystemService
doTemplateCleanupForUser(userId);
}
- protected void notifyLockoutResetMonitors() {
+ public void notifyLockoutResetMonitors() {
for (int i = 0; i < mLockoutMonitors.size(); i++) {
mLockoutMonitors.get(i).sendLockoutReset();
}
diff --git a/services/core/java/com/android/server/biometrics/face/CustomFaceService.java b/services/core/java/com/android/server/biometrics/face/CustomFaceService.java
new file mode 100644
index 000000000000..1a79610e33db
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/face/CustomFaceService.java
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2021 PixelExperience
+ *
+ * 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.face;
+
+import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS;
+import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_TIMEOUT;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.hardware.face.Face;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.server.biometrics.AuthenticationClient;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import com.android.internal.util.custom.faceunlock.IFaceService;
+import com.android.internal.util.custom.faceunlock.IFaceServiceReceiver;
+import com.android.internal.util.custom.faceunlock.FaceUnlockUtils;
+
+/**
+ * @hide
+ */
+public class CustomFaceService {
+
+ protected static final String TAG = "CustomFaceService";
+
+ public static final int HAL_DEVICE_ID = 1008;
+
+ private Context mContext;
+ private FaceService mFaceService;
+ private Handler mHandler;
+
+ private int mCurrentUserId;
+
+ private Handler mServiceHandler;
+ private boolean mIsServiceBinding = false;
+ private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (FaceUnlockUtils.isFaceUnlockSupported()) {
+ if (getService(mCurrentUserId) == null) {
+ bind(mCurrentUserId);
+ }
+ }
+ }
+ };
+
+ final SparseArray<IFaceService> mServices = new SparseArray<>();
+ final IFaceServiceReceiver mReceiver = new IFaceServiceReceiver.Stub() {
+ @Override
+ public void onEnrollResult(int faceId, int userId, int remaining) {
+ mHandler.post(() -> {
+ mFaceService.handleEnrollResult(new Face(
+ mFaceService.getBiometricUtils().getUniqueName(
+ mContext, userId), faceId, HAL_DEVICE_ID), remaining);
+ });
+ }
+
+ @Override
+ public void onAuthenticated(int faceId, int userId, byte[] token) {
+ mHandler.post(() -> {
+ final boolean authenticated = faceId != 0;
+ if (token == null || faceId <= 0) {
+ if (token == null && faceId > 0) {
+ Slog.e("FaceService", "token should not be null for authentication success");
+ }
+ Slog.w("FaceService", "onAuthenticated failure");
+ mFaceService.handleAuthenticated(authenticated, new Face("", 0, HAL_DEVICE_ID), null);
+ return;
+ }
+ Face face = new Face("", faceId, HAL_DEVICE_ID);
+ ArrayList<Byte> token_AL = new ArrayList<>(token.length);
+ for (byte b : token) {
+ token_AL.add(new Byte(b));
+ }
+ mFaceService.handleAuthenticated(authenticated, face, token_AL);
+ });
+ }
+
+ @Override
+ public void onAcquired(int userId, int acquiredInfo, int vendorCode) {
+ mHandler.post(() -> {
+ mFaceService.handleAcquired(HAL_DEVICE_ID, acquiredInfo, vendorCode);
+ });
+ }
+
+ @Override
+ public void onError(int error, int vendorCode) {
+ mHandler.post(() -> {
+ mFaceService.handleError(HAL_DEVICE_ID, error, vendorCode);
+ });
+ }
+
+ @Override
+ public void onRemoved(int[] faceIds, int userId) throws RemoteException {
+ mHandler.post(() -> {
+ if (faceIds.length > 0) {
+ for (int i = 0; i < faceIds.length; i++) {
+ mFaceService.handleRemoved(new Face("", faceIds[i], HAL_DEVICE_ID), (faceIds.length - i) - 1);
+ }
+ return;
+ }
+ mFaceService.handleRemoved(new Face("", 0, HAL_DEVICE_ID), 0);
+ });
+ }
+
+ @Override
+ public void onEnumerate(int[] faceIds, int userId) throws RemoteException {
+ mHandler.post(() -> {
+ if (faceIds.length > 0) {
+ for (int i = 0; i < faceIds.length; i++) {
+ mFaceService.handleEnumerate(new Face("", faceIds[i], HAL_DEVICE_ID), (faceIds.length - i) - 1);
+ }
+ return;
+ }
+ mFaceService.handleEnumerate(null, 0);
+ });
+ }
+
+ @Override
+ public void onLockoutChanged(long duration) throws RemoteException {
+ if (duration == 0) {
+ mFaceService.mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_NONE;
+ } else if (duration == Long.MAX_VALUE) {
+ mFaceService.mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_PERMANENT;
+ } else {
+ mFaceService.mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_TIMED;
+ }
+ mHandler.post(() -> {
+ if (duration == 0) {
+ mFaceService.notifyLockoutResetMonitors();
+ }
+ });
+ }
+ };
+
+ public CustomFaceService(Context context, FaceService service, Handler handler) {
+ mContext = context;
+ mFaceService = service;
+ mHandler = handler;
+ mContext.registerReceiver(mUserUnlockReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
+ }
+
+ public int authenticate(long operationId) {
+ IFaceService service = getService(mCurrentUserId);
+ if (service != null) {
+ try {
+ service.authenticate(operationId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "authenticate failed", e);
+ }
+ return BIOMETRIC_SUCCESS;
+ }
+ bind(mCurrentUserId);
+ Slog.w(TAG, "authenticate(): Face service not started!");
+ return BIOMETRIC_ERROR_TIMEOUT;
+ }
+
+ public int cancel() {
+ IFaceService service = getService(mCurrentUserId);
+ if (service == null) {
+ return BIOMETRIC_SUCCESS;
+ }
+
+ try {
+ service.cancel();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "cancel failed", e);
+ }
+ return BIOMETRIC_SUCCESS;
+ }
+
+ public int remove(int biometricId) {
+ IFaceService service = getService(mCurrentUserId);
+ if (service != null) {
+ try {
+ service.remove(biometricId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "remove failed", e);
+ }
+ return BIOMETRIC_SUCCESS;
+ }
+ bind(mCurrentUserId);
+ Slog.w(TAG, "remove(): Face service not started!");
+ return BIOMETRIC_ERROR_TIMEOUT;
+ }
+
+ public int enumerate() {
+ IFaceService service = getService(mCurrentUserId);
+ if (service != null) {
+ mServiceHandler.post(() -> {
+ try {
+ service.enumerate();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "enumerate failed", e);
+ mHandler.post(() -> {
+ mFaceService.handleError(HAL_DEVICE_ID, 8, 0);
+ });
+ }
+ });
+ return BIOMETRIC_SUCCESS;
+ }
+ bind(mCurrentUserId);
+ Slog.w(TAG, "enumerate(): Face service not started!");
+ return BIOMETRIC_ERROR_TIMEOUT;
+ }
+
+ public int enroll(byte[] cryptoToken, int timeout, int[] disabledFeatures) {
+ IFaceService service = getService(mCurrentUserId);
+ if (service != null) {
+ try {
+ service.enroll(cryptoToken, timeout, disabledFeatures);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "enroll failed", e);
+ }
+ return BIOMETRIC_SUCCESS;
+ }
+ bind(mCurrentUserId);
+ Slog.w(FaceService.TAG, "enroll(): Face service not started!");
+ return BIOMETRIC_ERROR_TIMEOUT;
+ }
+
+ public void resetLockout(byte[] cryptoToken) {
+ IFaceService service = getService(mCurrentUserId);
+ if (service != null) {
+ try {
+ service.resetLockout(cryptoToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return;
+ }
+ bind(mCurrentUserId);
+ Slog.w(TAG, "resetLockout(): Face service not started!");
+ }
+
+ public int getAuthenticatorId() {
+ int authId = 0;
+ IFaceService service = getService(mCurrentUserId);
+ if (service != null) {
+ try {
+ authId = service.getAuthenticatorId();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return authId;
+ }
+ bind(mCurrentUserId);
+ Slog.w(TAG, "updateActiveGroup(): Face service not started!");
+ return authId;
+ }
+
+ public long generateChallenge(int timeout) {
+ IFaceService service = getService(mCurrentUserId);
+ if (service != null) {
+ try {
+ return service.generateChallenge(timeout);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ bind(mCurrentUserId);
+ Slog.w(TAG, "startGenerateChallenge(): Face service not started!");
+ }
+ return BIOMETRIC_SUCCESS;
+ }
+
+ public int revokeChallenge() {
+ IFaceService service = getService(mCurrentUserId);
+ if (service != null) {
+ try {
+ return service.revokeChallenge();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return BIOMETRIC_SUCCESS;
+ }
+
+ public void setCurrentUserId(int userId) {
+ mCurrentUserId = userId;
+ }
+
+ public void setServiceHandler(Handler handler) {
+ mServiceHandler = handler;
+ }
+
+ public boolean callForBind(int userId) {
+ return bind(userId);
+ }
+
+ private boolean bind(int userId) {
+ Slog.d(TAG, "bind");
+ if (!isServiceEnabled()) {
+ Slog.d(TAG, "Face service disabled");
+ return false;
+ } else if (mIsServiceBinding) {
+ Slog.d(TAG, "Face service is binding");
+ return true;
+ } else {
+ if (userId != UserHandle.USER_NULL && getService(userId) == null) {
+ if (createService(userId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private boolean createService(int userId) {
+ try {
+ Intent intent = getServiceIntent();
+ if (intent == null) {
+ Slog.d(TAG, "Face service not found");
+ return false;
+ }
+ boolean result = mContext.bindServiceAsUser(intent, new FaceServiceConnection(userId), 1, UserHandle.of(userId));
+ if (result) {
+ mIsServiceBinding = true;
+ }
+ return result;
+ } catch (Exception e) {
+ Slog.e(TAG, "bind failed", e);
+ }
+ return false;
+ }
+
+ public IFaceService getService(int userId) {
+ if (userId == UserHandle.USER_NULL) {
+ mFaceService.updateActiveGroup(ActivityManager.getCurrentUser(), null);
+ }
+ return mServices.get(mCurrentUserId);
+ }
+
+ private Intent getServiceIntent() {
+ Intent intent = new Intent("org.pixelexperience.faceunlock.BIND");
+ intent.setComponent(ComponentName.unflattenFromString(
+ "org.pixelexperience.faceunlock/org.pixelexperience.faceunlock.service.FaceAuthService"));
+ return intent;
+ }
+
+ public String getServicePackageName() {
+ return "org.pixelexperience.faceunlock";
+ }
+
+ private boolean isServiceEnabled() {
+ if (!FaceUnlockUtils.isFaceUnlockSupported()) {
+ return false;
+ }
+ PackageManager pm = mContext.getPackageManager();
+ Intent intent = getServiceIntent();
+ ResolveInfo info = pm.resolveService(intent, PackageManager.MATCH_ALL);
+ return info != null && info.serviceInfo.isEnabled();
+ }
+
+ public boolean isSupported() {
+ return FaceUnlockUtils.isFaceUnlockSupported();
+ }
+
+ public boolean isDetected() {
+ boolean enabled = isServiceEnabled();
+ if (enabled) {
+ mHandler.post(() -> {
+ if (getService(mCurrentUserId) == null) {
+ bind(mCurrentUserId);
+ }
+ });
+ }
+ return enabled;
+ }
+
+ private class FaceServiceConnection implements ServiceConnection {
+ int mUserId;
+
+ public FaceServiceConnection(int userId) {
+ mUserId = userId;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Slog.d(TAG, "Face service connected");
+ IFaceService faceService = IFaceService.Stub.asInterface(service);
+ if (faceService != null) {
+ synchronized (mServices) {
+ try {
+ faceService.setCallback(mReceiver);
+ mServices.put(mUserId, faceService);
+ mHandler.post(() -> {
+ if (mServices.size() == 1) {
+ mFaceService.loadAuthenticatorIds();
+ }
+ mFaceService.updateActiveGroup(mUserId, null);
+ mFaceService.doTemplateCleanupForUser(mUserId);
+ });
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ mIsServiceBinding = false;
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ Slog.d(TAG, "Face service disconnected");
+ mServices.remove(mUserId);
+ mIsServiceBinding = false;
+ if (mUserId == mCurrentUserId) {
+ mHandler.postDelayed(() -> {
+ mFaceService.handleError(HAL_DEVICE_ID, 8, 0);
+ bind(mUserId);
+ }, 100);
+ mContext.unbindService(this);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index e5a1898459a2..e43f4f9e3c3b 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -60,6 +60,7 @@ import android.util.Slog;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.biometrics.AuthenticationClient;
@@ -226,7 +227,7 @@ public class FaceService extends BiometricServiceBase {
@Override
public boolean shouldFrameworkHandleLockout() {
- return false;
+ return mCustomFaceService.isSupported();
}
@Override
@@ -379,7 +380,7 @@ public class FaceService extends BiometricServiceBase {
public void enroll(int userId, final IBinder token, final byte[] cryptoToken,
final IFaceServiceReceiver receiver, final String opPackageName,
final int[] disabledFeatures) {
- checkPermission(MANAGE_BIOMETRIC);
+ checkPermission(MANAGE_BIOMETRIC, opPackageName);
updateActiveGroup(userId, opPackageName);
mHandler.post(() -> {
@@ -419,7 +420,7 @@ public class FaceService extends BiometricServiceBase {
@Override // Binder call
public void cancelEnrollment(final IBinder token) {
- checkPermission(MANAGE_BIOMETRIC);
+ checkPermission(MANAGE_BIOMETRIC, mCustomFaceService.getServicePackageName());
cancelEnrollmentInternal(token);
}
@@ -559,6 +560,10 @@ public class FaceService extends BiometricServiceBase {
return false;
}
+ if (mCustomFaceService.isSupported()) {
+ return mCustomFaceService.isDetected();
+ }
+
final long token = Binder.clearCallingIdentity();
try {
IBiometricsFace daemon = getFaceDaemon();
@@ -585,7 +590,7 @@ public class FaceService extends BiometricServiceBase {
@Override // Binder call
public List<Face> getEnrolledFaces(int userId, String opPackageName) {
- checkPermission(MANAGE_BIOMETRIC);
+ checkPermission(MANAGE_BIOMETRIC, opPackageName);
if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
@@ -597,7 +602,7 @@ public class FaceService extends BiometricServiceBase {
@Override // Binder call
public boolean hasEnrolledFaces(int userId, String opPackageName) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
+ checkPermission(USE_BIOMETRIC_INTERNAL, opPackageName);
if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
@@ -845,8 +850,9 @@ public class FaceService extends BiometricServiceBase {
private UsageStats mUsageStats;
private boolean mRevokeChallengePending = false;
// One of the AuthenticationClient constants
- private int mCurrentUserLockoutMode;
+ protected int mCurrentUserLockoutMode;
+ private CustomFaceService mCustomFaceService;
private NotificationManager mNotificationManager;
private int[] mBiometricPromptIgnoreList;
@@ -916,6 +922,7 @@ public class FaceService extends BiometricServiceBase {
mDaemon = null;
mHalDeviceId = 0;
mCurrentUserId = UserHandle.USER_NULL;
+ mCustomFaceService.setCurrentUserId(mCurrentUserId);
}
}
});
@@ -985,6 +992,9 @@ public class FaceService extends BiometricServiceBase {
private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() {
@Override
public int authenticate(long operationId, int groupId) throws RemoteException {
+ if (mCustomFaceService.isSupported()) {
+ return mCustomFaceService.authenticate(operationId);
+ }
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.w(TAG, "authenticate(): no face HAL!");
@@ -995,6 +1005,9 @@ public class FaceService extends BiometricServiceBase {
@Override
public int cancel() throws RemoteException {
+ if (mCustomFaceService.isSupported()) {
+ return mCustomFaceService.cancel();
+ }
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.w(TAG, "cancel(): no face HAL!");
@@ -1005,6 +1018,9 @@ public class FaceService extends BiometricServiceBase {
@Override
public int remove(int groupId, int biometricId) throws RemoteException {
+ if (mCustomFaceService.isSupported()) {
+ return mCustomFaceService.remove(biometricId);
+ }
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.w(TAG, "remove(): no face HAL!");
@@ -1015,6 +1031,9 @@ public class FaceService extends BiometricServiceBase {
@Override
public int enumerate() throws RemoteException {
+ if (mCustomFaceService.isSupported()) {
+ return mCustomFaceService.enumerate();
+ }
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.w(TAG, "enumerate(): no face HAL!");
@@ -1026,6 +1045,16 @@ public class FaceService extends BiometricServiceBase {
@Override
public int enroll(byte[] cryptoToken, int groupId, int timeout,
ArrayList<Integer> disabledFeatures) throws RemoteException {
+ if (mCustomFaceService.isSupported()) {
+ int[] dfs = new int[0];
+ if (disabledFeatures != null && disabledFeatures.size() > 0) {
+ dfs = new int[disabledFeatures.size()];
+ for (int i = 0; i < disabledFeatures.size(); i++) {
+ dfs[i] = disabledFeatures.get(i).intValue();
+ }
+ }
+ return mCustomFaceService.enroll(cryptoToken, timeout, dfs);
+ }
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.w(TAG, "enroll(): no face HAL!");
@@ -1040,6 +1069,10 @@ public class FaceService extends BiometricServiceBase {
@Override
public void resetLockout(byte[] cryptoToken) throws RemoteException {
+ if (mCustomFaceService.isSupported()) {
+ mCustomFaceService.resetLockout(cryptoToken);
+ return;
+ }
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.w(TAG, "resetLockout(): no face HAL!");
@@ -1077,6 +1110,8 @@ public class FaceService extends BiometricServiceBase {
.getIntArray(R.array.config_face_acquire_enroll_ignorelist);
mEnrollIgnoreListVendor = getContext().getResources()
.getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist);
+
+ mCustomFaceService = new CustomFaceService(getContext(), this, mHandler);
}
@Override
@@ -1092,6 +1127,11 @@ public class FaceService extends BiometricServiceBase {
public void onStart() {
super.onStart();
publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper());
+ if (mCustomFaceService.isSupported()) {
+ mCustomFaceService.setServiceHandler(BackgroundThread.getHandler());
+ mHalDeviceId = CustomFaceService.HAL_DEVICE_ID;
+ return;
+ }
// Get the face daemon on FaceService's on thread so SystemServerInitThreadPool isn't
// blocked
SystemServerInitThreadPool.submit(() -> mHandler.post(this::getFaceDaemon),
@@ -1136,10 +1176,27 @@ public class FaceService extends BiometricServiceBase {
mDaemon = null;
mCurrentUserId = UserHandle.USER_NULL; // Force updateActiveGroup() to re-evaluate
+ mCustomFaceService.setCurrentUserId(mCurrentUserId);
}
@Override
protected void updateActiveGroup(int userId, String clientPackage) {
+ if (mCustomFaceService.isSupported()) {
+ mCurrentUserId = userId;
+ mCustomFaceService.setCurrentUserId(mCurrentUserId);
+ if (mCustomFaceService.getService(mCurrentUserId) != null) {
+ long authId = 0;
+ if (hasEnrolledBiometrics(mCurrentUserId)) {
+ authId = (long) mCustomFaceService.getAuthenticatorId();
+ }
+ mAuthenticatorIds.put(userId, authId);
+ } else {
+ mCustomFaceService.callForBind(userId);
+ Slog.w(TAG, "updateActiveGroup(): Face service not started!");
+ }
+ return;
+ }
+
IBiometricsFace daemon = getFaceDaemon();
if (daemon != null) {
@@ -1164,6 +1221,7 @@ public class FaceService extends BiometricServiceBase {
daemon.setActiveUser(userId, faceDir.getAbsolutePath());
mCurrentUserId = userId;
+ mCustomFaceService.setCurrentUserId(mCurrentUserId);
mAuthenticatorIds.put(userId,
hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId().value : 0L);
}
@@ -1190,7 +1248,16 @@ public class FaceService extends BiometricServiceBase {
@Override
protected void handleUserSwitching(int userId) {
- super.handleUserSwitching(userId);
+ if (mCustomFaceService.isSupported()) {
+ updateActiveGroup(userId, null);
+ if (mCustomFaceService.getService(userId) != null) {
+ doTemplateCleanupForUser(userId);
+ } else {
+ mCustomFaceService.callForBind(userId);
+ }
+ } else {
+ super.handleUserSwitching(userId);
+ }
// Will be updated when we get the callback from HAL
mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_NONE;
}
@@ -1279,6 +1346,9 @@ public class FaceService extends BiometricServiceBase {
}
private long startGenerateChallenge(IBinder token) {
+ if (mCustomFaceService.isSupported()) {
+ return mCustomFaceService.generateChallenge(CHALLENGE_TIMEOUT_SEC);
+ }
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.w(TAG, "startGenerateChallenge: no face HAL!");
@@ -1293,6 +1363,9 @@ public class FaceService extends BiometricServiceBase {
}
private int startRevokeChallenge(IBinder token) {
+ if (mCustomFaceService.isSupported()) {
+ return mCustomFaceService.revokeChallenge();
+ }
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.w(TAG, "startRevokeChallenge: no face HAL!");
@@ -1310,6 +1383,12 @@ public class FaceService extends BiometricServiceBase {
return 0;
}
+ private void checkPermission(String permission, String packageName) {
+ if (!mCustomFaceService.isSupported() || !mCustomFaceService.getServicePackageName().equals(packageName)) {
+ checkPermission(permission);
+ }
+ }
+
private void dumpInternal(PrintWriter pw) {
JSONObject dump = new JSONObject();
try {
@@ -1371,6 +1450,9 @@ public class FaceService extends BiometricServiceBase {
return;
}
+ // Disable if custom face unlock service is in use
+ if (mCustomFaceService.isSupported()) return;
+
// The debug method takes two file descriptors. The first is for text
// output, which we will drop. The second is for binary data, which
// will be the protobuf data.