Loading services/core/java/com/android/server/biometrics/BiometricService.java +15 −0 Original line number Original line Diff line number Diff line Loading @@ -73,6 +73,7 @@ import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.DumpUtils; import com.android.internal.util.DumpUtils; import com.android.server.SystemService; import com.android.server.SystemService; import com.android.server.biometrics.sensors.CoexCoordinator; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.PrintWriter; Loading Loading @@ -1100,6 +1101,12 @@ public class BiometricService extends SystemService { } } return new ArrayList<>(); return new ArrayList<>(); } } public boolean isAdvancedCoexLogicEnabled(Context context) { return (Build.IS_USERDEBUG || Build.IS_ENG) && Settings.Secure.getInt(context.getContentResolver(), CoexCoordinator.SETTING_ENABLE_NAME, 0) != 0; } } } /** /** Loading @@ -1126,6 +1133,12 @@ public class BiometricService extends SystemService { mSettingObserver = mInjector.getSettingObserver(context, mHandler, mSettingObserver = mInjector.getSettingObserver(context, mHandler, mEnabledOnKeyguardCallbacks); mEnabledOnKeyguardCallbacks); // TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't // need to depend on context. We can remove this code once the advanced logic is enabled // by default. CoexCoordinator coexCoordinator = CoexCoordinator.getInstance(); coexCoordinator.setAdvancedLogicEnabled(injector.isAdvancedCoexLogicEnabled(context)); try { try { injector.getActivityManagerService().registerUserSwitchObserver( injector.getActivityManagerService().registerUserSwitchObserver( new UserSwitchObserver() { new UserSwitchObserver() { Loading Loading @@ -1437,5 +1450,7 @@ public class BiometricService extends SystemService { pw.println(); pw.println(); pw.println("CurrentSession: " + mCurrentAuthSession); pw.println("CurrentSession: " + mCurrentAuthSession); pw.println(); pw.println(); pw.println("CoexCoordinator: " + CoexCoordinator.getInstance().toString()); pw.println(); } } } } services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -359,7 +359,8 @@ public class BiometricScheduler { * @param gestureAvailabilityDispatcher may be null if the sensor does not support gestures * @param gestureAvailabilityDispatcher may be null if the sensor does not support gestures * (such as fingerprint swipe). * (such as fingerprint swipe). */ */ public BiometricScheduler(@NonNull String tag, @SensorType int sensorType, public BiometricScheduler(@NonNull String tag, @SensorType int sensorType, @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { this(tag, sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface( this(tag, sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface( ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS, ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS, Loading services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java +86 −2 Original line number Original line Diff line number Diff line Loading @@ -16,11 +16,17 @@ package com.android.server.biometrics.sensors; package com.android.server.biometrics.sensors; import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FACE; import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_UDFPS; import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTypeToString; import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTypeToString; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.Slog; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.biometrics.sensors.fingerprint.Udfps; import java.util.HashMap; import java.util.HashMap; import java.util.Map; import java.util.Map; Loading @@ -33,6 +39,8 @@ import java.util.Map; public class CoexCoordinator { public class CoexCoordinator { private static final String TAG = "BiometricCoexCoordinator"; private static final String TAG = "BiometricCoexCoordinator"; public static final String SETTING_ENABLE_NAME = "com.android.server.biometrics.sensors.CoexCoordinator.enable"; private static final boolean DEBUG = true; private static final boolean DEBUG = true; /** /** Loading @@ -54,16 +62,30 @@ public class CoexCoordinator { private static CoexCoordinator sInstance; private static CoexCoordinator sInstance; /** * @return a singleton instance. */ @NonNull @NonNull static CoexCoordinator getInstance() { public static CoexCoordinator getInstance() { if (sInstance == null) { if (sInstance == null) { sInstance = new CoexCoordinator(); sInstance = new CoexCoordinator(); } } return sInstance; return sInstance; } } @VisibleForTesting public void setAdvancedLogicEnabled(boolean enabled) { mAdvancedLogicEnabled = enabled; } @VisibleForTesting void reset() { mClientMap.clear(); } // SensorType to AuthenticationClient map // SensorType to AuthenticationClient map private final Map<Integer, AuthenticationClient<?>> mClientMap; private final Map<Integer, AuthenticationClient<?>> mClientMap; private boolean mAdvancedLogicEnabled; private CoexCoordinator() { private CoexCoordinator() { // Singleton // Singleton Loading Loading @@ -105,8 +127,33 @@ public class CoexCoordinator { callback.sendHapticFeedback(); callback.sendHapticFeedback(); // For BP, BiometricService will add the authToken to Keystore. // For BP, BiometricService will add the authToken to Keystore. callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */); callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */); } else if (isUnknownClient(client)) { // Client doesn't exist in our map for some reason. Give the user feedback so the // device doesn't feel like it's stuck. All other cases below can assume that the // client exists in our map. callback.sendHapticFeedback(); callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); } else if (mAdvancedLogicEnabled && client.isKeyguard()) { if (isSingleAuthOnly(client)) { // Single sensor authentication callback.sendHapticFeedback(); callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); } else { // Multi sensor authentication AuthenticationClient<?> udfps = mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null); if (isCurrentFaceAuth(client)) { if (isPointerDown(udfps)) { // Face auth success while UDFPS pointer down. No callback, no haptic. // Feedback will be provided after UDFPS result. } else { callback.sendHapticFeedback(); callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); } } } } else { } else { // Keyguard, FingerprintManager, FaceManager, etc // Non-keyguard authentication. For example, Fingerprint Settings use of // FingerprintManager for highlighting fingers callback.sendHapticFeedback(); callback.sendHapticFeedback(); callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); } } Loading @@ -123,4 +170,41 @@ public class CoexCoordinator { callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */); callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */); } } } } private boolean isCurrentFaceAuth(@NonNull AuthenticationClient<?> client) { return client == mClientMap.getOrDefault(SENSOR_TYPE_FACE, null); } private boolean isPointerDown(@Nullable AuthenticationClient<?> client) { if (client instanceof Udfps) { return ((Udfps) client).isPointerDown(); } return false; } private boolean isUnknownClient(@NonNull AuthenticationClient<?> client) { for (AuthenticationClient<?> c : mClientMap.values()) { if (c == client) { return false; } } return true; } private boolean isSingleAuthOnly(@NonNull AuthenticationClient<?> client) { if (mClientMap.values().size() != 1) { return false; } for (AuthenticationClient<?> c : mClientMap.values()) { if (c != client) { return false; } } return true; } public String toString() { return "Enabled: " + mAdvancedLogicEnabled; } } } services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java +2 −2 Original line number Original line Diff line number Diff line Loading @@ -494,8 +494,8 @@ public class Sensor { mToken = new Binder(); mToken = new Binder(); mHandler = handler; mHandler = handler; mSensorProperties = sensorProperties; mSensorProperties = sensorProperties; mScheduler = new UserAwareBiometricScheduler(tag, BiometricScheduler.SENSOR_TYPE_FACE, mScheduler = new UserAwareBiometricScheduler(tag, null /* gestureAvailabilityDispatcher */, BiometricScheduler.SENSOR_TYPE_FACE, null /* gestureAvailabilityDispatcher */, () -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL, () -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL, new UserAwareBiometricScheduler.UserSwitchCallback() { new UserAwareBiometricScheduler.UserSwitchCallback() { @NonNull @NonNull Loading services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -27,4 +27,5 @@ public interface Udfps { void onPointerDown(int x, int y, float minor, float major); void onPointerDown(int x, int y, float minor, float major); void onPointerUp(); void onPointerUp(); void onUiReady(); void onUiReady(); boolean isPointerDown(); } } Loading
services/core/java/com/android/server/biometrics/BiometricService.java +15 −0 Original line number Original line Diff line number Diff line Loading @@ -73,6 +73,7 @@ import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.DumpUtils; import com.android.internal.util.DumpUtils; import com.android.server.SystemService; import com.android.server.SystemService; import com.android.server.biometrics.sensors.CoexCoordinator; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.PrintWriter; Loading Loading @@ -1100,6 +1101,12 @@ public class BiometricService extends SystemService { } } return new ArrayList<>(); return new ArrayList<>(); } } public boolean isAdvancedCoexLogicEnabled(Context context) { return (Build.IS_USERDEBUG || Build.IS_ENG) && Settings.Secure.getInt(context.getContentResolver(), CoexCoordinator.SETTING_ENABLE_NAME, 0) != 0; } } } /** /** Loading @@ -1126,6 +1133,12 @@ public class BiometricService extends SystemService { mSettingObserver = mInjector.getSettingObserver(context, mHandler, mSettingObserver = mInjector.getSettingObserver(context, mHandler, mEnabledOnKeyguardCallbacks); mEnabledOnKeyguardCallbacks); // TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't // need to depend on context. We can remove this code once the advanced logic is enabled // by default. CoexCoordinator coexCoordinator = CoexCoordinator.getInstance(); coexCoordinator.setAdvancedLogicEnabled(injector.isAdvancedCoexLogicEnabled(context)); try { try { injector.getActivityManagerService().registerUserSwitchObserver( injector.getActivityManagerService().registerUserSwitchObserver( new UserSwitchObserver() { new UserSwitchObserver() { Loading Loading @@ -1437,5 +1450,7 @@ public class BiometricService extends SystemService { pw.println(); pw.println(); pw.println("CurrentSession: " + mCurrentAuthSession); pw.println("CurrentSession: " + mCurrentAuthSession); pw.println(); pw.println(); pw.println("CoexCoordinator: " + CoexCoordinator.getInstance().toString()); pw.println(); } } } }
services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -359,7 +359,8 @@ public class BiometricScheduler { * @param gestureAvailabilityDispatcher may be null if the sensor does not support gestures * @param gestureAvailabilityDispatcher may be null if the sensor does not support gestures * (such as fingerprint swipe). * (such as fingerprint swipe). */ */ public BiometricScheduler(@NonNull String tag, @SensorType int sensorType, public BiometricScheduler(@NonNull String tag, @SensorType int sensorType, @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { this(tag, sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface( this(tag, sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface( ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS, ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS, Loading
services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java +86 −2 Original line number Original line Diff line number Diff line Loading @@ -16,11 +16,17 @@ package com.android.server.biometrics.sensors; package com.android.server.biometrics.sensors; import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FACE; import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_UDFPS; import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTypeToString; import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTypeToString; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.Slog; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.biometrics.sensors.fingerprint.Udfps; import java.util.HashMap; import java.util.HashMap; import java.util.Map; import java.util.Map; Loading @@ -33,6 +39,8 @@ import java.util.Map; public class CoexCoordinator { public class CoexCoordinator { private static final String TAG = "BiometricCoexCoordinator"; private static final String TAG = "BiometricCoexCoordinator"; public static final String SETTING_ENABLE_NAME = "com.android.server.biometrics.sensors.CoexCoordinator.enable"; private static final boolean DEBUG = true; private static final boolean DEBUG = true; /** /** Loading @@ -54,16 +62,30 @@ public class CoexCoordinator { private static CoexCoordinator sInstance; private static CoexCoordinator sInstance; /** * @return a singleton instance. */ @NonNull @NonNull static CoexCoordinator getInstance() { public static CoexCoordinator getInstance() { if (sInstance == null) { if (sInstance == null) { sInstance = new CoexCoordinator(); sInstance = new CoexCoordinator(); } } return sInstance; return sInstance; } } @VisibleForTesting public void setAdvancedLogicEnabled(boolean enabled) { mAdvancedLogicEnabled = enabled; } @VisibleForTesting void reset() { mClientMap.clear(); } // SensorType to AuthenticationClient map // SensorType to AuthenticationClient map private final Map<Integer, AuthenticationClient<?>> mClientMap; private final Map<Integer, AuthenticationClient<?>> mClientMap; private boolean mAdvancedLogicEnabled; private CoexCoordinator() { private CoexCoordinator() { // Singleton // Singleton Loading Loading @@ -105,8 +127,33 @@ public class CoexCoordinator { callback.sendHapticFeedback(); callback.sendHapticFeedback(); // For BP, BiometricService will add the authToken to Keystore. // For BP, BiometricService will add the authToken to Keystore. callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */); callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */); } else if (isUnknownClient(client)) { // Client doesn't exist in our map for some reason. Give the user feedback so the // device doesn't feel like it's stuck. All other cases below can assume that the // client exists in our map. callback.sendHapticFeedback(); callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); } else if (mAdvancedLogicEnabled && client.isKeyguard()) { if (isSingleAuthOnly(client)) { // Single sensor authentication callback.sendHapticFeedback(); callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); } else { // Multi sensor authentication AuthenticationClient<?> udfps = mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null); if (isCurrentFaceAuth(client)) { if (isPointerDown(udfps)) { // Face auth success while UDFPS pointer down. No callback, no haptic. // Feedback will be provided after UDFPS result. } else { callback.sendHapticFeedback(); callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); } } } } else { } else { // Keyguard, FingerprintManager, FaceManager, etc // Non-keyguard authentication. For example, Fingerprint Settings use of // FingerprintManager for highlighting fingers callback.sendHapticFeedback(); callback.sendHapticFeedback(); callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); } } Loading @@ -123,4 +170,41 @@ public class CoexCoordinator { callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */); callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */); } } } } private boolean isCurrentFaceAuth(@NonNull AuthenticationClient<?> client) { return client == mClientMap.getOrDefault(SENSOR_TYPE_FACE, null); } private boolean isPointerDown(@Nullable AuthenticationClient<?> client) { if (client instanceof Udfps) { return ((Udfps) client).isPointerDown(); } return false; } private boolean isUnknownClient(@NonNull AuthenticationClient<?> client) { for (AuthenticationClient<?> c : mClientMap.values()) { if (c == client) { return false; } } return true; } private boolean isSingleAuthOnly(@NonNull AuthenticationClient<?> client) { if (mClientMap.values().size() != 1) { return false; } for (AuthenticationClient<?> c : mClientMap.values()) { if (c != client) { return false; } } return true; } public String toString() { return "Enabled: " + mAdvancedLogicEnabled; } } }
services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java +2 −2 Original line number Original line Diff line number Diff line Loading @@ -494,8 +494,8 @@ public class Sensor { mToken = new Binder(); mToken = new Binder(); mHandler = handler; mHandler = handler; mSensorProperties = sensorProperties; mSensorProperties = sensorProperties; mScheduler = new UserAwareBiometricScheduler(tag, BiometricScheduler.SENSOR_TYPE_FACE, mScheduler = new UserAwareBiometricScheduler(tag, null /* gestureAvailabilityDispatcher */, BiometricScheduler.SENSOR_TYPE_FACE, null /* gestureAvailabilityDispatcher */, () -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL, () -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL, new UserAwareBiometricScheduler.UserSwitchCallback() { new UserAwareBiometricScheduler.UserSwitchCallback() { @NonNull @NonNull Loading
services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -27,4 +27,5 @@ public interface Udfps { void onPointerDown(int x, int y, float minor, float major); void onPointerDown(int x, int y, float minor, float major); void onPointerUp(); void onPointerUp(); void onUiReady(); void onUiReady(); boolean isPointerDown(); } }