Loading core/res/AndroidManifest.xml +4 −0 Original line number Diff line number Diff line Loading @@ -5614,6 +5614,10 @@ <permission android:name="android.permission.MANAGE_FINGERPRINT" android:protectionLevel="signature|privileged" /> <!-- Allows managing (adding, removing) face templates. Reserved for the system. @hide --> <permission android:name="android.permission.MANAGE_FACE" android:protectionLevel="signature|privileged" /> <!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide --> <permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT" android:protectionLevel="signature" /> Loading services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +28 −0 Original line number Diff line number Diff line Loading @@ -18,11 +18,13 @@ package com.android.server.biometrics.sensors.face; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.MANAGE_BIOMETRIC; import static android.Manifest.permission.MANAGE_FACE; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricsProtoEnums; Loading @@ -45,7 +47,9 @@ import android.os.IBinder; import android.os.NativeHandle; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ShellCallback; import android.os.UserHandle; import android.util.Pair; import android.util.Slog; Loading Loading @@ -444,6 +448,15 @@ public class FaceService extends SystemService { mLockoutResetDispatcher.addCallback(callback, opPackageName); } @Override // Binder call public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) throws RemoteException { (new FaceShellCommand(FaceService.this)) .exec(this, in, out, err, args, callback, resultReceiver); } @Override // Binder call protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { Loading Loading @@ -732,4 +745,19 @@ public class FaceService extends SystemService { * @param handle a handle that was obtained from {@link #acquireSurfaceHandle(Surface)}. */ public static native void releaseSurfaceHandle(@NonNull NativeHandle handle); void syncEnrollmentsNow() { Utils.checkPermissionOrShell(getContext(), MANAGE_FACE); if (Utils.isVirtualEnabled(getContext())) { Slog.i(TAG, "Sync virtual enrollments"); final int userId = ActivityManager.getCurrentUser(); for (ServiceProvider provider : mServiceProviders) { for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */, true /* favorHalEnrollments */); } } } } } services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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; import android.os.ShellCommand; import java.io.PrintWriter; /** Handles shell commands for {@link FaceService}. */ public class FaceShellCommand extends ShellCommand { private final FaceService mService; public FaceShellCommand(FaceService service) { mService = service; } @Override public int onCommand(String cmd) { if (cmd == null) { onHelp(); return 1; } try { switch (cmd) { case "help": return doHelp(); case "sync": return doSync(); default: getOutPrintWriter().println("Unrecognized command: " + cmd); } } catch (Exception e) { getOutPrintWriter().println("Exception: " + e); } return -1; } @Override public void onHelp() { PrintWriter pw = getOutPrintWriter(); pw.println("Face Service commands:"); pw.println(" help"); pw.println(" Print this help text."); pw.println(" sync"); pw.println(" Sync enrollments now (virtualized sensors only)."); } private int doHelp() { onHelp(); return 0; } private int doSync() { mService.syncEnrollmentsNow(); return 0; } } services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java +3 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,9 @@ public interface ServiceProvider { void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback); void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments); void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, boolean clearSchedulerBuffer); Loading services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +9 −0 Original line number Diff line number Diff line Loading @@ -540,6 +540,12 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { @Override public void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback) { scheduleInternalCleanup(sensorId, userId, callback, false /* favorHalEnrollments */); } @Override public void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments) { mHandler.post(() -> { final List<Face> enrolledList = getEnrolledFaces(sensorId, userId); final FaceInternalCleanupClient client = Loading @@ -551,6 +557,9 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { mBiometricContext, enrolledList, FaceUtils.getInstance(sensorId), mSensors.get(sensorId).getAuthenticatorIds()); if (favorHalEnrollments) { client.setFavorHalEnrollments(); } scheduleForSensor(sensorId, client, callback); }); } Loading Loading
core/res/AndroidManifest.xml +4 −0 Original line number Diff line number Diff line Loading @@ -5614,6 +5614,10 @@ <permission android:name="android.permission.MANAGE_FINGERPRINT" android:protectionLevel="signature|privileged" /> <!-- Allows managing (adding, removing) face templates. Reserved for the system. @hide --> <permission android:name="android.permission.MANAGE_FACE" android:protectionLevel="signature|privileged" /> <!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide --> <permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT" android:protectionLevel="signature" /> Loading
services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +28 −0 Original line number Diff line number Diff line Loading @@ -18,11 +18,13 @@ package com.android.server.biometrics.sensors.face; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.MANAGE_BIOMETRIC; import static android.Manifest.permission.MANAGE_FACE; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricsProtoEnums; Loading @@ -45,7 +47,9 @@ import android.os.IBinder; import android.os.NativeHandle; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ShellCallback; import android.os.UserHandle; import android.util.Pair; import android.util.Slog; Loading Loading @@ -444,6 +448,15 @@ public class FaceService extends SystemService { mLockoutResetDispatcher.addCallback(callback, opPackageName); } @Override // Binder call public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) throws RemoteException { (new FaceShellCommand(FaceService.this)) .exec(this, in, out, err, args, callback, resultReceiver); } @Override // Binder call protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { Loading Loading @@ -732,4 +745,19 @@ public class FaceService extends SystemService { * @param handle a handle that was obtained from {@link #acquireSurfaceHandle(Surface)}. */ public static native void releaseSurfaceHandle(@NonNull NativeHandle handle); void syncEnrollmentsNow() { Utils.checkPermissionOrShell(getContext(), MANAGE_FACE); if (Utils.isVirtualEnabled(getContext())) { Slog.i(TAG, "Sync virtual enrollments"); final int userId = ActivityManager.getCurrentUser(); for (ServiceProvider provider : mServiceProviders) { for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */, true /* favorHalEnrollments */); } } } } }
services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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; import android.os.ShellCommand; import java.io.PrintWriter; /** Handles shell commands for {@link FaceService}. */ public class FaceShellCommand extends ShellCommand { private final FaceService mService; public FaceShellCommand(FaceService service) { mService = service; } @Override public int onCommand(String cmd) { if (cmd == null) { onHelp(); return 1; } try { switch (cmd) { case "help": return doHelp(); case "sync": return doSync(); default: getOutPrintWriter().println("Unrecognized command: " + cmd); } } catch (Exception e) { getOutPrintWriter().println("Exception: " + e); } return -1; } @Override public void onHelp() { PrintWriter pw = getOutPrintWriter(); pw.println("Face Service commands:"); pw.println(" help"); pw.println(" Print this help text."); pw.println(" sync"); pw.println(" Sync enrollments now (virtualized sensors only)."); } private int doHelp() { onHelp(); return 0; } private int doSync() { mService.syncEnrollmentsNow(); return 0; } }
services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java +3 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,9 @@ public interface ServiceProvider { void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback); void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments); void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, boolean clearSchedulerBuffer); Loading
services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +9 −0 Original line number Diff line number Diff line Loading @@ -540,6 +540,12 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { @Override public void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback) { scheduleInternalCleanup(sensorId, userId, callback, false /* favorHalEnrollments */); } @Override public void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments) { mHandler.post(() -> { final List<Face> enrolledList = getEnrolledFaces(sensorId, userId); final FaceInternalCleanupClient client = Loading @@ -551,6 +557,9 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { mBiometricContext, enrolledList, FaceUtils.getInstance(sensorId), mSensors.get(sensorId).getAuthenticatorIds()); if (favorHalEnrollments) { client.setFavorHalEnrollments(); } scheduleForSensor(sensorId, client, callback); }); } Loading