diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlNativeHandleUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlNativeHandleUtils.java new file mode 100644 index 0000000000000..77e6cebed789f --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlNativeHandleUtils.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors.face.aidl; + +import android.annotation.Nullable; +import android.os.ParcelFileDescriptor; + +import java.io.FileDescriptor; +import java.io.IOException; + +/** + * A utility class for the AIDL implementation of NativeHandle - {@link + * android.hardware.common.NativeHandle}. + */ +public final class AidlNativeHandleUtils { + + /** + * Converts a {@link android.os.NativeHandle} to a {@link android.hardware.common.NativeHandle} + * by duplicating the underlying file descriptors. + * + * Both the original and new handle must be closed after use. + * + * @param handle {@link android.os.NativeHandle}. Can be null. + * @return a {@link android.hardware.common.NativeHandle} representation of {@code handle}. + * Returns null if {@code handle} is null. + * @throws IOException if any of the underlying calls to {@code dup} fail. + */ + public static @Nullable android.hardware.common.NativeHandle dup( + @Nullable android.os.NativeHandle handle) throws IOException { + if (handle == null) { + return null; + } + android.hardware.common.NativeHandle res = new android.hardware.common.NativeHandle(); + final FileDescriptor[] fds = handle.getFileDescriptors(); + res.ints = handle.getInts().clone(); + res.fds = new ParcelFileDescriptor[fds.length]; + for (int i = 0; i < fds.length; ++i) { + res.fds[i] = ParcelFileDescriptor.dup(fds[i]); + } + return res; + } + + /** + * Closes the file descriptors contained within a {@link android.hardware.common.NativeHandle}. + * This is a no-op if the handle is null. + * + * This should only be used for handles that own their file descriptors, for example handles + * obtained using {@link #dup(android.os.NativeHandle)}. + * + * @param handle {@link android.hardware.common.NativeHandle}. Can be null. + * @throws IOException if any of the underlying calls to {@code close} fail. + */ + public static void close(@Nullable android.hardware.common.NativeHandle handle) + throws IOException { + if (handle != null) { + for (ParcelFileDescriptor fd : handle.fds) { + if (fd != null) { + fd.close(); + } + } + } + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java index f950862bacd9a..f09df1e1812e3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java @@ -39,6 +39,7 @@ import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.EnrollClient; import com.android.server.biometrics.sensors.face.FaceUtils; +import java.io.IOException; import java.util.ArrayList; /** @@ -51,6 +52,7 @@ public class FaceEnrollClient extends EnrollClient { @NonNull private final int[] mEnrollIgnoreList; @NonNull private final int[] mEnrollIgnoreListVendor; @Nullable private ICancellationSignal mCancellationSignal; + @Nullable private android.hardware.common.NativeHandle mPreviewSurface; private final int mMaxTemplatesPerUser; FaceEnrollClient(@NonNull Context context, @NonNull LazyDaemon lazyDaemon, @@ -66,6 +68,24 @@ public class FaceEnrollClient extends EnrollClient { mEnrollIgnoreListVendor = getContext().getResources() .getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist); mMaxTemplatesPerUser = maxTemplatesPerUser; + try { + // We must manually close the duplicate handle after it's no longer needed. + // The caller is responsible for closing the original handle. + mPreviewSurface = AidlNativeHandleUtils.dup(previewSurface); + } catch (IOException e) { + mPreviewSurface = null; + Slog.e(TAG, "Failed to dup previewSurface", e); + } + } + + @Override + public void destroy() { + try { + AidlNativeHandleUtils.close(mPreviewSurface); + } catch (IOException e) { + Slog.e(TAG, "Failed to close mPreviewSurface", e); + } + super.destroy(); } @Override @@ -94,10 +114,9 @@ public class FaceEnrollClient extends EnrollClient { try { // TODO(b/172593978): Pass features. - // TODO(b/172593521): Pass mPreviewSurface as android.hardware.common.NativeHandle. mCancellationSignal = getFreshDaemon().enroll(mSequentialId, HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken), - null /* mPreviewSurface */); + mPreviewSurface); } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting enroll", e); onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);