From 7daab42d9d514cee5e834cdfb8f22b133cf82837 Mon Sep 17 00:00:00 2001 From: jhenrique09 Date: Sun, 7 Feb 2021 17:04:10 -0300 Subject: [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 --- packages/SystemUI/Android.bp | 1 + .../android/keyguard/KeyguardUpdateMonitor.java | 14 + services/core/Android.bp | 1 + .../server/biometrics/BiometricServiceBase.java | 18 +- .../server/biometrics/face/CustomFaceService.java | 448 +++++++++++++++++++++ .../server/biometrics/face/FaceService.java | 96 ++++- 6 files changed, 562 insertions(+), 16 deletions(-) create mode 100644 services/core/java/com/android/server/biometrics/face/CustomFaceService.java 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 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 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 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 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 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. -- cgit v1.2.3