summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2021-07-19 19:25:44 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2021-07-19 19:25:44 +0000
commitc4815d0f2d03ad5e08e1053d2f3431a788dc97ab (patch)
tree323790e2912e68e2db43999f15d0b7723c4f882b
parentc4adbc278e61ca62d8deeeb906ec29d951a8a243 (diff)
parent164f70d4f10291fdee6f59321e5688b8d5d25031 (diff)
Merge "4/n: Make CoexCoordinator multi-sensor-aware" into sc-dev
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java83
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java48
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java14
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java2
12 files changed, 150 insertions, 24 deletions
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index adda10eb109f..61266071f788 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.IBiometricService;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -48,8 +49,11 @@ import java.util.Locale;
/**
* A scheduler for biometric HAL operations. Maintains a queue of {@link BaseClientMonitor}
- * operations, without caring about its implementation details. Operations may perform one or more
+ * operations, without caring about its implementation details. Operations may perform zero or more
* interactions with the HAL before finishing.
+ *
+ * We currently assume (and require) that each biometric sensor have its own instance of a
+ * {@link BiometricScheduler}. See {@link CoexCoordinator}.
*/
public class BiometricScheduler {
@@ -58,6 +62,55 @@ public class BiometricScheduler {
protected static final int LOG_NUM_RECENT_OPERATIONS = 50;
/**
+ * Unknown sensor type. This should never be used, and is a sign that something is wrong during
+ * initialization.
+ */
+ public static final int SENSOR_TYPE_UNKNOWN = 0;
+
+ /**
+ * Face authentication.
+ */
+ public static final int SENSOR_TYPE_FACE = 1;
+
+ /**
+ * Any UDFPS type. See {@link FingerprintSensorPropertiesInternal#isAnyUdfpsType()}.
+ */
+ public static final int SENSOR_TYPE_UDFPS = 2;
+
+ /**
+ * Any other fingerprint sensor. We can add additional definitions in the future when necessary.
+ */
+ public static final int SENSOR_TYPE_FP_OTHER = 3;
+
+ @IntDef({SENSOR_TYPE_UNKNOWN, SENSOR_TYPE_FACE, SENSOR_TYPE_UDFPS, SENSOR_TYPE_FP_OTHER})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SensorType {}
+
+ public static @SensorType int sensorTypeFromFingerprintProperties(
+ @NonNull FingerprintSensorPropertiesInternal props) {
+ if (props.isAnyUdfpsType()) {
+ return SENSOR_TYPE_UDFPS;
+ }
+
+ return SENSOR_TYPE_FP_OTHER;
+ }
+
+ public static String sensorTypeToString(@SensorType int sensorType) {
+ switch (sensorType) {
+ case SENSOR_TYPE_UNKNOWN:
+ return "Unknown";
+ case SENSOR_TYPE_FACE:
+ return "Face";
+ case SENSOR_TYPE_UDFPS:
+ return "Udfps";
+ case SENSOR_TYPE_FP_OTHER:
+ return "OtherFp";
+ default:
+ return "UnknownUnknown";
+ }
+ }
+
+ /**
* Contains all the necessary information for a HAL operation.
*/
@VisibleForTesting
@@ -207,6 +260,7 @@ public class BiometricScheduler {
}
@NonNull protected final String mBiometricTag;
+ private final @SensorType int mSensorType;
@Nullable private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@NonNull private final IBiometricService mBiometricService;
@NonNull protected final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -218,6 +272,7 @@ public class BiometricScheduler {
private int mTotalOperationsHandled;
private final int mRecentOperationsLimit;
@NonNull private final List<Integer> mRecentOperations;
+ @NonNull private final CoexCoordinator mCoexCoordinator;
// Internal callback, notified when an operation is complete. Notifies the requester
// that the operation is complete, before performing internal scheduler work (such as
@@ -226,6 +281,12 @@ public class BiometricScheduler {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
Slog.d(getTag(), "[Started] " + clientMonitor);
+
+ if (clientMonitor instanceof AuthenticationClient) {
+ mCoexCoordinator.addAuthenticationClient(mSensorType,
+ (AuthenticationClient<?>) clientMonitor);
+ }
+
if (mCurrentOperation.mClientCallback != null) {
mCurrentOperation.mClientCallback.onClientStarted(clientMonitor);
}
@@ -248,6 +309,11 @@ public class BiometricScheduler {
}
Slog.d(getTag(), "[Finishing] " + clientMonitor + ", success: " + success);
+ if (clientMonitor instanceof AuthenticationClient) {
+ mCoexCoordinator.removeAuthenticationClient(mSensorType,
+ (AuthenticationClient<?>) clientMonitor);
+ }
+
mCurrentOperation.mState = Operation.STATE_FINISHED;
if (mCurrentOperation.mClientCallback != null) {
@@ -271,10 +337,12 @@ public class BiometricScheduler {
}
@VisibleForTesting
- BiometricScheduler(@NonNull String tag,
+ BiometricScheduler(@NonNull String tag, @SensorType int sensorType,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
- @NonNull IBiometricService biometricService, int recentOperationsLimit) {
+ @NonNull IBiometricService biometricService, int recentOperationsLimit,
+ @NonNull CoexCoordinator coexCoordinator) {
mBiometricTag = tag;
+ mSensorType = sensorType;
mInternalCallback = new InternalCallback();
mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;
mPendingOperations = new ArrayDeque<>();
@@ -282,6 +350,7 @@ public class BiometricScheduler {
mCrashStates = new ArrayDeque<>();
mRecentOperationsLimit = recentOperationsLimit;
mRecentOperations = new ArrayList<>();
+ mCoexCoordinator = coexCoordinator;
}
/**
@@ -290,10 +359,11 @@ public class BiometricScheduler {
* @param gestureAvailabilityDispatcher may be null if the sensor does not support gestures
* (such as fingerprint swipe).
*/
- public BiometricScheduler(@NonNull String tag,
+ public BiometricScheduler(@NonNull String tag, @SensorType int sensorType,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- this(tag, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface(
- ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS);
+ this(tag, sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS,
+ CoexCoordinator.getInstance());
}
/**
@@ -645,6 +715,7 @@ public class BiometricScheduler {
public void dump(PrintWriter pw) {
pw.println("Dump of BiometricScheduler " + getTag());
+ pw.println("Type: " + mSensorType);
pw.println("Current operation: " + mCurrentOperation);
pw.println("Pending operations: " + mPendingOperations.size());
for (Operation operation : mPendingOperations) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
index cccb6e2d3c90..08bf2e020f75 100644
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
@@ -16,7 +16,13 @@
package com.android.server.biometrics.sensors;
+import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTypeToString;
+
import android.annotation.NonNull;
+import android.util.Slog;
+
+import java.util.HashMap;
+import java.util.Map;
/**
* Singleton that contains the core logic for determining if haptics and authentication callbacks
@@ -27,6 +33,7 @@ import android.annotation.NonNull;
public class CoexCoordinator {
private static final String TAG = "BiometricCoexCoordinator";
+ private static final boolean DEBUG = true;
/**
* Callback interface notifying the owner of "results" from the CoexCoordinator's business
@@ -47,10 +54,6 @@ public class CoexCoordinator {
private static CoexCoordinator sInstance;
- private CoexCoordinator() {
- // Singleton
- }
-
@NonNull
static CoexCoordinator getInstance() {
if (sInstance == null) {
@@ -59,6 +62,43 @@ public class CoexCoordinator {
return sInstance;
}
+ // SensorType to AuthenticationClient map
+ private final Map<Integer, AuthenticationClient<?>> mClientMap;
+
+ private CoexCoordinator() {
+ // Singleton
+ mClientMap = new HashMap<>();
+ }
+
+ public void addAuthenticationClient(@BiometricScheduler.SensorType int sensorType,
+ @NonNull AuthenticationClient<?> client) {
+ if (DEBUG) {
+ Slog.d(TAG, "addAuthenticationClient(" + sensorTypeToString(sensorType) + ")"
+ + ", client: " + client);
+ }
+
+ if (mClientMap.containsKey(sensorType)) {
+ Slog.w(TAG, "Overwriting existing client: " + mClientMap.get(sensorType)
+ + " with new client: " + client);
+ }
+
+ mClientMap.put(sensorType, client);
+ }
+
+ public void removeAuthenticationClient(@BiometricScheduler.SensorType int sensorType,
+ @NonNull AuthenticationClient<?> client) {
+ if (DEBUG) {
+ Slog.d(TAG, "removeAuthenticationClient(" + sensorTypeToString(sensorType) + ")"
+ + ", client: " + client);
+ }
+
+ if (!mClientMap.containsKey(sensorType)) {
+ Slog.e(TAG, "sensorType: " + sensorType + " does not exist in map. Client: " + client);
+ return;
+ }
+ mClientMap.remove(sensorType);
+ }
+
public void onAuthenticationSucceeded(@NonNull AuthenticationClient<?> client,
@NonNull Callback callback) {
if (client.isBiometricPrompt()) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
index e6e293eb9b4c..b056bf897b5c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
@@ -83,24 +83,26 @@ public class UserAwareBiometricScheduler extends BiometricScheduler {
}
@VisibleForTesting
- UserAwareBiometricScheduler(@NonNull String tag,
+ UserAwareBiometricScheduler(@NonNull String tag, @SensorType int sensorType,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull IBiometricService biometricService,
@NonNull CurrentUserRetriever currentUserRetriever,
- @NonNull UserSwitchCallback userSwitchCallback) {
- super(tag, gestureAvailabilityDispatcher, biometricService, LOG_NUM_RECENT_OPERATIONS);
+ @NonNull UserSwitchCallback userSwitchCallback,
+ @NonNull CoexCoordinator coexCoordinator) {
+ super(tag, sensorType, gestureAvailabilityDispatcher, biometricService,
+ LOG_NUM_RECENT_OPERATIONS, coexCoordinator);
mCurrentUserRetriever = currentUserRetriever;
mUserSwitchCallback = userSwitchCallback;
}
- public UserAwareBiometricScheduler(@NonNull String tag,
+ public UserAwareBiometricScheduler(@NonNull String tag, @SensorType int sensorType,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull CurrentUserRetriever currentUserRetriever,
@NonNull UserSwitchCallback userSwitchCallback) {
- this(tag, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface(
+ this(tag, sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE)), currentUserRetriever,
- userSwitchCallback);
+ userSwitchCallback, CoexCoordinator.getInstance());
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 2f71f44b6bef..4abd402a4da8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -494,7 +494,8 @@ public class Sensor {
mToken = new Binder();
mHandler = handler;
mSensorProperties = sensorProperties;
- mScheduler = new UserAwareBiometricScheduler(tag, null /* gestureAvailabilityDispatcher */,
+ mScheduler = new UserAwareBiometricScheduler(tag, BiometricScheduler.SENSOR_TYPE_FACE,
+ null /* gestureAvailabilityDispatcher */,
() -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL,
new UserAwareBiometricScheduler.UserSwitchCallback() {
@NonNull
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 26c5bca7f726..e95273ae6a41 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -355,7 +355,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
public Face10(@NonNull Context context, @NonNull FaceSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
this(context, sensorProps, lockoutResetDispatcher,
- new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */));
+ new BiometricScheduler(TAG, BiometricScheduler.SENSOR_TYPE_FACE,
+ null /* gestureAvailabilityTracker */));
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index b3b818fd6d3d..59e4b582ca84 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -449,7 +449,9 @@ class Sensor {
mHandler = handler;
mSensorProperties = sensorProperties;
mLockoutCache = new LockoutCache();
- mScheduler = new UserAwareBiometricScheduler(tag, gestureAvailabilityDispatcher,
+ mScheduler = new UserAwareBiometricScheduler(tag,
+ BiometricScheduler.sensorTypeFromFingerprintProperties(mSensorProperties),
+ gestureAvailabilityDispatcher,
() -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL,
new UserAwareBiometricScheduler.UserSwitchCallback() {
@NonNull
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 7daea88f0f22..a6385a541b03 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -352,7 +352,9 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
final Handler handler = new Handler(Looper.getMainLooper());
final BiometricScheduler scheduler =
- new BiometricScheduler(TAG, gestureAvailabilityDispatcher);
+ new BiometricScheduler(TAG,
+ BiometricScheduler.sensorTypeFromFingerprintProperties(sensorProps),
+ gestureAvailabilityDispatcher);
final HalResultController controller = new HalResultController(sensorProps.sensorId,
context, handler,
scheduler);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index d1020a6ff068..312c52c4a844 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -138,7 +138,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
TestableBiometricScheduler(@NonNull String tag,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- super(tag, gestureAvailabilityDispatcher);
+ super(tag, BiometricScheduler.SENSOR_TYPE_FP_OTHER, gestureAvailabilityDispatcher);
mInternalCallback = new TestableInternalCallback();
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 109fb22520c8..a8bf0c751e87 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -75,8 +75,9 @@ public class BiometricSchedulerTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mToken = new Binder();
- mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */,
- mBiometricService, LOG_NUM_RECENT_OPERATIONS);
+ mScheduler = new BiometricScheduler(TAG, BiometricScheduler.SENSOR_TYPE_UNKNOWN,
+ null /* gestureAvailabilityTracker */, mBiometricService, LOG_NUM_RECENT_OPERATIONS,
+ CoexCoordinator.getInstance());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
index 3a9e629b6ed6..7fccd49db04b 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
@@ -74,6 +74,7 @@ public class UserAwareBiometricSchedulerTest {
mUserStoppedCallback = new TestUserStoppedCallback();
mScheduler = new UserAwareBiometricScheduler(TAG,
+ BiometricScheduler.SENSOR_TYPE_UNKNOWN,
null /* gestureAvailabilityDispatcher */,
mBiometricService,
() -> mCurrentUserId,
@@ -92,7 +93,8 @@ public class UserAwareBiometricSchedulerTest {
return new TestStartUserClient(mContext, Object::new, mToken, newUserId,
TEST_SENSOR_ID, mUserStartedCallback, mStartOperationsFinish);
}
- });
+ },
+ CoexCoordinator.getInstance());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
index b8fbe34a7dcb..a13dff21439d 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
@@ -32,6 +32,7 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -78,6 +79,7 @@ public class SensorTest {
when(mContext.getSystemService(Context.BIOMETRIC_SERVICE)).thenReturn(mBiometricService);
mScheduler = new UserAwareBiometricScheduler(TAG,
+ BiometricScheduler.SENSOR_TYPE_FACE,
null /* gestureAvailabilityDispatcher */,
() -> USER_ID,
mUserSwitchCallback);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
index 5dfc24889815..0d520ca9a4e4 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
@@ -32,6 +32,7 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -78,6 +79,7 @@ public class SensorTest {
when(mContext.getSystemService(Context.BIOMETRIC_SERVICE)).thenReturn(mBiometricService);
mScheduler = new UserAwareBiometricScheduler(TAG,
+ BiometricScheduler.SENSOR_TYPE_FP_OTHER,
null /* gestureAvailabilityDispatcher */,
() -> USER_ID,
mUserSwitchCallback);