From e4c6b83572325f2ea441a88c6837664c0e8b014d Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Fri, 6 Mar 2020 14:59:24 -0800 Subject: [PATCH] Take in a Surface then convert to a NativeHandle We need to pass Surface objects to HIDL, but the Surface type is currently not supported in HIDL. The closest thing to a Surface in HIDL is a NativeHandle. The initial plan was to convert Surface objects to NativeHandle objects in framework, before passing them to HIDL. Unfortunately, there is no canonical way to perform the conversion using just the framework APIs. The only viable approach is to use the NDK conversion functions through the JNI. Bug: 150966034 Test: Manual, with a biometrics.face@1.1 HAL Change-Id: I24f775b576fcab7c0260537d6f9cdc35a4794436 --- .../BiometricNativeHandleUtils.java | 79 ---------------- .../biometrics/IBiometricNativeHandle.aidl | 26 ------ .../android/hardware/face/FaceManager.java | 21 ++--- .../android/hardware/face/IFaceService.aidl | 4 +- .../fingerprint/FingerprintManager.java | 32 +++---- .../fingerprint/IFingerprintService.aidl | 8 +- .../biometrics/AuthenticationClient.java | 24 ++--- .../biometrics/BiometricServiceBase.java | 15 ++-- .../server/biometrics/EnrollClient.java | 24 ++--- .../com/android/server/biometrics/Utils.java | 32 ------- .../server/biometrics/face/FaceService.java | 27 +++--- .../fingerprint/FingerprintAuthenticator.java | 2 +- .../fingerprint/FingerprintService.java | 38 ++++---- services/core/jni/Android.bp | 5 ++ ...metrics_SurfaceToNativeHandleConverter.cpp | 89 +++++++++++++++++++ services/core/jni/onload.cpp | 4 + 16 files changed, 178 insertions(+), 252 deletions(-) delete mode 100644 core/java/android/hardware/biometrics/BiometricNativeHandleUtils.java delete mode 100644 core/java/android/hardware/biometrics/IBiometricNativeHandle.aidl create mode 100644 services/core/jni/com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp diff --git a/core/java/android/hardware/biometrics/BiometricNativeHandleUtils.java b/core/java/android/hardware/biometrics/BiometricNativeHandleUtils.java deleted file mode 100644 index 5544eaeca7f3f..0000000000000 --- a/core/java/android/hardware/biometrics/BiometricNativeHandleUtils.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 android.hardware.biometrics; - -import android.os.NativeHandle; -import android.os.ParcelFileDescriptor; - -import java.io.IOException; - -/** - * A class that contains utilities for IBiometricNativeHandle. - * - * @hide - */ -public final class BiometricNativeHandleUtils { - - private BiometricNativeHandleUtils() { - } - - /** - * Converts a {@link NativeHandle} into an {@link IBiometricNativeHandle} by duplicating the - * underlying file descriptors. - * - * Both the original and new handle must be closed after use. - * - * @param h {@link NativeHandle}. Usually used to identify a WindowManager window. Can be null. - * @return A {@link IBiometricNativeHandle} representation of {@code h}. Will be null if - * {@code h} or its raw file descriptors are null. - */ - public static IBiometricNativeHandle dup(NativeHandle h) { - IBiometricNativeHandle handle = null; - if (h != null && h.getFileDescriptors() != null && h.getInts() != null) { - handle = new IBiometricNativeHandle(); - handle.ints = h.getInts().clone(); - handle.fds = new ParcelFileDescriptor[h.getFileDescriptors().length]; - for (int i = 0; i < h.getFileDescriptors().length; ++i) { - try { - handle.fds[i] = ParcelFileDescriptor.dup(h.getFileDescriptors()[i]); - } catch (IOException e) { - return null; - } - } - } - return handle; - } - - /** - * Closes the handle's file descriptors. - * - * @param h {@link IBiometricNativeHandle} handle. - */ - public static void close(IBiometricNativeHandle h) { - if (h != null) { - for (ParcelFileDescriptor fd : h.fds) { - if (fd != null) { - try { - fd.close(); - } catch (IOException e) { - // do nothing. - } - } - } - } - } -} diff --git a/core/java/android/hardware/biometrics/IBiometricNativeHandle.aidl b/core/java/android/hardware/biometrics/IBiometricNativeHandle.aidl deleted file mode 100644 index 6dcdc1be3a50a..0000000000000 --- a/core/java/android/hardware/biometrics/IBiometricNativeHandle.aidl +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 android.hardware.biometrics; - -/** - * Representation of a native handle. - * Copied from /common/aidl/android/hardware/common/NativeHandle.aidl - * @hide - */ -parcelable IBiometricNativeHandle { - ParcelFileDescriptor[] fds; - int[] ints; -} diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index b4222524114ce..333f71100ac82 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -29,9 +29,7 @@ import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricFaceConstants; -import android.hardware.biometrics.BiometricNativeHandleUtils; import android.hardware.biometrics.CryptoObject; -import android.hardware.biometrics.IBiometricNativeHandle; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.os.Binder; import android.os.CancellationSignal; @@ -40,13 +38,13 @@ import android.os.Handler; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.Looper; -import android.os.NativeHandle; import android.os.PowerManager; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; import android.util.Log; import android.util.Slog; +import android.view.Surface; import com.android.internal.R; import com.android.internal.os.SomeArgs; @@ -251,15 +249,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan /** * Defaults to {@link FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, - * int[], NativeHandle)} with {@code windowId} set to null. + * int[], Surface)} with {@code surface} set to null. * - * @see FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, int[], - * NativeHandle) + * @see FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, int[], Surface) */ @RequiresPermission(MANAGE_BIOMETRIC) public void enroll(int userId, byte[] token, CancellationSignal cancel, EnrollmentCallback callback, int[] disabledFeatures) { - enroll(userId, token, cancel, callback, disabledFeatures, null /* windowId */); + enroll(userId, token, cancel, callback, disabledFeatures, null /* surface */); } /** @@ -277,13 +274,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @param flags optional flags * @param userId the user to whom this face will belong to * @param callback an object to receive enrollment events - * @param windowId optional ID of a camera preview window for a single-camera device. Must be - * null if not used. + * @param surface optional camera preview surface for a single-camera device. Must be null if + * not used. * @hide */ @RequiresPermission(MANAGE_BIOMETRIC) public void enroll(int userId, byte[] token, CancellationSignal cancel, - EnrollmentCallback callback, int[] disabledFeatures, @Nullable NativeHandle windowId) { + EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface surface) { if (callback == null) { throw new IllegalArgumentException("Must supply an enrollment callback"); } @@ -298,12 +295,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } if (mService != null) { - IBiometricNativeHandle handle = BiometricNativeHandleUtils.dup(windowId); try { mEnrollmentCallback = callback; Trace.beginSection("FaceManager#enroll"); mService.enroll(userId, mToken, token, mServiceReceiver, - mContext.getOpPackageName(), disabledFeatures, handle); + mContext.getOpPackageName(), disabledFeatures, surface); } catch (RemoteException e) { Log.w(TAG, "Remote exception in enroll: ", e); // Though this may not be a hardware issue, it will cause apps to give up or @@ -313,7 +309,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan 0 /* vendorCode */)); } finally { Trace.endSection(); - BiometricNativeHandleUtils.close(handle); } } } diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 37b7456c52f3e..7b37dbbaecc75 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -15,11 +15,11 @@ */ package android.hardware.face; -import android.hardware.biometrics.IBiometricNativeHandle; import android.hardware.biometrics.IBiometricServiceReceiverInternal; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.hardware.face.IFaceServiceReceiver; import android.hardware.face.Face; +import android.view.Surface; /** * Communication channel from client to the face service. These methods are all require the @@ -52,7 +52,7 @@ interface IFaceService { // Start face enrollment void enroll(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver, - String opPackageName, in int [] disabledFeatures, in IBiometricNativeHandle windowId); + String opPackageName, in int [] disabledFeatures, in Surface surface); // Start remote face enrollment void enrollRemotely(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver, diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 2a71da83027d6..f2fe34b398002 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -32,9 +32,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricFingerprintConstants; -import android.hardware.biometrics.BiometricNativeHandleUtils; import android.hardware.biometrics.BiometricPrompt; -import android.hardware.biometrics.IBiometricNativeHandle; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.os.Binder; import android.os.CancellationSignal; @@ -43,12 +41,12 @@ import android.os.Handler; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.Looper; -import android.os.NativeHandle; import android.os.PowerManager; import android.os.RemoteException; import android.os.UserHandle; import android.security.identity.IdentityCredential; import android.util.Slog; +import android.view.Surface; import java.security.Signature; import java.util.List; @@ -419,17 +417,17 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Defaults to {@link FingerprintManager#authenticate(CryptoObject, CancellationSignal, int, - * AuthenticationCallback, Handler, int, NativeHandle)} with {@code windowId} set to null. + * AuthenticationCallback, Handler, int, Surface)} with {@code surface} set to null. * * @see FingerprintManager#authenticate(CryptoObject, CancellationSignal, int, - * AuthenticationCallback, Handler, int, NativeHandle) + * AuthenticationCallback, Handler, int, Surface) * * @hide */ @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) { - authenticate(crypto, cancel, flags, callback, handler, userId, null /* windowId */); + authenticate(crypto, cancel, flags, callback, handler, userId, null /* surface */); } /** @@ -437,14 +435,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing * CancellationSignal, int, AuthenticationCallback, Handler)}. This version does not * display the BiometricPrompt. * @param userId the user ID that the fingerprint hardware will authenticate for. - * @param windowId for optical fingerprint sensors that require active illumination by the OLED + * @param surface for optical fingerprint sensors that require active illumination by the OLED * display. Should be null for devices that don't require illumination. * @hide */ @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId, - @Nullable NativeHandle windowId) { + @Nullable Surface surface) { if (callback == null) { throw new IllegalArgumentException("Must supply an authentication callback"); } @@ -459,14 +457,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } if (mService != null) { - IBiometricNativeHandle handle = BiometricNativeHandleUtils.dup(windowId); try { useHandler(handler); mAuthenticationCallback = callback; mCryptoObject = crypto; long sessionId = crypto != null ? crypto.getOpId() : 0; mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags, - mContext.getOpPackageName(), handle); + mContext.getOpPackageName(), surface); } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating: ", e); // Though this may not be a hardware issue, it will cause apps to give up or try @@ -474,25 +471,23 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */)); - } finally { - BiometricNativeHandleUtils.close(handle); } } } /** * Defaults to {@link FingerprintManager#enroll(byte[], CancellationSignal, int, int, - * EnrollmentCallback, NativeHandle)} with {@code windowId} set to null. + * EnrollmentCallback, Surface)} with {@code surface} set to null. * * @see FingerprintManager#enroll(byte[], CancellationSignal, int, int, EnrollmentCallback, - * NativeHandle) + * Surface) * * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) public void enroll(byte [] token, CancellationSignal cancel, int flags, int userId, EnrollmentCallback callback) { - enroll(token, cancel, flags, userId, callback, null /* windowId */); + enroll(token, cancel, flags, userId, callback, null /* surface */); } /** @@ -513,7 +508,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing */ @RequiresPermission(MANAGE_FINGERPRINT) public void enroll(byte [] token, CancellationSignal cancel, int flags, - int userId, EnrollmentCallback callback, @Nullable NativeHandle windowId) { + int userId, EnrollmentCallback callback, @Nullable Surface surface) { if (userId == UserHandle.USER_CURRENT) { userId = getCurrentUserId(); } @@ -531,11 +526,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } if (mService != null) { - IBiometricNativeHandle handle = BiometricNativeHandleUtils.dup(windowId); try { mEnrollmentCallback = callback; mService.enroll(mToken, token, userId, mServiceReceiver, flags, - mContext.getOpPackageName(), handle); + mContext.getOpPackageName(), surface); } catch (RemoteException e) { Slog.w(TAG, "Remote exception in enroll: ", e); // Though this may not be a hardware issue, it will cause apps to give up or try @@ -543,8 +537,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */)); - } finally { - BiometricNativeHandleUtils.close(handle); } } } diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index c33e445c2818a..c928f015eb328 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -15,12 +15,12 @@ */ package android.hardware.fingerprint; -import android.hardware.biometrics.IBiometricNativeHandle; import android.hardware.biometrics.IBiometricServiceReceiverInternal; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.hardware.fingerprint.IFingerprintClientActiveCallback; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.Fingerprint; +import android.view.Surface; import java.util.List; /** @@ -33,7 +33,7 @@ interface IFingerprintService { // through FingerprintManager now. void authenticate(IBinder token, long sessionId, int userId, IFingerprintServiceReceiver receiver, int flags, String opPackageName, - in IBiometricNativeHandle windowId); + in Surface surface); // This method prepares the service to start authenticating, but doesn't start authentication. // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be @@ -42,7 +42,7 @@ interface IFingerprintService { // startPreparedClient(). void prepareForAuthentication(IBinder token, long sessionId, int userId, IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName, int cookie, - int callingUid, int callingPid, int callingUserId, in IBiometricNativeHandle windowId); + int callingUid, int callingPid, int callingUserId, in Surface surface); // Starts authentication with the previously prepared client. void startPreparedClient(int cookie); @@ -57,7 +57,7 @@ interface IFingerprintService { // Start fingerprint enrollment void enroll(IBinder token, in byte [] cryptoToken, int groupId, IFingerprintServiceReceiver receiver, - int flags, String opPackageName, in IBiometricNativeHandle windowId); + int flags, String opPackageName, in Surface surface); // Cancel enrollment in progress void cancelEnrollment(IBinder token); diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index 7bbda9f3f732d..19d83be3f02a3 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -20,14 +20,12 @@ import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; -import android.hardware.biometrics.IBiometricNativeHandle; import android.os.IBinder; -import android.os.NativeHandle; import android.os.RemoteException; import android.security.KeyStore; import android.util.Slog; +import android.view.Surface; -import java.io.IOException; import java.util.ArrayList; /** @@ -44,7 +42,7 @@ public abstract class AuthenticationClient extends ClientMonitor { public static final int LOCKOUT_PERMANENT = 2; private final boolean mRequireConfirmation; - private final NativeHandle mWindowId; + private final Surface mSurface; // We need to track this state since it's possible for applications to request for // authentication while the device is already locked out. In that case, the client is created @@ -74,24 +72,12 @@ public abstract class AuthenticationClient extends ClientMonitor { BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token, BiometricServiceBase.ServiceListener listener, int targetUserId, int groupId, long opId, boolean restricted, String owner, int cookie, boolean requireConfirmation, - IBiometricNativeHandle windowId) { + Surface surface) { super(context, constants, daemon, halDeviceId, token, listener, targetUserId, groupId, restricted, owner, cookie); mOpId = opId; mRequireConfirmation = requireConfirmation; - mWindowId = Utils.dupNativeHandle(windowId); - } - - @Override - public void destroy() { - if (mWindowId != null && mWindowId.getFileDescriptors() != null) { - try { - mWindowId.close(); - } catch (IOException e) { - Slog.e(getLogTag(), "Failed to close windowId NativeHandle: ", e); - } - } - super.destroy(); + mSurface = surface; } protected long getStartTimeMs() { @@ -251,7 +237,7 @@ public abstract class AuthenticationClient extends ClientMonitor { onStart(); try { mStartTimeMs = System.currentTimeMillis(); - final int result = getDaemonWrapper().authenticate(mOpId, getGroupId(), mWindowId); + final int result = getDaemonWrapper().authenticate(mOpId, getGroupId(), mSurface); if (result != 0) { Slog.w(getLogTag(), "startAuthentication failed, result=" + result); mMetricsLogger.histogram(mConstants.tagAuthStartError(), result); diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java index 49006de686f8a..4a5186b45abc8 100644 --- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java +++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java @@ -32,7 +32,6 @@ import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricsProtoEnums; -import android.hardware.biometrics.IBiometricNativeHandle; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.hardware.biometrics.IBiometricServiceReceiverInternal; @@ -44,7 +43,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.IHwBinder; import android.os.IRemoteCallback; -import android.os.NativeHandle; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -53,6 +51,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; +import android.view.Surface; import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.IStatusBarService; @@ -224,9 +223,9 @@ public abstract class BiometricServiceBase extends SystemService public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId, IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId, boolean restricted, String owner, int cookie, boolean requireConfirmation, - IBiometricNativeHandle windowId) { + Surface surface) { super(context, getConstants(), daemon, halDeviceId, token, listener, targetUserId, - groupId, opId, restricted, owner, cookie, requireConfirmation, windowId); + groupId, opId, restricted, owner, cookie, requireConfirmation, surface); } @Override @@ -287,10 +286,10 @@ public abstract class BiometricServiceBase extends SystemService public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId, IBinder token, ServiceListener listener, int userId, int groupId, byte[] cryptoToken, boolean restricted, String owner, - final int[] disabledFeatures, int timeoutSec, IBiometricNativeHandle windowId) { + final int[] disabledFeatures, int timeoutSec, Surface surface) { super(context, getConstants(), daemon, halDeviceId, token, listener, userId, groupId, cryptoToken, restricted, owner, getBiometricUtils(), - disabledFeatures, timeoutSec, windowId); + disabledFeatures, timeoutSec, surface); } @Override @@ -476,13 +475,13 @@ public abstract class BiometricServiceBase extends SystemService */ protected interface DaemonWrapper { int ERROR_ESRCH = 3; // Likely HAL is dead. see errno.h. - int authenticate(long operationId, int groupId, NativeHandle windowId) + int authenticate(long operationId, int groupId, Surface surface) throws RemoteException; int cancel() throws RemoteException; int remove(int groupId, int biometricId) throws RemoteException; int enumerate() throws RemoteException; int enroll(byte[] token, int groupId, int timeout, - ArrayList disabledFeatures, NativeHandle windowId) throws RemoteException; + ArrayList disabledFeatures, Surface surface) throws RemoteException; void resetLockout(byte[] token) throws RemoteException; } diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java index 684795ec66b51..3f43032ee498c 100644 --- a/services/core/java/com/android/server/biometrics/EnrollClient.java +++ b/services/core/java/com/android/server/biometrics/EnrollClient.java @@ -20,13 +20,11 @@ import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; -import android.hardware.biometrics.IBiometricNativeHandle; import android.os.IBinder; -import android.os.NativeHandle; import android.os.RemoteException; import android.util.Slog; +import android.view.Surface; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -38,7 +36,7 @@ public abstract class EnrollClient extends ClientMonitor { private final BiometricUtils mBiometricUtils; private final int[] mDisabledFeatures; private final int mTimeoutSec; - private final NativeHandle mWindowId; + private final Surface mSurface; private long mEnrollmentStartTimeMs; @@ -48,26 +46,14 @@ public abstract class EnrollClient extends ClientMonitor { BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token, BiometricServiceBase.ServiceListener listener, int userId, int groupId, byte[] cryptoToken, boolean restricted, String owner, BiometricUtils utils, - final int[] disabledFeatures, int timeoutSec, IBiometricNativeHandle windowId) { + final int[] disabledFeatures, int timeoutSec, Surface surface) { super(context, constants, daemon, halDeviceId, token, listener, userId, groupId, restricted, owner, 0 /* cookie */); mBiometricUtils = utils; mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length); mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length); mTimeoutSec = timeoutSec; - mWindowId = Utils.dupNativeHandle(windowId); - } - - @Override - public void destroy() { - if (mWindowId != null && mWindowId.getFileDescriptors() != null) { - try { - mWindowId.close(); - } catch (IOException e) { - Slog.e(getLogTag(), "Failed to close windowId NativeHandle: ", e); - } - } - super.destroy(); + mSurface = surface; } @Override @@ -119,7 +105,7 @@ public abstract class EnrollClient extends ClientMonitor { } final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), mTimeoutSec, - disabledFeatures, mWindowId); + disabledFeatures, mSurface); if (result != 0) { Slog.w(getLogTag(), "startEnroll failed, result=" + result); mMetricsLogger.histogram(mConstants.tagEnrollStartError(), result); diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java index 3235499511a5d..14378da0a90b3 100644 --- a/services/core/java/com/android/server/biometrics/Utils.java +++ b/services/core/java/com/android/server/biometrics/Utils.java @@ -23,17 +23,12 @@ import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricPrompt.AuthenticationResultType; -import android.hardware.biometrics.IBiometricNativeHandle; import android.os.Build; import android.os.Bundle; -import android.os.NativeHandle; import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; -import java.io.FileDescriptor; -import java.io.IOException; - public class Utils { public static boolean isDebugEnabled(Context context, int targetUserId) { if (targetUserId == UserHandle.USER_NULL) { @@ -261,31 +256,4 @@ public class Utils { throw new IllegalArgumentException("Unsupported dismissal reason: " + reason); } } - - /** - * Converts an {@link IBiometricNativeHandle} to a {@link NativeHandle} by duplicating the - * the underlying file descriptors. - * - * Both the original and new handle must be closed after use. - * - * @param h {@link IBiometricNativeHandle} received as a binder call argument. Usually used to - * identify a WindowManager window. Can be null. - * @return A {@link NativeHandle} representation of {@code h}. Will be null if either {@code h} - * or its contents are null. - */ - public static NativeHandle dupNativeHandle(IBiometricNativeHandle h) { - NativeHandle handle = null; - if (h != null && h.fds != null && h.ints != null) { - FileDescriptor[] fds = new FileDescriptor[h.fds.length]; - for (int i = 0; i < h.fds.length; ++i) { - try { - fds[i] = h.fds[i].dup().getFileDescriptor(); - } catch (IOException e) { - return null; - } - } - handle = new NativeHandle(fds, h.ints, true /* own */); - } - return handle; - } } 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 f222f39a3b851..467e7f180a600 100644 --- a/services/core/java/com/android/server/biometrics/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/face/FaceService.java @@ -34,7 +34,6 @@ import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; -import android.hardware.biometrics.IBiometricNativeHandle; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.hardware.biometrics.IBiometricServiceReceiverInternal; import android.hardware.biometrics.face.V1_0.IBiometricsFace; @@ -57,6 +56,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Slog; +import android.view.Surface; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; @@ -216,9 +216,9 @@ public class FaceService extends BiometricServiceBase { DaemonWrapper daemon, long halDeviceId, IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId, boolean restricted, String owner, int cookie, boolean requireConfirmation, - IBiometricNativeHandle windowId) { + Surface surface) { super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId, - restricted, owner, cookie, requireConfirmation, windowId); + restricted, owner, cookie, requireConfirmation, surface); } @Override @@ -375,7 +375,7 @@ public class FaceService extends BiometricServiceBase { @Override // Binder call public void enroll(int userId, final IBinder token, final byte[] cryptoToken, final IFaceServiceReceiver receiver, final String opPackageName, - final int[] disabledFeatures, IBiometricNativeHandle windowId) { + final int[] disabledFeatures, Surface surface) { checkPermission(MANAGE_BIOMETRIC); updateActiveGroup(userId, opPackageName); @@ -386,7 +386,7 @@ public class FaceService extends BiometricServiceBase { final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, 0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures, - ENROLL_TIMEOUT_SEC, windowId) { + ENROLL_TIMEOUT_SEC, surface) { @Override public int[] getAcquireIgnorelist() { @@ -436,7 +436,7 @@ public class FaceService extends BiometricServiceBase { final AuthenticationClientImpl client = new FaceAuthClient(getContext(), mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, - 0 /* cookie */, false /* requireConfirmation */, null /* windowId */); + 0 /* cookie */, false /* requireConfirmation */, null /* surface */); authenticateInternal(client, opId, opPackageName); } @@ -452,7 +452,7 @@ public class FaceService extends BiometricServiceBase { mDaemonWrapper, mHalDeviceId, token, new BiometricPromptServiceListenerImpl(wrapperReceiver), mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, cookie, - requireConfirmation, null /* windowId */); + requireConfirmation, null /* surface */); authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId); } @@ -986,7 +986,7 @@ public class FaceService extends BiometricServiceBase { */ private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() { @Override - public int authenticate(long operationId, int groupId, NativeHandle windowId) + public int authenticate(long operationId, int groupId, Surface surface) throws RemoteException { IBiometricsFace daemon = getFaceDaemon(); if (daemon == null) { @@ -1028,7 +1028,7 @@ public class FaceService extends BiometricServiceBase { @Override public int enroll(byte[] cryptoToken, int groupId, int timeout, - ArrayList disabledFeatures, NativeHandle windowId) throws RemoteException { + ArrayList disabledFeatures, Surface surface) throws RemoteException { IBiometricsFace daemon = getFaceDaemon(); if (daemon == null) { Slog.w(TAG, "enroll(): no face HAL!"); @@ -1042,11 +1042,12 @@ public class FaceService extends BiometricServiceBase { android.hardware.biometrics.face.V1_1.IBiometricsFace.castFrom( daemon); if (daemon11 != null) { - return daemon11.enroll_1_1(token, timeout, disabledFeatures, windowId); - } else if (windowId == null) { + return daemon11.enroll_1_1(token, timeout, disabledFeatures, + convertSurfaceToNativeHandle(surface)); + } else if (surface == null) { return daemon.enroll(token, timeout, disabledFeatures); } else { - Slog.e(TAG, "enroll(): windowId is only supported in @1.1 HAL"); + Slog.e(TAG, "enroll(): surface is only supported in @1.1 HAL"); return ERROR_ESRCH; } } @@ -1323,6 +1324,8 @@ public class FaceService extends BiometricServiceBase { return 0; } + private native NativeHandle convertSurfaceToNativeHandle(Surface surface); + private void dumpInternal(PrintWriter pw) { JSONObject dump = new JSONObject(); try { diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java index 5bbeef153ea45..3eac5a20c7acd 100644 --- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java @@ -38,7 +38,7 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId) throws RemoteException { mFingerprintService.prepareForAuthentication(token, sessionId, userId, wrapperReceiver, - opPackageName, cookie, callingUid, callingPid, callingUserId, null /* windowId */); + opPackageName, cookie, callingUid, callingPid, callingUserId, null /* surface */); } @Override diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java index 4d5545010f63c..0aff5042a9f48 100644 --- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java @@ -38,7 +38,6 @@ import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; -import android.hardware.biometrics.IBiometricNativeHandle; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.hardware.biometrics.IBiometricServiceReceiverInternal; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; @@ -62,6 +61,7 @@ import android.util.Slog; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.proto.ProtoOutputStream; +import android.view.Surface; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; @@ -135,9 +135,9 @@ public class FingerprintService extends BiometricServiceBase { DaemonWrapper daemon, long halDeviceId, IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId, boolean restricted, String owner, int cookie, - boolean requireConfirmation, IBiometricNativeHandle windowId) { + boolean requireConfirmation, Surface surface) { super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId, - restricted, owner, cookie, requireConfirmation, windowId); + restricted, owner, cookie, requireConfirmation, surface); } @Override @@ -201,7 +201,7 @@ public class FingerprintService extends BiometricServiceBase { @Override // Binder call public void enroll(final IBinder token, final byte[] cryptoToken, final int userId, final IFingerprintServiceReceiver receiver, final int flags, - final String opPackageName, IBiometricNativeHandle windowId) { + final String opPackageName, Surface surface) { checkPermission(MANAGE_FINGERPRINT); final boolean restricted = isRestricted(); @@ -209,7 +209,7 @@ public class FingerprintService extends BiometricServiceBase { final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId, cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */, - ENROLL_TIMEOUT_SEC, windowId) { + ENROLL_TIMEOUT_SEC, surface) { @Override public boolean shouldVibrate() { return true; @@ -233,14 +233,14 @@ public class FingerprintService extends BiometricServiceBase { @Override // Binder call public void authenticate(final IBinder token, final long opId, final int groupId, final IFingerprintServiceReceiver receiver, final int flags, - final String opPackageName, IBiometricNativeHandle windowId) { + final String opPackageName, Surface surface) { updateActiveGroup(groupId, opPackageName); final boolean restricted = isRestricted(); final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(), mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId, opId, restricted, opPackageName, 0 /* cookie */, false /* requireConfirmation */, - windowId); + surface); authenticateInternal(client, opId, opPackageName); } @@ -248,7 +248,7 @@ public class FingerprintService extends BiometricServiceBase { public void prepareForAuthentication(IBinder token, long opId, int groupId, IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId, - IBiometricNativeHandle windowId) { + Surface surface) { checkPermission(MANAGE_BIOMETRIC); updateActiveGroup(groupId, opPackageName); final boolean restricted = true; // BiometricPrompt is always restricted @@ -257,7 +257,7 @@ public class FingerprintService extends BiometricServiceBase { new BiometricPromptServiceListenerImpl(wrapperReceiver), mCurrentUserId, groupId, opId, restricted, opPackageName, cookie, false /* requireConfirmation */, - windowId); + surface); authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId); } @@ -656,7 +656,7 @@ public class FingerprintService extends BiometricServiceBase { */ private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() { @Override - public int authenticate(long operationId, int groupId, NativeHandle windowId) + public int authenticate(long operationId, int groupId, Surface surface) throws RemoteException { IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { @@ -667,11 +667,12 @@ public class FingerprintService extends BiometricServiceBase { android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprint.castFrom( daemon); if (daemon22 != null) { - return daemon22.authenticate_2_2(operationId, groupId, windowId); - } else if (windowId == null) { + return daemon22.authenticate_2_2(operationId, groupId, + convertSurfaceToNativeHandle(surface)); + } else if (surface == null) { return daemon.authenticate(operationId, groupId); } else { - Slog.e(TAG, "authenticate(): windowId is only supported in @2.2 HAL"); + Slog.e(TAG, "authenticate(): surface is only supported in @2.2 HAL"); return ERROR_ESRCH; } } @@ -708,7 +709,7 @@ public class FingerprintService extends BiometricServiceBase { @Override public int enroll(byte[] cryptoToken, int groupId, int timeout, - ArrayList disabledFeatures, NativeHandle windowId) throws RemoteException { + ArrayList disabledFeatures, Surface surface) throws RemoteException { IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "enroll(): no fingerprint HAL!"); @@ -722,11 +723,12 @@ public class FingerprintService extends BiometricServiceBase { for (byte b : cryptoToken) { cryptoTokenAsList.add(b); } - return daemon22.enroll_2_2(cryptoTokenAsList, groupId, timeout, windowId); - } else if (windowId == null) { + return daemon22.enroll_2_2(cryptoTokenAsList, groupId, timeout, + convertSurfaceToNativeHandle(surface)); + } else if (surface == null) { return daemon.enroll(cryptoToken, groupId, timeout); } else { - Slog.e(TAG, "enroll(): windowId is only supported in @2.2 HAL"); + Slog.e(TAG, "enroll(): surface is only supported in @2.2 HAL"); return ERROR_ESRCH; } } @@ -1029,6 +1031,8 @@ public class FingerprintService extends BiometricServiceBase { PendingIntent.FLAG_UPDATE_CURRENT); } + private native NativeHandle convertSurfaceToNativeHandle(Surface surface); + private void dumpInternal(PrintWriter pw) { JSONObject dump = new JSONObject(); try { diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 27bd58ec30100..b04189f263146 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -26,6 +26,7 @@ cc_library_static { "stats/SubsystemSleepStatePuller.cpp", "com_android_server_adb_AdbDebuggingManager.cpp", "com_android_server_am_BatteryStatsService.cpp", + "com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp", "com_android_server_connectivity_Vpn.cpp", "com_android_server_ConsumerIrService.cpp", "com_android_server_devicepolicy_CryptoTestHelper.cpp", @@ -89,6 +90,7 @@ cc_defaults { shared_libs: [ "libadb_pairing_server", "libadb_pairing_connection", + "libandroid", "libandroid_runtime", "libandroidfw", "libaudioclient", @@ -104,6 +106,7 @@ cc_defaults { "libkeystore_binder", "libmtp", "libnativehelper", + "libnativewindow", "libutils", "libui", "libinput", @@ -142,6 +145,7 @@ cc_defaults { "android.hardware.gnss@2.1", "android.hardware.gnss.measurement_corrections@1.0", "android.hardware.gnss.visibility_control@1.0", + "android.hardware.graphics.bufferqueue@1.0", "android.hardware.input.classifier@1.0", "android.hardware.ir@1.0", "android.hardware.light@2.0", @@ -157,6 +161,7 @@ cc_defaults { "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.3", "android.hardware.vr@1.0", + "android.hidl.token@1.0-utils", "android.frameworks.schedulerservice@1.0", "android.frameworks.sensorservice@1.0", "android.frameworks.stats@1.0", diff --git a/services/core/jni/com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp b/services/core/jni/com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp new file mode 100644 index 0000000000000..7c20b56487293 --- /dev/null +++ b/services/core/jni/com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 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. + */ + +#define LOG_TAG "SurfaceToNativeHandleConverter" + +#include +#include "jni.h" + +#include +#include +#include +#include +#include + +namespace android { + +namespace { +constexpr int WINDOW_HAL_TOKEN_SIZE_MAX = 256; + +native_handle_t* convertHalTokenToNativeHandle(const HalToken& halToken) { + // We attempt to store halToken in the ints of the native_handle_t after its + // size. The first int stores the size of the token. We store this in an int + // to avoid alignment issues where size_t and int do not have the same + // alignment. + size_t nhDataByteSize = halToken.size(); + if (nhDataByteSize > WINDOW_HAL_TOKEN_SIZE_MAX) { + // The size of the token isn't reasonable.. + return nullptr; + } + size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1; + + // We don't check for overflow, whether numInts can fit in an int, since we + // expect WINDOW_HAL_TOKEN_SIZE_MAX to be a reasonable limit. + // create a native_handle_t with 0 numFds and numInts number of ints. + native_handle_t* nh = native_handle_create(0, numInts); + if (!nh) { + return nullptr; + } + // Store the size of the token in the first int. + nh->data[0] = nhDataByteSize; + memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize); + return nh; +} +} // namespace + +using ::android::sp; + +static jobject convertSurfaceToNativeHandle(JNIEnv* env, jobject /* clazz */, + jobject previewSurface) { + ANativeWindow* previewAnw = ANativeWindow_fromSurface(env, previewSurface); + sp surface = static_cast(previewAnw); + sp igbp = surface->getIGraphicBufferProducer(); + sp hgbp = new TWGraphicBufferProducer(igbp); + HalToken halToken; + createHalToken(hgbp, &halToken); + native_handle_t* native_handle = convertHalTokenToNativeHandle(halToken); + return JNativeHandle::MakeJavaNativeHandleObj(env, native_handle); +} + +static const JNINativeMethod method_table[] = { + {"convertSurfaceToNativeHandle", "(Landroid/view/Surface;)Landroid/os/NativeHandle;", + reinterpret_cast(convertSurfaceToNativeHandle)}, +}; + +int register_android_server_FingerprintService(JNIEnv* env) { + return jniRegisterNativeMethods(env, + "com/android/server/biometrics/fingerprint/FingerprintService", + method_table, NELEM(method_table)); +} + +int register_android_server_FaceService(JNIEnv* env) { + return jniRegisterNativeMethods(env, "com/android/server/biometrics/face/FaceService", + method_table, NELEM(method_table)); +} + +}; // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index a5339a5d2e62b..2bbc6815e6039 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -62,6 +62,8 @@ int register_android_server_incremental_IncrementalManagerService(JNIEnv* env); int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv* env); int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env); int register_android_server_AdbDebuggingManager(JNIEnv* env); +int register_android_server_FingerprintService(JNIEnv* env); +int register_android_server_FaceService(JNIEnv* env); }; using namespace android; @@ -117,5 +119,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env); register_android_server_stats_pull_StatsPullAtomService(env); register_android_server_AdbDebuggingManager(env); + register_android_server_FingerprintService(env); + register_android_server_FaceService(env); return JNI_VERSION_1_4; }